add v4 User endpoint

This commit is contained in:
Irfan 2020-07-11 13:10:40 +05:00
parent 3a2a9b06ce
commit 359070af5e
10 changed files with 258 additions and 30 deletions

View File

@ -53,13 +53,14 @@ CACHE_DRIVER=array
CACHE_METHOD=queue
# Caching TTL (in seconds) on specific endpoints
CACHE_DEFAULT_EXPIRE=86400
CACHE_META_EXPIRE=300
CACHE_USER_EXPIRE=300
CACHE_404_EXPIRE=604800
CACHE_SEARCH_EXPIRE=432000
CACHE_PRODUCERS_EXPIRE=432000
CACHE_MAGAZINES_EXPIRE=432000
CACHE_DEFAULT_EXPIRE=86400 # 1 day
CACHE_META_EXPIRE=300 # 5 minutes
CACHE_USER_EXPIRE=300 # 5 minutes
CACHE_USERLIST_EXPIRE=3600 # 1 hour
CACHE_404_EXPIRE=604800 # 7 days
CACHE_SEARCH_EXPIRE=432000 # 5 days
CACHE_PRODUCERS_EXPIRE=432000 # 5 days
CACHE_MAGAZINES_EXPIRE=432000 # 5 days
# You can even add your own by
# including the endpoint's name

View File

@ -42,7 +42,6 @@ class Club extends Model
'_id', 'request_hash', 'expiresAt', 'image_url'
];
public function getImageAttribute()
{
$imageUrl = $this->attributes['image_url'];

View File

@ -2,6 +2,12 @@
namespace App\Http\Controllers\V4DB;
use App\Anime;
use App\Http\HttpHelper;
use App\Http\HttpResponse;
use App\Profile;
use App\User;
use Illuminate\Http\Request;
use Jikan\Request\User\RecentlyOnlineUsersRequest;
use Jikan\Request\User\UserAnimeListRequest;
use Jikan\Request\User\UserClubsRequest;
@ -11,13 +17,67 @@ use Jikan\Request\User\UserFriendsRequest;
use Jikan\Request\User\UserHistoryRequest;
use Jikan\Request\User\UserRecommendationsRequest;
use Jikan\Request\User\UserReviewsRequest;
use MongoDB\BSON\UTCDateTime;
class UserController extends Controller
{
public function profile(string $username)
public function profile(Request $request, string $username)
{
$user = $this->jikan->getUserProfile(new UserProfileRequest($username));
return response($this->serializer->serialize($user, 'json'));
$results = Profile::query()
->where('request_hash', $this->fingerprint)
->get();
if (
$results->isEmpty()
|| $this->isExpired($request, $results)
) {
$response = Profile::scrape($username);
if (HttpHelper::hasError($response)) {
return HttpResponse::notFound($request);
}
if ($results->isEmpty()) {
$meta = [
'createdAt' => new UTCDateTime(),
'modifiedAt' => new UTCDateTime(),
'request_hash' => $this->fingerprint
];
}
$meta['modifiedAt'] = new UTCDateTime();
$response = $meta + $response;
if ($results->isEmpty()) {
Profile::query()
->insert($response);
}
if ($this->isExpired($request, $results)) {
Profile::query()
->where('request_hash', $this->fingerprint)
->update($response);
}
$results = Profile::query()
->where('request_hash', $this->fingerprint)
->get();
}
if ($results->isEmpty()) {
return HttpResponse::notFound($request);
}
$response = (new \App\Http\Resources\V4\ProfileResource(
$results->first()
))->response();
return $this->prepareResponse(
$response,
$results,
$request
);
}
public function history(string $username, ?string $type = null)

View File

@ -0,0 +1,33 @@
<?php
namespace App\Http\Resources\V4;
use Illuminate\Http\Resources\Json\JsonResource;
class ProfileResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'mal_id' => $this->mal_id,
'username' => $this->username,
'url' => $this->url,
'images' => $this->images,
'last_online' => $this->last_online,
'gender' => $this->gender,
'birthday' => $this->birthday,
'location' => $this->location,
'joined' => $this->joined,
'anime_stats' => $this->anime_stats,
'manga_stats' => $this->manga_stats,
'favorites' => $this->favorites,
'about' => $this->about,
];
}
}

78
app/Profile.php Normal file
View File

@ -0,0 +1,78 @@
<?php
namespace App;
use App\Http\HttpHelper;
use Jenssegers\Mongodb\Eloquent\Model;
use Jikan\Helper\Media;
use Jikan\Helper\Parser;
use Jikan\Jikan;
use Jikan\Model\Common\YoutubeMeta;
use Jikan\Request\Anime\AnimeRequest;
use Jikan\Request\User\UserProfileRequest;
class Profile extends Model
{
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'mal_id', 'username', 'url', 'image_url', 'last_online', 'gender', 'birthday', 'location', 'joined', 'anime_stats', 'manga_stats', 'favorites', 'about'
];
/**
* The accessors to append to the model's array form.
*
* @var array
*/
protected $appends = ['images'];
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'users';
/**
* The attributes excluded from the model's JSON form.
*
* @var array
*/
protected $hidden = [
'_id', 'image_url'
];
public function setImagesAttribute($value)
{
$this->attributes['images'] = $this->getImagesAttribute();
}
public function getImagesAttribute()
{
$imageUrl = $this->attributes['image_url'];
return [
'jpg' => [
'image_url' => $imageUrl,
],
'webp' => [
'image_url' => str_replace('.jpg', '.webp', $imageUrl),
]
];
}
public static function scrape(string $username)
{
$data = app('JikanParser')->getUserProfile(new UserProfileRequest($username));
return json_decode(
app('SerializerV4')
->serialize($data, 'json'),
true
);
}
}

View File

@ -14,7 +14,7 @@
"flipbox/lumen-generator": "^6",
"illuminate/redis": "^7",
"jenssegers/mongodb": "^4.0",
"jikan-me/jikan": "v3.0.0-alpha.9",
"jikan-me/jikan": "v3.0.0-alpha.10",
"jms/serializer": "^1.13",
"laravel/lumen-framework": "^7.0",
"league/flysystem": "^1.0",

23
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"content-hash": "9d6fb513e40aa21d6baf7214d9ed9b79",
"content-hash": "1ed69715f37c5e76091e7f4b6d4edb89",
"packages": [
{
"name": "brick/math",
@ -2210,16 +2210,16 @@
},
{
"name": "jikan-me/jikan",
"version": "v3.0.0-alpha.9",
"version": "v3.0.0-alpha.10",
"source": {
"type": "git",
"url": "https://github.com/jikan-me/jikan.git",
"reference": "d9aba6d2d16c0ab387c08740d64db2ffef3fcb11"
"reference": "0d1a587ab092e729f277860347b9fd371177fd0d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/jikan-me/jikan/zipball/d9aba6d2d16c0ab387c08740d64db2ffef3fcb11",
"reference": "d9aba6d2d16c0ab387c08740d64db2ffef3fcb11",
"url": "https://api.github.com/repos/jikan-me/jikan/zipball/0d1a587ab092e729f277860347b9fd371177fd0d",
"reference": "0d1a587ab092e729f277860347b9fd371177fd0d",
"shasum": ""
},
"require": {
@ -2227,14 +2227,15 @@
"php": "^7.1"
},
"require-dev": {
"brianium/paratest": "1.*",
"brianium/paratest": "~4.0",
"doctrine/collections": "^1.5",
"friendsofphp/php-cs-fixer": "^2.16",
"jakub-onderka/php-parallel-lint": "^1.0",
"jikan-me/jikan-fixtures": "dev-master",
"php-vcr/php-vcr": "~1.3.2",
"php-vcr/phpunit-testlistener-vcr": "^3.0",
"phpro/grumphp": "^0.15.2",
"phpunit/phpunit": "^6.3",
"php-vcr/php-vcr": "~1.4",
"php-vcr/phpunit-testlistener-vcr": "~3.2",
"phpro/grumphp": "^0.19",
"phpunit/phpunit": "~9.0",
"squizlabs/php_codesniffer": "^3.3"
},
"type": "library",
@ -2256,7 +2257,7 @@
}
],
"description": "Jikan is an unofficial MyAnimeList API",
"time": "2020-07-10T15:19:00+00:00"
"time": "2020-07-11T07:32:17+00:00"
},
{
"name": "jms/metadata",

View File

@ -138,14 +138,32 @@ return [
'MagazineController@resource' => 'magazines_manga',
'UserController@recentlyOnline' => 'users_recently_online',
'UserController@profile' => 'users',
'UserController@history' => 'users_history',
'UserController@friends' => 'users_friends',
'UserController@profile' => [
'table_name' => 'users',
'ttl' => env('CACHE_DEFAULT_EXPIRE')
],
'UserController@history' => [
'table_name' => 'users_history',
'ttl' => env('CACHE_USER_EXPIRE')
],
'UserController@friends' => [
'table_name' => 'users_friends',
'ttl' => env('CACHE_USER_EXPIRE')
],
'UserController@recommendations' => [
'table_name' => 'users_recommendations',
'ttl' => env('CACHE_USER_EXPIRE')
],
'UserController@reviews' => [
'table_name' => 'users_reviews',
'ttl' => env('CACHE_USER_EXPIRE')
],
'UserController@clubs' => [
'table_name' => 'users_clubs',
'ttl' => env('CACHE_USER_EXPIRE')
],
'UserController@animelist' => 'users_animelist',
'UserController@mangalist' => 'users_mangalist',
'UserController@recommendations' => 'users_recommendations',
'UserController@reviews' => 'users_reviews',
'UserController@clubs' => 'users_clubs',
'GenreController@mainAnime' => [
'table_name' => 'common',

View File

@ -8,7 +8,7 @@ class CreateIndex extends Migration
{
const IGNORE = [
'anime', 'manga', 'people', 'characters', 'magazines', 'producers', 'clubs'
'anime', 'manga', 'people', 'characters', 'magazines', 'producers', 'clubs', 'users'
];
/**

View File

@ -0,0 +1,38 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateProfilesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->unique(['request_hash' => 1], 'request_hash');
$table->unique(['mal_id' => 1], 'mal_id');
$table->unique(['username' => 1], 'username');
$table->date('last_online')->index();
$table->index('gender');
$table->date('birthday')->index();
$table->index('location');
$table->date('joined')->index();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('users');
}
}