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' => 'Street', 'slug' => 'street-' . Str::lower(Str::random(6)), 'description' => null, 'image' => null, 'is_active' => true, 'sort_order' => 0, 'created_at' => now(), 'updated_at' => now(), ]); } function createReadyDraftForPublishEndpoint(int $ownerId, int $categoryId, string $status = 'draft'): array { $uploadId = (string) Str::uuid(); $hash = 'aabbccddeeff00112233'; DB::table('uploads')->insert([ 'id' => $uploadId, 'user_id' => $ownerId, 'type' => 'image', 'status' => $status, 'moderation_status' => 'approved', 'title' => 'Publish Endpoint Test', '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/main.jpg", 'jpg'); Storage::disk('local')->put("tmp/drafts/{$uploadId}/preview.webp", 'preview'); DB::table('upload_files')->insert([ 'upload_id' => $uploadId, 'path' => "tmp/drafts/{$uploadId}/main/main.jpg", 'type' => 'main', 'hash' => $hash, 'size' => 3, 'mime' => 'image/jpeg', 'created_at' => now(), ]); return [$uploadId, $hash]; } it('owner can publish valid draft', function () { Storage::fake('local'); $owner = User::factory()->create(); $categoryId = createCategoryForPublishEndpointTests(); [$uploadId, $hash] = createReadyDraftForPublishEndpoint($owner->id, $categoryId); $response = $this->actingAs($owner)->postJson("/api/uploads/{$uploadId}/publish"); $response->assertOk()->assertJsonStructure([ 'success', 'upload_id', 'status', 'published_at', 'final_path', ])->assertJson([ 'success' => true, 'upload_id' => $uploadId, 'status' => 'published', 'final_path' => 'files/artworks/aa/bb/' . $hash, ]); }); it('guest denied', function () { Storage::fake('local'); $owner = User::factory()->create(); $categoryId = createCategoryForPublishEndpointTests(); [$uploadId] = createReadyDraftForPublishEndpoint($owner->id, $categoryId); $response = $this->postJson("/api/uploads/{$uploadId}/publish"); expect(in_array($response->getStatusCode(), [401, 403]))->toBeTrue(); }); it('other user denied', function () { Storage::fake('local'); $owner = User::factory()->create(); $other = User::factory()->create(); $categoryId = createCategoryForPublishEndpointTests(); [$uploadId] = createReadyDraftForPublishEndpoint($owner->id, $categoryId); $response = $this->actingAs($other)->postJson("/api/uploads/{$uploadId}/publish"); $response->assertStatus(403); }); it('incomplete draft rejected', function () { Storage::fake('local'); $owner = User::factory()->create(); $categoryId = createCategoryForPublishEndpointTests(); [$uploadId] = createReadyDraftForPublishEndpoint($owner->id, $categoryId); DB::table('uploads')->where('id', $uploadId)->update(['title' => null]); $response = $this->actingAs($owner)->postJson("/api/uploads/{$uploadId}/publish"); $response->assertStatus(422); }); it('already published rejected', function () { Storage::fake('local'); $owner = User::factory()->create(); $categoryId = createCategoryForPublishEndpointTests(); [$uploadId] = createReadyDraftForPublishEndpoint($owner->id, $categoryId, 'published'); $response = $this->actingAs($owner)->postJson("/api/uploads/{$uploadId}/publish"); $response->assertStatus(422); });