initial commit

This commit is contained in:
irfan-dahir 2018-04-21 12:59:48 +05:00
parent 3767540254
commit 8d49e8bd26
48 changed files with 7183 additions and 0 deletions

1
$null Executable file
View File

@ -0,0 +1 @@
{"name":"Abigail","state":"CA"}

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
/vendor
/.idea
Homestead.json
Homestead.yaml
.env

0
app/Console/Commands/.gitkeep Executable file
View File

29
app/Console/Kernel.php Executable file
View File

@ -0,0 +1,29 @@
<?php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Laravel\Lumen\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* @var array
*/
protected $commands = [
//
];
/**
* Define the application's command schedule.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
* @return void
*/
protected function schedule(Schedule $schedule)
{
//
}
}

10
app/Events/Event.php Executable file
View File

@ -0,0 +1,10 @@
<?php
namespace App\Events;
use Illuminate\Queue\SerializesModels;
abstract class Event
{
use SerializesModels;
}

16
app/Events/ExampleEvent.php Executable file
View File

@ -0,0 +1,16 @@
<?php
namespace App\Events;
class ExampleEvent extends Event
{
/**
* Create a new event instance.
*
* @return void
*/
public function __construct()
{
//
}
}

99
app/Exceptions/Handler.php Executable file
View File

@ -0,0 +1,99 @@
<?php
namespace App\Exceptions;
use Exception;
use Illuminate\Validation\ValidationException;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Laravel\Lumen\Exceptions\Handler as ExceptionHandler;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Illuminate\Http\Response;
use Symfony\Component\Debug\Exception\FlattenException;
use Symfony\Component\Console\Application as ConsoleApplication;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Debug\ExceptionHandler as SymfonyExceptionHandler;
use Bugsnag\BugsnagLaravel\Facades\Bugsnag;
class Handler extends ExceptionHandler
{
/**
* A list of the exception types that should not be reported.
*
* @var array
*/
protected $dontReport = [
AuthorizationException::class,
HttpException::class,
ModelNotFoundException::class,
ValidationException::class,
];
/**
* Report or log an exception.
*
* This is a great spot to send exceptions to Sentry, Bugsnag, etc.
*
* @param \Exception $e
* @return void
*/
public function report(Exception $e)
{
parent::report($e);
}
/**
* Render an exception into an HTTP response.
*
* @param \Illuminate\Http\Request $request
* @param \Exception $e
* @return \Illuminate\Http\Response
*/
public function render($request, Exception $e)
{
Bugsnag::notifyException($e);
if ($e instanceof HttpResponseException) {
} elseif ($e instanceof ModelNotFoundException) {
$e = new NotFoundHttpException($e->getMessage(), $e);
} elseif ($e instanceof AuthorizationException) {
$e = new HttpException(403, $e->getMessage());
} elseif ($e instanceof ValidationException && $e->getResponse()) {
}
$fe = FlattenException::create($e);
//$decorated = $this->decorate($handler->getContent($fe), $handler->getStylesheet($fe));
return response()->json(['error' => $this->getContent($fe->getStatusCode())], $fe->getStatusCode());
//return response()->json($this->getContent($fe), $fe->getStatusCode());
//$response->exception = $e;
//return $response;
//if ($e instanceof CustomException) {
// return response('Custom Message');
//}
//return response(['error' => $e->getMessage()], 400);
//var_dump(parent::render($request, $e));
//return parent::render($request, $e);
}
public function getContent($statusCode) {
switch ($statusCode) {
case 404:
return 'Invalid or incomplete endpoint';
case 400:
return 'Bad Request';
case 500:
return 'Server Error';
default:
return 'Unknown error';
}
}
}

View File

@ -0,0 +1,194 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Exceptions\Handler as Handler;
use Jikan\Jikan;
use Bugsnag\BugsnagLaravel\Facades\Bugsnag;
use Lazer\Classes\Database as Lazer;
class AnimeController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public $id;
public $extend;
public $extendArgs;
private $validExtends = ['episodes', 'characters_staff', 'news', 'videos', 'pictures', 'stats', 'forum', 'moreinfo'];
public function request($id, $extend = null, $extendArgs = null) {
$this->id = $id;
$this->extend = $extend;
$this->extendArgs = is_array($extendArgs) ? $extendArgs[0] : $extendArgs;
$this->hash = sha1('anime' . $this->id . $this->extend . $this->extendArgs);
$this->response['request_hash'] = $this->hash;
$this->response['request_cached'] = false;
if (app('redis')->exists($this->hash)) {
$this->response['request_cached'] = true;
return response()->json(
$this->response + json_decode(app('redis')->get($this->hash), true)
);
}
$jikan = new Jikan;
if (isset($this->extend)) {
if (!in_array($this->extend, $this->validExtends)) {
return response()->json(
['error' => 'Invalid extended request: "' . $this->extend . '"'], 400
);
}
switch ($this->extend) {
case 'episodes':
try {
if (!isset($this->extendArgs) || empty($this->extendArgs)) {
$this->extendArgs = 1;
} else {
intval($this->extendArgs);
}
$this->extendArgs = $this->extendArgs <= 0 ? 1 : $this->extendArgs;
$jikan->Anime($this->id, [EPISODES => $this->extendArgs]);
} catch (\Exception $e) {
Bugsnag::notifyException($e);
return response()->json(
['error' => $e->getMessage()], 404
);
}
break;
case 'characters_staff':
try {
$jikan->Anime($this->id, [CHARACTERS_STAFF]);
} catch (\Exception $e) {
Bugsnag::notifyException($e);
return response()->json(
['error' => $e->getMessage()], 404
);
}
break;
case 'news':
try {
$jikan->Anime($this->id, [NEWS]);
} catch (\Exception $e) {
Bugsnag::notifyException($e);
return response()->json(
['error' => $e->getMessage()], 404
);
}
break;
case 'videos':
try {
$jikan->Anime($this->id, [VIDEOS]);
} catch (\Exception $e) {
Bugsnag::notifyException($e);
return response()->json(
['error' => $e->getMessage()], 404
);
}
break;
case 'pictures':
try {
$jikan->Anime($this->id, [PICTURES]);
} catch (\Exception $e) {
Bugsnag::notifyException($e);
return response()->json(
['error' => $e->getMessage()], 404
);
}
break;
case 'stats':
try {
$jikan->Anime($this->id, [STATS]);
} catch (\Exception $e) {
Bugsnag::notifyException($e);
return response()->json(
['error' => $e->getMessage()], 404
);
}
break;
case 'moreinfo':
try {
$jikan->Anime($this->id, [MORE_INFO]);
} catch (\Exception $e) {
Bugsnag::notifyException($e);
return response()->json(
['error' => $e->getMessage()], 404
);
}
break;
case 'forum':
try {
$jikan->Anime($this->id, [FORUM]);
} catch (\Exception $e) {
Bugsnag::notifyException($e);
return response()->json(
['error' => $e->getMessage()], 404
);
}
break;
}
} else {
try {
$jikan->Anime($this->id);
} catch (\Exception $e) {
Bugsnag::notifyException($e);
return response()->json(
['error' => $e->getMessage()], 404
);
}
}
if (empty($jikan->response) || $jikan->response === false) {
return response()->json(['error' => 'MyAnimeList Rate Limiting reached. Slow down!'], 429);
}
$this->cache = json_encode($jikan->response);
if ($this->cache !== false) {
if (app('redis')->set($this->hash, $this->cache)) {
app('redis')->expire($this->hash, CACHE_EXPIRE);
}
}
return response()->json(
$this->response + $jikan->response
);
}
}

View File

@ -0,0 +1,97 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Exceptions\Handler as Handler;
use Jikan\Jikan;
use Bugsnag\BugsnagLaravel\Facades\Bugsnag;
class CharacterController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public $id;
public $extend;
public $extendArgs;
private $validExtends = ['pictures'];
public function request($id, $extend = null, $extendArgs = null) {
$this->id = $id;
$this->extend = $extend;
$this->extendArgs = $extendArgs;
$this->hash = sha1('character' . $this->id . $this->extend . $this->extendArgs);
$this->response['request_hash'] = $this->hash;
$this->response['request_cached'] = false;
if (app('redis')->exists($this->hash)) {
$this->response['request_cached'] = true;
return response()->json(
$this->response + json_decode(app('redis')->get($this->hash), true)
);
}
$jikan = new Jikan;
if (isset($this->extend)) {
if (!in_array($this->extend, $this->validExtends)) {
return response()->json(
['error' => 'Invalid extended request: "' . $this->extend . '"'], 400
);
}
switch ($this->extend) {
case 'pictures':
try {
$jikan->Character($this->id, [PICTURES]);
} catch (\Exception $e) {
Bugsnag::notifyException($e);
return response()->json(
['error' => $e->getMessage()], 404
);
}
break;
}
} else {
try {
$jikan->Character($this->id);
} catch (\Exception $e) {
Bugsnag::notifyException($e);
return response()->json(
['error' => $e->getMessage()], 404
);
}
}
if (empty($jikan->response) || $jikan->response === false) {
return response()->json(['error' => 'MyAnimeList Rate Limiting reached. Slow down!'], 429);
}
$this->cache = json_encode($jikan->response);
if ($this->cache !== false) {
if (app('redis')->set($this->hash, $this->cache)) {
app('redis')->expire($this->hash, CACHE_EXPIRE);
}
}
return response()->json(
$this->response + $jikan->response
);
}
}

View File

@ -0,0 +1,12 @@
<?php
namespace App\Http\Controllers;
use Laravel\Lumen\Routing\Controller as BaseController;
class Controller extends BaseController
{
private $hash;
private $cache;
private $response = [];
}

View File

@ -0,0 +1,18 @@
<?php
namespace App\Http\Controllers;
class ExampleController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
//
}
//
}

View File

@ -0,0 +1,157 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Exceptions\Handler as Handler;
use Jikan\Jikan;
use Bugsnag\BugsnagLaravel\Facades\Bugsnag;
class MangaController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public $id;
public $extend;
public $extendArgs;
private $validExtends = ['characters', 'news', 'pictures', 'stats', 'forum', 'moreinfo'];
public function request($id, $extend = null, $extendArgs = null) {
$this->id = $id;
$this->extend = $extend;
$this->extendArgs = $extendArgs;
$this->hash = sha1('manga' . $this->id . $this->extend . $this->extendArgs);
$this->response['request_hash'] = $this->hash;
$this->response['request_cached'] = false;
if (app('redis')->exists($this->hash)) {
$this->response['request_cached'] = true;
return response()->json(
$this->response + json_decode(app('redis')->get($this->hash), true)
);
}
$jikan = new Jikan;
if (isset($this->extend)) {
if (!in_array($this->extend, $this->validExtends)) {
return response()->json(
['error' => 'Invalid extended request: "' . $this->extend . '"'], 400
);
}
switch ($this->extend) {
case 'characters':
try {
$jikan->Manga($this->id, [CHARACTERS]);
} catch (\Exception $e) {
return response()->json(
['error' => $e->getMessage()], 404
);
}
break;
case 'news':
try {
$jikan->Manga($this->id, [NEWS]);
} catch (\Exception $e) {
return response()->json(
['error' => $e->getMessage()], 404
);
}
break;
case 'pictures':
try {
$jikan->Manga($this->id, [PICTURES]);
} catch (\Exception $e) {
return response()->json(
['error' => $e->getMessage()], 404
);
}
break;
case 'stats':
try {
$jikan->Manga($this->id, [STATS]);
} catch (\Exception $e) {
return response()->json(
['error' => $e->getMessage()], 404
);
}
break;
case 'moreinfo':
try {
$jikan->Manga($this->id, [MORE_INFO]);
} catch (\Exception $e) {
return response()->json(
['error' => $e->getMessage()], 404
);
}
break;
case 'forum':
try {
$jikan->Manga($this->id, [FORUM]);
} catch (\Exception $e) {
return response()->json(
['error' => $e->getMessage()], 404
);
}
break;
}
} else {
try {
$jikan->Manga($this->id);
} catch (\Exception $e) {
return response()->json(
['error' => $e->getMessage()], 404
);
}
}
if (empty($jikan->response) || $jikan->response === false) {
return response()->json(['error' => 'MyAnimeList Rate Limiting reached. Slow down!'], 429);
}
$this->cache = json_encode($jikan->response);
if ($this->cache !== false) {
if (app('redis')->set($this->hash, $this->cache)) {
app('redis')->expire($this->hash, CACHE_EXPIRE);
}
}
return response()->json(
$this->response + $jikan->response
);
}
}

View File

@ -0,0 +1,157 @@
<?php
namespace App\Http\Controllers;
class MetaController extends Controller
{
private const VALID_REQUESTS = ['status', 'requests'];
private const VALID_TYPE = ['anime', 'manga', 'character', 'people', 'person', 'search', 'top', 'season'];
private const VALID_PERIOD = ['today', 'weekly', 'monthly'];
private const LIMIT = 50;
private $request;
private $type;
private $period;
private $page;
public function request($request, $type = null, $period = null, $page = 0) {
$this->request = $request;
if (!is_null($type)) {
if (!in_array($type, self::VALID_TYPE)) {
return response()->json([
'error' => 'Invalid type request'
], 400);
}
$this->type = $type;
}
if (!is_null($period)) {
if (!in_array($period, self::VALID_PERIOD)) {
return response()->json([
'error' => 'Invalid period request'
]);
}
$this->period = $period;
}
if (!is_null($page)) {
$this->page = $page - 1;
if ($this->page < 0) {
$this->page = 0;
}
}
if (in_array($request, self::VALID_REQUESTS)) {
return response()->json($this->{$request}());
}
/* $key = "meta:requests:".date("m-o");
if (!app('redis')->exists($key)) {
return response()->json([
'error' => 'Requests for this period do not exist'
], 404);
}*/
}
public function status() {
$key = "meta:requests:".date("m-o");
$requests_this_month = 0;
$requests_this_week = 0;
$requests_today = 0;
$requests = [];
if (app('redis')->exists($key)) {
$requests = app('redis')->hGetAll($key);
}
$today = strtotime('today UTC');
$last_week = strtotime("-1 week");
$now = time();
foreach ($requests as $time => $data) {
$data = json_decode($data, true);
$count = count($data);
$requests_this_month += $count;
if ($time >= $last_week && $time <= $now) {
$requests_this_week += $count;
}
if ($time >= $today && $time <= $now) {
$requests_today += $count;
}
}
$info = app('redis')->info();
return response()->json([
'cached_requests' => app('redis')->dbsize(),
'requests_today' => $requests_today,
'requests_this_week' => $requests_this_week,
'requests_this_month' => $requests_this_month,
'connected_clients' => $info['Clients']['connected_clients'],
'total_connections_received' => $info['Stats']['total_connections_received'],
'db_keys' => $info['Keyspace']['db0']['keys'],
'db_expires' => $info['Keyspace']['db0']['expires'],
'db_avg_ttl' => $info['Keyspace']['db0']['avg_ttl'],
]);
}
public function requests() {
if (is_null($this->type)) {
$requests = [];
$requestsHashKey = app('redis')->sort('requests', [
'by' => 'requests:*->time',
'limit' => [$this->page*self::LIMIT, self::LIMIT],
'sort' => 'desc'
]);
foreach ($requestsHashKey as $value) {
$data = app('redis')->hMGet($value, ['time', 'request', 'request_type']);
if (!isset($request[$data[1]])){
$request[$data[1]] = [];
}
$request[$data[1]][] = (int) $data[0];
}
return $request;
}
$requests = [];
$requestsHashKey = app('redis')->sort('requests', [
'by' => 'requests:*->time',
// 'limit' => [$this->page*self::LIMIT, self::LIMIT],
'sort' => 'desc'
]);
foreach ($requestsHashKey as $value) {
$data = app('redis')->hMGet($value, ['time', 'request', 'request_type']);
if ($data[2] != $this->type) {
continue;
}
if (!isset($request[$data[1]])) {
$request[$data[1]] = [];
}
$request[$data[1]][] = (int) $data[0];
}
return $request;
}
}

View File

@ -0,0 +1,97 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Exceptions\Handler as Handler;
use Jikan\Jikan;
use Bugsnag\BugsnagLaravel\Facades\Bugsnag;
class PersonController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public $id;
public $extend;
public $extendArgs;
private $validExtends = ['pictures'];
public function request($id, $extend = null, $extendArgs = null) {
$this->id = $id;
$this->extend = $extend;
$this->extendArgs = $extendArgs;
$this->hash = sha1('person' . $this->id . $this->extend . $this->extendArgs);
$this->response['request_hash'] = $this->hash;
$this->response['request_cached'] = false;
if (app('redis')->exists($this->hash)) {
$this->response['request_cached'] = true;
return response()->json(
$this->response + json_decode(app('redis')->get($this->hash), true)
);
}
$jikan = new Jikan;
if (isset($this->extend)) {
if (!in_array($this->extend, $this->validExtends)) {
return response()->json(
['error' => 'Invalid extended request: "' . $this->extend . '"'], 400
);
}
switch ($this->extend) {
case 'pictures':
try {
$jikan->Person($this->id, [PICTURES]);
} catch (\Exception $e) {
Bugsnag::notifyException($e);
return response()->json(
['error' => $e->getMessage()], 404
);
}
break;
}
} else {
try {
$jikan->Person($this->id);
} catch (\Exception $e) {
Bugsnag::notifyException($e);
return response()->json(
['error' => $e->getMessage()], 404
);
}
}
if (empty($jikan->response) || $jikan->response === false) {
return response()->json(['error' => 'MyAnimeList Rate Limiting reached. Slow down!'], 429);
}
$this->cache = json_encode($jikan->response);
if ($this->cache !== false) {
if (app('redis')->set($this->hash, $this->cache)) {
app('redis')->expire($this->hash, CACHE_EXPIRE);
}
}
return response()->json(
$this->response + $jikan->response
);
}
}

View File

@ -0,0 +1,82 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Exceptions\Handler as Handler;
use Jikan\Jikan;
use Bugsnag\BugsnagLaravel\Facades\Bugsnag;
use Lazer\Classes\Database as Lazer;
class ScheduleController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public $day;
private $validDays = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'];
public function request($day = null) {
$antiXss = new \voku\helper\AntiXSS();
if (!is_null($day)) {
$this->day = $antiXss->xss_clean($day);
if (!in_array($this->day, $this->validDays)) {
return response()->json(
['error' => 'Invalid day request: "' . $this->day . '"'], 400
);
}
}
$this->hash = sha1('schedule' . $this->day);
$this->response['request_hash'] = $this->hash;
$this->response['request_cached'] = false;
if (app('redis')->exists($this->hash)) {
$this->response['request_cached'] = true;
return response()->json(
$this->response + json_decode(app('redis')->get($this->hash), true)
);
}
$jikan = new Jikan;
try {
$jikan->Schedule();
} catch (\Exception $e) {
Bugsnag::notifyException($e);
return response()->json(
['error' => $e->getMessage()], 404
);
}
if (empty($jikan->response) || $jikan->response === false) {
return response()->json(['error' => 'MyAnimeList Rate Limiting reached. Slow down!'], 429);
}
if (!is_null($this->day)) {
$day = $jikan->response[$this->day];
$jikan->response = [];
$jikan->response[$this->day] = $day;
}
$this->cache = json_encode($jikan->response);
if ($this->cache !== false) {
if (app('redis')->set($this->hash, $this->cache)) {
app('redis')->expire($this->hash, CACHE_EXPIRE);
}
}
return response()->json(
$this->response + $jikan->response
);
}
}

View File

@ -0,0 +1,258 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Exceptions\Handler as Handler;
use Jikan;
use Bugsnag\BugsnagLaravel\Facades\Bugsnag;
use Lazer\Classes\Database as Lazer;
class SearchController extends Controller
{
/**
* Create a new controller instance.
*build
* @return void
*/
public $type;
public $query;
public $page;
public $config = [];
public $configObj;
private $validTypes = ['anime', 'manga', 'character', 'person', 'people'];
private $validSubTypes = [
'tv' => 1,
'ova' => 2,
'movie' => 3,
'special' => 4,
'ona' => 5,
'music' => 6,
'manga' => 1,
'novel' => 2,
'oneshot' => 3,
'doujin' => 4,
'manhwa' => 5,
'manhua' => 6
];
private $validStatus = [
'airing' => 1,
'completed' => 2,
'complete' => 2,
'tba' => 3,
'upcoming' => 3
];
private $validRating = [
'g' => 1,
'pg' => 2,
'pg13' => 3,
'r17' => 4,
'r' => 5,
'rx' => 6
];
private $validGenre = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43];
public function request($type = null, $query = null, $page = 1) {
$antiXss = new \voku\helper\AntiXSS();
$this->type = $type;
$this->query = urlencode($antiXss->xss_clean($query));
$this->page = $page;
$jikan = new \Jikan\Jikan;
if ($type == 'anime' || $type == 'manga') {
$this->buildConfig();
if (!empty($this->config)) {
$this->configObj = new \Jikan\Helper\SearchConfig($type);
foreach ($this->config as $key => $value) {
if (is_array($value)) {
$this->configObj->{"set".$key}(...$value);
} else {
$this->configObj->{"set".$key}($value);
}
}
}
}
$this->hash = sha1('search' . $this->type . $this->query . $this->page . $this->configToString());
$this->response['request_hash'] = $this->hash;
$this->response['request_cached'] = false;
if (app('redis')->exists($this->hash)) {
$this->response['request_cached'] = true;
return response()->json(
$this->response + json_decode(app('redis')->get($this->hash), true)
);
}
if (!in_array($this->type, $this->validTypes)) {
return response()->json(
['error' => 'Invalid type request: "' . $this->type . '"'], 400
);
}
switch ($this->type) {
case 'anime':
try {
if (!empty($this->config)) {
$jikan->Search($this->query, ANIME, $this->page, $this->configObj);
} else {
$jikan->Search($this->query, ANIME, $this->page);
}
} catch (\Exception $e) {
Bugsnag::notifyException($e);
return response()->json(
['error' => $e->getMessage()], 404
);
}
break;
case 'manga':
try {
if (!empty($this->config)) {
$jikan->Search($this->query, MANGA, $this->page, $this->configObj);
} else {
$jikan->Search($this->query, MANGA, $this->page);
}
} catch (\Exception $e) {
Bugsnag::notifyException($e);
return response()->json(
['error' => $e->getMessage()], 404
);
}
break;
case 'person':
case 'people':
try {
$jikan->Search($this->query, PERSON, $this->page);
} catch (\Exception $e) {
Bugsnag::notifyException($e);
return response()->json(
['error' => $e->getMessage()], 404
);
}
break;
case 'character':
try {
$jikan->Search($this->query, CHARACTER, $this->page);
} catch (\Exception $e) {
Bugsnag::notifyException($e);
return response()->json(
['error' => $e->getMessage()], 404
);
}
break;
}
if (empty($jikan->response) || $jikan->response === false) {
return response()->json(['error' => 'MyAnimeList Rate Limiting reached. Slow down!'], 429);
}
$this->cache = json_encode($jikan->response);
if ($this->cache !== false) {
if (app('redis')->set($this->hash, $this->cache)) {
app('redis')->expire($this->hash, CACHE_EXPIRE_SEARCH);
}
}
return response()->json(
$this->response + $jikan->response
);
}
private function buildConfig() {
$antiXss = new \voku\helper\AntiXSS();
if (!isset($_GET)) {return;}
if (isset($_GET['type'])) {
$subtype = strtolower($antiXss->xss_clean($_GET['type']));
if (array_key_exists($subtype, $this->validSubTypes)) {
$this->config['Type'] = $this->validSubTypes[$subtype];
}
}
if (isset($_GET['score'])) {
$this->config['Score'] = (float) $_GET['score'];
}
if (isset($_GET['status'])) {
$status = strtolower($antiXss->xss_clean($_GET['status']));
if (array_key_exists($status, $this->validStatus)) {
$this->config['Status'] = $this->validStatus[$status];
}
}
if (isset($_GET['rated'])) {
$rated = strtolower($antiXss->xss_clean($_GET['rated']));
if (array_key_exists($rated, $this->validRating)) {
$this->config['Rated'] = $this->validRating[$rated];
}
}
if (isset($_GET['start_date'])) {
$startDate = $antiXss->xss_clean($_GET['start_date']);
if (preg_match("~[0-9]{4}-[0-9]{2}-[0-9]{2}~", $startDate)) {
$this->config['StartDate'] = explode("-", $startDate);
}
}
if (isset($_GET['end_date'])) {
$endDate = $antiXss->xss_clean($_GET['end_date']);
if (preg_match("~[0-9]{4}-[0-9]{2}-[0-9]{2}~", $endDate)) {
$this->config['EndDate'] = explode("-", $endDate);
}
}
if (isset($_GET['genre'])) {
if (!is_array($_GET['genre'])) {
return response()->json(
['error' => 'Bad genre parse: "' . $this->type . '"'], 400
);
}
$this->config['genre'] = [];
foreach ($_GET['genre'] as $genre) {
$genre = (int) $genre;
if (in_array($genre, $this->validGenre)) {
$this->config['genre'][] = $genre;
}
}
}
if (isset($_GET['genre_exclude'])) {
$this->config['GenreInclude'] = ((int) $_GET['genre_exclude'] == 1) ? false : true;
}
}
private function configToString() {
$url = "?";
foreach ($this->config as $key => $value) {
if (is_array($value)) {
$value = implode(",", $value);
}
$url .= $key . "=" . $value . "&";
}
return $url;
}
}

View File

@ -0,0 +1,83 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Exceptions\Handler as Handler;
use Jikan\Jikan;
use Bugsnag\BugsnagLaravel\Facades\Bugsnag;
use Lazer\Classes\Database as Lazer;
class SeasonController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public $year;
public $season;
private $validSeasons = ['summer', 'spring', 'fall', 'winter'];
public function request($year = null, $season = null) {
$antiXss = new \voku\helper\AntiXSS();
if (!is_null($year) && !is_null($season)) {
$this->year = (int) $year;
$this->season = $antiXss->xss_clean($season);
if (!in_array($this->season, $this->validSeasons)) {
return response()->json(
['error' => 'Invalid season request: "' . $this->year . '/' . $this->season . '"'], 400
);
}
}
$this->hash = sha1('season' . $this->year . $this->season);
$this->response['request_hash'] = $this->hash;
$this->response['request_cached'] = false;
if (app('redis')->exists($this->hash)) {
$this->response['request_cached'] = true;
return response()->json(
$this->response + json_decode(app('redis')->get($this->hash), true)
);
}
$jikan = new Jikan;
try {
if (!is_null($this->year) && !is_null($this->season)) {
$jikan->Seasonal($this->season, $this->year);
} else {
$jikan->Seasonal();
}
} catch (\Exception $e) {
Bugsnag::notifyException($e);
return response()->json(
['error' => $e->getMessage()], 404
);
}
if (empty($jikan->response) || $jikan->response === false) {
return response()->json(['error' => 'MyAnimeList Rate Limiting reached. Slow down!'], 429);
}
$this->cache = json_encode($jikan->response);
if ($this->cache !== false) {
if (app('redis')->set($this->hash, $this->cache)) {
app('redis')->expire($this->hash, CACHE_EXPIRE);
}
}
return response()->json(
$this->response + $jikan->response
);
}
}

View File

@ -0,0 +1,88 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Exceptions\Handler as Handler;
use Jikan\Jikan;
use Bugsnag\BugsnagLaravel\Facades\Bugsnag;
use Lazer\Classes\Database as Lazer;
class TopController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public $type;
public $subtype;
public $page;
private $validTypes = ['anime', 'manga'];
private $validSubTypes = ['airing', 'upcoming', 'tv', 'movie', 'ova', 'special', 'manga', 'novels', 'oneshots', 'doujin', 'manhwa', 'manhua', 'bypopularity', 'favorite'];
public function request($type = null, $page = 1, $subtype = null) {
$antiXss = new \voku\helper\AntiXSS();
$this->type = $antiXss->xss_clean($type);
$this->page = (int) $page;
if (!in_array($this->type, $this->validTypes)) {
return response()->json(
['error' => 'Invalid type request: "' . $this->type . '/' . $this->page . '/' . $this->subtype . '"'], 400
);
}
if (!is_null($subtype)) {
$this->subtype = $antiXss->xss_clean($subtype);
if (!in_array($this->subtype, $this->validSubTypes)) {
return response()->json(
['error' => 'Invalid sub type request: "' . $this->type . '/' . $this->page . '/' . $this->subtype . '"'], 400
);
}
}
$this->hash = sha1('top' . $this->type . $this->page . $this->subtype);
$this->response['request_hash'] = $this->hash;
$this->response['request_cached'] = false;
if (app('redis')->exists($this->hash)) {
$this->response['request_cached'] = true;
return response()->json(
$this->response + json_decode(app('redis')->get($this->hash), true)
);
}
$jikan = new Jikan;
try {
$jikan->Top($this->type, $this->page, $this->subtype);
} catch (\Exception $e) {
Bugsnag::notifyException($e);
return response()->json(
['error' => $e->getMessage()], 404
);
}
if (empty($jikan->response) || $jikan->response === false) {
return response()->json(['error' => 'MyAnimeList Rate Limiting reached. Slow down!'], 429);
}
$this->cache = json_encode($jikan->response);
if ($this->cache !== false) {
if (app('redis')->set($this->hash, $this->cache)) {
app('redis')->expire($this->hash, CACHE_EXPIRE_SEARCH);
}
}
return response()->json(
$this->response + $jikan->response
);
}
}

View File

@ -0,0 +1,44 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Contracts\Auth\Factory as Auth;
class Authenticate
{
/**
* The authentication guard factory instance.
*
* @var \Illuminate\Contracts\Auth\Factory
*/
protected $auth;
/**
* Create a new middleware instance.
*
* @param \Illuminate\Contracts\Auth\Factory $auth
* @return void
*/
public function __construct(Auth $auth)
{
$this->auth = $auth;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string|null $guard
* @return mixed
*/
public function handle($request, Closure $next, $guard = null)
{
if ($this->auth->guard($guard)->guest()) {
return response('Unauthorized.', 401);
}
return $next($request);
}
}

26
app/Http/Middleware/Cache.php Executable file
View File

@ -0,0 +1,26 @@
<?php
namespace App\Http\Middleware;
use Closure;
class Cache
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$response = $next($request);
$data = $response->original;
if (!array_key_exists('error', $data)) {
}
return $response;
}
}

View File

@ -0,0 +1,20 @@
<?php
namespace App\Http\Middleware;
use Closure;
class ExampleMiddleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
return $next($request);
}
}

View File

@ -0,0 +1,44 @@
<?php
namespace App\Http\Middleware;
use Closure;
class Meta
{
private $request;
public function handle($request, Closure $next)
{
$req = $_SERVER['REQUEST_URI'];
$req_type = explode('/', $req)[1];
$response = $next($request);
if (isset($response->original['error'])) {
return $response;
}
$date = date("m-o");
$time = round(microtime(true) * 1000);
$key = "requests:".$date.":".$time;
if (!app('redis')->exists($key)) {
app('redis')->hMSet($key, [
'key' => $key,
'time' => $time,
'ip' => $_SERVER['REMOTE_ADDR'],
'request' => $req,
'request_type' => $req_type
// 'count' => 0
]);
app('redis')->sAdd('requests', $key);
}
// app('redis')->hIncrBy($key, 'count', 1);
return $response;
}
}

View File

@ -0,0 +1,78 @@
<?php
namespace App\Http\Middleware;
use Closure;
class Throttle
{
private $ip;
private $hit;
private $sessions = [];
private $rateLimited = false;
private $request_hash;
private $request_cached;
public function handle($request, Closure $next)
{
$response = $next($request);
$this->loadSessions(); // load the session
if (!isset($response->original['error'])) { // don't throttle errors
$this->request_hash = $response->original['request_hash'];
$this->request_cached = $response->original['request_cached'];
if (!$this->request_cached) { // don't throttle cached requests
$this->hit(); // increase API Call Count
}
}
$this->rateLimit(); // check if it's over the limit
$this->save(); // save the updated session
if ($this->rateLimited) {
return response()->json(['error' => 'You have reached your limit of ' . RATE_LIMIT . ' API calls per day, please try again later'], 429);
}
return $response;
}
public function hit() {
$this->ip = $_SERVER['REMOTE_ADDR'];
$date = date("d-m-Y");
if (!isset($this->sessions[$this->ip])) { // register the session
$this->sessions[$this->ip] = [
$date => 0
];
}
if (!isset($this->sessions[$this->ip][$date])) { // register today's session
$this->sessions[$this->ip][$date] = 0;
}
$this->sessions[$this->ip][$date]++; // increase API Call count
$this->hit = $this->sessions[$this->ip][$date];
}
public function rateLimit() {
$this->rateLimited = ($this->hit > RATE_LIMIT) ? true : false;
}
public function loadSessions() {
$this->sessions = file_exists(SESSION_STORAGE_PATH) ? json_decode(file_get_contents(SESSION_STORAGE_PATH), true) : file_put_contents(SESSION_STORAGE_PATH, json_encode([]));
}
public function save() {
file_put_contents(SESSION_STORAGE_PATH, json_encode($this->sessions));
}
}

26
app/Jobs/ExampleJob.php Executable file
View File

@ -0,0 +1,26 @@
<?php
namespace App\Jobs;
class ExampleJob extends Job
{
/**
* Create a new job instance.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
//
}
}

24
app/Jobs/Job.php Executable file
View File

@ -0,0 +1,24 @@
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
abstract class Job implements ShouldQueue
{
/*
|--------------------------------------------------------------------------
| Queueable Jobs
|--------------------------------------------------------------------------
|
| This job base class provides a central location to place any logic that
| is shared across all of your jobs. The trait included with the class
| provides access to the "queueOn" and "delay" queue helper methods.
|
*/
use InteractsWithQueue, Queueable, SerializesModels;
}

View File

@ -0,0 +1,31 @@
<?php
namespace App\Listeners;
use App\Events\ExampleEvent;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
class ExampleListener
{
/**
* Create the event listener.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* @param ExampleEvent $event
* @return void
*/
public function handle(ExampleEvent $event)
{
//
}
}

View File

@ -0,0 +1,20 @@
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
//
$this->app->alias('bugsnag.logger', \Illuminate\Contracts\Logging\Log::class);
$this->app->alias('bugsnag.logger', \Psr\Log\LoggerInterface::class);
}
}

View File

@ -0,0 +1,39 @@
<?php
namespace App\Providers;
use App\User;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
//
}
/**
* Boot the authentication services for the application.
*
* @return void
*/
public function boot()
{
// Here you may define how you wish users to be authenticated for your Lumen
// application. The callback which receives the incoming request instance
// should return either a User instance or null. You're free to obtain
// the User instance via an API token or any other method necessary.
$this->app['auth']->viaRequest('api', function ($request) {
if ($request->input('api_token')) {
return User::where('api_token', $request->input('api_token'))->first();
}
});
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Providers;
use Laravel\Lumen\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider
{
/**
* The event listener mappings for the application.
*
* @var array
*/
protected $listen = [
'App\Events\SomeEvent' => [
'App\Listeners\EventListener',
],
];
}

32
app/User.php Executable file
View File

@ -0,0 +1,32 @@
<?php
namespace App;
use Illuminate\Auth\Authenticatable;
use Laravel\Lumen\Auth\Authorizable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
class User extends Model implements AuthenticatableContract, AuthorizableContract
{
use Authenticatable, Authorizable;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name', 'email',
];
/**
* The attributes excluded from the model's JSON form.
*
* @var array
*/
protected $hidden = [
'password',
];
}

35
artisan Executable file
View File

@ -0,0 +1,35 @@
#!/usr/bin/env php
<?php
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Output\ConsoleOutput;
/*
|--------------------------------------------------------------------------
| Create The Application
|--------------------------------------------------------------------------
|
| First we need to get an application instance. This creates an instance
| of the application / container and bootstraps the application so it
| is ready to receive HTTP / Console requests from the environment.
|
*/
$app = require __DIR__.'/bootstrap/app.php';
/*
|--------------------------------------------------------------------------
| Run The Artisan Application
|--------------------------------------------------------------------------
|
| When we run the console application, the current CLI command will be
| executed in this console and the response sent back to a terminal
| or another output device for the developers. Here goes nothing!
|
*/
$kernel = $app->make(
'Illuminate\Contracts\Console\Kernel'
);
exit($kernel->handle(new ArgvInput, new ConsoleOutput));

123
bootstrap/app.php Executable file
View File

@ -0,0 +1,123 @@
<?php
require_once __DIR__.'/../vendor/autoload.php';
try {
(new Dotenv\Dotenv(__DIR__.'/../'))->load();
} catch (Dotenv\Exception\InvalidPathException $e) {
//
}
/*
Defines
*/
define('SESSION_STORAGE_PATH', '/var/www/api.jikan/storage/app/sessions.json');
define('RATE_LIMIT', 5000); // per day
//define('CACHE_EXPIRE', 3600 * 24 * 3); // 3 days
// define('CACHE_EXPIRE_SEARCH', 3600 * 6); // 6 hours
define('CACHE_EXPIRE', 4); // 60 seconds | dev
define('CACHE_EXPIRE_SEARCH', 4); // 60 seconds | dev
define('REST_VERSION', '2.2');
define('SOURCE_VERSION', '1.15.5');
/*
|--------------------------------------------------------------------------
| Create The Application
|--------------------------------------------------------------------------
|
| Here we will load the environment and create the application instance
| that serves as the central piece of this framework. We'll use this
| application as an "IoC" container and router for this framework.
|
*/
$app = new Laravel\Lumen\Application(
realpath(__DIR__.'/../')
);
$app->withFacades();
$app->withEloquent();
/*
|--------------------------------------------------------------------------
| Register Container Bindings
|--------------------------------------------------------------------------
|
| Now we will register a few bindings in the service container. We will
| register the exception handler and the console kernel. You may add
| your own bindings here if you like or you can make another file.
|
*/
$app->singleton(
Illuminate\Contracts\Debug\ExceptionHandler::class,
App\Exceptions\Handler::class
);
$app->singleton(
Illuminate\Contracts\Console\Kernel::class,
App\Console\Kernel::class
);
/*
|--------------------------------------------------------------------------
| Register Middleware
|--------------------------------------------------------------------------
|
| Next, we will register the middleware with the application. These can
| be global middleware that run before and after each request into a
| route or middleware that'll be assigned to some specific routes.
|
*/
/*$app->middleware([App\Http\Middleware\Meta::class]);
$app->middleware([App\Http\Middleware\Throttle::class]);*/
// $app->routeMiddleware([
// 'auth' => App\Http\Middleware\Authenticate::class,
// ]);
$app->routeMiddleware([
'meta' => App\Http\Middleware\Meta::class,
'throttle' => App\Http\Middleware\Throttle::class
]);
/*
|--------------------------------------------------------------------------
| Register Service Providers
|--------------------------------------------------------------------------
|
| Here we will register all of the application's service providers which
| are used to bind services into the container. Service providers are
| totally optional, so you are not required to uncomment this line.
|
*/
$app->register(Bugsnag\BugsnagLaravel\BugsnagServiceProvider::class);
$app->register(Illuminate\Redis\RedisServiceProvider::class);
// $app->register(App\Providers\AppServiceProvider::class);
// $app->register(App\Providers\AuthServiceProvider::class);
// $app->register(App\Providers\EventServiceProvider::class);
/*
|--------------------------------------------------------------------------
| Load The Application Routes
|--------------------------------------------------------------------------
|
| Next we will include the routes file so that they can all be added to
| the application. This will provide all of the URLs the application
| can respond to, as well as the controllers that may handle them.
|
*/
$app->router->group([
'namespace' => 'App\Http\Controllers',
], function ($router) {
require __DIR__.'/../routes/web.php';
});
return $app;

44
composer.json Executable file
View File

@ -0,0 +1,44 @@
{
"name": "laravel/lumen",
"description": "The Laravel Lumen Framework.",
"keywords": ["framework", "laravel", "lumen"],
"license": "MIT",
"type": "project",
"require": {
"php": ">=7.0",
"laravel/lumen-framework": "5.5.*",
"vlucas/phpdotenv": "~2.2",
"jikan-me/jikan": "dev-master",
"bugsnag/bugsnag-laravel": "^2.0",
"danielmewes/php-rql": "dev-master",
"illuminate/redis": "^5.5",
"predis/predis": "^1.1",
"voku/anti-xss": "^4.0"
},
"require-dev": {
"fzaninotto/faker": "~1.4",
"phpunit/phpunit": "~6.0",
"mockery/mockery": "~0.9"
},
"autoload": {
"psr-4": {
"App\\": "app/"
}
},
"autoload-dev": {
"classmap": [
"tests/",
"database/"
]
},
"scripts": {
"post-root-package-install": [
"php -r \"copy('.env.example', '.env');\""
]
},
"minimum-stability": "dev",
"prefer-stable": true,
"config": {
"optimize-autoloader": true
}
}

4941
composer.lock generated Executable file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,19 @@
<?php
/*
|--------------------------------------------------------------------------
| Model Factories
|--------------------------------------------------------------------------
|
| Here you may define all of your model factories. Model factories give
| you a convenient way to create models for testing and seeding your
| database. Just tell the factory how a default model should look.
|
*/
$factory->define(App\User::class, function (Faker\Generator $faker) {
return [
'name' => $faker->name,
'email' => $faker->email,
];
});

0
database/migrations/.gitkeep Executable file
View File

View File

@ -0,0 +1,16 @@
<?php
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
// $this->call('UsersTableSeeder');
}
}

27
phpunit.xml Executable file
View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
bootstrap="bootstrap/app.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false">
<testsuites>
<testsuite name="Application Test Suite">
<directory suffix="Test.php">./tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./app</directory>
</whitelist>
</filter>
<php>
<env name="APP_ENV" value="testing"/>
<env name="CACHE_DRIVER" value="array"/>
<env name="QUEUE_DRIVER" value="sync"/>
</php>
</phpunit>

27
public/.htaccess Executable file
View File

@ -0,0 +1,27 @@
<IfModule mod_rewrite.c>
<IfModule mod_negotiation.c>
Options -MultiViews
</IfModule>
RewriteEngine On
# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [L,R=301]
# Handle Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
# Handle Authorization Header
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
</IfModule>
# BEGIN GZIP
<ifmodule mod_deflate.c>
AddOutputFilterByType DEFLATE text/text text/json text/html text/plain text/xml text/css application/x-javascript application/javascript
</ifmodule>
# END GZIP

29
public/index.php Executable file
View File

@ -0,0 +1,29 @@
<?php
/*
|--------------------------------------------------------------------------
| Create The Application
|--------------------------------------------------------------------------
|
| First we need to get an application instance. This creates an instance
| of the application / container and bootstraps the application so it
| is ready to receive HTTP / Console requests from the environment.
|
*/
$app = require __DIR__.'/../bootstrap/app.php';
/*
|--------------------------------------------------------------------------
| Run The Application
|--------------------------------------------------------------------------
|
| Once we have the application, we can handle the incoming request
| through the kernel, and send the associated response back to
| the client's browser allowing them to enjoy the creative
| and wonderful application we have prepared for them.
|
*/
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: *");
$app->run();

0
resources/views/.gitkeep Executable file
View File

73
routes/web.php Executable file
View File

@ -0,0 +1,73 @@
<?php
/*
|--------------------------------------------------------------------------
| Application Routes
|--------------------------------------------------------------------------
|
| Here is where you can register all of the routes for an application.
| It is a breeze. Simply tell Lumen the URIs it should respond to
| and give it the Closure to call when that URI is requested.
|
*/
$router->get('/', function () use ($router) {
return response()->json([
'Author' => '@irfanDahir',
'Contact' => 'contact@jikan.moe',
'JikanREST' => REST_VERSION,
'JikanPHP' => SOURCE_VERSION,
'Home' => 'https://jikan.moe/',
'Docs' => 'https://jikan.docs.apiary.io',
'GitHub' => 'https://github.com/jikan-me/jikan',
'PRODUCTION_API_URL' => 'https://api.jikan.moe/',
'RATE_LIMIT' => RATE_LIMIT,
'CACHED_REQUESTS' => app('redis')->dbSize(),
]);
});
$router->get('meta/{request:[A-Za-z]+}[/{type:[A-Za-z]+}[/{period:[A-Za-z]+}[/{page:[0-9]+}]]]', [
'uses' => 'MetaController@request'
]);
$router->group(['middleware' => ['meta', 'throttle']], function() use ($router) {
$router->get('anime[/{id:[0-9]+}[/{extend:[A-Za-z_]+}[/{extendArgs}]]]', [
'uses' => 'AnimeController@request'
]);
$router->get('manga[/{id:[0-9]+}[/{extend:[A-Za-z]+}]]', [
'uses' => 'MangaController@request'
]);
$router->get('person[/{id:[0-9]+}[/{extend:[A-Za-z]+}]]', [
'uses' => 'PersonController@request'
]);
$router->get('character[/{id:[0-9]+}[/{extend:[A-Za-z]+}]]', [
'uses' => 'CharacterController@request'
]);
$router->get('search[/{type}/{query}[/{page:[0-9]+}]]', [
'uses' => 'SearchController@request'
]);
$router->get('season[/{year:[0-9]{4}}/{season:[A-Za-z]+}]', [
'uses' => 'SeasonController@request'
]);
$router->get('schedule[/{day:[A-Za-z]+}]', [
'uses' => 'ScheduleController@request'
]);
$router->get('top/{type:[A-Za-z]+}[/{page:[0-9]+}[/{subtype:[A-Za-z]+}]]', [
'uses' => 'TopController@request'
]);
});

2
storage/app/.gitignore vendored Executable file
View File

@ -0,0 +1,2 @@
*
!.gitignore

2
storage/framework/cache/.gitignore vendored Executable file
View File

@ -0,0 +1,2 @@
*
!.gitignore

2
storage/framework/views/.gitignore vendored Executable file
View File

@ -0,0 +1,2 @@
*
!.gitignore

2
storage/logs/.gitignore vendored Executable file
View File

@ -0,0 +1,2 @@
*
!.gitignore

21
tests/ExampleTest.php Executable file
View File

@ -0,0 +1,21 @@
<?php
use Laravel\Lumen\Testing\DatabaseMigrations;
use Laravel\Lumen\Testing\DatabaseTransactions;
class ExampleTest extends TestCase
{
/**
* A basic test example.
*
* @return void
*/
public function testExample()
{
$this->get('/');
$this->assertEquals(
$this->app->version(), $this->response->getContent()
);
}
}

14
tests/TestCase.php Executable file
View File

@ -0,0 +1,14 @@
<?php
abstract class TestCase extends Laravel\Lumen\Testing\TestCase
{
/**
* Creates the application.
*
* @return \Laravel\Lumen\Application
*/
public function createApplication()
{
return require __DIR__.'/../bootstrap/app.php';
}
}