mirror of
https://github.com/jikan-me/jikan-rest.git
synced 2025-02-20 11:23:35 +08:00
fixed a bug around season endpoints
- added a new parameter: "continuing" - continuing items from previous seasons are now excluded by default - should fix #521
This commit is contained in:
parent
7dd9625588
commit
4a122b9a2f
@ -39,11 +39,12 @@ interface AnimeRepository extends Repository
|
||||
?AnimeScheduleFilterEnum $filter = null
|
||||
): EloquentBuilder;
|
||||
|
||||
public function getAiredBetween(
|
||||
public function getItemsBySeason(
|
||||
Carbon $from,
|
||||
Carbon $to,
|
||||
?AnimeTypeEnum $type = null,
|
||||
?string $premiered = null
|
||||
?string $premiered = null,
|
||||
bool $includeContinuingItems = false
|
||||
): EloquentBuilder;
|
||||
|
||||
public function getUpcomingSeasonItems(?AnimeTypeEnum $type = null): EloquentBuilder;
|
||||
|
26
app/Dto/Concerns/HasContinuingParameter.php
Normal file
26
app/Dto/Concerns/HasContinuingParameter.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace App\Dto\Concerns;
|
||||
|
||||
use App\Casts\ContextualBooleanCast;
|
||||
use OpenApi\Annotations as OA;
|
||||
use Spatie\LaravelData\Attributes\Validation\BooleanType;
|
||||
use Spatie\LaravelData\Attributes\WithCast;
|
||||
use Spatie\LaravelData\Optional;
|
||||
|
||||
/**
|
||||
* @OA\Parameter(
|
||||
* name="continuing",
|
||||
* in="query",
|
||||
* required=false,
|
||||
* description="This is a flag. When supplied it will include entries which are continuing from previous seasons. MAL includes these items on the seasons view in the ″TV (continuing)″ section. (Example: https://myanimelist.net/anime/season/2024/winter) <br />Example usage: `?continuing`",
|
||||
* @OA\Schema(type="boolean")
|
||||
* ),
|
||||
*/
|
||||
trait HasContinuingParameter
|
||||
{
|
||||
use PreparesData;
|
||||
|
||||
#[BooleanType, WithCast(ContextualBooleanCast::class)]
|
||||
public bool|Optional $continuing = false;
|
||||
}
|
@ -17,7 +17,6 @@ trait PreparesData
|
||||
{
|
||||
// let's always set the limit parameter to the globally configured default value
|
||||
if (property_exists(static::class, "limit") && !$properties->has("limit")) {
|
||||
/** @noinspection PhpUndefinedFieldInspection */
|
||||
$properties->put("limit", max_results_per_page(
|
||||
property_exists(static::class, "defaultLimit") ? static::$defaultLimit : null));
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ use App\Dto\Concerns\HasLimitParameter;
|
||||
use App\Dto\Concerns\HasPageParameter;
|
||||
use App\Dto\Concerns\HasSfwParameter;
|
||||
use App\Dto\Concerns\HasUnapprovedParameter;
|
||||
use App\Dto\Concerns\HasContinuingParameter;
|
||||
use App\Enums\AnimeTypeEnum;
|
||||
use App\Rules\Attributes\EnumValidation;
|
||||
use Spatie\LaravelData\Attributes\WithCast;
|
||||
@ -20,7 +21,13 @@ use Spatie\LaravelData\Optional;
|
||||
|
||||
abstract class QueryAnimeSeasonCommand extends Data implements DataRequest
|
||||
{
|
||||
use HasSfwParameter, HasKidsParameter, HasUnapprovedParameter, HasLimitParameter, HasRequestFingerprint, HasPageParameter;
|
||||
use HasSfwParameter,
|
||||
HasKidsParameter,
|
||||
HasUnapprovedParameter,
|
||||
HasLimitParameter,
|
||||
HasRequestFingerprint,
|
||||
HasPageParameter,
|
||||
HasContinuingParameter;
|
||||
|
||||
#[WithCast(EnumCast::class, AnimeTypeEnum::class), EnumValidation(AnimeTypeEnum::class)]
|
||||
public AnimeTypeEnum|Optional $filter;
|
||||
|
@ -32,8 +32,6 @@ abstract class QueryAnimeSeasonHandlerBase implements RequestHandler
|
||||
{
|
||||
$requestParams = collect($request->all());
|
||||
$type = $requestParams->has("filter") ? $request->filter : null;
|
||||
$season = $requestParams->has("season") ? $request->season : null;
|
||||
$year = $requestParams->has("year") ? $request->year : null;
|
||||
$results = $this->getSeasonItems($request, $type);
|
||||
// apply sfw, kids and unapproved filters
|
||||
/** @noinspection PhpUndefinedMethodInspection */
|
||||
|
@ -53,7 +53,8 @@ final class QueryCurrentAnimeSeasonHandler extends QueryAnimeSeasonHandlerBase
|
||||
*/
|
||||
[$from, $to] = $this->getSeasonRange($year, $season);
|
||||
$premiered = ucfirst($season)." {$year}";
|
||||
$includeContinuingItems = $request->continuing;
|
||||
|
||||
return $this->repository->getAiredBetween($from, $to, $type, $premiered);
|
||||
return $this->repository->getItemsBySeason($from, $to, $type, $premiered, $includeContinuingItems);
|
||||
}
|
||||
}
|
||||
|
@ -28,8 +28,8 @@ final class QuerySpecificAnimeSeasonHandler extends QueryAnimeSeasonHandlerBase
|
||||
|
||||
[$from, $to] = $this->getSeasonRange($request->year, $request->season);
|
||||
$premiered = ucfirst($request->season)." {$request->year}";
|
||||
$includeContinuingItems = $request->continuing;
|
||||
|
||||
return $this->repository->getAiredBetween($from, $to, $type, $premiered);
|
||||
// ->where("status", "!=", AnimeStatusEnum::upcoming()->label);
|
||||
return $this->repository->getItemsBySeason($from, $to, $type, $premiered, $includeContinuingItems);
|
||||
}
|
||||
}
|
||||
|
@ -2,21 +2,12 @@
|
||||
|
||||
namespace App\Http\Controllers\V4DB;
|
||||
|
||||
use App\Anime;
|
||||
use App\Dto\QueryAnimeSeasonListCommand;
|
||||
use App\Dto\QueryCurrentAnimeSeasonCommand;
|
||||
use App\Dto\QuerySpecificAnimeSeasonCommand;
|
||||
use App\Dto\QueryUpcomingAnimeSeasonCommand;
|
||||
use App\Http\HttpResponse;
|
||||
use App\Http\QueryBuilder\AnimeSearchQueryBuilder;
|
||||
use App\Http\Resources\V4\AnimeCollection;
|
||||
use App\Http\Resources\V4\ResultsResource;
|
||||
use Exception;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Jikan\Request\SeasonList\SeasonListRequest;
|
||||
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
|
||||
use OpenApi\Annotations as OA;
|
||||
|
||||
/**
|
||||
*
|
||||
@ -38,6 +29,7 @@ class SeasonController extends Controller
|
||||
*
|
||||
* @OA\Parameter(ref="#/components/parameters/sfw"),
|
||||
* @OA\Parameter(ref="#/components/parameters/unapproved"),
|
||||
* @OA\Parameter(ref="#/components/parameters/continuing"),
|
||||
* @OA\Parameter(ref="#/components/parameters/page"),
|
||||
* @OA\Parameter(ref="#/components/parameters/limit"),
|
||||
*
|
||||
@ -89,6 +81,7 @@ class SeasonController extends Controller
|
||||
*
|
||||
* @OA\Parameter(ref="#/components/parameters/sfw"),
|
||||
* @OA\Parameter(ref="#/components/parameters/unapproved"),
|
||||
* @OA\Parameter(ref="#/components/parameters/continuing"),
|
||||
* @OA\Parameter(ref="#/components/parameters/page"),
|
||||
* @OA\Parameter(ref="#/components/parameters/limit"),
|
||||
*
|
||||
@ -177,6 +170,7 @@ class SeasonController extends Controller
|
||||
*
|
||||
* @OA\Parameter(ref="#/components/parameters/sfw"),
|
||||
* @OA\Parameter(ref="#/components/parameters/unapproved"),
|
||||
* @OA\Parameter(ref="#/components/parameters/continuing"),
|
||||
* @OA\Parameter(ref="#/components/parameters/page"),
|
||||
* @OA\Parameter(ref="#/components/parameters/limit"),
|
||||
*
|
||||
|
@ -110,11 +110,12 @@ final class DefaultAnimeRepository extends DatabaseRepository implements AnimeRe
|
||||
return $queryable;
|
||||
}
|
||||
|
||||
public function getAiredBetween(
|
||||
public function getItemsBySeason(
|
||||
Carbon $from,
|
||||
Carbon $to,
|
||||
?AnimeTypeEnum $type = null,
|
||||
?string $premiered = null
|
||||
?string $premiered = null,
|
||||
bool $includeContinuingItems = false
|
||||
): EloquentBuilder
|
||||
{
|
||||
$queryable = $this->queryable(true);
|
||||
@ -127,9 +128,10 @@ final class DefaultAnimeRepository extends DatabaseRepository implements AnimeRe
|
||||
$finalFilter = [];
|
||||
|
||||
// if the premiered parameter for the filter is not null, look for those items which have a premiered attribute set,
|
||||
// and equals to the parameter value, OR look for those items which doesn't have premired attribute set,
|
||||
// and equals to the parameter value, OR look for those items which doesn't have premiered attribute set,
|
||||
// they don't have a garbled aired string and their aired.from date is within the from-to parameters range.
|
||||
// Additionally, we want to include all those items which are carry overs from previous seasons.
|
||||
// Additionally, we want to include all those items which are carry overs from previous seasons,
|
||||
// if the includeContinuingItems argument is set to true.
|
||||
if ($premiered !== null) {
|
||||
$finalFilter['$or'] = [
|
||||
['premiered' => $premiered],
|
||||
@ -140,12 +142,14 @@ final class DefaultAnimeRepository extends DatabaseRepository implements AnimeRe
|
||||
],
|
||||
...$airedFilter
|
||||
],
|
||||
];
|
||||
if ($includeContinuingItems) {
|
||||
// this condition will include "continuing" items from previous seasons
|
||||
[
|
||||
$finalFilter['$or'][] = [
|
||||
'aired.from' => ['$lte' => $from->toAtomString()],
|
||||
'airing' => true
|
||||
]
|
||||
];
|
||||
}
|
||||
} else {
|
||||
$finalFilter = array_merge($finalFilter, $airedFilter);
|
||||
$finalFilter['aired.string'] = [
|
||||
|
@ -3046,6 +3046,9 @@
|
||||
{
|
||||
"$ref": "#/components/parameters/unapproved"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/parameters/continuing"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/parameters/page"
|
||||
},
|
||||
@ -3115,6 +3118,9 @@
|
||||
{
|
||||
"$ref": "#/components/parameters/unapproved"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/parameters/continuing"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/parameters/page"
|
||||
},
|
||||
@ -3191,6 +3197,9 @@
|
||||
{
|
||||
"$ref": "#/components/parameters/unapproved"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/parameters/continuing"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/parameters/page"
|
||||
},
|
||||
@ -9027,6 +9036,15 @@
|
||||
}
|
||||
},
|
||||
"parameters": {
|
||||
"continuing": {
|
||||
"name": "continuing",
|
||||
"in": "query",
|
||||
"description": "This is a flag. When supplied it will include entries which are continuing from previous seasons. MAL includes these items on the seasons view in the ″TV (continuing)″ section. (Example: https://myanimelist.net/anime/season/2024/winter) <br />Example usage: `?continuing`",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"kids": {
|
||||
"name": "kids",
|
||||
"in": "query",
|
||||
|
@ -131,9 +131,51 @@ class SeasonControllerTest extends TestCase
|
||||
$state["airing"] = true;
|
||||
$f->create($state);
|
||||
|
||||
$content = $this->getJsonResponse([], "/v4/seasons/2024/winter");
|
||||
$content = $this->getJsonResponse([], "/v4/seasons/2024/winter?continuing=true");
|
||||
$this->seeStatusCode(200);
|
||||
$this->assertIsArray($content["data"]);
|
||||
$this->assertCount(3, $content["data"]);
|
||||
}
|
||||
|
||||
public function testShouldNotIncludeContinuingItemsByDefault()
|
||||
{
|
||||
Carbon::setTestNow(Carbon::parse("2024-01-11"));
|
||||
// an item in the future airing
|
||||
$f = Anime::factory(1);
|
||||
$startDate = "2024-02-24";
|
||||
$carbonStartDate = Carbon::parse($startDate);
|
||||
$state = $f->serializeStateDefinition([
|
||||
"aired" => new CarbonDateRange($carbonStartDate, null)
|
||||
]);
|
||||
$state["aired"]["string"] = "Feb 24, 2024 to ?";
|
||||
$state["premiered"] = null;
|
||||
$state["status"] = "Not yet aired";
|
||||
$state["airing"] = false;
|
||||
$f->create($state);
|
||||
|
||||
// the absolutely correct item
|
||||
$f = Anime::factory(1);
|
||||
$state = $f->serializeStateDefinition([
|
||||
"aired" => new CarbonDateRange(Carbon::parse("2024-01-10"), Carbon::parse("2024-02-15"))
|
||||
]);
|
||||
$state["premiered"] = "Winter 2024";
|
||||
$state["status"] = "Currently Airing";
|
||||
$state["airing"] = true;
|
||||
$f->create($state);
|
||||
|
||||
// the continuing item
|
||||
$f = Anime::factory(1);
|
||||
$state = $f->serializeStateDefinition([
|
||||
"aired" => new CarbonDateRange(Carbon::parse("2023-10-10"), null)
|
||||
]);
|
||||
$state["premiered"] = "Fall 2023";
|
||||
$state["status"] = "Currently Airing";
|
||||
$state["airing"] = true;
|
||||
$f->create($state);
|
||||
|
||||
$content = $this->getJsonResponse([], "/v4/seasons/2024/winter");
|
||||
$this->seeStatusCode(200);
|
||||
$this->assertIsArray($content["data"]);
|
||||
$this->assertCount(2, $content["data"]);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user