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";