From 5e7b03b167941c3ff473230ee8be27cae82ef4de Mon Sep 17 00:00:00 2001 From: Kyrch Date: Tue, 10 Feb 2026 02:10:56 -0300 Subject: [PATCH] feat(graphql): made animethemeShuffle.spoiler optional (#1093) --- .../Queries/Wiki/AnimeThemeShuffleQuery.php | 10 +- app/Http/Kernel.php | 2 + app/Http/Middleware/Api/SetServingJsonApi.php | 23 +++ app/Models/Wiki/Anime/AnimeTheme.php | 4 +- .../Wiki/AnimeThemeShuffleQueryTest.php | 176 ++++++++++++++++++ 5 files changed, 209 insertions(+), 6 deletions(-) create mode 100644 app/Http/Middleware/Api/SetServingJsonApi.php create mode 100644 tests/Feature/GraphQL/Schema/Queries/Wiki/AnimeThemeShuffleQueryTest.php diff --git a/app/GraphQL/Schema/Queries/Wiki/AnimeThemeShuffleQuery.php b/app/GraphQL/Schema/Queries/Wiki/AnimeThemeShuffleQuery.php index dd3fb047b..d2f465551 100644 --- a/app/GraphQL/Schema/Queries/Wiki/AnimeThemeShuffleQuery.php +++ b/app/GraphQL/Schema/Queries/Wiki/AnimeThemeShuffleQuery.php @@ -64,9 +64,7 @@ class AnimeThemeShuffleQuery extends BaseQuery new Argument(self::ATTRIBUTE_YEAR_GTE, Type::int()), - new Argument(self::ATTRIBUTE_SPOILER, Type::boolean()) - ->required() - ->withDefaultValue(false), + new Argument(self::ATTRIBUTE_SPOILER, Type::boolean()), ]; } @@ -100,7 +98,11 @@ class AnimeThemeShuffleQuery extends BaseQuery } }); - $builder->whereRelation(AnimeTheme::RELATION_ENTRIES, AnimeThemeEntry::ATTRIBUTE_SPOILER, Arr::boolean($args, self::ATTRIBUTE_SPOILER)); + $builder->whereHas(AnimeTheme::RELATION_VIDEOS); + + if (is_bool($spoiler = Arr::get($args, self::ATTRIBUTE_SPOILER))) { + $builder->whereRelation(AnimeTheme::RELATION_ENTRIES, AnimeThemeEntry::ATTRIBUTE_SPOILER, $spoiler); + } $builder->inRandomOrder(); diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index aafcc7815..44831517c 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace App\Http; use App\Http\Middleware\Api\SetAcceptJsonHeader; +use App\Http\Middleware\Api\SetServingJsonApi; use App\Http\Middleware\Auth\Authenticate; use App\Http\Middleware\Auth\RedirectIfAuthenticated; use App\Http\Middleware\GraphQL\RateLimitPerQuery; @@ -90,6 +91,7 @@ class Kernel extends HttpKernel 'throttle:api', SubstituteBindings::class, LogRequest::class, + SetServingJsonApi::class, ], 'graphql' => [ diff --git a/app/Http/Middleware/Api/SetServingJsonApi.php b/app/Http/Middleware/Api/SetServingJsonApi.php new file mode 100644 index 000000000..1b000a7cc --- /dev/null +++ b/app/Http/Middleware/Api/SetServingJsonApi.php @@ -0,0 +1,23 @@ +state([AnimeTheme::ATTRIBUTE_TYPE => $type->value]) + ->has(AnimeThemeEntry::factory()->has(Video::factory())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + AnimeTheme::factory() + ->has(AnimeThemeEntry::factory()->has(Video::factory())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $response = graphql([ + 'query' => ' + query($type: [ThemeType!]) { + animethemeShuffle(type: $type) { + type + } + } + ', + 'variables' => [ + 'type' => [$type->name], + ], + ]); + + $response->assertOk(); + $response->assertJsonCount(1); + $response->assertJson( + fn (AssertableJson $json) => $json->has( + 'data.animethemeShuffle', + fn (AssertableJson $themes) => $themes->each(fn (AssertableJson $theme) => $theme->where(AnimeTheme::ATTRIBUTE_TYPE, $type->name)) + ) + ); +}); + +test('filter by anime media format', function () { + $format = Arr::random(AnimeMediaFormat::cases()); + + AnimeTheme::factory() + ->for(Anime::factory()->state([Anime::ATTRIBUTE_MEDIA_FORMAT => $format->value])) + ->has(AnimeThemeEntry::factory()->has(Video::factory())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + AnimeTheme::factory() + ->has(AnimeThemeEntry::factory()->has(Video::factory())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $response = graphql([ + 'query' => ' + query($format: [AnimeMediaFormat!]) { + animethemeShuffle(mediaFormat: $format) { + anime { + mediaFormat + } + } + } + ', + 'variables' => [ + 'format' => [$format->name], + ], + ]); + + $response->assertOk(); + $response->assertJsonCount(1); + $response->assertJson( + fn (AssertableJson $json) => $json->has( + 'data.animethemeShuffle', + fn (AssertableJson $themes) => $themes->each(fn (AssertableJson $theme) => $theme->where('anime.mediaFormat', $format->name)) + ) + ); +}); + +test('filter by year', function () { + $yearGte = fake()->numberBetween(1964, date('Y') - 1); + $yearLte = fake()->numberBetween($yearGte, date('Y')); + + AnimeTheme::factory() + ->for(Anime::factory()->state([Anime::ATTRIBUTE_YEAR => fake()->numberBetween($yearLte, $yearGte)])) + ->has(AnimeThemeEntry::factory()->has(Video::factory())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + AnimeTheme::factory() + ->has(AnimeThemeEntry::factory()->has(Video::factory())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $response = graphql([ + 'query' => ' + query($yearLte: Int, $yearGte: Int) { + animethemeShuffle(year_lte: $yearLte, year_gte: $yearGte) { + anime { + year + } + } + } + ', + 'variables' => [ + 'yearLte' => $yearLte, + 'yearGte' => $yearGte, + ], + ]); + + $response->assertOk(); + $response->assertJsonCount(1); + $response->assertJson( + fn (AssertableJson $json) => $json->has( + 'data.animethemeShuffle', + fn (AssertableJson $themes) => $themes->each(fn (AssertableJson $theme) => $theme->where('anime.year', fn (int $year) => $year <= $yearLte) + ->where('anime.year', fn (int $year) => $year >= $yearGte)) + ) + ); +}); + +test('filter by entry spoiler', function () { + $spoiler = fake()->boolean(); + + AnimeTheme::factory() + ->for(Anime::factory()) + ->has(AnimeThemeEntry::factory()->state([AnimeThemeEntry::ATTRIBUTE_SPOILER => $spoiler])->has(Video::factory())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + AnimeTheme::factory() + ->has(AnimeThemeEntry::factory()->has(Video::factory())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $response = graphql([ + 'query' => ' + query($spoiler: Boolean) { + animethemeShuffle(spoiler: $spoiler) { + animethemeentries { + spoiler + } + } + } + ', + 'variables' => [ + 'spoiler' => $spoiler, + ], + ]); + + $response->assertOk(); + $response->assertJsonCount(1); + $response->assertJson( + fn (AssertableJson $json) => $json->has( + 'data.animethemeShuffle', + fn (AssertableJson $themes) => $themes->each( + fn (AssertableJson $theme) => $theme->has( + AnimeTheme::RELATION_ENTRIES, + fn (AssertableJson $entries) => $entries->each( + fn (AssertableJson $entry) => $entry->where(AnimeThemeEntry::ATTRIBUTE_SPOILER, $spoiler) + ) + ) + ) + ) + ); +});