argument('path'); $userId = $this->option('user-id'); $dryRun = $this->option('dry-run'); // Validate path if (!File::isDirectory($path)) { $this->error("Directory not found: {$path}"); return 1; } // Check for manifest.json $manifestPath = $path . '/manifest.json'; if (!File::exists($manifestPath)) { $this->error("manifest.json not found in {$path}"); $this->info("Expected format:"); $this->line($this->getManifestExample()); return 1; } // Load manifest $manifest = json_decode(File::get($manifestPath), true); if (!$manifest || !isset($manifest['documents'])) { $this->error("Invalid manifest.json format"); return 1; } // Validate user $user = User::find($userId); if (!$user) { $this->error("User not found: {$userId}"); return 1; } $this->info("Importing documents from: {$path}"); $this->info("Attributed to: {$user->name}"); if ($dryRun) { $this->warn("DRY RUN - No changes will be made"); } $this->newLine(); $successCount = 0; $errorCount = 0; foreach ($manifest['documents'] as $item) { try { $this->processDocument($path, $item, $user, $dryRun); $successCount++; } catch (\Exception $e) { $this->error("Error processing {$item['file']}: {$e->getMessage()}"); $errorCount++; } } $this->newLine(); $this->info("Import complete!"); $this->info("Success: {$successCount}"); if ($errorCount > 0) { $this->error("Errors: {$errorCount}"); } return 0; } protected function processDocument(string $basePath, array $item, User $user, bool $dryRun): void { $filePath = $basePath . '/' . $item['file']; // Validate file exists if (!File::exists($filePath)) { throw new \Exception("File not found: {$filePath}"); } // Find or create category $category = DocumentCategory::where('slug', $item['category'])->first(); if (!$category) { throw new \Exception("Category not found: {$item['category']}"); } $this->line("Processing: {$item['title']}"); $this->line(" Category: {$category->name}"); $this->line(" File: {$item['file']}"); if ($dryRun) { $this->line(" [DRY RUN] Would create document"); return; } // Copy file to storage $fileInfo = pathinfo($filePath); $storagePath = 'documents/' . uniqid() . '.' . $fileInfo['extension']; Storage::disk('private')->put($storagePath, File::get($filePath)); // Create document $document = Document::create([ 'document_category_id' => $category->id, 'title' => $item['title'], 'document_number' => $item['document_number'] ?? null, 'description' => $item['description'] ?? null, 'access_level' => $item['access_level'] ?? $category->default_access_level, 'status' => 'active', 'created_by' => $user->id, 'updated_by' => $user->id, ]); // Add first version $document->addVersion( filePath: $storagePath, originalFilename: $fileInfo['basename'], mimeType: File::mimeType($filePath), fileSize: File::size($filePath), uploadedBy: $user, versionNotes: $item['version_notes'] ?? 'Initial import' ); AuditLog::create([ 'user_id' => $user->id, 'action' => 'document.imported', 'auditable_type' => Document::class, 'auditable_id' => $document->id, 'old_values' => null, 'new_values' => ['title' => $item['title']], 'ip_address' => '127.0.0.1', 'user_agent' => 'CLI Import', ]); $this->info(" ✓ Created document ID: {$document->id}"); } protected function getManifestExample(): string { return <<<'JSON' { "documents": [ { "file": "bylaws.pdf", "title": "協會章程", "category": "association-bylaws", "document_number": "2024-001", "description": "協會章程修正版", "access_level": "members", "version_notes": "Initial import" }, { "file": "meeting-2024-01.pdf", "title": "2024年1月會議記錄", "category": "meeting-minutes", "access_level": "members" } ] } JSON; } }