Passed
Push — master ( 1a3428...ce640e )
by Darko
07:39
created

ApiV2Controller::apiSearch()   B

Complexity

Conditions 8
Paths 33

Size

Total Lines 59
Code Lines 47

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 47
dl 0
loc 59
rs 7.9119
c 0
b 0
f 0
cc 8
nc 33
nop 1

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace App\Http\Controllers\Api;
4
5
use App\Events\UserAccessedApi;
6
use App\Http\Controllers\BasePageController;
7
use App\Models\Category;
8
use App\Models\Release;
9
use App\Models\Settings;
10
use App\Models\User;
11
use App\Models\UserDownload;
12
use App\Models\UserRequest;
13
use App\Transformers\ApiTransformer;
14
use App\Transformers\CategoryTransformer;
15
use App\Transformers\DetailsTransformer;
16
use Blacklight\Releases;
17
use Illuminate\Http\JsonResponse;
18
use Illuminate\Http\RedirectResponse;
19
use Illuminate\Http\Request;
20
use Illuminate\Support\Carbon;
21
use Illuminate\Support\Facades\DB;
22
23
class ApiV2Controller extends BasePageController
24
{
25
    private ApiController $api;
26
27
    public function __construct()
28
    {
29
        $this->api = new ApiController;
30
    }
31
32
    public function capabilities(): JsonResponse
33
    {
34
        $category = Category::getForApi();
35
36
        $capabilities = [
37
            'server' => [
38
                'title' => config('app.name'),
39
                'strapline' => Settings::settingValue('strapline'),
40
                'email' => config('mail.from.address'),
41
                'url' => url('/'),
42
            ],
43
            'limits' => [
44
                'max' => 100,
45
                'default' => 100,
46
            ],
47
            'registration' => [
48
                'available' => 'no',
49
                'open' => (int) Settings::settingValue('registerstatus') === 0 ? 'yes' : 'no',
50
            ],
51
            'searching' => [
52
                'search' => ['available' => 'yes', 'supportedParams' => 'id'],
53
                'tv-search' => ['available' => 'yes', 'supportedParams' => 'id,vid,tvdbid,traktid,rid,tvmazeid,imdbid,tmdbid,season,ep'],
54
                'movie-search' => ['available' => 'yes', 'supportedParams' => 'id, imdbid, tmdbid, traktid'],
55
                'audio-search' => ['available' => 'no',  'supportedParams' => ''],
56
            ],
57
            'categories' => fractal($category, new CategoryTransformer),
58
        ];
59
60
        return response()->json($capabilities);
61
    }
62
63
    /**
64
     * @throws \Throwable
65
     */
66
    public function movie(Request $request): JsonResponse
67
    {
68
        // Validate API token and get user in one query
69
        if ($request->missing('api_token') || $request->isNotFilled('api_token')) {
70
            return response()->json(['error' => 'Missing parameter (apikey)'], 403);
71
        }
72
73
        $user = User::query()
74
            ->where('api_token', $request->input('api_token'))
75
            ->with('role') // Eager load role to avoid N+1
76
            ->first();
77
78
        if (! $user) {
79
            return response()->json(['error' => 'Invalid API key'], 403);
80
        }
81
82
        // Process request asynchronously where possible
83
        UserRequest::addApiRequest($request->input('api_token'), $request->getRequestUri());
84
        event(new UserAccessedApi($user));
85
86
        // Get request parameters efficiently
87
        $params = [
88
            'imdbId' => $request->input('imdbid', -1),
89
            'tmdbId' => $request->input('tmdbid', -1),
90
            'traktId' => $request->input('traktid', -1),
91
            'minSize' => max(0, (int) $request->input('minsize', 0)),
92
            'searchName' => $request->input('id', ''),
93
        ];
94
95
        // Perform search
96
        $relData = (new Releases)->moviesSearch(
97
            $params['imdbId'],
98
            $params['tmdbId'],
99
            $params['traktId'],
100
            $this->api->offset($request),
101
            $this->api->limit($request),
102
            $params['searchName'],
103
            $this->api->categoryID($request),
104
            $this->api->maxAge($request),
105
            $params['minSize'],
106
            User::getCategoryExclusionForApi($request)
107
        );
108
109
        // Get both timestamps in a single query
110
        $timestamps = DB::selectOne('
111
            SELECT
112
                (SELECT MIN(timestamp) FROM user_requests WHERE users_id = ?) as api_time,
113
                (SELECT MIN(timestamp) FROM user_downloads WHERE users_id = ?) as grab_time
114
        ', [$user->id, $user->id]);
115
116
        // Build response
117
        $response = [
118
            'Total' => $relData[0]->_totalrows ?? 0,
119
            'apiCurrent' => UserRequest::getApiRequests($user->id),
120
            'apiMax' => $user->role->apirequests,
0 ignored issues
show
Bug introduced by
The property apirequests does not seem to exist on Spatie\Permission\Models\Role.
Loading history...
121
            'grabCurrent' => UserDownload::getDownloadRequests($user->id),
122
            'grabMax' => $user->role->downloadrequests,
0 ignored issues
show
Bug introduced by
The property downloadrequests does not seem to exist on Spatie\Permission\Models\Role.
Loading history...
123
            'apiOldestTime' => $timestamps->api_time ? Carbon::parse($timestamps->api_time)->toRfc2822String() : '',
124
            'grabOldestTime' => $timestamps->grab_time ? Carbon::parse($timestamps->grab_time)->toRfc2822String() : '',
125
            'Results' => fractal($relData, new ApiTransformer($user)),
126
        ];
127
128
        return response()->json($response);
129
    }
130
131
    /**
132
     * @throws \Exception
133
     * @throws \Throwable
134
     */
135
    public function apiSearch(Request $request): JsonResponse
136
    {
137
        if ($request->missing('api_token') || $request->isNotFilled('api_token')) {
138
            return response()->json(['error' => 'Missing parameter (api_token)'], 403);
139
        }
140
        $releases = new Releases;
141
        $user = User::query()->where('api_token', $request->input('api_token'))->first();
142
        $offset = $this->api->offset($request);
143
        $catExclusions = User::getCategoryExclusionForApi($request);
144
        $minSize = $request->has('minsize') && $request->input('minsize') > 0 ? $request->input('minsize') : 0;
145
        $maxAge = $this->api->maxAge($request);
146
        $groupName = $this->api->group($request);
147
        UserRequest::addApiRequest($request->input('api_token'), $request->getRequestUri());
148
        event(new UserAccessedApi($user));
149
        $categoryID = $this->api->categoryID($request);
150
        $limit = $this->api->limit($request);
151
152
        if ($request->has('id')) {
153
            $relData = $releases->apiSearch(
154
                $request->input('id'),
155
                $groupName,
156
                $offset,
157
                $limit,
158
                $maxAge,
0 ignored issues
show
Bug introduced by
It seems like $maxAge can also be of type Illuminate\Http\Response; however, parameter $maxAge of Blacklight\Releases::apiSearch() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

158
                /** @scrutinizer ignore-type */ $maxAge,
Loading history...
159
                $catExclusions,
160
                $categoryID,
161
                $minSize
162
            );
163
        } else {
164
            $relData = $releases->getBrowseRange(
165
                1,
166
                $categoryID,
167
                $offset,
168
                $limit,
169
                '',
170
                $maxAge,
0 ignored issues
show
Bug introduced by
It seems like $maxAge can also be of type Illuminate\Http\Response; however, parameter $maxAge of Blacklight\Releases::getBrowseRange() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

170
                /** @scrutinizer ignore-type */ $maxAge,
Loading history...
171
                $catExclusions,
172
                $groupName,
173
                $minSize
174
            );
175
        }
176
177
        $time = UserRequest::whereUsersId($user->id)->min('timestamp');
178
        $apiOldestTime = $time !== null ? Carbon::createFromTimeString($time)->toRfc2822String() : '';
179
        $grabTime = UserDownload::whereUsersId($user->id)->min('timestamp');
180
        $oldestGrabTime = $grabTime !== null ? Carbon::createFromTimeString($grabTime)->toRfc2822String() : '';
181
182
        $response = [
183
            'Total' => $relData[0]->_totalrows ?? 0,
184
            'apiCurrent' => UserRequest::getApiRequests($user->id),
185
            'apiMax' => $user->role->apirequests,
0 ignored issues
show
Bug introduced by
The property apirequests does not seem to exist on Spatie\Permission\Models\Role.
Loading history...
186
            'grabCurrent' => UserDownload::getDownloadRequests($user->id),
187
            'grabMax' => $user->role->downloadrequests,
0 ignored issues
show
Bug introduced by
The property downloadrequests does not seem to exist on Spatie\Permission\Models\Role.
Loading history...
188
            'apiOldestTime' => $apiOldestTime,
189
            'grabOldestTime' => $oldestGrabTime,
190
            'Results' => fractal($relData, new ApiTransformer($user)),
191
        ];
192
193
        return response()->json($response);
194
    }
195
196
    /**
197
     * @throws \Exception
198
     * @throws \Throwable
199
     */
200
    public function tv(Request $request): JsonResponse
201
    {
202
        if ($request->missing('api_token') || $request->isNotFilled('api_token')) {
203
            return response()->json(['error' => 'Missing parameter (api_token)'], 403);
204
        }
205
        $releases = new Releases;
206
        $user = User::query()->where('api_token', $request->input('api_token'))->first();
207
        if ($user === null) {
208
            return response()->json(['error' => 'Invalid API Token'], 403);
209
        }
210
        $catExclusions = User::getCategoryExclusionForApi($request);
211
        $minSize = $request->has('minsize') && $request->input('minsize') > 0 ? $request->input('minsize') : 0;
212
        $this->api->verifyEmptyParameter($request, 'id');
213
        $this->api->verifyEmptyParameter($request, 'vid');
214
        $this->api->verifyEmptyParameter($request, 'tvdbid');
215
        $this->api->verifyEmptyParameter($request, 'traktid');
216
        $this->api->verifyEmptyParameter($request, 'rid');
217
        $this->api->verifyEmptyParameter($request, 'tvmazeid');
218
        $this->api->verifyEmptyParameter($request, 'imdbid');
219
        $this->api->verifyEmptyParameter($request, 'tmdbid');
220
        $this->api->verifyEmptyParameter($request, 'season');
221
        $this->api->verifyEmptyParameter($request, 'ep');
222
        $maxAge = $this->api->maxAge($request);
223
        UserRequest::addApiRequest($request->input('api_token'), $request->getRequestUri());
224
        event(new UserAccessedApi($user));
225
226
        $siteIdArr = [
227
            'id' => $request->input('vid') ?? null,
228
            'tvdb' => $request->input('tvdbid') ?? null,
229
            'trakt' => $request->input('traktid') ?? null,
230
            'tvrage' => $request->input('rid') ?? null,
231
            'tvmaze' => $request->input('tvmazeid') ?? null,
232
            'imdb' => $request->input('imdbid') ?? null,
233
            'tmdb' => $request->input('tmdbid') ?? null,
234
        ];
235
236
        // Process season only queries or Season and Episode/Airdate queries
237
238
        $series = $request->input('season') ?? '';
239
        $episode = $request->input('ep') ?? '';
240
241
        if (preg_match('#^(19|20)\d{2}$#', $series, $year) && str_contains($episode, '/')) {
242
            $airDate = str_replace('/', '-', $year[0].'-'.$episode);
243
        }
244
245
        $relData = $releases->apiTvSearch(
246
            $siteIdArr,
247
            $series,
248
            $episode,
249
            $airDate ?? '',
250
            $this->api->offset($request),
251
            $this->api->limit($request),
252
            $request->input('id') ?? '',
253
            $this->api->categoryID($request),
254
            $maxAge,
0 ignored issues
show
Bug introduced by
It seems like $maxAge can also be of type Illuminate\Http\Response; however, parameter $maxAge of Blacklight\Releases::apiTvSearch() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

254
            /** @scrutinizer ignore-type */ $maxAge,
Loading history...
255
            $minSize,
256
            $catExclusions
257
        );
258
259
        $time = UserRequest::whereUsersId($user->id)->min('timestamp');
260
        $apiOldestTime = $time !== null ? Carbon::createFromTimeString($time)->toRfc2822String() : '';
261
        $grabTime = UserDownload::whereUsersId($user->id)->min('timestamp');
262
        $oldestGrabTime = $grabTime !== null ? Carbon::createFromTimeString($grabTime)->toRfc2822String() : '';
263
264
        $response = [
265
            'Total' => $relData[0]->_totalrows ?? 0,
266
            'apiCurrent' => UserRequest::getApiRequests($user->id),
267
            'apiMax' => $user->role->apirequests,
0 ignored issues
show
Bug introduced by
The property apirequests does not seem to exist on Spatie\Permission\Models\Role.
Loading history...
268
            'grabCurrent' => UserDownload::getDownloadRequests($user->id),
269
            'grabMax' => $user->role->downloadrequests,
0 ignored issues
show
Bug introduced by
The property downloadrequests does not seem to exist on Spatie\Permission\Models\Role.
Loading history...
270
            'apiOldestTime' => $apiOldestTime,
271
            'grabOldestTime' => $oldestGrabTime,
272
            'Results' => fractal($relData, new ApiTransformer($user)),
273
        ];
274
275
        return response()->json($response);
276
    }
277
278
    public function getNzb(Request $request): \Illuminate\Foundation\Application|JsonResponse|\Illuminate\Routing\Redirector|RedirectResponse|\Illuminate\Contracts\Foundation\Application
279
    {
280
        if ($request->missing('api_token') || $request->isNotFilled('api_token')) {
281
            return response()->json(['error' => 'Missing parameter (api_token)'], 403);
282
        }
283
        $user = User::query()->where('api_token', $request->input('api_token'))->first();
284
        if ($user === null) {
285
            return response()->json(['error' => 'Invalid API Token'], 403);
286
        }
287
        event(new UserAccessedApi($user));
288
        UserRequest::addApiRequest($request->input('api_token'), $request->getRequestUri());
289
        $relData = Release::checkGuidForApi($request->input('id'));
290
        if ($relData) {
291
            return redirect('/getnzb?r='.$request->input('api_token').'&id='.$request->input('id').(($request->has('del') && $request->input('del') === '1') ? '&del=1' : ''));
292
        }
293
294
        return response()->json(['data' => 'No such item (the guid you provided has no release in our database)'], 404);
295
    }
296
297
    public function details(Request $request): JsonResponse
298
    {
299
        if ($request->missing('api_token') || $request->isNotFilled('api_token')) {
300
            return response()->json(['error' => 'Missing parameter (api_token)'], 403);
301
        }
302
        if ($request->missing('id')) {
303
            return response()->json(['error' => 'Missing parameter (guid is required for single release details)'], 400);
304
        }
305
306
        UserRequest::addApiRequest($request->input('api_token'), $request->getRequestUri());
307
        $user = User::query()->where('api_token', $request->input('api_token'))->first();
308
        if ($user === null) {
309
            return response()->json(['error' => 'Invalid API Token'], 403);
310
        }
311
        event(new UserAccessedApi($user));
312
        $relData = Release::getByGuid($request->input('id'));
313
314
        $relData = fractal($relData, new DetailsTransformer($user));
315
316
        return response()->json($relData);
317
    }
318
}
319