JSON → MySQL migraatio: tietokantapohjainen datatallennus

Lisätty:
- db.php: PDO-tietokantakerros (kaikki CRUD-funktiot)
- migrate.php: JSON → MySQL migraatioskripti
- db_config.php lisätty .gitignore:en (sisältää tunnukset)

Muutettu:
- api.php: kaikki JSON load/save → db*() funktiot
- session.cookie_samesite: Strict → Lax (captcha-fix alias-domaineilla)
- Poistettu kaikki JSON-tiedosto I/O (paitsi tiedostoupload + logot)

Hyödyt:
- Git deploy ei enää ylikirjoita dataa
- Tiedostolukot ja transaktiot → ei korruptiota
- Parempi suorituskyky isoilla tietomäärillä

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-10 15:00:38 +02:00
parent c714f39bc5
commit 13e0d1255f
4 changed files with 1615 additions and 910 deletions

1
.gitignore vendored
View File

@@ -1,2 +1,3 @@
data/backups/ data/backups/
data/files/ data/files/
db_config.php

1126
api.php

File diff suppressed because it is too large Load Diff

1046
db.php Normal file

File diff suppressed because it is too large Load Diff

200
migrate.php Normal file
View File

@@ -0,0 +1,200 @@
<?php
/**
* Noxus Intra — JSON → MySQL migraatioskripti
*
* Aja kerran: php migrate.php
* Lukee kaikki data/*.json -tiedostot ja siirtää ne MySQL-tietokantaan.
*/
require_once __DIR__ . '/db.php';
echo "=== Noxus Intra: JSON → MySQL migraatio ===\n\n";
// 1. Luo taulut
echo "1. Luodaan tietokantarakenne...\n";
initDatabase();
echo " ✓ Taulut luotu\n\n";
$dataDir = __DIR__ . '/data';
// 2. Yritykset
echo "2. Siirretään yritykset...\n";
$companiesFile = $dataDir . '/companies.json';
$companies = file_exists($companiesFile) ? json_decode(file_get_contents($companiesFile), true) : [];
$companyCount = 0;
foreach ($companies as $c) {
dbSaveCompany($c);
$companyCount++;
echo "{$c['nimi']} (id: {$c['id']})\n";
}
echo " Yhteensä: $companyCount yritystä\n\n";
// 3. Käyttäjät
echo "3. Siirretään käyttäjät...\n";
$usersFile = $dataDir . '/users.json';
$users = file_exists($usersFile) ? json_decode(file_get_contents($usersFile), true) : [];
$userCount = 0;
foreach ($users as $u) {
dbSaveUser($u);
$userCount++;
echo "{$u['username']} ({$u['role']})\n";
}
echo " Yhteensä: $userCount käyttäjää\n\n";
// 4. Globaalit asetukset
echo "4. Siirretään globaalit asetukset...\n";
$configFile = $dataDir . '/config.json';
if (file_exists($configFile)) {
$config = json_decode(file_get_contents($configFile), true) ?: [];
dbSaveConfig($config);
echo " ✓ config.json siirretty\n";
}
echo "\n";
// 5. Salasanan palautustokenit
echo "5. Siirretään reset-tokenit...\n";
$tokensFile = $dataDir . '/reset_tokens.json';
if (file_exists($tokensFile)) {
$tokens = json_decode(file_get_contents($tokensFile), true) ?: [];
$db = getDb();
foreach ($tokens as $t) {
try {
$stmt = $db->prepare("INSERT IGNORE INTO reset_tokens (user_id, token, created_at) VALUES (?, ?, ?)");
$expires = $t['expires'] ?? time();
$created = date('Y-m-d H:i:s', $expires - 3600); // Arvio luontiajasta
$stmt->execute([$t['user_id'], $t['token'], $created]);
} catch (Exception $e) {
echo " ⚠ Token ohitettu: " . $e->getMessage() . "\n";
}
}
echo "" . count($tokens) . " tokenia\n";
}
echo "\n";
// 6. Yrityskohtainen data
echo "6. Siirretään yrityskohtainen data...\n";
$companiesDir = $dataDir . '/companies';
if (is_dir($companiesDir)) {
$dirs = array_filter(scandir($companiesDir), fn($d) => $d !== '.' && $d !== '..' && is_dir("$companiesDir/$d"));
foreach ($dirs as $companyId) {
$compDir = "$companiesDir/$companyId";
echo "\n === $companyId ===\n";
// Yrityksen config (postilaatikot, tikettisäännöt, api_key, cors_origins)
$compConfig = "$compDir/config.json";
if (file_exists($compConfig)) {
$cfg = json_decode(file_get_contents($compConfig), true) ?: [];
// Postilaatikot
$mailboxes = $cfg['mailboxes'] ?? [];
foreach ($mailboxes as $mb) {
dbSaveMailbox($companyId, $mb);
}
echo "" . count($mailboxes) . " postilaatikkoa\n";
// Tikettisäännöt
$rules = $cfg['ticket_rules'] ?? [];
foreach ($rules as $rule) {
dbSaveTicketRule($companyId, $rule);
}
echo "" . count($rules) . " tikettisääntöä\n";
// API-avain ja CORS
if (!empty($cfg['api_key'])) {
dbSetCompanyApiKey($companyId, $cfg['api_key']);
echo " ✓ API-avain\n";
}
if (!empty($cfg['cors_origins'])) {
dbSetCompanyCorsOrigins($companyId, $cfg['cors_origins']);
echo " ✓ CORS-asetukset\n";
}
}
// Asiakkaat
$custFile = "$compDir/customers.json";
if (file_exists($custFile)) {
$customers = json_decode(file_get_contents($custFile), true) ?: [];
foreach ($customers as $cust) {
// Migroi vanhat flat-kentät liittymiksi jos tarpeen
if (!isset($cust['liittymat'])) {
$cust['liittymat'] = [];
if (!empty($cust['asennusosoite'] ?? '') || !empty($cust['liittymanopeus'] ?? '')) {
$cust['liittymat'][] = [
'asennusosoite' => $cust['asennusosoite'] ?? '',
'postinumero' => $cust['postinumero'] ?? '',
'kaupunki' => $cust['kaupunki'] ?? '',
'liittymanopeus' => $cust['liittymanopeus'] ?? '',
'hinta' => $cust['hinta'] ?? 0,
'sopimuskausi' => $cust['sopimuskausi'] ?? '',
'alkupvm' => $cust['alkupvm'] ?? '',
];
}
}
dbSaveCustomer($companyId, $cust);
}
echo "" . count($customers) . " asiakasta\n";
}
// Liidit
$leadsFile = "$compDir/leads.json";
if (file_exists($leadsFile)) {
$leads = json_decode(file_get_contents($leadsFile), true) ?: [];
foreach ($leads as $lead) {
dbSaveLead($companyId, $lead);
}
echo "" . count($leads) . " liidiä\n";
}
// Tiketit
$ticketsFile = "$compDir/tickets.json";
if (file_exists($ticketsFile)) {
$tickets = json_decode(file_get_contents($ticketsFile), true) ?: [];
foreach ($tickets as $ticket) {
dbSaveTicket($companyId, $ticket);
}
echo "" . count($tickets) . " tikettiä\n";
}
// Arkisto
$archiveFile = "$compDir/archive.json";
if (file_exists($archiveFile)) {
$archives = json_decode(file_get_contents($archiveFile), true) ?: [];
foreach ($archives as $arc) {
if (!empty($arc['id'])) {
dbArchiveCustomer($companyId, $arc);
}
}
echo "" . count($archives) . " arkistoitua\n";
}
// Changelog
$logFile = "$compDir/changelog.json";
if (file_exists($logFile)) {
$logs = json_decode(file_get_contents($logFile), true) ?: [];
$db = getDb();
$stmt = $db->prepare("
INSERT IGNORE INTO changelog (id, company_id, timestamp, user, action, customer_id, customer_name, details)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
");
foreach ($logs as $log) {
$stmt->execute([
$log['id'] ?? bin2hex(random_bytes(8)),
$companyId,
$log['timestamp'] ?? date('Y-m-d H:i:s'),
$log['user'] ?? '',
$log['action'] ?? '',
$log['customer_id'] ?? '',
$log['customer_name'] ?? '',
$log['details'] ?? '',
]);
}
echo "" . count($logs) . " lokimerkintää\n";
}
}
}
echo "\n=== Migraatio valmis! ===\n";
echo "\nSeuraavat vaiheet:\n";
echo "1. Testaa: php -r \"require 'db.php'; print_r(dbLoadCompanies());\"\n";
echo "2. Ota MySQL-pohjainen api.php käyttöön\n";