Merge branch 'master' into feature/queue-resource-updater

This commit is contained in:
Irfan 2022-11-25 17:34:48 +05:00 committed by GitHub
commit 5a86bffddc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 3602 additions and 1125 deletions

1
.github/CODEOWNERS vendored Normal file
View File

@ -0,0 +1 @@
* @jikan-me/maintainers

View File

@ -28,8 +28,8 @@ jobs:
ghcr.io/jikan-me/jikan-rest-php
jikanme/jikan-rest-php
tags: |
type=raw,value=latest
type=sha
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'master') }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v2

View File

@ -14,6 +14,7 @@ use Jikan\Exception\ParserException;
use Laravel\Lumen\Exceptions\Handler as ExceptionHandler;
use Predis\Connection\ConnectionException;
use Symfony\Component\HttpClient\Exception\TimeoutException;
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\HttpException;
@ -95,6 +96,27 @@ class Handler extends ExceptionHandler
], 500);
}
// BadRequestException from Controllers
if ($e instanceof BadRequestException) {
return response()
->json([
'status' => 400,
'type' => 'BadRequestException',
'message' => $e->getMessage(),
'error' => null
], 400);
}
if ($e instanceof ValidationException) {
return response()
->json([
'status' => 400,
'type' => 'BadRequestException',
'message' => $e->getMessage(),
'error' => null
], 400);
}
// BadResponseException from Jikan PHP API
// This is basically the response MyAnimeList returns to Jikan
if ($e instanceof BadResponseException) {

View File

@ -0,0 +1,22 @@
<?php
namespace App\Helpers;
use App\Providers\SerializerFactory;
class ScraperHelper
{
/**
* @param object|array $response
* @return array
*/
public static function getSerializedJSON(object|array $response): array
{
return \json_decode(
SerializerFactory::createV4()
->serialize($response, 'json'),
true
);
}
}

View File

@ -24,6 +24,7 @@ use App\Http\Resources\V4\NewsResource;
use App\Jobs\UpdateResource;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Jikan\Helper\Constants;
use Jikan\Request\Anime\AnimeCharactersAndStaffRequest;
use Jikan\Request\Anime\AnimeEpisodeRequest;
use Jikan\Request\Anime\AnimeEpisodesRequest;
@ -40,6 +41,7 @@ use Jikan\Request\Anime\AnimeVideosEpisodesRequest;
use Jikan\Request\Anime\AnimeVideosRequest;
use Laravel\Lumen\Http\ResponseFactory;
use MongoDB\BSON\UTCDateTime;
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class AnimeController extends Controller
@ -1099,9 +1101,27 @@ class AnimeController extends Controller
|| $this->isExpired($request, $results)
) {
$page = $request->get('page') ?? 1;
$anime = $this->jikan->getAnimeReviews(new AnimeReviewsRequest($id, $page));
$response = \json_decode($this->serializer->serialize($anime, 'json'), true);
$sort = $request->get('sort') ?? Constants::REVIEWS_SORT_MOST_VOTED;
if (!in_array($sort, [Constants::REVIEWS_SORT_MOST_VOTED, Constants::REVIEWS_SORT_NEWEST, Constants::REVIEWS_SORT_OLDEST])) {
throw new BadRequestException('Invalid sort for reviews. Please refer to the documentation: https://docs.api.jikan.moe/');
}
$spoilers = $request->get('spoilers') ?? false;
$preliminary = $request->get('preliminary') ?? false;
$anime = $this->jikan
->getAnimeReviews(
new AnimeReviewsRequest(
$id,
$page,
$sort,
$spoilers,
$preliminary
)
);
$response = \json_decode($this->serializer->serialize($anime, 'json'), true);
$results = $this->updateCache($request, $results, $response);
}

View File

@ -36,7 +36,7 @@ class Controller extends BaseController
* )
* ),
* @OA\Server(
* description="Jikan REST API Beta",
* description="Jikan REST API",
* url="https://api.jikan.moe/v4",
* ),
* @OA\ExternalDocumentation(
@ -49,12 +49,12 @@ class Controller extends BaseController
/**
* @var Serializer
*/
protected $serializer;
protected Serializer $serializer;
/**
* @var MalClient
*/
protected $jikan;
protected MalClient $jikan;
/**
* @var Request
@ -64,16 +64,16 @@ class Controller extends BaseController
/**
* @var array
*/
private $response;
private array $response;
protected $expired = false;
protected bool $expired = false;
protected $fingerprint;
protected string $fingerprint;
/**
* AnimeController constructor.
*
* @param Serializer $serializer
* @param Request $request
* @param MalClient $jikan
*/
public function __construct(Request $request, MalClient $jikan)

View File

@ -2,38 +2,28 @@
namespace App\Http\Controllers\V4DB;
use App\Anime;
use App\Helpers\ScraperHelper;
use App\Http\HttpHelper;
use App\Http\HttpResponse;
use App\Http\Resources\V4\AnimeCharactersResource;
use App\Http\Resources\V4\AnimeForumResource;
use App\Http\QueryBuilder\Scraper\Query;
use App\Http\QueryBuilder\Scraper\QueryResolver;
use App\Http\QueryBuilder\Scraper\ScraperHandler;
use App\Http\Resources\V4\ExternalLinksResource;
use App\Http\Resources\V4\MangaRelationsResource;
use App\Http\Resources\V4\ResultsResource;
use App\Http\Resources\V4\ReviewsResource;
use App\Http\Resources\V4\UserUpdatesResource;
use App\Http\Resources\V4\RecommendationsResource;
use App\Http\Resources\V4\MoreInfoResource;
use App\Http\Resources\V4\AnimeNewsResource;
use App\Http\Resources\V4\AnimeStatisticsResource;
use App\Http\Resources\V4\ForumResource;
use App\Http\Resources\V4\MangaCharactersResource;
use App\Http\Resources\V4\MangaStatisticsResource;
use App\Http\Resources\V4\NewsResource;
use App\Http\Resources\V4\PicturesResource;
use App\Http\Validation\ValidationTypeEnum;
use App\Manga;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\Facades\DB;
use Jikan\Request\Anime\AnimeCharactersAndStaffRequest;
use Jikan\Request\Anime\AnimeForumRequest;
use Jikan\Request\Anime\AnimeMoreInfoRequest;
use Jikan\Request\Anime\AnimeNewsRequest;
use Jikan\Request\Anime\AnimePicturesRequest;
use Jikan\Request\Anime\AnimeRecentlyUpdatedByUsersRequest;
use Jikan\Request\Anime\AnimeRecommendationsRequest;
use Jikan\Request\Anime\AnimeReviewsRequest;
use Jikan\Request\Anime\AnimeStatsRequest;
use Jikan\Exception\BadResponseException;
use Jikan\Helper\Constants;
use Jikan\Request\Manga\MangaCharactersRequest;
use Jikan\Request\Manga\MangaForumRequest;
use Jikan\Request\Manga\MangaMoreInfoRequest;
@ -41,11 +31,10 @@ use Jikan\Request\Manga\MangaNewsRequest;
use Jikan\Request\Manga\MangaPicturesRequest;
use Jikan\Request\Manga\MangaRecentlyUpdatedByUsersRequest;
use Jikan\Request\Manga\MangaRecommendationsRequest;
use Jikan\Request\Manga\MangaRequest;
use Jikan\Request\Manga\MangaReviewsRequest;
use Jikan\Request\Manga\MangaStatsRequest;
use MongoDB\BSON\UTCDateTime;
use mysql_xdevapi\Result;
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
class MangaController extends Controller
{
@ -719,9 +708,20 @@ class MangaController extends Controller
* description="Error: Bad request. When required parameters were not supplied.",
* ),
* )
* @throws \Exception
*/
public function reviews(Request $request, int $id)
{
$validation = $this->validate($request, [
'page' => 'nullable|numeric',
'sort' => 'nullable|string'
]);
$page = $request->get('page') ?? 1;
$spoilers = $request->get('spoilers') ?? false;
$preliminary = $request->get('preliminary') ?? false;
$sort = $request->get('sort');
$results = DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->get();
@ -730,9 +730,19 @@ class MangaController extends Controller
$results->isEmpty()
|| $this->isExpired($request, $results)
) {
$page = $request->get('page') ?? 1;
$manga = $this->jikan->getMangaReviews(new MangaReviewsRequest($id, $page));
$response = \json_decode($this->serializer->serialize($manga, 'json'), true);
$response = ScraperHelper::getSerializedJSON(
app('JikanParser')
->getMangaReviews(
new MangaReviewsRequest(
$id,
$page,
in_array($sort, [Constants::REVIEWS_SORT_MOST_VOTED, Constants::REVIEWS_SORT_NEWEST, Constants::REVIEWS_SORT_OLDEST]) ? $sort : Constants::REVIEWS_SORT_MOST_VOTED,
$spoilers,
$preliminary
)
)
);
$results = $this->updateCache($request, $results, $response);
}

View File

@ -9,7 +9,9 @@ use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Jikan\Helper\Constants;
use Jikan\Request\Reviews\RecentReviewsRequest;
use Jikan\Request\Reviews\ReviewsRequest;
use MongoDB\BSON\UTCDateTime;
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
class ReviewsController extends Controller
{
@ -73,7 +75,26 @@ class ReviewsController extends Controller
|| $this->isExpired($request, $results)
) {
$page = $request->get('page') ?? 1;
$anime = $this->jikan->getRecentReviews(new RecentReviewsRequest(Constants::RECENT_REVIEW_ANIME, $page));
$sort = $request->get('sort') ?? Constants::REVIEWS_SORT_MOST_VOTED;
if (!in_array($sort, [Constants::REVIEWS_SORT_MOST_VOTED, Constants::REVIEWS_SORT_NEWEST, Constants::REVIEWS_SORT_OLDEST])) {
throw new BadRequestException('Invalid sort for reviews. Please refer to the documentation: https://docs.api.jikan.moe/');
}
$spoilers = $request->get('spoilers') ?? false;
$preliminary = $request->get('preliminary') ?? false;
$anime = $this->jikan
->getReviews(
new ReviewsRequest(
Constants::ANIME,
$page,
$sort,
$spoilers,
$preliminary
)
);
$response = \json_decode($this->serializer->serialize($anime, 'json'), true);
$results = $this->updateCache($request, $results, $response);
@ -149,9 +170,27 @@ class ReviewsController extends Controller
|| $this->isExpired($request, $results)
) {
$page = $request->get('page') ?? 1;
$anime = $this->jikan->getRecentReviews(new RecentReviewsRequest(Constants::RECENT_REVIEW_MANGA, $page));
$response = \json_decode($this->serializer->serialize($anime, 'json'), true);
$sort = $request->get('sort') ?? Constants::REVIEWS_SORT_MOST_VOTED;
if (!in_array($sort, [Constants::REVIEWS_SORT_MOST_VOTED, Constants::REVIEWS_SORT_NEWEST, Constants::REVIEWS_SORT_OLDEST])) {
throw new BadRequestException('Invalid sort for reviews. Please refer to the documentation: https://docs.api.jikan.moe/');
}
$spoilers = $request->get('spoilers') ?? false;
$preliminary = $request->get('preliminary') ?? false;
$anime = $this->jikan
->getReviews(
new ReviewsRequest(
Constants::MANGA,
$page,
$sort,
$spoilers,
$preliminary
)
);
$response = \json_decode($this->serializer->serialize($anime, 'json'), true);
$results = $this->updateCache($request, $results, $response);
}

View File

@ -641,6 +641,14 @@ class SearchController extends ControllerWithQueryBuilderProvider
}
/**
*
* @OA\Schema(
* schema="producers_query_orderby",
* description="Producers Search Query Order By",
* type="string",
* enum={"mal_id", "count", "favorites", "established"}
* )
*
* @OA\Get(
* path="/producers",
* operationId="getProducers",

View File

@ -4,15 +4,26 @@ namespace App\Http\Controllers\V4DB;
use App\Anime;
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\Helper\Constants;
use Jikan\Model\Common\DateRange;
use Jikan\Request\SeasonList\SeasonListRequest;
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
/**
*
*/
class SeasonController extends Controller
{
/**
*
*/
private const VALID_SEASONS = [
'Summer',
'Spring',
@ -40,6 +51,13 @@ class SeasonController extends Controller
* @OA\Schema(type="string")
* ),
*
* @OA\Parameter(
* name="filter",
* description="Entry types",
* in="query",
* @OA\Schema(type="string",enum={"tv","movie","ova","special","ona","music"})
* ),
*
* @OA\Parameter(ref="#/components/parameters/page"),
*
* @OA\Response(
@ -81,6 +99,7 @@ class SeasonController extends Controller
$maxResultsPerPage = env('MAX_RESULTS_PER_PAGE', 30);
$page = $request->get('page') ?? 1;
$limit = $request->get('limit') ?? $maxResultsPerPage;
$type = $request->get('filter');
if (!empty($limit)) {
$limit = (int) $limit;
@ -113,14 +132,24 @@ class SeasonController extends Controller
list($season, $year) = $this->getSeasonStr();
}
$range = $this->getSeasonRange($year, $season);
$results = Anime::query()
->where('premiered', "{$season} $year")
->whereBetween('aired.from', [$range['from'], $range['to']]);
if (array_key_exists(strtolower($type), AnimeSearchQueryBuilder::MAP_TYPES)) {
$results = $results
->where('type', AnimeSearchQueryBuilder::MAP_TYPES[$type]);
}
$results = $results
->orderBy('members', 'desc')
->paginate(
$limit,
['*'],
null,
$page);
$page
);
$response = (new AnimeCollection(
$results
@ -212,6 +241,13 @@ class SeasonController extends Controller
* operationId="getSeasonUpcoming",
* tags={"seasons"},
*
* @OA\Parameter(
* name="filter",
* description="Entry types",
* in="query",
* @OA\Schema(type="string",enum={"tv","movie","ova","special","ona","music"})
* ),
*
* @OA\Parameter(ref="#/components/parameters/page"),
*
* @OA\Response(
@ -233,6 +269,8 @@ class SeasonController extends Controller
$maxResultsPerPage = env('MAX_RESULTS_PER_PAGE', 30);
$page = $request->get('page') ?? 1;
$limit = $request->get('limit') ?? $maxResultsPerPage;
$type = $request->get('filter');
if (!empty($limit)) {
$limit = (int) $limit;
@ -246,20 +284,17 @@ class SeasonController extends Controller
}
}
// $nextYear = (new \DateTime(null, new \DateTimeZone('Asia/Tokyo')))
// ->modify('+1 year')
// ->format('Y');
$results = Anime::query()
->where('status', 'Not yet aired')
// ->where('premiered', 'like', "%{$nextYear}%")
->orderBy('members', 'desc');
->where('status', 'Not yet aired');
if (array_key_exists(strtolower($type), AnimeSearchQueryBuilder::MAP_TYPES)) {
$results = $results
->where('type', AnimeSearchQueryBuilder::MAP_TYPES[$type]);
}
$season = 'Later';
$results = $results
->orderBy('members', 'desc')
->paginate(
$limit,
['*'],
@ -302,4 +337,25 @@ class SeasonController extends Controller
default: throw new Exception('Could not generate seasonal string');
}
}
/**
* @param int $year
* @param string $season
* @return string[]
*/
private function getSeasonRange(int $year, string $season) : array
{
[$monthStart, $monthEnd] = match ($season) {
'Winter' => [1, 3],
'Spring' => [4, 6],
'Summer' => [7, 9],
'Fall' => [10, 12],
default => throw new BadRequestException('Invalid season supplied'),
};
return [
'from' => Carbon::createFromDate($year, $monthStart, 1)->toAtomString(),
'to' => Carbon::createFromDate($year, $monthEnd, 1)->modify('last day of this month')->toAtomString()
];
}
}

View File

@ -14,6 +14,7 @@ use App\Http\Resources\V4\UserProfileMangaListResource;
use App\Profile;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Jikan\Helper\Constants;
use Jikan\Request\User\RecentlyOnlineUsersRequest;
use Jikan\Request\User\UserAnimeListRequest;
use Jikan\Request\User\UserClubsRequest;
@ -23,6 +24,7 @@ use Jikan\Request\User\UserMangaListRequest;
use Jikan\Request\User\UserRecommendationsRequest;
use Jikan\Request\User\UserReviewsRequest;
use MongoDB\BSON\UTCDateTime;
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
/**
* Class Controller
@ -964,9 +966,16 @@ class UserController extends Controller
|| $this->isExpired($request, $results)
) {
$page = $request->get('page') ?? 1;
$data = $this->jikan->getUserReviews(new UserReviewsRequest($username, $page));
$response = \json_decode($this->serializer->serialize($data, 'json'), true);
$data = $this->jikan
->getUserReviews(
new UserReviewsRequest(
$username,
$page,
)
);
$response = \json_decode($this->serializer->serialize($data, 'json'), true);
$results = $this->updateCache($request, $results, $response);
}

View File

@ -19,17 +19,57 @@ class ReviewsResource extends JsonResource
* @OA\Property(
* property="url",
* type="string",
* description="MyAnimeList URL"
* description="MyAnimeList review URL"
* ),
* @OA\Property(
* property="type",
* type="string",
* description="Entry Type"
* description="Entry type"
* ),
* @OA\Property(
* property="votes",
* property="reactions",
* type="object",
* description="User reaction count on the review",
* @OA\Property(
* property="overall",
* type="integer",
* description="Number of user votes on the Review"
* description="Overall reaction count"
* ),
* @OA\Property(
* property="nice",
* type="integer",
* description="Nice reaction count"
* ),
* @OA\Property(
* property="love_it",
* type="integer",
* description="Love it reaction count"
* ),
* @OA\Property(
* property="funny",
* type="integer",
* description="Funny reaction count"
* ),
* @OA\Property(
* property="confusing",
* type="integer",
* description="Confusing reaction count"
* ),
* @OA\Property(
* property="informative",
* type="integer",
* description="Informative reaction count"
* ),
* @OA\Property(
* property="well_written",
* type="integer",
* description="Well written reaction count"
* ),
* @OA\Property(
* property="creative",
* type="integer",
* description="Creative reaction count"
* )
* ),
* @OA\Property(
* property="date",
@ -37,44 +77,30 @@ class ReviewsResource extends JsonResource
* description="Review created date ISO8601"
* ),
* @OA\Property(
* property="chapters_read",
* type="integer",
* description="Number of chapters read by the reviewer"
* ),
* @OA\Property(
* property="review",
* type="string",
* description="Review content"
* ),
* @OA\Property(
* property="scores",
* type="object",
* description="Review Scores breakdown",
* @OA\Property(
* property="overall",
* property="score",
* type="integer",
* description="Overall Score"
* description="Number of user votes on the Review"
* ),
* @OA\Property(
* property="story",
* type="integer",
* description="Story Score"
* @OA\Property (
* property="tags",
* type="array",
* description="Review tags",
* @OA\Items(type="string"),
* ),
* @OA\Property(
* property="art",
* type="integer",
* description="Art Score"
* ),
* @OA\Property(
* property="character",
* type="integer",
* description="Character Score"
* ),
* @OA\Property(
* property="enjoyment",
* type="integer",
* description="Enjoyment Score"
* @OA\Property (
* property="is_spoiler",
* type="bool",
* description="The review contains spoiler"
* ),
* @OA\Property (
* property="is_preliminary",
* type="bool",
* description="The review was made before the entry was completed"
* ),
* ),
*
@ -89,17 +115,57 @@ class ReviewsResource extends JsonResource
* @OA\Property(
* property="url",
* type="string",
* description="MyAnimeList URL"
* description="MyAnimeList review URL"
* ),
* @OA\Property(
* property="type",
* type="string",
* description="Entry Type"
* description="Entry type"
* ),
* @OA\Property(
* property="votes",
* property="reactions",
* type="object",
* description="User reaction count on the review",
* @OA\Property(
* property="overall",
* type="integer",
* description="Number of user votes on the Review"
* description="Overall reaction count"
* ),
* @OA\Property(
* property="nice",
* type="integer",
* description="Nice reaction count"
* ),
* @OA\Property(
* property="love_it",
* type="integer",
* description="Love it reaction count"
* ),
* @OA\Property(
* property="funny",
* type="integer",
* description="Funny reaction count"
* ),
* @OA\Property(
* property="confusing",
* type="integer",
* description="Confusing reaction count"
* ),
* @OA\Property(
* property="informative",
* type="integer",
* description="Informative reaction count"
* ),
* @OA\Property(
* property="well_written",
* type="integer",
* description="Well written reaction count"
* ),
* @OA\Property(
* property="creative",
* type="integer",
* description="Creative reaction count"
* )
* ),
* @OA\Property(
* property="date",
@ -112,45 +178,31 @@ class ReviewsResource extends JsonResource
* description="Review content"
* ),
* @OA\Property(
* property="score",
* type="integer",
* description="Number of user votes on the Review"
* ),
* @OA\Property (
* property="tags",
* type="array",
* description="Review tags",
* @OA\Items(type="string"),
* ),
* @OA\Property (
* property="is_spoiler",
* type="bool",
* description="The review contains spoiler"
* ),
* @OA\Property (
* property="is_preliminary",
* type="bool",
* description="The review was made before the entry was completed"
* ),
* @OA\Property(
* property="episodes_watched",
* type="integer",
* description="Number of episodes watched"
* ),
* @OA\Property(
* property="scores",
* type="object",
* description="Review Scores breakdown",
* @OA\Property(
* property="overall",
* type="integer",
* description="Overall Score"
* ),
* @OA\Property(
* property="story",
* type="integer",
* description="Story Score"
* ),
* @OA\Property(
* property="animation",
* type="integer",
* description="Animation Score"
* ),
* @OA\Property(
* property="sound",
* type="integer",
* description="Sound Score"
* ),
* @OA\Property(
* property="character",
* type="integer",
* description="Character Score"
* ),
* @OA\Property(
* property="enjoyment",
* type="integer",
* description="Enjoyment Score"
* ),
* ),
* ),
*
*

View File

@ -21,7 +21,7 @@
"flipbox/lumen-generator": "^9.0",
"illuminate/redis": "^9.0",
"jenssegers/mongodb": "^3.8",
"jikan-me/jikan": "^3",
"jikan-me/jikan": "^4",
"jms/serializer": "^3.0",
"laravel/legacy-factories": "^1.1",
"laravel/lumen-framework": "^9.0",

3940
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,7 @@ FROM composer:2.3.9 as composer
FROM mlocati/php-extension-installer:1.5.29 as php-ext-installer
FROM php:8.0-bullseye as runtime
ARG GITHUB_PERSONAL_TOKEN
LABEL org.opencontainers.image.source=https://github.com/jikan-me/jikan-rest/docker/base_image/php-8.0
COPY --from=composer /usr/bin/composer /usr/bin/composer
COPY --from=php-ext-installer /usr/bin/install-php-extensions /usr/local/bin/
ENV COMPOSER_HOME="/tmp/composer"

View File

@ -0,0 +1,3 @@
# Jikan Rest Base image
The base image for Jikan REST app, to speed up container builds. This is mostly for internal use.

View File

@ -3,6 +3,7 @@ FROM composer:2.3.9 as composer
FROM mlocati/php-extension-installer:1.5.29 as php-ext-installer
FROM php:8.1-bullseye as runtime
ARG GITHUB_PERSONAL_TOKEN
LABEL org.opencontainers.image.source=https://github.com/jikan-me/jikan-rest/docker/base_image/php-8.1
COPY --from=composer /usr/bin/composer /usr/bin/composer
COPY --from=php-ext-installer /usr/bin/install-php-extensions /usr/local/bin/
ENV COMPOSER_HOME="/tmp/composer"

View File

@ -4199,6 +4199,15 @@
},
"type": "object"
},
"magazines_query_orderby": {
"description": "Order by magazine data",
"type": "string",
"enum": [
"mal_id",
"name",
"count"
]
},
"manga_news": {
"description": "Manga News Resource",
"allOf": [
@ -4323,6 +4332,16 @@
}
]
},
"producers_query_orderby": {
"description": "Producers Search Query Order By",
"type": "string",
"enum": [
"mal_id",
"count",
"favorites",
"established"
]
},
"seasons": {
"description": "List of available seasons",
"properties": {
@ -4638,15 +4657,6 @@
"created"
]
},
"magazines_query_orderby": {
"description": "Order by magazine data",
"type": "string",
"enum": [
"mal_id",
"name",
"count"
]
},
"manga_search_query_type": {
"description": "Available Manga types",
"type": "string",
@ -4699,17 +4709,6 @@
"favorites"
]
},
"producers_query_orderby": {
"description": "Order by producers data",
"type": "string",
"enum": [
"mal_id",
"name",
"count",
"favorites",
"established"
]
},
"users_search_query_gender": {
"description": "Users Search Query Gender",
"type": "string",
@ -8467,54 +8466,77 @@
"type": "integer"
},
"url": {
"description": "MyAnimeList URL",
"description": "MyAnimeList review URL",
"type": "string"
},
"type": {
"description": "Entry Type",
"description": "Entry type",
"type": "string"
},
"votes": {
"description": "Number of user votes on the Review",
"reactions": {
"description": "User reaction count on the review",
"properties": {
"overall": {
"description": "Overall reaction count",
"type": "integer"
},
"nice": {
"description": "Nice reaction count",
"type": "integer"
},
"love_it": {
"description": "Love it reaction count",
"type": "integer"
},
"funny": {
"description": "Funny reaction count",
"type": "integer"
},
"confusing": {
"description": "Confusing reaction count",
"type": "integer"
},
"informative": {
"description": "Informative reaction count",
"type": "integer"
},
"well_written": {
"description": "Well written reaction count",
"type": "integer"
},
"creative": {
"description": "Creative reaction count",
"type": "integer"
}
},
"type": "object"
},
"date": {
"description": "Review created date ISO8601",
"type": "string"
},
"chapters_read": {
"description": "Number of chapters read by the reviewer",
"type": "integer"
},
"review": {
"description": "Review content",
"type": "string"
},
"scores": {
"description": "Review Scores breakdown",
"properties": {
"overall": {
"description": "Overall Score",
"score": {
"description": "Number of user votes on the Review",
"type": "integer"
},
"story": {
"description": "Story Score",
"type": "integer"
},
"art": {
"description": "Art Score",
"type": "integer"
},
"character": {
"description": "Character Score",
"type": "integer"
},
"enjoyment": {
"description": "Enjoyment Score",
"type": "integer"
"tags": {
"description": "Review tags",
"type": "array",
"items": {
"type": "string"
}
},
"type": "object"
"is_spoiler": {
"description": "The review contains spoiler",
"type": "bool"
},
"is_preliminary": {
"description": "The review was made before the entry was completed",
"type": "bool"
}
},
"type": "object"
@ -8526,17 +8548,51 @@
"type": "integer"
},
"url": {
"description": "MyAnimeList URL",
"description": "MyAnimeList review URL",
"type": "string"
},
"type": {
"description": "Entry Type",
"description": "Entry type",
"type": "string"
},
"votes": {
"description": "Number of user votes on the Review",
"reactions": {
"description": "User reaction count on the review",
"properties": {
"overall": {
"description": "Overall reaction count",
"type": "integer"
},
"nice": {
"description": "Nice reaction count",
"type": "integer"
},
"love_it": {
"description": "Love it reaction count",
"type": "integer"
},
"funny": {
"description": "Funny reaction count",
"type": "integer"
},
"confusing": {
"description": "Confusing reaction count",
"type": "integer"
},
"informative": {
"description": "Informative reaction count",
"type": "integer"
},
"well_written": {
"description": "Well written reaction count",
"type": "integer"
},
"creative": {
"description": "Creative reaction count",
"type": "integer"
}
},
"type": "object"
},
"date": {
"description": "Review created date ISO8601",
"type": "string"
@ -8545,39 +8601,28 @@
"description": "Review content",
"type": "string"
},
"score": {
"description": "Number of user votes on the Review",
"type": "integer"
},
"tags": {
"description": "Review tags",
"type": "array",
"items": {
"type": "string"
}
},
"is_spoiler": {
"description": "The review contains spoiler",
"type": "bool"
},
"is_preliminary": {
"description": "The review was made before the entry was completed",
"type": "bool"
},
"episodes_watched": {
"description": "Number of episodes watched",
"type": "integer"
},
"scores": {
"description": "Review Scores breakdown",
"properties": {
"overall": {
"description": "Overall Score",
"type": "integer"
},
"story": {
"description": "Story Score",
"type": "integer"
},
"animation": {
"description": "Animation Score",
"type": "integer"
},
"sound": {
"description": "Sound Score",
"type": "integer"
},
"character": {
"description": "Character Score",
"type": "integer"
},
"enjoyment": {
"description": "Enjoyment Score",
"type": "integer"
}
},
"type": "object"
}
},
"type": "object"

View File

@ -406,9 +406,14 @@ class AnimeControllerV4Test extends TestCase
[
'mal_id',
'url',
'votes',
'type',
'reactions',
'date',
'review',
'score',
'tags',
'is_spoiler',
'is_preliminary',
'episodes_watched',
'scores' => [
'overall',
@ -508,7 +513,7 @@ class AnimeControllerV4Test extends TestCase
]
]);
$this->get('/v4/anime/1/userupdates?page=100')
$this->get('/v4/anime/1/userupdates?page=200')
->seeStatusCode(404);
}

View File

@ -228,9 +228,14 @@ class MangaControllerV4Test extends TestCase
[
'mal_id',
'url',
'votes',
'type',
'reactions',
'date',
'review',
'score',
'tags',
'is_spoiler',
'is_preliminary',
'chapters_read',
'scores' => [
'overall',
@ -331,7 +336,7 @@ class MangaControllerV4Test extends TestCase
]
]);
$this->get('/v4/manga/1/userupdates?page=100')
$this->get('/v4/manga/1/userupdates?page=200')
->seeStatusCode(404);
}

View File

@ -112,7 +112,6 @@ class PersonControllerTest extends TestCase
'images' => [
'jpg' => [
'image_url',
'small_image_url',
],
'webp' => [
'image_url',

View File

@ -17,18 +17,14 @@ class ReviewsControllerTest extends TestCase
'mal_id',
'url',
'type',
'votes',
'reactions',
'date',
'review',
'score',
'tags',
'is_spoiler',
'is_preliminary',
'episodes_watched',
'scores' => [
'overall',
'story',
'animation',
'sound',
'character',
'enjoyment',
],
'entry' => [
'mal_id',
'url',
@ -77,17 +73,14 @@ class ReviewsControllerTest extends TestCase
'mal_id',
'url',
'type',
'votes',
'reactions',
'date',
'review',
'score',
'tags',
'is_spoiler',
'is_preliminary',
'chapters_read',
'scores' => [
'overall',
'story',
'art',
'character',
'enjoyment',
],
'entry' => [
'mal_id',
'url',

View File

@ -274,9 +274,13 @@ class UserControllerTest extends TestCase
'mal_id',
'url',
'type',
'votes',
'reactions',
'date',
'review',
'score',
'tags',
'is_spoiler',
'is_preliminary',
'entry' => [
'mal_id',
'url',