mirror of
https://github.com/jikan-me/jikan-rest.git
synced 2025-02-20 11:23:35 +08:00
Merge branch 'master' into irfan-dahir-patch-1
This commit is contained in:
commit
8d1e935c0b
@ -6,7 +6,7 @@ APP_DEBUG=false
|
||||
APP_KEY=
|
||||
APP_TIMEZONE=UTC
|
||||
APP_URL=http://localhost
|
||||
APP_VERSION="4.2.1"
|
||||
APP_VERSION="4.2.2"
|
||||
|
||||
###
|
||||
# Logging
|
||||
|
13
.github/workflows/container-image-release.yml
vendored
13
.github/workflows/container-image-release.yml
vendored
@ -86,10 +86,14 @@ jobs:
|
||||
digest="${{ steps.build.outputs.digest }}"
|
||||
touch "/tmp/digests/${digest#sha256:}"
|
||||
|
||||
- name: Transform platform value
|
||||
id: platform_transform
|
||||
run: echo "platform=$(echo '${{ matrix.platform }}' | sed 's/\//_/g')" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Upload digest
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: digests
|
||||
name: digests-${{ steps.platform_transform.outputs.platform }}
|
||||
path: /tmp/digests/*
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
@ -101,9 +105,10 @@ jobs:
|
||||
- build-app-image
|
||||
steps:
|
||||
- name: Download digests
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: digests
|
||||
pattern: digests-*
|
||||
merge-multiple: true
|
||||
path: /tmp/digests
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
|
@ -15,6 +15,7 @@ use Jikan\Helper\Constants;
|
||||
use Jikan\Jikan;
|
||||
use Jikan\Request\Anime\AnimeRequest;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use MongoDB\Model\BSONDocument;
|
||||
|
||||
class Anime extends JikanApiSearchableModel
|
||||
{
|
||||
@ -103,7 +104,6 @@ class Anime extends JikanApiSearchableModel
|
||||
|| !is_string($premiered)
|
||||
|| !preg_match('~(Winter|Spring|Summer|Fall|)\s([\d+]{4})~', $premiered)
|
||||
) {
|
||||
Log::warning("Invalid premiered value in Anime model[$this->mal_id]: " . $premiered);
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -182,14 +182,11 @@ class Anime extends JikanApiSearchableModel
|
||||
}
|
||||
|
||||
$producer = (int)$value;
|
||||
/** @noinspection PhpParamsInspection */
|
||||
return $query->whereRaw([
|
||||
'$or' => [
|
||||
['producers.mal_id' => $producer],
|
||||
['licensors.mal_id' => $producer],
|
||||
['studios.mal_id' => $producer]
|
||||
]
|
||||
]);
|
||||
return $query->where(function (\Jenssegers\Mongodb\Eloquent\Builder $query) use ($producer) {
|
||||
return $query->where('producers.mal_id', $producer)
|
||||
->orWhere('licensors.mal_id', $producer)
|
||||
->orWhere('studios.mal_id', $producer);
|
||||
});
|
||||
}
|
||||
|
||||
/** @noinspection PhpUnused */
|
||||
@ -199,16 +196,24 @@ class Anime extends JikanApiSearchableModel
|
||||
return $query;
|
||||
}
|
||||
|
||||
$producers = collect(explode(',', $value))->filter()->toArray();
|
||||
$orFilters = [];
|
||||
foreach ($producers as $producer) {
|
||||
$producer = (int)$producer;
|
||||
$orFilters[] = ['producers.mal_id' => $producer];
|
||||
$orFilters[] = ['licensors.mal_id' => $producer];
|
||||
$orFilters[] = ['studios.mal_id' => $producer];
|
||||
}
|
||||
/** @noinspection PhpParamsInspection */
|
||||
return $query->whereRaw(['$or' => $orFilters]);
|
||||
/* @var \Illuminate\Support\Collection $producers */
|
||||
$producers = collect(explode(',', $value))->filter();
|
||||
|
||||
return $query->where(function (\Jenssegers\Mongodb\Eloquent\Builder $query) use ($producers) {
|
||||
$firstProducer = (int)$producers->first();
|
||||
$query = $query->where('producers.mal_id', $firstProducer)
|
||||
->orWhere('licensors.mal_id', $firstProducer)
|
||||
->orWhere('studios.mal_id', $firstProducer);
|
||||
|
||||
foreach ($producers->skip(1) as $producer) {
|
||||
$producer = (int)$producer;
|
||||
$query = $query->orWhere('producers.mal_id', $producer)
|
||||
->orWhere('licensors.mal_id', $producer)
|
||||
->orWhere('studios.mal_id', $producer);
|
||||
}
|
||||
|
||||
return $query;
|
||||
});
|
||||
}
|
||||
|
||||
/** @noinspection PhpUnused */
|
||||
@ -403,7 +408,7 @@ class Anime extends JikanApiSearchableModel
|
||||
];
|
||||
}
|
||||
|
||||
private function adaptBroadcastValue(array|string|null $broadcast): array
|
||||
private function adaptBroadcastValue(array|string|null|BSONDocument $broadcast): array
|
||||
{
|
||||
$null_value = [
|
||||
'day' => null,
|
||||
@ -419,6 +424,10 @@ class Anime extends JikanApiSearchableModel
|
||||
return $broadcast;
|
||||
}
|
||||
|
||||
if ($broadcast instanceof BSONDocument) {
|
||||
return $broadcast->getArrayCopy();
|
||||
}
|
||||
|
||||
if (!preg_match('~(.*) at (.*) \(~', $broadcast, $matches)) {
|
||||
return [
|
||||
'day' => null,
|
||||
|
@ -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));
|
||||
}
|
||||
@ -44,7 +43,7 @@ trait PreparesData
|
||||
}
|
||||
}
|
||||
// if the property is optional and the value is an empty string, we want to ignore it.
|
||||
if ($property->type->isOptional && $propertyVal === "") {
|
||||
if ($property->type->isOptional && $propertyVal === "" && !$property->type->acceptsType("bool")) {
|
||||
$propertyVal = null;
|
||||
}
|
||||
|
||||
@ -53,7 +52,7 @@ trait PreparesData
|
||||
} else {
|
||||
$properties->forget($propertyRawName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $properties;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ use App\Anime;
|
||||
use App\Contracts\RequestHandler;
|
||||
use App\Dto\QueryRandomAnimeCommand;
|
||||
use App\Http\Resources\V4\AnimeResource;
|
||||
use Spatie\LaravelData\Optional;
|
||||
|
||||
/**
|
||||
* @implements RequestHandler<QueryRandomAnimeCommand, AnimeResource>
|
||||
@ -18,12 +19,13 @@ final class QueryRandomAnimeHandler implements RequestHandler
|
||||
public function handle($request): AnimeResource
|
||||
{
|
||||
$queryable = Anime::query();
|
||||
// apply sfw, kids and unapproved filters
|
||||
/** @noinspection PhpUndefinedMethodInspection */
|
||||
$queryable = $queryable->filter(collect($request->all()));
|
||||
|
||||
$o = Optional::create();
|
||||
$sfwParam = $request->sfw === $o ? false : $request->sfw;
|
||||
$unapprovedParam = $request->unapproved === $o ? false : $request->unapproved;
|
||||
|
||||
return new AnimeResource(
|
||||
$queryable->random()->first()
|
||||
$queryable->random(1, $sfwParam, $unapprovedParam)->first()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ use App\Contracts\RequestHandler;
|
||||
use App\Dto\QueryRandomMangaCommand;
|
||||
use App\Http\Resources\V4\MangaResource;
|
||||
use App\Manga;
|
||||
use Spatie\LaravelData\Optional;
|
||||
|
||||
/**
|
||||
* @implements RequestHandler<QueryRandomMangaCommand, MangaResource>
|
||||
@ -18,12 +19,13 @@ final class QueryRandomMangaHandler implements RequestHandler
|
||||
public function handle($request)
|
||||
{
|
||||
$queryable = Manga::query();
|
||||
// apply sfw, kids and unapproved filters
|
||||
/** @noinspection PhpUndefinedMethodInspection */
|
||||
$queryable = $queryable->filter(collect($request->all()));
|
||||
|
||||
$o = Optional::create();
|
||||
$sfwParam = $request->sfw === $o ? false : $request->sfw;
|
||||
$unapprovedParam = $request->unapproved === $o ? false : $request->unapproved;
|
||||
|
||||
return new MangaResource(
|
||||
$queryable->random()->first()
|
||||
$queryable->random(1, $sfwParam, $unapprovedParam)->first()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -13,8 +13,6 @@ class ScheduleController extends Controller
|
||||
* operationId="getSchedules",
|
||||
* tags={"schedules"},
|
||||
*
|
||||
* @OA\Parameter(ref="#/components/parameters/page"),
|
||||
*
|
||||
* @OA\Parameter(
|
||||
* name="filter",
|
||||
* in="query",
|
||||
@ -39,7 +37,6 @@ class ScheduleController extends Controller
|
||||
* @OA\Schema(type="string",enum={"true", "false"})
|
||||
* ),
|
||||
*
|
||||
* @OA\Parameter(ref="#/components/parameters/sfw"),
|
||||
* @OA\Parameter(ref="#/components/parameters/unapproved"),
|
||||
* @OA\Parameter(ref="#/components/parameters/page"),
|
||||
* @OA\Parameter(ref="#/components/parameters/limit"),
|
||||
|
@ -25,7 +25,6 @@ class SearchController extends Controller
|
||||
* operationId="getAnimeSearch",
|
||||
* tags={"anime"},
|
||||
*
|
||||
* @OA\Parameter(ref="#/components/parameters/sfw"),
|
||||
* @OA\Parameter(ref="#/components/parameters/unapproved"),
|
||||
* @OA\Parameter(ref="#/components/parameters/page"),
|
||||
* @OA\Parameter(ref="#/components/parameters/limit"),
|
||||
@ -159,7 +158,6 @@ class SearchController extends Controller
|
||||
* operationId="getMangaSearch",
|
||||
* tags={"manga"},
|
||||
*
|
||||
* @OA\Parameter(ref="#/components/parameters/sfw"),
|
||||
* @OA\Parameter(ref="#/components/parameters/unapproved"),
|
||||
* @OA\Parameter(ref="#/components/parameters/page"),
|
||||
* @OA\Parameter(ref="#/components/parameters/limit"),
|
||||
|
@ -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"),
|
||||
*
|
||||
|
@ -2,9 +2,12 @@
|
||||
|
||||
namespace App;
|
||||
|
||||
use App\Enums\AnimeRatingEnum;
|
||||
use App\Enums\MangaTypeEnum;
|
||||
use App\Filters\FilterQueryString;
|
||||
use Illuminate\Support\Collection;
|
||||
use Jenssegers\Mongodb\Eloquent\Builder;
|
||||
use Jikan\Helper\Constants;
|
||||
|
||||
class JikanApiModel extends \Jenssegers\Mongodb\Eloquent\Model
|
||||
{
|
||||
@ -19,10 +22,44 @@ class JikanApiModel extends \Jenssegers\Mongodb\Eloquent\Model
|
||||
protected array $filters = [];
|
||||
|
||||
/** @noinspection PhpUnused */
|
||||
public function scopeRandom(Builder $query, int $numberOfRandomItems = 1): Collection
|
||||
public function scopeRandom(Builder $query, int $numberOfRandomItems = 1, bool $sfw = false, bool $unapproved = false): Collection
|
||||
{
|
||||
return $query->raw(fn(\Jenssegers\Mongodb\Collection $collection) => $collection->aggregate([
|
||||
['$sample' => ['size' => $numberOfRandomItems]]
|
||||
]));
|
||||
return $query->raw(function(\Jenssegers\Mongodb\Collection $collection) use ($numberOfRandomItems, $sfw, $unapproved) {
|
||||
$sfwFilter = [
|
||||
'demographics.mal_id' => [
|
||||
'$nin' => [
|
||||
Constants::GENRE_ANIME_HENTAI,
|
||||
Constants::GENRE_ANIME_EROTICA,
|
||||
Constants::GENRE_MANGA_HENTAI,
|
||||
Constants::GENRE_MANGA_EROTICA
|
||||
]
|
||||
],
|
||||
'rating' => ['$ne' => AnimeRatingEnum::rx()->label],
|
||||
'type' => ['$ne' => MangaTypeEnum::doujin()->label],
|
||||
'genres.mal_id' => ['$nin' => [
|
||||
Constants::GENRE_ANIME_HENTAI,
|
||||
Constants::GENRE_MANGA_HENTAI
|
||||
]]
|
||||
];
|
||||
|
||||
$pipelineParams = [
|
||||
['$sample' => ['size' => $numberOfRandomItems]]
|
||||
];
|
||||
|
||||
if ($sfw && $unapproved) {
|
||||
array_unshift($pipelineParams, [
|
||||
'$match' => [
|
||||
...$sfwFilter,
|
||||
'approved' => false
|
||||
]
|
||||
]);
|
||||
} else if ($sfw) {
|
||||
array_unshift($pipelineParams, ['$match' => $sfwFilter]);
|
||||
} else if ($unapproved) {
|
||||
array_unshift($pipelineParams, ['$match' => ['approved' => false]]);
|
||||
}
|
||||
|
||||
return $collection->aggregate($pipelineParams);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -111,14 +111,10 @@ class Manga extends JikanApiSearchableModel
|
||||
return $query;
|
||||
}
|
||||
|
||||
/** @var \Illuminate\Support\Collection $magazines */
|
||||
$magazines = collect(explode(',', $value))->filter()->map(fn($x) => (int)$x)->toArray();
|
||||
|
||||
/** @noinspection PhpParamsInspection */
|
||||
return $query->whereRaw([
|
||||
"serializations.mal_id" => [
|
||||
'$in' => $magazines
|
||||
]
|
||||
]);
|
||||
return $query->whereIn("serializations.mal_id", $magazines);
|
||||
}
|
||||
|
||||
/** @noinspection PhpUnused */
|
||||
|
@ -5,16 +5,14 @@ namespace App\Repositories;
|
||||
use App\Anime;
|
||||
use App\Contracts\AnimeRepository;
|
||||
use App\Contracts\Repository;
|
||||
use App\Enums\AnimeRatingEnum;
|
||||
use App\Enums\AnimeScheduleFilterEnum;
|
||||
use App\Enums\AnimeSeasonEnum;
|
||||
use App\Enums\AnimeStatusEnum;
|
||||
use App\Enums\AnimeTypeEnum;
|
||||
use Illuminate\Contracts\Database\Query\Builder as EloquentBuilder;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Jikan\Helper\Constants;
|
||||
use Laravel\Scout\Builder as ScoutBuilder;
|
||||
use MongoDB\BSON\UTCDateTime;
|
||||
|
||||
/**
|
||||
* @implements Repository<Anime>
|
||||
@ -113,51 +111,96 @@ 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
|
||||
{
|
||||
/** @noinspection PhpParamsInspection */
|
||||
$queryable = $this->queryable(true);
|
||||
|
||||
$airedFilter = ["aired.from" => [
|
||||
$airedFilter = ['aired.from' => [
|
||||
'$gte' => $from->toAtomString(),
|
||||
'$lte' => $to->modify("last day of this month")->toAtomString()
|
||||
'$lte' => $to->modify('last day of this month')->toAtomString()
|
||||
]];
|
||||
|
||||
$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,
|
||||
// they don't have a garbled aired string and their aired.from date is within the from-to parameters range
|
||||
// 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,
|
||||
// if the includeContinuingItems argument is set to true.
|
||||
if ($premiered !== null) {
|
||||
$finalFilter['$or'] = [
|
||||
["premiered" => $premiered],
|
||||
['premiered' => $premiered],
|
||||
[
|
||||
"premiered" => null,
|
||||
"aired.string" => [
|
||||
'$not' => ['$regex' => "{$from->year} to ?"]
|
||||
'premiered' => null,
|
||||
'aired.string' => [
|
||||
'$nin' => ["{$from->year} to ?"]
|
||||
],
|
||||
...$airedFilter
|
||||
]
|
||||
],
|
||||
];
|
||||
if ($includeContinuingItems) {
|
||||
// these conditions will include "continuing" items from previous seasons
|
||||
// long running shows
|
||||
$finalFilter['$or'][] = [
|
||||
'aired.from' => ['$lte' => $from->toAtomString()],
|
||||
'aired.to' => null,
|
||||
'episodes' => null,
|
||||
'airing' => true
|
||||
];
|
||||
// We want to include those which are currently airing, and their aired.to is past the date of the
|
||||
// current season start.
|
||||
$finalFilter['$or'][] = [
|
||||
'aired.from' => ['$lte' => $from->toAtomString()],
|
||||
'aired.to' => ['$gte' => $from->toAtomString()],
|
||||
'airing' => true
|
||||
];
|
||||
// In many cases MAL doesn't show the date until an airing show is going to be aired. So we need to get
|
||||
// clever here.
|
||||
// We want to include those shows which have started in previous season only (not before) and it's going
|
||||
// to continue in the current season.
|
||||
$finalFilter['$or'][] = [
|
||||
// note: this expression only works with mongodb version 5.0.0 or higher
|
||||
'$expr' => [
|
||||
'$lte' => [
|
||||
[
|
||||
'$dateDiff' => [
|
||||
'startDate' => [
|
||||
'$dateFromString' => [
|
||||
'dateString' => '$aired.from'
|
||||
]
|
||||
],
|
||||
'endDate' => new UTCDateTime($from),
|
||||
'unit' => 'month'
|
||||
]
|
||||
],
|
||||
3 // there are 3 months in a season, so anything that started in 3 months or less will be included
|
||||
]
|
||||
],
|
||||
'aired.to' => null,
|
||||
'episodes' => ['$gte' => 14],
|
||||
'airing' => true
|
||||
];
|
||||
}
|
||||
} else {
|
||||
$finalFilter = array_merge($finalFilter, $airedFilter);
|
||||
$finalFilter["aired.string"] = [
|
||||
'$not' => ['$regex' => "{$from->year} to ?"]
|
||||
$finalFilter['aired.string'] = [
|
||||
'$nin' => ["{$from->year} to ?"]
|
||||
];
|
||||
}
|
||||
|
||||
if (!is_null($type)) {
|
||||
$finalFilter["type"] = $type->label;
|
||||
$finalFilter['type'] = $type->label;
|
||||
}
|
||||
|
||||
$queryable = $queryable->whereRaw($finalFilter);
|
||||
|
||||
return $queryable->orderBy("members", "desc");
|
||||
return $queryable->orderBy('members', 'desc');
|
||||
}
|
||||
|
||||
public function getUpcomingSeasonItems(
|
||||
|
@ -65,7 +65,7 @@ final class CachedData implements ArrayAccess
|
||||
|
||||
$expiry = $this->expiry();
|
||||
|
||||
return time() > $expiry;
|
||||
return Carbon::now()->unix() > $expiry;
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace App\Support;
|
||||
use Laravel\Scout\Builder as ScoutBuilder;
|
||||
use Illuminate\Contracts\Database\Query\Builder;
|
||||
use Jenssegers\Mongodb\Eloquent\Builder as MongoDbBuilder;
|
||||
|
||||
class RepositoryQueryBase
|
||||
{
|
||||
@ -15,7 +16,7 @@ class RepositoryQueryBase
|
||||
{
|
||||
}
|
||||
|
||||
protected function queryable(bool $createNew = false): Builder
|
||||
protected function queryable(bool $createNew = false): Builder|MongoDbBuilder
|
||||
{
|
||||
if ($createNew) {
|
||||
$callback = $this->getQueryable;
|
||||
|
@ -32,6 +32,7 @@ trait SyntheticMongoDbTransaction
|
||||
$tablesWithoutModels = [
|
||||
"anime_characters_staff",
|
||||
"anime_episodes",
|
||||
"anime_episode",
|
||||
"anime_forum",
|
||||
"anime_moreinfo",
|
||||
"anime_news",
|
||||
@ -42,6 +43,7 @@ trait SyntheticMongoDbTransaction
|
||||
"anime_userupdates",
|
||||
"anime_videos",
|
||||
"character_pictures",
|
||||
"characters_pictures",
|
||||
"clubs_members",
|
||||
"demographics_manga",
|
||||
"demographics_anime",
|
||||
|
398
composer.lock
generated
398
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -4,6 +4,7 @@ namespace Database\Factories;
|
||||
use App\CarbonDateRange;
|
||||
use App\Anime;
|
||||
use App\Testing\JikanDataGenerator;
|
||||
use Illuminate\Support\Collection;
|
||||
use MongoDB\BSON\UTCDateTime;
|
||||
|
||||
|
||||
@ -139,4 +140,47 @@ class AnimeFactory extends JikanMediaModelFactory
|
||||
"request_hash" => sprintf("request:%s:%s", "v4", $this->getItemTestUrl("anime", $mal_id))
|
||||
];
|
||||
}
|
||||
|
||||
protected function getOverridesFromQueryStringParameters(Collection $additionalParams): array
|
||||
{
|
||||
$overrides = parent::getOverridesFromQueryStringParameters($additionalParams);
|
||||
|
||||
if ($additionalParams->has("producers")) {
|
||||
$overrides["producers"] = [];
|
||||
$producerIds = explode(",", $additionalParams["producers"]);
|
||||
foreach ($producerIds as $producerId) {
|
||||
$overrides["producers"][] = [
|
||||
"mal_id" => (int)$producerId,
|
||||
"type" => "anime",
|
||||
"name" => "Producer ${producerId}",
|
||||
"url" => "https://myanimelist.net/anime/producer/${producerId}/x"
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $overrides;
|
||||
}
|
||||
|
||||
protected function getOppositeOverridesFromQueryStringParameters(Collection $additionalParams): array
|
||||
{
|
||||
$overrides = parent::getOppositeOverridesFromQueryStringParameters($additionalParams);
|
||||
|
||||
if ($additionalParams->has("producers")) {
|
||||
$overrides["producers"] = [];
|
||||
$producerIds = explode(",", $additionalParams["producers"]);
|
||||
do {
|
||||
$randomEls = $this->faker->randomElements([11, 60, 89, 54, 32, 22, 108, 65], $this->faker->numberBetween(1, 3));
|
||||
} while (count(array_intersect($randomEls, $producerIds)) > 0);
|
||||
foreach ($randomEls as $producerId) {
|
||||
$overrides["produces"][] = [
|
||||
"mal_id" => (int)$producerId,
|
||||
"type" => "anime",
|
||||
"name" => "Producer ${producerId}",
|
||||
"url" => "https://myanimelist.net/anime/producer/${producerId}/x"
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $overrides;
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ use App\Enums\AnimeRatingEnum;
|
||||
use App\Enums\AnimeTypeEnum;
|
||||
use App\Enums\MangaTypeEnum;
|
||||
use App\Testing\JikanDataGenerator;
|
||||
use Illuminate\Database\Eloquent\Factories\Sequence;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Collection;
|
||||
@ -56,6 +57,18 @@ abstract class JikanMediaModelFactory extends JikanModelFactory implements Media
|
||||
* @return self
|
||||
*/
|
||||
public function overrideFromQueryStringParameters(array $additionalParams, bool $doOpposite = false): self
|
||||
{
|
||||
if ($this->count === 1) {
|
||||
return $this->state($this->serializeStateDefinition($this->getStateOverrides($additionalParams, $doOpposite)));
|
||||
}
|
||||
|
||||
// we want to generate overrides for each manufactured item, so all of them will call the faker for values,
|
||||
// and they should have their own values, increasing the randomness of the generated data
|
||||
/** @noinspection PhpParamsInspection */
|
||||
return $this->state(new Sequence(fn(Sequence $_) => $this->serializeStateDefinition($this->getStateOverrides($additionalParams, $doOpposite))));
|
||||
}
|
||||
|
||||
private function getStateOverrides(array $additionalParams, bool $doOpposite = false): array
|
||||
{
|
||||
$additionalParams = collect($additionalParams);
|
||||
|
||||
@ -66,7 +79,7 @@ abstract class JikanMediaModelFactory extends JikanModelFactory implements Media
|
||||
$overrides = $this->getOverridesFromQueryStringParameters($additionalParams);
|
||||
}
|
||||
|
||||
return $this->state($this->serializeStateDefinition($overrides));
|
||||
return $overrides;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -158,6 +171,10 @@ abstract class JikanMediaModelFactory extends JikanModelFactory implements Media
|
||||
$overrides = [...$overrides, ...$a];
|
||||
}
|
||||
|
||||
if ($additionalParams->has("score")) {
|
||||
$overrides["score"] = floatval($additionalParams["score"]);
|
||||
}
|
||||
|
||||
if ($additionalParams->has("min_score") && !$additionalParams->has("max_score")) {
|
||||
$min_score = floatval($additionalParams["min_score"]);
|
||||
if ($this->isScoreValueValid($min_score)) {
|
||||
@ -227,7 +244,7 @@ abstract class JikanMediaModelFactory extends JikanModelFactory implements Media
|
||||
if ($additionalParams->has("start_date") && !empty($additionalParams["start_date"])
|
||||
&& !$additionalParams->has("end_date")) {
|
||||
$startDate = $this->adaptDateString($additionalParams["start_date"]);
|
||||
$dt = Carbon::parse($startDate)->addDays($this->faker->numberBetween(0, 25));
|
||||
$dt = Carbon::parse($startDate)->addDays($this->faker->numberBetween(1, 25));
|
||||
$overrides[$activityMarkerKeyName] = new CarbonDateRange($dt, null);
|
||||
}
|
||||
|
||||
@ -236,7 +253,7 @@ abstract class JikanMediaModelFactory extends JikanModelFactory implements Media
|
||||
$endDate = $this->adaptDateString($additionalParams["end_date"]);
|
||||
$to = Carbon::parse($endDate);
|
||||
$from = $to->copy()->subDays($this->faker->randomElement([30, 60, 90, 120, 180]));
|
||||
$overrides[$activityMarkerKeyName] = new CarbonDateRange($from, $to->subDays($this->faker->numberBetween(0, 25)));
|
||||
$overrides[$activityMarkerKeyName] = new CarbonDateRange($from, $to->subDays($this->faker->numberBetween(1, 25)));
|
||||
}
|
||||
|
||||
if ($additionalParams->has(["start_date", "end_date"])
|
||||
@ -283,17 +300,26 @@ abstract class JikanMediaModelFactory extends JikanModelFactory implements Media
|
||||
$overrides = [...$overrides, ...$a];
|
||||
}
|
||||
|
||||
if ($additionalParams->has("score")) {
|
||||
$specifiedScore = floatval($additionalParams["score"]);
|
||||
do {
|
||||
$randomScore = $this->faker->randomFloat(2, 1.00, 9.99);
|
||||
} while ($randomScore === $specifiedScore);
|
||||
|
||||
$overrides["score"] = $randomScore;
|
||||
}
|
||||
|
||||
if ($additionalParams->has("min_score") && !$additionalParams->has("max_score")) {
|
||||
$min_score = floatval($additionalParams["min_score"]);
|
||||
if ($this->isScoreValueValid($min_score)) {
|
||||
$overrides["score"] = $this->faker->randomFloat(2, 1.00, floatval($additionalParams["min_score"]));
|
||||
$overrides["score"] = $this->faker->randomFloat(2, 1.00, floatval($additionalParams["min_score"]) - 0.01);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$additionalParams->has("min_score") && $additionalParams->has("max_score")) {
|
||||
$max_score = $additionalParams["max_score"];
|
||||
if ($this->isScoreValueValid($max_score)) {
|
||||
$overrides["score"] = $this->faker->randomFloat(2, floatval($additionalParams["max_score"]), 9.99);
|
||||
$overrides["score"] = $this->faker->randomFloat(2, floatval($additionalParams["max_score"]) + 0.01, 9.99);
|
||||
}
|
||||
}
|
||||
|
||||
@ -304,8 +330,8 @@ abstract class JikanMediaModelFactory extends JikanModelFactory implements Media
|
||||
if ($this->isScoreValueValid($min_score) && $this->isScoreValueValid($max_score))
|
||||
{
|
||||
$overrides["score"] = $this->faker->randomElement([
|
||||
$this->faker->randomFloat(2, 1.00, floatval($additionalParams["min_score"])),
|
||||
$this->faker->randomFloat(2, floatval($additionalParams["max_score"]), 9.99)
|
||||
$this->faker->randomFloat(2, 1.00, floatval($additionalParams["min_score"]) - 0.01),
|
||||
$this->faker->randomFloat(2, floatval($additionalParams["max_score"]) + 0.01, 9.99)
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@ -7,12 +7,18 @@ use Jikan\Model\Common\DateRange;
|
||||
use JMS\Serializer\Serializer;
|
||||
use \Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Spatie\Enum\Laravel\Faker\FakerEnumProvider;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
abstract class JikanModelFactory extends Factory
|
||||
{
|
||||
public function configure(): JikanModelFactory|static
|
||||
{
|
||||
$this->faker->addProvider(new FakerEnumProvider($this->faker));
|
||||
if (array_key_exists("GITHUB_JOB", $_ENV) && $_ENV["GITHUB_JOB"] !== "") {
|
||||
$this->faker->seed($_ENV["GITHUB_JOB"]);
|
||||
} else {
|
||||
$this->faker->seed(Str::random());
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ namespace Database\Factories;
|
||||
use App\CarbonDateRange;
|
||||
use App\Testing\JikanDataGenerator;
|
||||
use App\Manga;
|
||||
use Illuminate\Support\Collection;
|
||||
use MongoDB\BSON\UTCDateTime;
|
||||
|
||||
class MangaFactory extends JikanMediaModelFactory
|
||||
@ -98,4 +99,48 @@ class MangaFactory extends JikanMediaModelFactory
|
||||
"request_hash" => sprintf("request:%s:%s", "v4", $this->getItemTestUrl("manga", $mal_id))
|
||||
];
|
||||
}
|
||||
|
||||
protected function getOverridesFromQueryStringParameters(Collection $additionalParams): array
|
||||
{
|
||||
$overrides = parent::getOverridesFromQueryStringParameters($additionalParams);
|
||||
|
||||
if ($additionalParams->has("magazines")) {
|
||||
$overrides["serializations"] = [];
|
||||
$magazineIds = explode(",", $additionalParams["magazines"]);
|
||||
foreach ($magazineIds as $magazineId) {
|
||||
$overrides["serializations"][] = [
|
||||
"mal_id" => (int)$magazineId,
|
||||
"type" => "manga",
|
||||
"name" => "Magazine {$magazineId}",
|
||||
"url" => "https://myanimelist.net/manga/magazine/{$magazineId}/x"
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $overrides;
|
||||
}
|
||||
|
||||
protected function getOppositeOverridesFromQueryStringParameters(Collection $additionalParams): array
|
||||
{
|
||||
$overrides = parent::getOppositeOverridesFromQueryStringParameters($additionalParams);
|
||||
|
||||
if ($additionalParams->has("magazines")) {
|
||||
$overrides["serializations"] = [];
|
||||
$magazineIds = explode(",", $additionalParams["magazines"]);
|
||||
do {
|
||||
$randomEls = $this->faker->randomElements([11, 60, 89, 54, 32, 22, 108, 65], $this->faker->numberBetween(1, 3));
|
||||
} while (count(array_intersect($randomEls, $magazineIds)) > 0);
|
||||
|
||||
foreach ($randomEls as $magazineId) {
|
||||
$overrides["serializations"][] = [
|
||||
"mal_id" => (int)$magazineId,
|
||||
"type" => "manga",
|
||||
"name" => "Magazine {$magazineId}",
|
||||
"url" => "https://myanimelist.net/manga/magazine/{$magazineId}/x"
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $overrides;
|
||||
}
|
||||
}
|
||||
|
@ -2283,9 +2283,6 @@
|
||||
],
|
||||
"operationId": "getSchedules",
|
||||
"parameters": [
|
||||
{
|
||||
"$ref": "#/components/parameters/page"
|
||||
},
|
||||
{
|
||||
"name": "filter",
|
||||
"in": "query",
|
||||
@ -2332,9 +2329,6 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/parameters/sfw"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/parameters/unapproved"
|
||||
},
|
||||
@ -2369,9 +2363,6 @@
|
||||
],
|
||||
"operationId": "getAnimeSearch",
|
||||
"parameters": [
|
||||
{
|
||||
"$ref": "#/components/parameters/sfw"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/parameters/unapproved"
|
||||
},
|
||||
@ -2527,9 +2518,6 @@
|
||||
],
|
||||
"operationId": "getMangaSearch",
|
||||
"parameters": [
|
||||
{
|
||||
"$ref": "#/components/parameters/sfw"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/parameters/unapproved"
|
||||
},
|
||||
@ -3058,6 +3046,9 @@
|
||||
{
|
||||
"$ref": "#/components/parameters/unapproved"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/parameters/continuing"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/parameters/page"
|
||||
},
|
||||
@ -3127,6 +3118,9 @@
|
||||
{
|
||||
"$ref": "#/components/parameters/unapproved"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/parameters/continuing"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/parameters/page"
|
||||
},
|
||||
@ -3203,6 +3197,9 @@
|
||||
{
|
||||
"$ref": "#/components/parameters/unapproved"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/parameters/continuing"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/parameters/page"
|
||||
},
|
||||
@ -9039,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",
|
||||
|
@ -138,6 +138,7 @@ class AnimeSearchEndpointTest extends TestCase
|
||||
"type = movie" => [["type" => "movie"]],
|
||||
"type = ova" => [["type" => "ova"]],
|
||||
"type = special" => [["type" => "special"]],
|
||||
"score = 8 and producers = 11" => [["score" => "8", "producers" => "11"]],
|
||||
];
|
||||
}
|
||||
|
||||
@ -260,16 +261,16 @@ class AnimeSearchEndpointTest extends TestCase
|
||||
*/
|
||||
public function testSearchByEndDate($params)
|
||||
{
|
||||
$overrides = $this->generateFiveSpecificAndTenRandomElementsInDb($params);
|
||||
$this->generateFiveSpecificAndTenRandomElementsInDb($params);
|
||||
|
||||
$content = $this->getJsonResponse($params);
|
||||
|
||||
$actualEndDate = Carbon::parse(data_get($content, "data.0.aired.to"));
|
||||
$paramEndDate = Carbon::parse($overrides["aired"]["to"]);
|
||||
$paramEndDate = Carbon::parse($params['end_date']);
|
||||
|
||||
$this->seeStatusCode(200);
|
||||
$this->assertPaginationData(5);
|
||||
$this->assertLessThanOrEqual(0, $actualEndDate->diff($paramEndDate)->days);
|
||||
$this->assertGreaterThanOrEqual(1, $actualEndDate->diff($paramEndDate)->days);
|
||||
// we created 5 elements according to parameters, so we expect 5 of them.
|
||||
$this->assertCount(5, $content["data"]);
|
||||
}
|
||||
|
@ -128,6 +128,7 @@ class MangaSearchEndpointTest extends TestCase
|
||||
[["type" => "novel"]],
|
||||
[["type" => "lightnovel"]],
|
||||
[["type" => "oneshot"]],
|
||||
[["score" => "8", "magazines" => "83"]]
|
||||
];
|
||||
}
|
||||
|
||||
@ -242,16 +243,16 @@ class MangaSearchEndpointTest extends TestCase
|
||||
*/
|
||||
public function testSearchByEndDate($params)
|
||||
{
|
||||
$overrides = $this->generateFiveSpecificAndTenRandomElementsInDb($params);
|
||||
$this->generateFiveSpecificAndTenRandomElementsInDb($params);
|
||||
|
||||
$content = $this->getJsonResponse($params);
|
||||
|
||||
$actualEndDate = Carbon::parse(data_get($content, "data.0.published.to"));
|
||||
$paramEndDate = Carbon::parse($overrides["published"]["to"]);
|
||||
$paramEndDate = Carbon::parse($params["end_date"]);
|
||||
|
||||
$this->seeStatusCode(200);
|
||||
$this->assertPaginationData(5);
|
||||
$this->assertLessThanOrEqual(0, $actualEndDate->diff($paramEndDate)->days);
|
||||
$this->assertGreaterThanOrEqual(1, $actualEndDate->diff($paramEndDate)->days);
|
||||
// we created 5 elements according to parameters, so we expect 5 of them.
|
||||
$this->assertCount(5, $content["data"]);
|
||||
}
|
||||
|
@ -15,6 +15,14 @@ class SeasonControllerTest extends TestCase
|
||||
use SyntheticMongoDbTransaction;
|
||||
use ScoutFlush;
|
||||
|
||||
private function continuingUrlProvider(): array
|
||||
{
|
||||
return [
|
||||
"?continuing=true" => ["/v4/seasons/2024/winter?continuing=true"],
|
||||
"?continuing" => ["/v4/seasons/2024/winter?continuing"],
|
||||
];
|
||||
}
|
||||
|
||||
public function testShouldFilterOutAnimeWithGarbledAiredString()
|
||||
{
|
||||
Carbon::setTestNow(Carbon::parse("2024-01-11"));
|
||||
@ -25,7 +33,7 @@ class SeasonControllerTest extends TestCase
|
||||
$state = $f->serializeStateDefinition([
|
||||
"aired" => new CarbonDateRange($carbonStartDate, null)
|
||||
]);
|
||||
$state["aired"]["string"] = "Jan 1, 2024 to ?";
|
||||
$state["aired"]["string"] = "2024 to ?";
|
||||
$state["premiered"] = null;
|
||||
$state["status"] = "Not yet aired";
|
||||
$state["airing"] = false;
|
||||
@ -49,4 +57,137 @@ class SeasonControllerTest extends TestCase
|
||||
$this->assertIsArray($content["data"]);
|
||||
$this->assertCount(1, $content["data"]);
|
||||
}
|
||||
|
||||
public function testShouldNotFilterOutFutureAiringDates()
|
||||
{
|
||||
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 "garbled" wrong item
|
||||
$f = Anime::factory(1);
|
||||
$startDate = "2024-01-01";
|
||||
$carbonStartDate = Carbon::parse($startDate);
|
||||
$state = $f->serializeStateDefinition([
|
||||
"aired" => new CarbonDateRange($carbonStartDate, null)
|
||||
]);
|
||||
$state["aired"]["string"] = "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);
|
||||
|
||||
$content = $this->getJsonResponse([], "/v4/seasons/2024/winter");
|
||||
$this->seeStatusCode(200);
|
||||
$this->assertIsArray($content["data"]);
|
||||
$this->assertCount(2, $content["data"]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @dataProvider continuingUrlProvider
|
||||
*/
|
||||
public function testShouldNotFilterOutContinuingItemsFromPreviousSeasons($requestUrl)
|
||||
{
|
||||
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([], $requestUrl);
|
||||
$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"]);
|
||||
}
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ final class DefaultCachedScraperServiceTest extends TestCase
|
||||
public function testIfFindListReturnsNotExpiredItems()
|
||||
{
|
||||
$testRequestHash = $this->requestHash();
|
||||
$now = Carbon::now();
|
||||
$now = Carbon::createFromDate(2022, 1, 11, "UTC")->addHours(8)->addMinutes(12);
|
||||
Carbon::setTestNow($now);
|
||||
// the cached data in the database
|
||||
// this should be an array of arrays as builder->get() returns multiple items
|
||||
@ -76,14 +76,14 @@ final class DefaultCachedScraperServiceTest extends TestCase
|
||||
public function testIfFindListUpdatesCacheIfItemsExpired()
|
||||
{
|
||||
$testRequestHash = $this->requestHash();
|
||||
$now = Carbon::now();
|
||||
$now = Carbon::createFromDate(2022, 1, 11, "UTC")->addHours(8)->addMinutes(12);
|
||||
Carbon::setTestNow($now);
|
||||
|
||||
// the cached data in the database
|
||||
// this should be an array of arrays as builder->get() returns multiple items
|
||||
$dummyResults = collect([[
|
||||
"request_hash" => $testRequestHash,
|
||||
"modifiedAt" => new UTCDateTime($now->sub("2 days")->getPreciseTimestamp(3)),
|
||||
"modifiedAt" => new UTCDateTime($now->copy()->subDays(2)->getPreciseTimestamp(3)),
|
||||
"results" => [
|
||||
["dummy" => "dummy1"],
|
||||
["dummy" => "dummy2"]
|
||||
@ -128,7 +128,7 @@ final class DefaultCachedScraperServiceTest extends TestCase
|
||||
public function testIfFindListUpdatesCacheIfCacheIsEmpty()
|
||||
{
|
||||
$testRequestHash = $this->requestHash();
|
||||
$now = Carbon::now();
|
||||
$now = Carbon::createFromDate(2022, 1, 11, "UTC")->addHours(8)->addMinutes(12);
|
||||
Carbon::setTestNow($now);
|
||||
|
||||
// the data returned by the scraper
|
||||
@ -175,7 +175,7 @@ final class DefaultCachedScraperServiceTest extends TestCase
|
||||
{
|
||||
$malId = 1;
|
||||
$testRequestHash = $this->requestHash();
|
||||
$now = Carbon::now();
|
||||
$now = Carbon::createFromDate(2022, 1, 11, "UTC")->addHours(8)->addMinutes(12);
|
||||
Carbon::setTestNow($now);
|
||||
$mockModel = Anime::factory()->makeOne([
|
||||
"mal_id" => $malId,
|
||||
@ -197,7 +197,7 @@ final class DefaultCachedScraperServiceTest extends TestCase
|
||||
{
|
||||
$malId = 1;
|
||||
$testRequestHash = $this->requestHash();
|
||||
$now = Carbon::now();
|
||||
$now = Carbon::createFromDate(2022, 1, 11, "UTC")->addHours(8)->addMinutes(12);
|
||||
Carbon::setTestNow($now);
|
||||
$mockModel = Anime::factory()->makeOne([
|
||||
"mal_id" => $malId,
|
||||
@ -224,11 +224,11 @@ final class DefaultCachedScraperServiceTest extends TestCase
|
||||
{
|
||||
$malId = 1;
|
||||
$testRequestHash = $this->requestHash();
|
||||
$now = Carbon::now();
|
||||
$now = Carbon::createFromDate(2022, 1, 11, "UTC")->addHours(8)->addMinutes(12);
|
||||
$mockModel = Anime::factory()->makeOne([
|
||||
"mal_id" => $malId,
|
||||
"modifiedAt" => new UTCDateTime($now->sub("3 days")->getPreciseTimestamp(3)),
|
||||
"createdAt" => new UTCDateTime($now->sub("3 days")->getPreciseTimestamp(3))
|
||||
"modifiedAt" => new UTCDateTime($now->copy()->sub("3 days")->getPreciseTimestamp(3)),
|
||||
"createdAt" => new UTCDateTime($now->copy()->sub("3 days")->getPreciseTimestamp(3))
|
||||
]);
|
||||
$now = Carbon::now();
|
||||
Carbon::setTestNow($now);
|
||||
@ -264,7 +264,7 @@ final class DefaultCachedScraperServiceTest extends TestCase
|
||||
{
|
||||
$username = "kompot";
|
||||
$testRequestHash = $this->requestHash();
|
||||
$now = Carbon::now();
|
||||
$now = Carbon::createFromDate(2022, 1, 11, "UTC")->addHours(8)->addMinutes(12);
|
||||
Carbon::setTestNow($now);
|
||||
$mockModel = Profile::factory()->makeOne([
|
||||
"username" => $username,
|
||||
@ -287,7 +287,7 @@ final class DefaultCachedScraperServiceTest extends TestCase
|
||||
{
|
||||
$username = "kompot";
|
||||
$testRequestHash = $this->requestHash();
|
||||
$now = Carbon::now();
|
||||
$now = Carbon::createFromDate(2022, 1, 11, "UTC")->addHours(8)->addMinutes(12);
|
||||
Carbon::setTestNow($now);
|
||||
$mockModel = Profile::factory()->makeOne([
|
||||
"username" => $username,
|
||||
@ -319,12 +319,12 @@ final class DefaultCachedScraperServiceTest extends TestCase
|
||||
$malId = 1;
|
||||
$username = "kompot";
|
||||
$testRequestHash = $this->requestHash();
|
||||
$now = Carbon::now();
|
||||
$now = Carbon::createFromDate(2022, 1, 11, "UTC")->addHours(8)->addMinutes(12);
|
||||
$mockModel = Profile::factory()->makeOne([
|
||||
"mal_id" => $malId,
|
||||
"username" => $username,
|
||||
"modifiedAt" => new UTCDateTime($now->sub("3 days")->getPreciseTimestamp(3)),
|
||||
"createdAt" => new UTCDateTime($now->sub("3 days")->getPreciseTimestamp(3))
|
||||
"modifiedAt" => new UTCDateTime($now->copy()->sub("3 days")->getPreciseTimestamp(3)),
|
||||
"createdAt" => new UTCDateTime($now->copy()->sub("3 days")->getPreciseTimestamp(3))
|
||||
]);
|
||||
$now = Carbon::now();
|
||||
Carbon::setTestNow($now);
|
||||
|
Loading…
x
Reference in New Issue
Block a user