mirror of
https://github.com/jikan-me/jikan-rest.git
synced 2025-02-20 11:23:35 +08:00
WIP: add insights
This commit is contained in:
parent
21535a403a
commit
f161bcb486
@ -61,7 +61,5 @@ class Kernel extends ConsoleKernel
|
|||||||
// Update common indexes daily
|
// Update common indexes daily
|
||||||
$schedule->command('indexer:common')
|
$schedule->command('indexer:common')
|
||||||
->daily();
|
->daily();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
155
app/Http/Controllers/V4DB/InsightsController.php
Normal file
155
app/Http/Controllers/V4DB/InsightsController.php
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\V4DB;
|
||||||
|
|
||||||
|
use App\Http\Resources\V4\InsightsCollection;
|
||||||
|
use App\Http\Resources\V4\TrendsCollection;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Pagination\LengthAwarePaginator;
|
||||||
|
use Illuminate\Pagination\Paginator;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use MongoDB\BSON\Regex;
|
||||||
|
|
||||||
|
class InsightsController extends Controller
|
||||||
|
{
|
||||||
|
|
||||||
|
public function main(Request $request)
|
||||||
|
{
|
||||||
|
if (!env('INSIGHTS')) {
|
||||||
|
return response()->json([
|
||||||
|
'status' => 403,
|
||||||
|
'type' => 'InsightsRuntimeException',
|
||||||
|
'message' => 'Insights service is disabled',
|
||||||
|
'error' => null
|
||||||
|
], 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
$maxResultsPerPage = (int) env('MAX_RESULTS_PER_PAGE', 25);
|
||||||
|
|
||||||
|
$page = $request->get('page') ?? 1;
|
||||||
|
$limit = $request->get('limit') ?? $maxResultsPerPage;
|
||||||
|
|
||||||
|
$limit = (int) $limit;
|
||||||
|
|
||||||
|
if ($limit <= 0) {
|
||||||
|
$limit = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($limit > $maxResultsPerPage) {
|
||||||
|
$limit = $maxResultsPerPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
$results = DB::table('insights')
|
||||||
|
->where('timestamp', '>', time() - env('INSIGHTS_MAX_STORE_TIME', 172800) )
|
||||||
|
->orderBy('timestamp', 'desc')
|
||||||
|
->paginate(
|
||||||
|
$limit,
|
||||||
|
['*'],
|
||||||
|
null,
|
||||||
|
$page
|
||||||
|
);
|
||||||
|
|
||||||
|
return new InsightsCollection(
|
||||||
|
$results
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const TRENDS = [
|
||||||
|
'anime',
|
||||||
|
'manga',
|
||||||
|
'people',
|
||||||
|
'characters',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function trends(Request $request)
|
||||||
|
{
|
||||||
|
if (!env('INSIGHTS')) {
|
||||||
|
return response()->json([
|
||||||
|
'status' => 403,
|
||||||
|
'type' => 'InsightsRuntimeException',
|
||||||
|
'message' => 'Insights service is disabled',
|
||||||
|
'error' => null
|
||||||
|
], 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
$maxResultsPerPage = (int) env('MAX_RESULTS_PER_PAGE', 25);
|
||||||
|
|
||||||
|
$page = $request->get('page') ?? 1;
|
||||||
|
$limit = $request->get('limit') ?? $maxResultsPerPage;
|
||||||
|
$trend = $request->get('trend') ?? null;
|
||||||
|
|
||||||
|
$limit = (int) $limit;
|
||||||
|
|
||||||
|
if ($limit <= 0) {
|
||||||
|
$limit = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($limit > $maxResultsPerPage) {
|
||||||
|
$limit = $maxResultsPerPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_null($trend) || !in_array($trend, self::TRENDS)) {
|
||||||
|
return response()->json([
|
||||||
|
'status' => 400,
|
||||||
|
'type' => 'BadRequestException',
|
||||||
|
'message' => 'Trend value is invalid',
|
||||||
|
'error' => null
|
||||||
|
], 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
// $results = DB::table('insights')
|
||||||
|
// ->where('url', 'regexp',"/\/v(\d)\/{$trend}\/(\d+).*/i")
|
||||||
|
// ->where('timestamp', '>', time() - env('INSIGHTS_MAX_STORE_TIME', 172800) )
|
||||||
|
// ->orderBy('timestamp', 'desc')
|
||||||
|
// ->paginate(
|
||||||
|
// $limit,
|
||||||
|
// ['*'],
|
||||||
|
// null,
|
||||||
|
// $page
|
||||||
|
// );
|
||||||
|
|
||||||
|
$results = DB::table('insights')
|
||||||
|
// ->where('url', 'regexp',"/\/v(\d)\/{$trend}\/(\d+).*/i")
|
||||||
|
->where('timestamp', '>', time() - env('INSIGHTS_MAX_STORE_TIME', 172800) )
|
||||||
|
->orderBy('timestamp', 'desc')
|
||||||
|
->raw(fn($collection) => $collection->aggregate([
|
||||||
|
[
|
||||||
|
'$group' => [
|
||||||
|
'_id' => [
|
||||||
|
'url' => '$url',
|
||||||
|
'timestamp' => '$timestamp'
|
||||||
|
],
|
||||||
|
'urlCount' => [ '$sum' => 1 ]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'$group' => [
|
||||||
|
'_id' => '$_id.url',
|
||||||
|
'count' => [ '$sum' => '$urlCount' ]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'$sort' => [ 'count' => -1 ]
|
||||||
|
],
|
||||||
|
['$skip' => ($page - 1) * $maxResultsPerPage],
|
||||||
|
['$limit' => $maxResultsPerPage],
|
||||||
|
]));
|
||||||
|
// ->raw(fn($collection) => $collection->aggregate([
|
||||||
|
// [
|
||||||
|
// '$group' => [
|
||||||
|
// '_id' => '$_id',
|
||||||
|
// 'url' => ['$first' => '$url'],
|
||||||
|
// 'count' => [ '$sum' => 1 ]
|
||||||
|
// ]
|
||||||
|
// ]
|
||||||
|
// ]));
|
||||||
|
|
||||||
|
return new TrendsCollection(
|
||||||
|
new LengthAwarePaginator(
|
||||||
|
$results, DB::table('insights')->count(), $maxResultsPerPage, $page
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -2,24 +2,12 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers\V4DB;
|
namespace App\Http\Controllers\V4DB;
|
||||||
|
|
||||||
use App\Anime;
|
|
||||||
use App\Http\HttpHelper;
|
|
||||||
use App\Http\HttpResponse;
|
|
||||||
use App\Http\QueryBuilder\SearchQueryBuilderAnime;
|
|
||||||
use App\Http\QueryBuilder\SearchQueryBuilderMagazine;
|
use App\Http\QueryBuilder\SearchQueryBuilderMagazine;
|
||||||
use App\Http\Resources\V4\AnimeCollection;
|
|
||||||
use App\Http\Resources\V4\MagazineCollection;
|
use App\Http\Resources\V4\MagazineCollection;
|
||||||
use App\Http\Resources\V4\MangaCollection;
|
use App\Http\Resources\V4\MangaCollection;
|
||||||
use App\Http\Resources\V4\NewsResource;
|
|
||||||
use App\Magazine;
|
use App\Magazine;
|
||||||
use App\Manga;
|
use App\Manga;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Jenssegers\Mongodb\Eloquent\Builder;
|
|
||||||
use Jikan\Request\Anime\AnimeNewsRequest;
|
|
||||||
use Jikan\Request\Magazine\MagazineRequest;
|
|
||||||
use Jikan\Request\Magazine\MagazinesRequest;
|
|
||||||
use MongoDB\BSON\UTCDateTime;
|
|
||||||
|
|
||||||
class MagazineController extends Controller
|
class MagazineController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -5,11 +5,9 @@ namespace App\Http\Controllers\V4DB;
|
|||||||
use App\Anime;
|
use App\Anime;
|
||||||
use App\Http\QueryBuilder\SearchQueryBuilderProducer;
|
use App\Http\QueryBuilder\SearchQueryBuilderProducer;
|
||||||
use App\Http\Resources\V4\AnimeCollection;
|
use App\Http\Resources\V4\AnimeCollection;
|
||||||
use App\Http\Resources\V4\MagazineCollection;
|
|
||||||
use App\Http\Resources\V4\ProducerCollection;
|
use App\Http\Resources\V4\ProducerCollection;
|
||||||
use App\Producer;
|
use App\Producer;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Jikan\Request\Producer\ProducersRequest;
|
|
||||||
|
|
||||||
class ProducerController extends Controller
|
class ProducerController extends Controller
|
||||||
{
|
{
|
||||||
|
52
app/Http/Middleware/Insights.php
Normal file
52
app/Http/Middleware/Insights.php
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Insights
|
||||||
|
* @package App\Http\Middleware
|
||||||
|
*/
|
||||||
|
class Insights
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Request $request
|
||||||
|
* @param Closure $next
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function handle(Request $request, Closure $next)
|
||||||
|
{
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Request $request
|
||||||
|
* @param $response
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function terminate(Request $request, $response)
|
||||||
|
{
|
||||||
|
if (isset($response->original['error'])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @todo scaling: implement as scheduled event if needed
|
||||||
|
// Delete requests older than INSIGHTS_MAX_STORE
|
||||||
|
DB::table('insights')
|
||||||
|
->where('timestamp', '<', time() - env('INSIGHTS_MAX_STORE_TIME', 172800) )
|
||||||
|
->delete();
|
||||||
|
|
||||||
|
DB::table('insights')
|
||||||
|
->insert([
|
||||||
|
'timestamp' => time(),
|
||||||
|
'url' => $request->getRequestUri(),
|
||||||
|
'type' =>
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
55
app/Http/Resources/V4/InsightsCollection.php
Normal file
55
app/Http/Resources/V4/InsightsCollection.php
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace App\Http\Resources\V4;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\Resources\Json\ResourceCollection;
|
||||||
|
use Illuminate\Pagination\LengthAwarePaginator;
|
||||||
|
|
||||||
|
class InsightsCollection extends ResourceCollection
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The resource that this resource collects.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $collects = 'App\Http\Resources\V4\InsightsResource';
|
||||||
|
|
||||||
|
|
||||||
|
private $pagination;
|
||||||
|
|
||||||
|
public function __construct(LengthAwarePaginator $resource)
|
||||||
|
{
|
||||||
|
$this->pagination = [
|
||||||
|
'last_visible_page' => $resource->lastPage(),
|
||||||
|
'has_next_page' => $resource->hasMorePages()
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->collection = $resource->getCollection();
|
||||||
|
|
||||||
|
parent::__construct($resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform the resource collection into an array.
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function toArray($request)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'pagination' => $this->pagination,
|
||||||
|
'data' => $this->collection
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withResponse($request, $response)
|
||||||
|
{
|
||||||
|
$jsonResponse = json_decode($response->getContent(), true);
|
||||||
|
unset($jsonResponse['links'],$jsonResponse['meta']);
|
||||||
|
$response->setContent(json_encode($jsonResponse));
|
||||||
|
}
|
||||||
|
}
|
17
app/Http/Resources/V4/InsightsResource.php
Normal file
17
app/Http/Resources/V4/InsightsResource.php
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Resources\V4;
|
||||||
|
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
|
class InsightsResource extends JsonResource
|
||||||
|
{
|
||||||
|
|
||||||
|
public function toArray($request)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'timestamp' => $this['timestamp'],
|
||||||
|
'url' => $this['url'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
55
app/Http/Resources/V4/TrendsCollection.php
Normal file
55
app/Http/Resources/V4/TrendsCollection.php
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace App\Http\Resources\V4;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\Resources\Json\ResourceCollection;
|
||||||
|
use Illuminate\Pagination\LengthAwarePaginator;
|
||||||
|
|
||||||
|
class TrendsCollection extends ResourceCollection
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The resource that this resource collects.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $collects = 'App\Http\Resources\V4\TrendsResource';
|
||||||
|
|
||||||
|
|
||||||
|
private $pagination;
|
||||||
|
|
||||||
|
public function __construct(LengthAwarePaginator $resource)
|
||||||
|
{
|
||||||
|
$this->pagination = [
|
||||||
|
'last_visible_page' => $resource->lastPage(),
|
||||||
|
'has_next_page' => $resource->hasMorePages()
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->collection = $resource->getCollection();
|
||||||
|
|
||||||
|
parent::__construct($resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform the resource collection into an array.
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function toArray($request)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'pagination' => $this->pagination,
|
||||||
|
'data' => $this->collection
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withResponse($request, $response)
|
||||||
|
{
|
||||||
|
$jsonResponse = json_decode($response->getContent(), true);
|
||||||
|
unset($jsonResponse['links'],$jsonResponse['meta']);
|
||||||
|
$response->setContent(json_encode($jsonResponse));
|
||||||
|
}
|
||||||
|
}
|
17
app/Http/Resources/V4/TrendsResource.php
Normal file
17
app/Http/Resources/V4/TrendsResource.php
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Resources\V4;
|
||||||
|
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
|
class TrendsResource extends JsonResource
|
||||||
|
{
|
||||||
|
|
||||||
|
public function toArray($request)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'url' => $this['_id'],
|
||||||
|
'count' => $this['count'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -70,6 +70,14 @@ $app->singleton(
|
|||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
$globalMiddleware = [];
|
||||||
|
|
||||||
|
if (env('INSIGHTS', false)) {
|
||||||
|
$globalMiddleware[] = \App\Http\Middleware\Insights::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
$app->middleware($globalMiddleware);
|
||||||
|
|
||||||
$app->routeMiddleware([
|
$app->routeMiddleware([
|
||||||
// 'slave-auth' => App\Http\Middleware\SlaveAuthentication::class,
|
// 'slave-auth' => App\Http\Middleware\SlaveAuthentication::class,
|
||||||
// 'meta' => App\Http\Middleware\Meta::class,
|
// 'meta' => App\Http\Middleware\Meta::class,
|
||||||
@ -77,7 +85,7 @@ $app->routeMiddleware([
|
|||||||
// 'throttle' => App\Http\Middleware\Throttle::class,
|
// 'throttle' => App\Http\Middleware\Throttle::class,
|
||||||
// 'etag' => \App\Http\Middleware\EtagMiddleware::class,
|
// 'etag' => \App\Http\Middleware\EtagMiddleware::class,
|
||||||
'microcaching' => \App\Http\Middleware\MicroCaching::class,
|
'microcaching' => \App\Http\Middleware\MicroCaching::class,
|
||||||
'source-health-monitor' => SourceHeartbeatMonitor::class
|
'source-health-monitor' => SourceHeartbeatMonitor::class,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -145,7 +153,7 @@ $commonMiddleware = [
|
|||||||
// 'cache-resolver',
|
// 'cache-resolver',
|
||||||
// 'throttle'
|
// 'throttle'
|
||||||
'source-health-monitor',
|
'source-health-monitor',
|
||||||
'microcaching'
|
'microcaching',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
@ -501,4 +501,20 @@ $router->group(
|
|||||||
'uses' => 'RandomController@users',
|
'uses' => 'RandomController@users',
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
$router->group(
|
||||||
|
[
|
||||||
|
'prefix' => 'insights'
|
||||||
|
],
|
||||||
|
function() use ($router) {
|
||||||
|
$router->get('/', [
|
||||||
|
'uses' => 'InsightsController@main'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$router->get('/trends', [
|
||||||
|
'uses' => 'InsightsController@trends'
|
||||||
|
]);
|
||||||
|
}
|
||||||
);
|
);
|
Loading…
x
Reference in New Issue
Block a user