'ok', 'timestamp' => now()->toISOString(), 'version' => config('app.version', '1.0.0'), 'server' => config('app.url'), 'database' => [ 'connection' => config('database.default'), 'status' => 'ok' ], 'storage' => [ 'disk' => config('filesystems.default'), 'available' => true ], 'administrators_count' => Amministratore::count(), 'features' => [ 'multi_database' => true, 'distribution' => true, 'migration' => true, 'backup' => true ] ]; // Test connessione database try { DB::connection()->getPdo(); } catch (\Exception $e) { $health['database']['status'] = 'error'; $health['database']['error'] = $e->getMessage(); $health['status'] = 'degraded'; } // Test storage try { Storage::disk()->exists('.'); } catch (\Exception $e) { $health['storage']['available'] = false; $health['storage']['error'] = $e->getMessage(); $health['status'] = 'degraded'; } return response()->json($health); } catch (\Exception $e) { return response()->json([ 'status' => 'error', 'error' => $e->getMessage(), 'timestamp' => now()->toISOString() ], 500); } } /** * Importa archivio amministratore da altro server */ public function importAdministrator(Request $request): JsonResponse { try { $request->validate([ 'codice_amministratore' => 'required|string|size:8', 'source_server' => 'required|url', 'migration_token' => 'required|string', 'archive' => 'required|file|mimes:zip|max:1048576' // Max 1GB ]); $codiceAmministratore = $request->input('codice_amministratore'); $sourceServer = $request->input('source_server'); $migrationToken = $request->input('migration_token'); Log::info("Inizio importazione amministratore {$codiceAmministratore} da {$sourceServer}"); // Verifica che l'amministratore non esista già if (Amministratore::where('codice_amministratore', $codiceAmministratore)->exists()) { return response()->json([ 'success' => false, 'error' => 'Amministratore già presente su questo server' ], 409); } // Salva archivio temporaneo $archive = $request->file('archive'); $tempPath = storage_path("app/temp/import_{$codiceAmministratore}_" . time() . ".zip"); if (!is_dir(dirname($tempPath))) { mkdir(dirname($tempPath), 0755, true); } $archive->move(dirname($tempPath), basename($tempPath)); // Estrae archivio $extractPath = storage_path("app/amministratori/{$codiceAmministratore}"); $zip = new \ZipArchive(); if ($zip->open($tempPath) !== TRUE) { throw new \Exception('Impossibile aprire archivio ZIP'); } $zip->extractTo($extractPath); $zip->close(); // Rimuove file temporaneo unlink($tempPath); Log::info("Archivio amministratore {$codiceAmministratore} estratto in {$extractPath}"); return response()->json([ 'success' => true, 'message' => 'Archivio importato con successo', 'transfer_id' => uniqid('transfer_'), 'extracted_to' => $extractPath, 'imported_at' => now()->toISOString() ]); } catch (\Exception $e) { Log::error("Errore importazione amministratore: " . $e->getMessage()); return response()->json([ 'success' => false, 'error' => $e->getMessage() ], 500); } } /** * Attiva amministratore dopo importazione */ public function activateAdministrator(Request $request): JsonResponse { try { $request->validate([ 'codice_amministratore' => 'required|string|size:8', 'activation_token' => 'required|string' ]); $codiceAmministratore = $request->input('codice_amministratore'); Log::info("Attivazione amministratore {$codiceAmministratore}"); // Verifica che l'archivio sia stato importato $archivePath = storage_path("app/amministratori/{$codiceAmministratore}"); if (!is_dir($archivePath)) { throw new \Exception('Archivio amministratore non trovato. Importare prima l\'archivio.'); } // Cerca metadata $metadataPath = storage_path("app/migrations/metadata_{$codiceAmministratore}.json"); if (!file_exists($metadataPath)) { throw new \Exception('Metadata migrazione non trovati'); } $metadata = json_decode(file_get_contents($metadataPath), true); // Crea record amministratore nel database $amministratore = Amministratore::create([ 'nome' => $metadata['amministratore']['nome'], 'cognome' => $metadata['amministratore']['cognome'], 'denominazione_studio' => $metadata['amministratore']['denominazione_studio'], 'codice_amministratore' => $codiceAmministratore, 'user_id' => 1, // TODO: gestire user associato 'database_attivo' => $metadata['amministratore']['database_name'], 'cartella_dati' => "amministratori/{$codiceAmministratore}", 'stato_sincronizzazione' => 'attivo', 'attivo' => true ]); // Ripristina database se presente $backupFiles = glob($archivePath . '/backup/database/*.sql'); if (!empty($backupFiles)) { $latestBackup = end($backupFiles); $this->restoreDatabase($amministratore, $latestBackup); } Log::info("Amministratore {$codiceAmministratore} attivato con successo"); return response()->json([ 'success' => true, 'message' => 'Amministratore attivato con successo', 'administrator_id' => $amministratore->id, 'database_restored' => !empty($backupFiles), 'activated_at' => now()->toISOString() ]); } catch (\Exception $e) { Log::error("Errore attivazione amministratore: " . $e->getMessage()); return response()->json([ 'success' => false, 'error' => $e->getMessage() ], 500); } } /** * Sincronizza dati amministratore */ public function syncAdministrator(Request $request): JsonResponse { try { $request->validate([ 'codice_amministratore' => 'required|string|size:8', 'last_sync' => 'nullable|date', 'sync_token' => 'required|string' ]); $codiceAmministratore = $request->input('codice_amministratore'); $lastSync = $request->input('last_sync'); $amministratore = Amministratore::where('codice_amministratore', $codiceAmministratore)->first(); if (!$amministratore) { return response()->json([ 'success' => false, 'error' => 'Amministratore non trovato' ], 404); } // Simula sincronizzazione (da implementare logica specifica) $changes = 0; if ($lastSync) { // Conta modifiche dalla data di ultima sincronizzazione // TODO: implementare logica di tracking modifiche } return response()->json([ 'success' => true, 'changes' => $changes, 'last_sync' => $amministratore->updated_at, 'synced_at' => now()->toISOString() ]); } catch (\Exception $e) { return response()->json([ 'success' => false, 'error' => $e->getMessage() ], 500); } } /** * Esegue backup amministratore */ public function backupAdministrator(Request $request): JsonResponse { try { $request->validate([ 'codice_amministratore' => 'required|string|size:8', 'backup_token' => 'required|string' ]); $codiceAmministratore = $request->input('codice_amministratore'); $amministratore = Amministratore::where('codice_amministratore', $codiceAmministratore)->first(); if (!$amministratore) { return response()->json([ 'success' => false, 'error' => 'Amministratore non trovato' ], 404); } $backupResult = $amministratore->createDatabaseBackup(); if ($backupResult['success']) { $amministratore->update(['ultimo_backup' => now()]); } return response()->json($backupResult); } catch (\Exception $e) { return response()->json([ 'success' => false, 'error' => $e->getMessage() ], 500); } } /** * Ottiene informazioni routing per amministratore */ public function getAdministratorRouting(string $codice): JsonResponse { try { $routingInfo = DistributionService::getAdministratorAccessUrl($codice); return response()->json($routingInfo); } catch (\Exception $e) { return response()->json([ 'success' => false, 'error' => $e->getMessage() ], 500); } } /** * Ripristina database da backup */ private function restoreDatabase(Amministratore $amministratore, string $backupPath): bool { try { $dbName = $amministratore->getDatabaseName(); // Crea database se non esiste DB::statement("CREATE DATABASE IF NOT EXISTS `{$dbName}` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"); // Ripristina da backup $command = sprintf( 'mysql -h %s -u %s -p%s %s < %s', env('DB_HOST', '127.0.0.1'), env('DB_USERNAME'), env('DB_PASSWORD'), escapeshellarg($dbName), escapeshellarg($backupPath) ); exec($command, $output, $returnCode); return $returnCode === 0; } catch (\Exception $e) { Log::error("Errore ripristino database: " . $e->getMessage()); return false; } } }