diff --git a/app/Console/Commands/MakeImageDB.php b/app/Console/Commands/MakeImageDB.php index bb5a79b..54eb1d3 100644 --- a/app/Console/Commands/MakeImageDB.php +++ b/app/Console/Commands/MakeImageDB.php @@ -10,6 +10,40 @@ use App\Models\ImageNode; class MakeImageDB extends Command { + /** + * Summary of processImage + * @param mixed $file + * @param mixed $parentId + * @param int $userId + * @param string $basePath + * @return void + */ + private function processImage($file, ?int $parentId, int $userId, string $basePath): void{ + $ext = strtolower($file->getExtension()); + if (!in_array($ext, ['jpg', 'jpeg', 'png'])) return; + + $imageFileName = $file->getFilename(); + + $relativePath = str_replace(public_path(), '', $file->getPathname()); + $relativePath = str_replace(DIRECTORY_SEPARATOR, '/', $relativePath); + $relativePath = '/' . ltrim($relativePath, '/'); + + ImageNode::create([ + 'user_id' => $userId, + 'parent_id' => $parentId, + 'name' => $imageFileName, + 'fs_type' => 'file', + 'fs_meta' => json_encode([ + 'real_name' => $file->getPathname(), + 'symbolic_name' => $relativePath, + 'title' => pathinfo($imageFileName, PATHINFO_FILENAME), + 'description' => '', + 'copyright' => '', + 'mime_type' => File::mimeType($file->getPathname()), + 'size' => $file->getSize(), + ]), + ]); + } /** * Summary of scanFolder * @param string $fullPath @@ -18,49 +52,21 @@ class MakeImageDB extends Command * @param string $basePath * @return void */ - private function scanFolder(string $fullPath, ?int $parentId, int $userId, string $basePath): void - { - $entries = File::directories($fullPath); - foreach ($entries as $folderPath) { - $folderName = basename($folderPath); + private function scanFolder(string $fullPath, ?int $parentId, int $userId, string $basePath): void { + $folderName = basename($fullPath); + $folderNode = ImageNode::create([ + 'user_id' => $userId, + 'name' => $folderName, + 'fs_type' => 'folder', + 'parent_id' => $parentId, + ]); - $folderNode = ImageNode::create([ - 'user_id' => $userId, - 'name' => $folderName, - 'fs_type' => 'folder', - 'parent_id' => $parentId, - ]); - - $this->scanFolder($folderPath, $folderNode->id, $userId, $basePath); + foreach (File::directories($fullPath) as $subdir) { + $this->scanFolder($subdir, $folderNode->id, $userId, $basePath); } - $files = File::files($fullPath); - foreach ($files as $file) { - $ext = strtolower($file->getExtension()); - if (!in_array($ext, ['jpg', 'jpeg', 'png'])) { - continue; // skip unsupported file types - } - - $imageFileName = $file->getFilename(); - $relativePath = str_replace(public_path(), '', $file->getPathname()); - $relativePath = str_replace(DIRECTORY_SEPARATOR, '/', $relativePath); - $relativePath = '/' . ltrim($relativePath, '/'); - - ImageNode::create([ - 'user_id' => $userId, - 'parent_id' => $parentId, - 'name' => $imageFileName, - 'fs_type' => 'file', - 'fs_meta' => json_encode([ - 'real_name' => $file->getPathname(), - 'symbolic_name' => $relativePath, - 'title' => pathinfo($imageFileName, PATHINFO_FILENAME), - 'description' => '', - 'copyright' => '', - 'mime_type' => File::mimeType($file->getPathname()), - 'size' => $file->getSize(), - ]), - ]); + foreach (File::files($fullPath) as $file) { + $this->processImage($file, $folderNode->id, $userId, $basePath); } } @@ -69,7 +75,7 @@ class MakeImageDB extends Command * * @var string */ - protected $signature = 'pagebuilder:make-imagedb'; + protected $signature = 'pagebuilder:make-imagedb {--testmode : Use test-imagedb folder instead of imagedb for testing}'; /** * The console command description. @@ -84,10 +90,19 @@ class MakeImageDB extends Command public function handle() { // The public path to the imagedb directory. If you change this, please also make sure you update // the .gitignore file so you don't accidentally push garbage to the repository. - $imageDbPath = public_path('imagedb'); + + // We set up a test directory just for unit testing, so we don't polute the local database, or file + // system with test data + $imageDbPath = $this->option('testmode') + ? public_path('test-imagedb') + : public_path('imagedb'); if (!File::exists($imageDbPath) || !File::isDirectory($imageDbPath)) { - $this->error("The 'public/imagedb' directory does not exist."); + if ($this->option('testmode')) { + $this->error("The 'public/test-imagedb' directory does not exist."); + } else { + $this->error("The 'public/imagedb' directory does not exist."); + } return Command::FAILURE; } @@ -96,7 +111,11 @@ class MakeImageDB extends Command $subdirs = File::directories($imageDbPath); if (empty($contents) && empty($subdirs)) { - $this->error("The 'public/imagedb' directory is empty. Nothing to index."); + if ($this->option('testmode')) { + $this->error("The 'public/test-imagedb' directory is empty. Nothing to index."); + } else { + $this->error("The 'public/imagedb' directory is empty. Nothing to index."); + } return Command::FAILURE; } @@ -132,9 +151,16 @@ class MakeImageDB extends Command $this->info("Selected user ID: $userId: $selectedLabel"); $this->info("Scanning and indexing image directory..."); - $this->scanFolder($imageDbPath, null, $userId, $imageDbPath); + + foreach (File::directories($imageDbPath) as $dir) { + $this->scanFolder($dir, null, $userId, $imageDbPath); + } + + foreach (File::files($imageDbPath) as $file) { + $this->processImage($file, null, $userId, $imageDbPath); + } + $this->info("Image DB creation complete."); - return Command::SUCCESS; } } diff --git a/tests/Feature/MakeImageDBCommandTest.php b/tests/Feature/MakeImageDBCommandTest.php new file mode 100644 index 0000000..6b9a60e --- /dev/null +++ b/tests/Feature/MakeImageDBCommandTest.php @@ -0,0 +1,92 @@ +imageDbPath = public_path('test-imagedb'); + File::deleteDirectory($this->imageDbPath); + File::makeDirectory($this->imageDbPath . '/subfolder', 0755, true); + + // Create a sample image file + File::put($this->imageDbPath . '/subfolder/example.jpg', 'fake image content'); + } + + protected function tearDown(): void { + File::deleteDirectory($this->imageDbPath); + parent::tearDown(); + } + + /** @test */ + public function it_indexes_folders_and_images_in_the_imagedb_directory() { + $user = User::factory()->create([ + 'name' => 'Test User', + 'email' => 'test@example.com', + ]); + + $this->artisan('pagebuilder:make-imagedb', ['--testmode' => true]) + ->expectsQuestion('Select a user to act as:', "{$user->name} ({$user->email})") + ->expectsOutput('Clearing existing image nodes...') + ->expectsOutput('Scanning and indexing image directory...') + ->expectsOutput('Image DB creation complete.') + ->assertExitCode(0); + + $this->assertDatabaseCount('image_nodes', 2); // 1 folder + 1 image + + $folder = ImageNode::where('fs_type', 'folder')->first(); + $image = ImageNode::where('fs_type', 'file')->first(); + + $this->assertNotNull($folder); + $this->assertEquals('subfolder', $folder->name); + + $this->assertNotNull($image); + $this->assertEquals('example.jpg', $image->name); + $this->assertEquals($folder->id, $image->parent_id); + } + + /** @test */ + public function it_errors_when_imagedb_directory_does_not_exist() { + // Ensure directory does not exist + File::deleteDirectory($this->imageDbPath); + + $this->artisan('pagebuilder:make-imagedb', ['--testmode' => true]) + ->expectsOutput("The 'public/test-imagedb' directory does not exist.") + ->assertExitCode(1); + } + + /** @test */ + public function it_errors_when_imagedb_directory_is_empty() { + // Delete existing dir + File::deleteDirectory($this->imageDbPath); + // Create an empty directory + File::makeDirectory($this->imageDbPath, 0755, true); + + $this->artisan('pagebuilder:make-imagedb', ['--testmode' => true]) + ->expectsOutput("The 'public/test-imagedb' directory is empty. Nothing to index.") + ->assertExitCode(1); + } + + /** @test */ + public function it_errors_when_no_users_exist() { + $this->artisan('pagebuilder:make-imagedb', ['--testmode' => true]) + ->expectsOutput("No users found in the database. Cannot continue!") + ->expectsOutput('(Use artisan serve and npm run dev to spool up a local instance, and register a user from the web interface)') + ->assertExitCode(1); + } +}