for($user)->unapproved()->unpublished()->create(array_merge([ 'artwork_status' => 'draft', 'title' => 'Fresh upload', ], $overrides)); } function policyApprovedArtworks(User $user, int $count, array $overrides = []): void { Artwork::factory()->for($user)->count($count)->create(array_merge([ 'is_approved' => true, 'is_public' => true, 'artwork_status' => 'published', 'published_at' => now()->subDay(), 'approval_source' => null, ], $overrides)); } it('sends new users without five approved artworks to review', function () { $user = User::factory()->create([ 'role' => 'user', 'created_at' => now()->subYear(), 'level' => 8, ]); policyApprovedArtworks($user, 4); $pending = policyPendingArtwork($user); $policy = app(ArtworkUploadPolicy::class)->assess($user, $pending); expect($policy['requires_review'])->toBeTrue() ->and($policy['approved_uploads'])->toBe(4) ->and($policy['reasons'])->toContain('insufficient_approved_uploads'); }); it('auto-publishes established creators with five approved artworks even without moderator source', function () { $user = User::factory()->create([ 'role' => 'user', 'created_at' => now()->subYear(), 'level' => 1, ]); policyApprovedArtworks($user, 5); $pending = policyPendingArtwork($user); $policy = app(ArtworkUploadPolicy::class)->assess($user, $pending); expect($policy['requires_review'])->toBeFalse() ->and($policy['approved_uploads'])->toBe(5) ->and($policy['reasons'])->toBe([]); }); it('does not auto-publish the sixth upload when a new user only has five queued or auto-trusted works', function () { $user = User::factory()->create([ 'role' => 'user', 'created_at' => now()->subYear(), 'level' => 8, ]); Artwork::factory()->for($user)->count(5)->unapproved()->unpublished()->create([ 'artwork_status' => 'review', 'is_public' => false, 'approval_source' => null, ]); policyApprovedArtworks($user, 5, ['approval_source' => 'trusted_auto']); $sixth = policyPendingArtwork($user); $policy = app(ArtworkUploadPolicy::class)->assess($user, $sixth); expect($policy['requires_review'])->toBeTrue() ->and($policy['approved_uploads'])->toBe(0) ->and($policy['reasons'])->toContain('insufficient_approved_uploads'); }); it('auto-publishes only after five moderator-approved or legacy published artworks', function () { $user = User::factory()->create([ 'role' => 'user', 'created_at' => now()->subYear(), 'level' => 4, ]); policyApprovedArtworks($user, 3, ['approval_source' => 'trusted_auto']); policyApprovedArtworks($user, 5, ['approval_source' => 'moderator']); $pending = policyPendingArtwork($user); $policy = app(ArtworkUploadPolicy::class)->assess($user, $pending); expect($policy['requires_review'])->toBeFalse() ->and($policy['approved_uploads'])->toBe(5); }); it('does not count the artwork currently being published', function () { $user = User::factory()->create([ 'role' => 'user', 'created_at' => now()->subYear(), 'level' => 4, ]); policyApprovedArtworks($user, 4); $pending = policyPendingArtwork($user, [ 'is_approved' => true, 'artwork_status' => 'published', 'published_at' => now(), ]); $policy = app(ArtworkUploadPolicy::class)->assess($user, $pending); expect($policy['approved_uploads'])->toBe(4) ->and($policy['requires_review'])->toBeTrue(); }); it('still reviews promotional uploads from trusted creators', function () { $user = User::factory()->create([ 'role' => 'user', 'created_at' => now()->subYear(), 'level' => 6, ]); policyApprovedArtworks($user, 5); $pending = policyPendingArtwork($user, [ 'title' => 'Buy now cheap backlinks', 'description' => 'Visit https://spam.example.com for a promo code', ]); $policy = app(ArtworkUploadPolicy::class)->assess($user, $pending); expect($policy['requires_review'])->toBeTrue() ->and($policy['reasons'])->toContain('promotional_content'); }); it('lets admins publish without review', function () { $admin = User::factory()->create(['role' => 'admin']); $pending = policyPendingArtwork($admin); $policy = app(ArtworkUploadPolicy::class)->assess($admin, $pending); expect($policy['requires_review'])->toBeFalse() ->and($policy['reasons'])->toBe([]); });