Skip to content
This repository was archived by the owner on Jan 1, 2021. It is now read-only.

Commit 6ed4371

Browse files
committed
Merge branch 'develop'
2 parents a57d7b5 + 1b68a10 commit 6ed4371

8 files changed

Lines changed: 134 additions & 30 deletions

File tree

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
/**
3+
* Created by PhpStorm.
4+
* User: leonardogalli
5+
* Date: 13.08.17
6+
* Time: 17:42
7+
*/
8+
9+
namespace App\Exceptions;
10+
use Carbon\Carbon;
11+
use Symfony\Component\HttpKernel\Exception\HttpException;
12+
13+
class TooManyRequestsHttpException extends HttpException
14+
{
15+
/**
16+
* Constructor.
17+
*
18+
* @param int|string $retryAfter The number of seconds or HTTP-date after which the request may be retried
19+
* @param string $message The internal exception message
20+
* @param \Exception $previous The previous exception
21+
* @param int $code The internal exception code
22+
*/
23+
public function __construct($retryAfter = null, $maxAttempts = null, \Exception $previous = null, $code = 0)
24+
{
25+
$headers = array();
26+
$message = "You have sent too many requests.";
27+
28+
if ($retryAfter) {
29+
$headers = array('Retry-After' => $retryAfter);
30+
$headers['X-RateLimit-Reset'] = Carbon::now()->getTimestamp() + $retryAfter;
31+
$message .= " Please retry after $retryAfter seconds.";
32+
}
33+
34+
if ($maxAttempts) {
35+
$headers['X-RateLimit-Limit'] = $maxAttempts;
36+
$headers['X-RateLimit-Remaining'] = 0;
37+
}
38+
39+
parent::__construct(429, $message, $previous, $headers, $code);
40+
}
41+
}

app/Http/Controllers/API/DiscoverController.php

Lines changed: 46 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use App\Http\Controllers\Controller;
1111
use Illuminate\Support\Facades\Cache;
1212
use Illuminate\Support\Facades\DB;
13+
use Illuminate\Support\Facades\Input;
1314
use Symfony\Component\HttpFoundation\Response;
1415
use Symfony\Component\HttpFoundation\JsonResponse;
1516
use Symfony\Component\HttpFoundation\Request;
@@ -30,13 +31,15 @@ public function upcoming() {
3031
$query->whereIn("type", array(4,5,6))->whereBetween("release_date", array(Carbon::now()->subWeek(), Carbon::now()->addWeeks(3)))->orderBy("release_date", "ASC");
3132
})->where("adult", "=", "0")->orderBy("popularity", "DESC")->get()->toArray();
3233
});
34+
$resp = $this->filterMovies($resp);
3335
return response()->json($resp);
3436
}
3537

3638
public function popular() {
3739
$movies = Cache::remember("discovery.popular", new Carbon('tomorrow midnight'), function(){
3840
return array_values(StevenLuMovie::all()->sortByDesc("TMDBMovie.popularity")->toArray());
3941
});
42+
$movies = $this->filterMovies($movies);
4043
return response()->json($movies);
4144
}
4245

@@ -48,36 +51,56 @@ public function popular() {
4851
public function recommendations(Request $request) {
4952
$ids = $request->input("tmdbIds");
5053
$ignoredIds = $request->input("ignoredIds");
51-
if ($ignoredIds != "")
52-
{
53-
$ignoredIds = ",".$ignoredIds;
54-
}
54+
$movies = Cache::remember("discovery.recommendations.$ids.$ignoredIds", new Carbon("tomorrow midnight"), function() use($ignoredIds, $ids){
55+
if ($ignoredIds != "")
56+
{
57+
$ignoredIds = ",".$ignoredIds;
58+
}
5559

56-
if ($ids == "" || $ids == null)
57-
{
58-
abort(422, "Please add some movies before using our recommendation engine :)");
59-
}
60-
$movies_db = DB::select("SELECT mo.id, mo.popularity, mo.imdb_id, mo.title, mo.overview, mo.vote_average, mo.vote_count, mo.tagline, mo.poster_path, mo.release_date, mo.release_year, mo.trailer_key, mo.trailer_site, mo.backdrop_path, mo.homepage, mo.runtime, mo.countO, mo.genres, mo.runtime, mo.adult FROM ( SELECT m.*, r.recommended_id, r.tmdbid, r.id as rid, count(m.id) as countO FROM movies m, recommendations r WHERE m.id = r.recommended_id AND r.tmdbid in ($ids) AND r.recommended_id not in ($ids$ignoredIds) AND m.adult = 0 GROUP BY m.id ) as mo;");
61-
$movies = json_decode(json_encode($movies_db), true);
60+
if ($ids == "" || $ids == null)
61+
{
62+
abort(422, "Please add some movies before using our recommendation engine :)");
63+
}
64+
$movies_db = DB::select("SELECT mo.id, mo.popularity, mo.imdb_id, mo.title, mo.overview, mo.vote_average, mo.vote_count, mo.tagline, mo.poster_path, mo.release_date, mo.release_year, mo.trailer_key, mo.trailer_site, mo.backdrop_path, mo.homepage, mo.runtime, mo.countO, mo.genres, mo.runtime, mo.adult FROM ( SELECT m.*, r.recommended_id, r.tmdbid, r.id as rid, count(m.id) as countO FROM movies m, recommendations r WHERE m.id = r.recommended_id AND r.tmdbid in ($ids) AND r.recommended_id not in ($ids$ignoredIds) AND m.adult = 0 GROUP BY m.id ) as mo;");
65+
$movies = json_decode(json_encode($movies_db), true);
6266

63-
$this->count_max = maximum($movies, "countO");
64-
$this->pop_max = maximum($movies, "popularity");
65-
$this->vote_max = maximum($movies, "vote_average");
67+
$this->count_max = maximum($movies, "countO");
68+
$this->pop_max = maximum($movies, "popularity");
69+
$this->vote_max = maximum($movies, "vote_average");
6670

67-
usort($movies, array($this, "compare_score"));
71+
usort($movies, array($this, "compare_score"));
6872

69-
$movies = array_slice($movies, 0, 30);
70-
$resp = [];
73+
$movies = array_slice($movies, 0, 30);
74+
$resp = [];
7175

72-
foreach ($movies as $movie) {
73-
unset($movie["countO"]);
74-
$movie["genres"] = explode(",", $movie["genres"]);
75-
$movie["adult"] = $movie["adult"] == 1;
76-
$resp[] = $movie;
77-
}
76+
foreach ($movies as $movie) {
77+
unset($movie["countO"]);
78+
$movie["genres"] = explode(",", $movie["genres"]);
79+
$movie["adult"] = $movie["adult"] == 1;
80+
$resp[] = $movie;
81+
}
7882

83+
return $resp;
84+
});
7985

80-
return response()->json($resp);
86+
$movies = $this->filterMovies($movies);
87+
88+
return response()->json(array_values($movies));
89+
}
90+
91+
function filterMovies($movies)
92+
{
93+
$yearLower = Input::get('yearLower', 1800);
94+
$yearUpper = Input::get('yearUpper', 2300);
95+
$genreIds = Input::get('genreIds', "");
96+
if (!(is_array($genreIds) || $genreIds === null))
97+
{
98+
$genreIds = explode(",", $genreIds);
99+
}
100+
return array_filter($movies, function($value) use ($yearLower, $yearUpper, $genreIds) {
101+
//dd($genreIds);
102+
return $value["release_year"] >= $yearLower && $value["release_year"] <= $yearUpper && ($genreIds != array("") ? count(array_intersect($value["genres"], $genreIds)) > 0 : true);
103+
});
81104
}
82105

83106
function score ($elem)

app/Http/Controllers/API/MappingsController.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,16 @@ public function find(MappingFindRequest $request)
6060
}
6161

6262
$type = $request->query("type");
63+
$language = $request->query("language", "en");
6364

6465
$titles = [];
6566
$years = [];
6667

6768
if ($type == "title" || $type == "all" || $type == null)
6869
{
69-
$titles = Mapping::where("tmdbid", "=", $tmdbid)->where("info_type", "=", "title")->get()->toArray();
70+
$titles = Mapping::where("tmdbid", "=", $tmdbid)->where("info_type", "=", "title")->whereHas("title_info", function($query) use($language){
71+
$query->where("language", "=", $language);
72+
})->get()->toArray();
7073
}
7174

7275
if ($type == "year" || $type == "all" || $type == null)
@@ -100,11 +103,12 @@ public function add(MappingAddRequest $request) {
100103
if ($type == "title")
101104
{
102105
$aka_title = $request->get("aka_title");
106+
$title_language = $request->get("language", "en");
103107
$aka_clean_title = Helper::clean_title($aka_title);
104108
$existing = Mapping::whereHas("title_info", function($query) use($aka_clean_title){
105109
$query->where("aka_clean_title", "=", $aka_clean_title);
106110
})->first();
107-
$info = new TitleInfo(["aka_title" => $aka_title, "aka_clean_title" => $aka_clean_title]);
111+
$info = new TitleInfo(["aka_title" => $aka_title, "aka_clean_title" => $aka_clean_title, "language" => $title_language]);
108112
}
109113
else
110114
{

app/Http/Kernel.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class Kernel extends HttpKernel
3737
],
3838

3939
'api' => [
40-
'throttle:60,1',
40+
'throttle:240,1',
4141
'bindings',
4242
\App\Http\Middleware\CheckDBMaintAPI::class,
4343
],
@@ -56,6 +56,6 @@ class Kernel extends HttpKernel
5656
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
5757
'can' => \Illuminate\Auth\Middleware\Authorize::class,
5858
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
59-
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
59+
'throttle' => \App\Http\Middleware\ThrottleRequestsException::class,
6060
];
6161
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
/**
3+
* Created by PhpStorm.
4+
* User: leonardogalli
5+
* Date: 13.08.17
6+
* Time: 17:34
7+
*/
8+
9+
namespace App\Http\Middleware;
10+
11+
use App\Exceptions\TooManyRequestsHttpException;
12+
use Illuminate\Routing\Middleware\ThrottleRequests;
13+
14+
class ThrottleRequestsException extends ThrottleRequests
15+
{
16+
/**
17+
* Create a 'too many attempts' response.
18+
*
19+
* @param string $key
20+
* @param int $maxAttempts
21+
* @return \Symfony\Component\HttpFoundation\Response
22+
*/
23+
protected function buildResponse($key, $maxAttempts)
24+
{
25+
$retryAfter = $this->limiter->availableIn($key);
26+
throw new TooManyRequestsHttpException($retryAfter, $maxAttempts);
27+
}
28+
}

app/Http/Requests/MappingRequests.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ public function rules()
3434
'type' => array(
3535
"required",
3636
Rule::in(['title', 'year']),
37+
),
38+
'language' => array(
39+
Rule::in(['en', 'fr', 'es', 'de', 'it', 'da', 'nl', 'ja', 'ru', 'pl', 'vi', 'sv', 'no', 'fi', 'tr', 'pt', 'nl', 'el', 'ko', 'hu'])
3740
)
3841
];
3942

@@ -64,7 +67,8 @@ public function messages()
6467
"aka_year.required" => "The alternative year is required with type 'year'.",
6568
"aka_year.regex" => "The alternative year has to be a valid movie year.",
6669
"aka_title.required" => "The alternative title is required with type 'title'",
67-
"aka_title.regex" => "The alternative title must be at least 3 letters long"
70+
"aka_title.regex" => "The alternative title must be at least 3 letters long",
71+
"language.in" => "The language must be a valid ISO639-1 code."
6872
];
6973
}
7074

@@ -98,6 +102,9 @@ public function rules()
98102
"sometimes",
99103
"required",
100104
Rule::in(['title', 'year', 'all']),
105+
),
106+
'language' => array(
107+
Rule::in(['en', 'fr', 'es', 'de', 'it', 'da', 'nl', 'ja', 'ru', 'pl', 'vi', 'sv', 'no', 'fi', 'tr', 'pt', 'nl', 'el', 'ko', 'hu'])
101108
)
102109
];
103110

@@ -116,6 +123,7 @@ public function messages()
116123
'tmdbid.regex' => 'The format of the tmdbid given is invalid!',
117124
"type.required" => "The type of mappings to return is required.",
118125
"type.in" => "The type of mapping has to be on of 'title', 'year' or 'all'.",
126+
"language.in" => "The language must be a valid ISO639-1 code."
119127
];
120128
}
121129

app/Mapping.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ class TitleInfo extends Model {
107107

108108
protected $connection = 'mappings_mysql';
109109

110-
protected $fillable = array('aka_title', "aka_clean_title");
110+
protected $fillable = array('aka_title', "aka_clean_title", "language");
111111

112112
/**
113113
* Indicates if the model should be timestamped.

config/exceptions.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@
103103
'Illuminate\Database\Eloquent\ModelNotFoundException' => 'warning',
104104
'Illuminate\Session\TokenMismatchException' => 'notice',
105105
'Symfony\Component\HttpKernel\Exception\NotFoundHttpException' => 'notice',
106-
'Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException' => 'error',
106+
'Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException' => 'warning',
107107
'Symfony\Component\HttpKernel\Exception\HttpExceptionInterface' => 'warning',
108108
'Symfony\Component\Debug\Exception\FatalErrorException' => 'critical',
109109
'Exception' => 'error',

0 commit comments

Comments
 (0)