348 lines
13 KiB
PHP
348 lines
13 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Models\Artwork;
|
|
use App\Models\Group;
|
|
use App\Models\GroupChallenge;
|
|
use App\Models\User;
|
|
use App\Models\World;
|
|
use App\Models\WorldSubmission;
|
|
use App\Services\GroupChallengeService;
|
|
use App\Services\Worlds\WorldService;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Str;
|
|
|
|
uses(RefreshDatabase::class);
|
|
|
|
function challengeLinkedWorld(?User $moderator = null, array $attributes = []): World
|
|
{
|
|
$moderator ??= User::factory()->create([
|
|
'role' => 'moderator',
|
|
'username' => 'worldchallenge-' . Str::lower(Str::random(6)),
|
|
]);
|
|
|
|
return World::factory()->create(array_merge([
|
|
'created_by_user_id' => $moderator->id,
|
|
'status' => World::STATUS_PUBLISHED,
|
|
'published_at' => now()->subDay(),
|
|
'accepts_submissions' => true,
|
|
'participation_mode' => World::PARTICIPATION_MODE_MANUAL_APPROVAL,
|
|
'submission_note_enabled' => true,
|
|
'community_section_enabled' => true,
|
|
'allow_readd_after_removal' => true,
|
|
'submission_starts_at' => now()->subDay(),
|
|
'submission_ends_at' => now()->addDays(7),
|
|
], $attributes));
|
|
}
|
|
|
|
function worldUpdatePayload(World $world, array $overrides = []): array
|
|
{
|
|
return array_merge([
|
|
'title' => $world->title,
|
|
'status' => $world->status,
|
|
'type' => $world->type,
|
|
'tagline' => $world->tagline,
|
|
'summary' => $world->summary,
|
|
'description' => $world->description,
|
|
'accepts_submissions' => (bool) $world->accepts_submissions,
|
|
'participation_mode' => $world->participation_mode,
|
|
'submission_note_enabled' => (bool) $world->submission_note_enabled,
|
|
'community_section_enabled' => (bool) $world->community_section_enabled,
|
|
'allow_readd_after_removal' => (bool) $world->allow_readd_after_removal,
|
|
'is_featured' => (bool) $world->is_featured,
|
|
'is_active_campaign' => (bool) $world->is_active_campaign,
|
|
'is_homepage_featured' => (bool) $world->is_homepage_featured,
|
|
'is_recurring' => (bool) $world->is_recurring,
|
|
'cta_label' => $world->cta_label,
|
|
'cta_url' => $world->cta_url,
|
|
'badge_label' => $world->badge_label,
|
|
'badge_description' => $world->badge_description,
|
|
'badge_url' => $world->badge_url,
|
|
'linked_challenge_id' => $world->linked_challenge_id,
|
|
'show_linked_challenge_section' => (bool) ($world->show_linked_challenge_section ?? true),
|
|
'show_linked_challenge_entries' => (bool) ($world->show_linked_challenge_entries ?? true),
|
|
'show_linked_challenge_winners' => (bool) ($world->show_linked_challenge_winners ?? true),
|
|
'show_linked_challenge_finalists' => (bool) ($world->show_linked_challenge_finalists ?? true),
|
|
'auto_grant_challenge_world_rewards' => (bool) ($world->auto_grant_challenge_world_rewards ?? true),
|
|
'challenge_teaser_override' => $world->challenge_teaser_override,
|
|
'relations' => [],
|
|
], $overrides);
|
|
}
|
|
|
|
function linkedGroupChallenge(Group $group, User $owner, array $attributes = []): GroupChallenge
|
|
{
|
|
return GroupChallenge::query()->create(array_merge([
|
|
'group_id' => $group->id,
|
|
'title' => 'Pixel Week Finals',
|
|
'slug' => 'pixel-week-finals-' . Str::lower(Str::random(6)),
|
|
'summary' => 'Challenge finale.',
|
|
'description' => 'Challenge finale description.',
|
|
'visibility' => GroupChallenge::VISIBILITY_PUBLIC,
|
|
'participation_scope' => GroupChallenge::PARTICIPATION_PUBLIC,
|
|
'status' => GroupChallenge::STATUS_ACTIVE,
|
|
'start_at' => now()->subDay(),
|
|
'end_at' => now()->addDay(),
|
|
'created_by_user_id' => $owner->id,
|
|
'featured_artwork_id' => null,
|
|
], $attributes));
|
|
}
|
|
|
|
it('syncs winner rewards from linked challenge outcomes', function (): void {
|
|
$moderator = User::factory()->create(['role' => 'moderator']);
|
|
$creator = User::factory()->create();
|
|
$groupOwner = User::factory()->create();
|
|
$group = Group::factory()->for($groupOwner, 'owner')->create();
|
|
$world = challengeLinkedWorld($moderator);
|
|
$artwork = Artwork::factory()->for($creator)->create([
|
|
'group_id' => $group->id,
|
|
'title' => 'Challenge Winner Artwork',
|
|
'slug' => 'challenge-winner-artwork',
|
|
'artwork_status' => 'published',
|
|
'published_at' => now()->subDay(),
|
|
'is_public' => true,
|
|
'visibility' => Artwork::VISIBILITY_PUBLIC,
|
|
]);
|
|
|
|
$submission = WorldSubmission::query()->create([
|
|
'world_id' => $world->id,
|
|
'artwork_id' => $artwork->id,
|
|
'submitted_by_user_id' => $creator->id,
|
|
'status' => WorldSubmission::STATUS_LIVE,
|
|
'reviewed_by_user_id' => $moderator->id,
|
|
'reviewed_at' => now()->subHour(),
|
|
]);
|
|
|
|
$challenge = linkedGroupChallenge($group, $groupOwner);
|
|
$challenge->artworks()->attach($artwork->id, ['submitted_by_user_id' => $groupOwner->id, 'sort_order' => 0]);
|
|
|
|
$world->worldRelations()->create([
|
|
'section_key' => 'related_programming',
|
|
'related_type' => 'challenge',
|
|
'related_id' => $challenge->id,
|
|
'context_label' => 'Challenge finale',
|
|
'sort_order' => 0,
|
|
'is_featured' => true,
|
|
]);
|
|
|
|
app(GroupChallengeService::class)->update($challenge, $groupOwner, [
|
|
'outcomes' => [[
|
|
'artwork_id' => $artwork->id,
|
|
'outcome_type' => 'winner',
|
|
'position' => 1,
|
|
'sort_order' => 0,
|
|
'title_override' => 'Grand Winner',
|
|
]],
|
|
]);
|
|
|
|
$this->assertDatabaseHas('world_reward_grants', [
|
|
'user_id' => $creator->id,
|
|
'world_id' => $world->id,
|
|
'artwork_id' => $artwork->id,
|
|
'world_submission_id' => $submission->id,
|
|
'reward_type' => 'winner',
|
|
'grant_source' => 'challenge',
|
|
]);
|
|
});
|
|
|
|
it('syncs finalist rewards from linked challenge outcomes', function (): void {
|
|
$moderator = User::factory()->create(['role' => 'moderator']);
|
|
$creator = User::factory()->create();
|
|
$groupOwner = User::factory()->create();
|
|
$group = Group::factory()->for($groupOwner, 'owner')->create();
|
|
$world = challengeLinkedWorld($moderator);
|
|
$artwork = Artwork::factory()->for($creator)->create([
|
|
'group_id' => $group->id,
|
|
'title' => 'Challenge Finalist Artwork',
|
|
'slug' => 'challenge-finalist-artwork',
|
|
'artwork_status' => 'published',
|
|
'published_at' => now()->subDay(),
|
|
'is_public' => true,
|
|
'visibility' => Artwork::VISIBILITY_PUBLIC,
|
|
]);
|
|
|
|
$submission = WorldSubmission::query()->create([
|
|
'world_id' => $world->id,
|
|
'artwork_id' => $artwork->id,
|
|
'submitted_by_user_id' => $creator->id,
|
|
'status' => WorldSubmission::STATUS_LIVE,
|
|
'reviewed_by_user_id' => $moderator->id,
|
|
'reviewed_at' => now()->subHour(),
|
|
]);
|
|
|
|
$challenge = linkedGroupChallenge($group, $groupOwner);
|
|
$challenge->artworks()->attach($artwork->id, ['submitted_by_user_id' => $groupOwner->id, 'sort_order' => 0]);
|
|
|
|
$world->worldRelations()->create([
|
|
'section_key' => 'related_programming',
|
|
'related_type' => 'challenge',
|
|
'related_id' => $challenge->id,
|
|
'context_label' => 'Challenge finale',
|
|
'sort_order' => 0,
|
|
'is_featured' => true,
|
|
]);
|
|
|
|
app(GroupChallengeService::class)->update($challenge, $groupOwner, [
|
|
'outcomes' => [[
|
|
'artwork_id' => $artwork->id,
|
|
'outcome_type' => 'finalist',
|
|
'sort_order' => 0,
|
|
'note' => 'Finalist award.',
|
|
]],
|
|
]);
|
|
|
|
$this->assertDatabaseHas('world_reward_grants', [
|
|
'user_id' => $creator->id,
|
|
'world_id' => $world->id,
|
|
'artwork_id' => $artwork->id,
|
|
'world_submission_id' => $submission->id,
|
|
'reward_type' => 'finalist',
|
|
'grant_source' => 'challenge',
|
|
]);
|
|
});
|
|
|
|
it('syncs challenge winner rewards when challenge relations are added to a world', function (): void {
|
|
$moderator = User::factory()->create(['role' => 'moderator']);
|
|
$creator = User::factory()->create();
|
|
$groupOwner = User::factory()->create();
|
|
$group = Group::factory()->for($groupOwner, 'owner')->create();
|
|
$world = challengeLinkedWorld($moderator);
|
|
$artwork = Artwork::factory()->for($creator)->create([
|
|
'group_id' => $group->id,
|
|
'title' => 'Relation Sync Artwork',
|
|
'slug' => 'relation-sync-artwork',
|
|
'artwork_status' => 'published',
|
|
'published_at' => now()->subDay(),
|
|
'is_public' => true,
|
|
'visibility' => Artwork::VISIBILITY_PUBLIC,
|
|
]);
|
|
|
|
WorldSubmission::query()->create([
|
|
'world_id' => $world->id,
|
|
'artwork_id' => $artwork->id,
|
|
'submitted_by_user_id' => $creator->id,
|
|
'status' => WorldSubmission::STATUS_LIVE,
|
|
'reviewed_by_user_id' => $moderator->id,
|
|
'reviewed_at' => now()->subHour(),
|
|
]);
|
|
|
|
$challenge = linkedGroupChallenge($group, $groupOwner, [
|
|
'featured_artwork_id' => $artwork->id,
|
|
]);
|
|
|
|
app(WorldService::class)->update($world, $moderator, worldUpdatePayload($world, [
|
|
'relations' => [[
|
|
'section_key' => 'related_programming',
|
|
'related_type' => 'challenge',
|
|
'related_id' => $challenge->id,
|
|
'context_label' => 'Challenge finale',
|
|
'sort_order' => 0,
|
|
'is_featured' => true,
|
|
]],
|
|
]));
|
|
|
|
$this->assertDatabaseHas('world_reward_grants', [
|
|
'user_id' => $creator->id,
|
|
'world_id' => $world->id,
|
|
'reward_type' => 'winner',
|
|
'grant_source' => 'challenge',
|
|
]);
|
|
});
|
|
|
|
it('syncs challenge winner rewards when a primary linked challenge is set on a world', function (): void {
|
|
$moderator = User::factory()->create(['role' => 'moderator']);
|
|
$creator = User::factory()->create();
|
|
$groupOwner = User::factory()->create();
|
|
$group = Group::factory()->for($groupOwner, 'owner')->create();
|
|
$world = challengeLinkedWorld($moderator);
|
|
$artwork = Artwork::factory()->for($creator)->create([
|
|
'group_id' => $group->id,
|
|
'title' => 'Primary Challenge Sync Artwork',
|
|
'slug' => 'primary-challenge-sync-artwork',
|
|
'artwork_status' => 'published',
|
|
'published_at' => now()->subDay(),
|
|
'is_public' => true,
|
|
'visibility' => Artwork::VISIBILITY_PUBLIC,
|
|
]);
|
|
|
|
WorldSubmission::query()->create([
|
|
'world_id' => $world->id,
|
|
'artwork_id' => $artwork->id,
|
|
'submitted_by_user_id' => $creator->id,
|
|
'status' => WorldSubmission::STATUS_LIVE,
|
|
'reviewed_by_user_id' => $moderator->id,
|
|
'reviewed_at' => now()->subHour(),
|
|
]);
|
|
|
|
$challenge = linkedGroupChallenge($group, $groupOwner, [
|
|
'featured_artwork_id' => $artwork->id,
|
|
]);
|
|
|
|
app(WorldService::class)->update($world, $moderator, worldUpdatePayload($world, [
|
|
'linked_challenge_id' => $challenge->id,
|
|
]));
|
|
|
|
$this->assertDatabaseHas('world_reward_grants', [
|
|
'user_id' => $creator->id,
|
|
'world_id' => $world->id,
|
|
'reward_type' => 'winner',
|
|
'grant_source' => 'challenge',
|
|
]);
|
|
});
|
|
|
|
it('revokes challenge-sourced winner rewards when linked challenge winners are cleared', function (): void {
|
|
$moderator = User::factory()->create(['role' => 'moderator']);
|
|
$creator = User::factory()->create();
|
|
$groupOwner = User::factory()->create();
|
|
$group = Group::factory()->for($groupOwner, 'owner')->create();
|
|
$world = challengeLinkedWorld($moderator);
|
|
$artwork = Artwork::factory()->for($creator)->create([
|
|
'group_id' => $group->id,
|
|
'title' => 'Revoked Challenge Winner',
|
|
'slug' => 'revoked-challenge-winner',
|
|
'artwork_status' => 'published',
|
|
'published_at' => now()->subDay(),
|
|
'is_public' => true,
|
|
'visibility' => Artwork::VISIBILITY_PUBLIC,
|
|
]);
|
|
|
|
$submission = WorldSubmission::query()->create([
|
|
'world_id' => $world->id,
|
|
'artwork_id' => $artwork->id,
|
|
'submitted_by_user_id' => $creator->id,
|
|
'status' => WorldSubmission::STATUS_LIVE,
|
|
'reviewed_by_user_id' => $moderator->id,
|
|
'reviewed_at' => now()->subHour(),
|
|
]);
|
|
|
|
$challenge = linkedGroupChallenge($group, $groupOwner);
|
|
|
|
$world->worldRelations()->create([
|
|
'section_key' => 'related_programming',
|
|
'related_type' => 'challenge',
|
|
'related_id' => $challenge->id,
|
|
'context_label' => 'Challenge finale',
|
|
'sort_order' => 0,
|
|
'is_featured' => true,
|
|
]);
|
|
|
|
$challengeService = app(GroupChallengeService::class);
|
|
$challengeService->update($challenge, $groupOwner, ['featured_artwork_id' => $artwork->id]);
|
|
|
|
$this->assertDatabaseHas('world_reward_grants', [
|
|
'user_id' => $creator->id,
|
|
'world_id' => $world->id,
|
|
'world_submission_id' => $submission->id,
|
|
'reward_type' => 'winner',
|
|
'grant_source' => 'challenge',
|
|
]);
|
|
|
|
$challengeService->update($challenge->fresh(), $groupOwner, ['featured_artwork_id' => null]);
|
|
|
|
$this->assertDatabaseMissing('world_reward_grants', [
|
|
'user_id' => $creator->id,
|
|
'world_id' => $world->id,
|
|
'reward_type' => 'winner',
|
|
'grant_source' => 'challenge',
|
|
]);
|
|
}); |