Initial commit

This commit is contained in:
2025-11-20 23:21:05 +08:00
commit 13bc6db529
378 changed files with 54527 additions and 0 deletions

View File

@@ -0,0 +1,189 @@
<?php
namespace App\Console\Commands;
use App\Models\AuditLog;
use App\Models\Document;
use App\Models\DocumentCategory;
use App\Models\User;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;
class ImportDocuments extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'documents:import
{path : Path to directory containing documents and manifest.json}
{--user-id=1 : User ID to attribute uploads to}
{--dry-run : Preview import without making changes}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Bulk import documents from a directory with manifest.json';
/**
* Execute the console command.
*/
public function handle()
{
$path = $this->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;
}
}