Files
SkinbaseNova/tests/Feature/Uploads/UploadPublishTest.php
2026-02-14 15:14:12 +01:00

265 lines
8.9 KiB
PHP

<?php
use App\Models\Upload;
use App\Models\User;
use App\Uploads\Services\PublishService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
uses(RefreshDatabase::class);
function createCategoryForUploadPublishFeatureTests(): int
{
$contentTypeId = DB::table('content_types')->insertGetId([
'name' => 'Photography',
'slug' => 'photography-' . Str::lower(Str::random(6)),
'description' => null,
'created_at' => now(),
'updated_at' => now(),
]);
return DB::table('categories')->insertGetId([
'content_type_id' => $contentTypeId,
'parent_id' => null,
'name' => 'Urban',
'slug' => 'urban-' . Str::lower(Str::random(6)),
'description' => null,
'image' => null,
'is_active' => true,
'sort_order' => 0,
'created_at' => now(),
'updated_at' => now(),
]);
}
it('publishes upload and moves draft files', function () {
Storage::fake('local');
$user = User::factory()->create();
$categoryId = createCategoryForUploadPublishFeatureTests();
$uploadId = (string) Str::uuid();
$hash = 'aabbccddeeff00112233';
DB::table('uploads')->insert([
'id' => $uploadId,
'user_id' => $user->id,
'type' => 'image',
'status' => 'draft',
'moderation_status' => 'approved',
'title' => 'Night City',
'category_id' => $categoryId,
'is_scanned' => true,
'has_tags' => true,
'preview_path' => "tmp/drafts/{$uploadId}/preview.webp",
'created_at' => now(),
'updated_at' => now(),
]);
Storage::disk('local')->put("tmp/drafts/{$uploadId}/main/night-city.jpg", 'jpg-binary');
Storage::disk('local')->put("tmp/drafts/{$uploadId}/preview.webp", 'preview');
Storage::disk('local')->put("tmp/drafts/{$uploadId}/thumb.webp", 'thumb');
DB::table('upload_files')->insert([
[
'upload_id' => $uploadId,
'path' => "tmp/drafts/{$uploadId}/main/night-city.jpg",
'type' => 'main',
'hash' => $hash,
'size' => 10,
'mime' => 'image/jpeg',
'created_at' => now(),
],
[
'upload_id' => $uploadId,
'path' => "tmp/drafts/{$uploadId}/preview.webp",
'type' => 'preview',
'hash' => null,
'size' => 7,
'mime' => 'image/webp',
'created_at' => now(),
],
]);
$published = app(PublishService::class)->publish($uploadId, $user);
expect($published)->toBeInstanceOf(Upload::class);
expect($published->status)->toBe('published');
expect($published->published_at)->not->toBeNull();
expect($published->final_path)->toBe('files/artworks/aa/bb/' . $hash);
Storage::disk('local')->assertMissing("tmp/drafts/{$uploadId}/main/night-city.jpg");
Storage::disk('local')->assertExists('files/artworks/aa/bb/' . $hash . '/main/night-city.jpg');
$updatedMain = DB::table('upload_files')
->where('upload_id', $uploadId)
->where('type', 'main')
->value('path');
expect($updatedMain)->toBe('files/artworks/aa/bb/' . $hash . '/main/night-city.jpg');
});
it('does not delete temp files on publish failure', function () {
Storage::fake('local');
$user = User::factory()->create();
$categoryId = createCategoryForUploadPublishFeatureTests();
$uploadId = (string) Str::uuid();
DB::table('uploads')->insert([
'id' => $uploadId,
'user_id' => $user->id,
'type' => 'image',
'status' => 'draft',
'moderation_status' => 'approved',
'title' => 'Will Fail',
'category_id' => $categoryId,
'is_scanned' => true,
'has_tags' => true,
'preview_path' => "tmp/drafts/{$uploadId}/preview.webp",
'created_at' => now(),
'updated_at' => now(),
]);
Storage::disk('local')->put("tmp/drafts/{$uploadId}/main/file.jpg", 'jpg-binary');
Storage::disk('local')->put("tmp/drafts/{$uploadId}/preview.webp", 'preview');
// missing hash should trigger failure and preserve temp files
DB::table('upload_files')->insert([
'upload_id' => $uploadId,
'path' => "tmp/drafts/{$uploadId}/main/file.jpg",
'type' => 'main',
'hash' => null,
'size' => 10,
'mime' => 'image/jpeg',
'created_at' => now(),
]);
expect(fn () => app(PublishService::class)->publish($uploadId, $user))
->toThrow(RuntimeException::class);
Storage::disk('local')->assertExists("tmp/drafts/{$uploadId}/main/file.jpg");
$status = DB::table('uploads')->where('id', $uploadId)->value('status');
expect($status)->toBe('draft');
});
it('publish persists generated slug when missing', function () {
Storage::fake('local');
$user = User::factory()->create();
$categoryId = createCategoryForUploadPublishFeatureTests();
$uploadId = (string) Str::uuid();
$hash = '0011aabbccddeeff2233';
DB::table('uploads')->insert([
'id' => $uploadId,
'user_id' => $user->id,
'type' => 'image',
'status' => 'draft',
'moderation_status' => 'approved',
'processing_state' => 'ready',
'title' => 'My Amazing Artwork',
'slug' => null,
'category_id' => $categoryId,
'is_scanned' => true,
'has_tags' => true,
'preview_path' => "tmp/drafts/{$uploadId}/preview.webp",
'created_at' => now(),
'updated_at' => now(),
]);
Storage::disk('local')->put("tmp/drafts/{$uploadId}/main/file.jpg", 'jpg-binary');
Storage::disk('local')->put("tmp/drafts/{$uploadId}/preview.webp", 'preview');
DB::table('upload_files')->insert([
'upload_id' => $uploadId,
'path' => "tmp/drafts/{$uploadId}/main/file.jpg",
'type' => 'main',
'hash' => $hash,
'size' => 10,
'mime' => 'image/jpeg',
'created_at' => now(),
]);
app(PublishService::class)->publish($uploadId, $user);
expect(DB::table('uploads')->where('id', $uploadId)->value('slug'))->toBe('my-amazing-artwork');
});
it('publish slug uniqueness appends numeric suffix for published uploads', function () {
Storage::fake('local');
$user = User::factory()->create();
$categoryId = createCategoryForUploadPublishFeatureTests();
$firstUploadId = (string) Str::uuid();
$secondUploadId = (string) Str::uuid();
DB::table('uploads')->insert([
[
'id' => $firstUploadId,
'user_id' => $user->id,
'type' => 'image',
'status' => 'draft',
'moderation_status' => 'approved',
'processing_state' => 'ready',
'title' => 'Duplicate Title',
'slug' => null,
'category_id' => $categoryId,
'is_scanned' => true,
'has_tags' => true,
'preview_path' => "tmp/drafts/{$firstUploadId}/preview.webp",
'created_at' => now(),
'updated_at' => now(),
],
[
'id' => $secondUploadId,
'user_id' => $user->id,
'type' => 'image',
'status' => 'draft',
'moderation_status' => 'approved',
'processing_state' => 'ready',
'title' => 'Duplicate Title',
'slug' => null,
'category_id' => $categoryId,
'is_scanned' => true,
'has_tags' => true,
'preview_path' => "tmp/drafts/{$secondUploadId}/preview.webp",
'created_at' => now(),
'updated_at' => now(),
],
]);
Storage::disk('local')->put("tmp/drafts/{$firstUploadId}/main/file.jpg", 'first');
Storage::disk('local')->put("tmp/drafts/{$firstUploadId}/preview.webp", 'preview');
Storage::disk('local')->put("tmp/drafts/{$secondUploadId}/main/file.jpg", 'second');
Storage::disk('local')->put("tmp/drafts/{$secondUploadId}/preview.webp", 'preview');
DB::table('upload_files')->insert([
[
'upload_id' => $firstUploadId,
'path' => "tmp/drafts/{$firstUploadId}/main/file.jpg",
'type' => 'main',
'hash' => 'aa11bb22cc33dd44',
'size' => 10,
'mime' => 'image/jpeg',
'created_at' => now(),
],
[
'upload_id' => $secondUploadId,
'path' => "tmp/drafts/{$secondUploadId}/main/file.jpg",
'type' => 'main',
'hash' => 'ee11ff22cc33dd44',
'size' => 10,
'mime' => 'image/jpeg',
'created_at' => now(),
],
]);
app(PublishService::class)->publish($firstUploadId, $user);
app(PublishService::class)->publish($secondUploadId, $user);
expect(DB::table('uploads')->where('id', $firstUploadId)->value('slug'))->toBe('duplicate-title');
expect(DB::table('uploads')->where('id', $secondUploadId)->value('slug'))->toBe('duplicate-title-2');
});