Completed
Push — dev ( 327b6b...3b3111 )
by Darko
09:05
created

User::getRange()   B

Complexity

Conditions 7
Paths 2

Size

Total Lines 33
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 0
Metric Value
cc 7
eloc 16
nc 2
nop 8
dl 0
loc 33
rs 8.8333
c 0
b 0
f 0
ccs 0
cts 8
cp 0
crap 56

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
namespace App\Models;
4
5
use Blacklight\ColorCLI;
6
use Illuminate\Http\Request;
7
use Illuminate\Support\Str;
8
use App\Jobs\SendInviteEmail;
9
use Illuminate\Support\Facades\DB;
10
use Spatie\Permission\Models\Role;
11
use Illuminate\Support\Facades\Hash;
12
use App\Jobs\SendAccountExpiredEmail;
13
use Spatie\Permission\Traits\HasRoles;
14
use Illuminate\Notifications\Notifiable;
15
use Illuminate\Support\Facades\Password;
16
use Illuminate\Support\Facades\Validator;
17
use Jrean\UserVerification\Traits\UserVerification;
18
use Illuminate\Foundation\Auth\User as Authenticatable;
19
20
/**
21
 * App\Models\User.
22
 *
23
 * @property int $id
24
 * @property string $username
25
 * @property string|null $firstname
26
 * @property string|null $lastname
27
 * @property string $email
28
 * @property string $password
29
 * @property int $user_roles_id FK to roles.id
30
 * @property string|null $host
31
 * @property int $grabs
32
 * @property string $rsstoken
33
 * @property \Carbon\Carbon|null $created_at
34
 * @property \Carbon\Carbon|null $updated_at
35
 * @property string|null $resetguid
36
 * @property string|null $lastlogin
37
 * @property string|null $apiaccess
38
 * @property int $invites
39
 * @property int|null $invitedby
40
 * @property int $movieview
41
 * @property int $xxxview
42
 * @property int $musicview
43
 * @property int $consoleview
44
 * @property int $bookview
45
 * @property int $gameview
46
 * @property string|null $saburl
47
 * @property string|null $sabapikey
48
 * @property bool|null $sabapikeytype
49
 * @property bool|null $sabpriority
50
 * @property bool $queuetype Type of queue, Sab or NZBGet
51
 * @property string|null $nzbgeturl
52
 * @property string|null $nzbgetusername
53
 * @property string|null $nzbgetpassword
54
 * @property string|null $nzbvortex_api_key
55
 * @property string|null $nzbvortex_server_url
56
 * @property string $userseed
57
 * @property string $notes
58
 * @property string|null $cp_url
59
 * @property string|null $cp_api
60
 * @property string|null $style
61
 * @property string|null $rolechangedate When does the role expire
62
 * @property string|null $remember_token
63
 * @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\ReleaseComment[] $comment
64
 * @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\UserDownload[] $download
65
 * @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\DnzbFailure[] $failedRelease
66
 * @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\Invitation[] $invitation
67
 * @property-read \Illuminate\Notifications\DatabaseNotificationCollection|\Illuminate\Notifications\DatabaseNotification[] $notifications
68
 * @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\UsersRelease[] $release
69
 * @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\UserRequest[] $request
70
 * @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\UserSerie[] $series
71
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereApiaccess($value)
72
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereBookview($value)
73
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereConsoleview($value)
74
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereCpApi($value)
75
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereCpUrl($value)
76
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereCreatedAt($value)
77
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereEmail($value)
78
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereFirstname($value)
79
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereGameview($value)
80
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereGrabs($value)
81
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereHost($value)
82
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereId($value)
83
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereInvitedby($value)
84
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereInvites($value)
85
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereLastlogin($value)
86
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereLastname($value)
87
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereMovieview($value)
88
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereMusicview($value)
89
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereNotes($value)
90
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereNzbgetpassword($value)
91
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereNzbgeturl($value)
92
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereNzbgetusername($value)
93
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereNzbvortexApiKey($value)
94
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereNzbvortexServerUrl($value)
95
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User wherePassword($value)
96
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereQueuetype($value)
97
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereRememberToken($value)
98
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereResetguid($value)
99
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereRolechangedate($value)
100
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereRsstoken($value)
101
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereSabapikey($value)
102
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereSabapikeytype($value)
103
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereSabpriority($value)
104
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereSaburl($value)
105
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereStyle($value)
106
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereUpdatedAt($value)
107
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereUserRolesId($value)
108
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereUsername($value)
109
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereUserseed($value)
110
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereXxxview($value)
111
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereVerified($value)
112
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereApiToken($value)
113
 * @mixin \Eloquent
114
 */
115
class User extends Authenticatable
116
{
117
    use Notifiable, UserVerification, HasRoles;
0 ignored issues
show
Bug introduced by
The trait Illuminate\Notifications\Notifiable requires the property $phone_number which is not provided by App\Models\User.
Loading history...
introduced by
The trait Spatie\Permission\Traits\HasRoles requires some properties which are not provided by App\Models\User: $name, $map, $permissions, $roles, $guard_name
Loading history...
introduced by
The trait Jrean\UserVerification\Traits\UserVerification requires some properties which are not provided by App\Models\User: $verified, $verification_token
Loading history...
118
119
    public const ERR_SIGNUP_BADUNAME = -1;
120
    public const ERR_SIGNUP_BADPASS = -2;
121
    public const ERR_SIGNUP_BADEMAIL = -3;
122
    public const ERR_SIGNUP_UNAMEINUSE = -4;
123
    public const ERR_SIGNUP_EMAILINUSE = -5;
124
    public const ERR_SIGNUP_BADINVITECODE = -6;
125
    public const ERR_SIGNUP_BADCAPTCHA = -7;
126
    public const SUCCESS = 1;
127
128
    public const ROLE_USER = 1;
129
    public const ROLE_ADMIN = 2;
130
    public const ROLE_DISABLED = 3;
131
    public const ROLE_MODERATOR = 4;
132
133
    /**
134
     * Users SELECT queue type.
135
     */
136
    public const QUEUE_NONE = 0;
137
    public const QUEUE_SABNZBD = 1;
138
    public const QUEUE_NZBGET = 2;
139
140
    /**
141
     * @var string
142
     */
143
    protected $table = 'users';
144
145
    /**
146
     * @var bool
147
     */
148
    protected $dateFormat = false;
149
150
    /**
151
     * @var array
152
     */
153
    protected $hidden = ['remember_token', 'password'];
154
155
    /**
156
     * @var array
157
     */
158
    protected $guarded = [];
159
160
    /**
161
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
162
     */
163
    public function role()
164
    {
165
        return $this->belongsTo(Role::class, 'roles_id');
166
    }
167
168
    /**
169
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
170
     */
171
    public function request()
172
    {
173
        return $this->hasMany(UserRequest::class, 'users_id');
174
    }
175
176
    /**
177
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
178
     */
179
    public function download()
180
    {
181
        return $this->hasMany(UserDownload::class, 'users_id');
182
    }
183
184
    /**
185
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
186
     */
187
    public function release()
188
    {
189
        return $this->hasMany(UsersRelease::class, 'users_id');
190
    }
191
192
    /**
193
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
194
     */
195
    public function series()
196
    {
197
        return $this->hasMany(UserSerie::class, 'users_id');
198
    }
199
200
    /**
201
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
202
     */
203
    public function invitation()
204
    {
205
        return $this->hasMany(Invitation::class, 'users_id');
206
    }
207
208
    /**
209
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
210
     */
211
    public function failedRelease()
212
    {
213
        return $this->hasMany(DnzbFailure::class, 'users_id');
214
    }
215
216
    /**
217
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
218
     */
219
    public function comment()
220
    {
221
        return $this->hasMany(ReleaseComment::class, 'users_id');
222
    }
223
224
    /**
225
     * @param $id
226
     * @throws \Exception
227
     */
228
    public static function deleteUser($id): void
229
    {
230
        self::whereId($id)->delete();
231
    }
232
233
    /**
234
     * @param string $role
235
     * @param string $username
236
     * @param string $host
237
     * @param string $email
238
     * @return int
239
     */
240
    public static function getCount($role = '', $username = '', $host = '', $email = ''): int
241
    {
242
        $res = self::query()->where('email', '<>', '[email protected]');
243
244
        if ($role !== '') {
245
            $res->where('roles_id', $role);
246
        }
247
248
        if ($username !== '') {
249
            $res->where('username', 'like', '%'.$username.'%');
250
        }
251
252
        if ($host !== '') {
253
            $res->where('host', 'like', '%'.$host.'%');
254
        }
255
256
        if ($email !== '') {
257
            $res->where('email', 'like', '%'.$email.'%');
258
        }
259
260
        return $res->count(['id']);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $res->count(array('id')) could return the type Illuminate\Database\Eloquent\Builder which is incompatible with the type-hinted return integer. Consider adding an additional type-check to rule them out.
Loading history...
261
    }
262
263
    /**
264
     * @param  int      $id
265
     * @param  string      $userName
266
     * @param  string      $email
267
     * @param  int     $grabs
268
     * @param  int     $role
269
     * @param  string    $notes
270
     * @param  int     $invites
271
     * @param  int     $movieview
272
     * @param  int    $musicview
273
     * @param  int   $gameview
274
     * @param  int    $xxxview
275
     * @param  int    $consoleview
276
     * @param  int    $bookview
277
     * @param string $queueType
278
     * @param string $nzbgetURL
279
     * @param string $nzbgetUsername
280
     * @param string $nzbgetPassword
281
     * @param string $saburl
282
     * @param string $sabapikey
283
     * @param string $sabpriority
284
     * @param string $sabapikeytype
285
     * @param bool   $nzbvortexServerUrl
286
     * @param bool   $nzbvortexApiKey
287
     * @param bool   $cp_url
288
     * @param bool   $cp_api
289
     * @param string $style
290
     *
291
     * @return int
292
     * @throws \Illuminate\Database\Eloquent\ModelNotFoundException
293
     */
294
    public static function updateUser($id, $userName, $email, $grabs, $role, $notes, $invites, $movieview, $musicview, $gameview, $xxxview, $consoleview, $bookview, $queueType = '', $nzbgetURL = '', $nzbgetUsername = '', $nzbgetPassword = '', $saburl = '', $sabapikey = '', $sabpriority = '', $sabapikeytype = '', $nzbvortexServerUrl = false, $nzbvortexApiKey = false, $cp_url = false, $cp_api = false, $style = 'None'): int
295
    {
296
        $userName = trim($userName);
297
298
        $rateLimit = Role::query()->where('id', $role)->first();
299
300
        $sql = [
301
            'username' => $userName,
302
            'grabs' => $grabs,
303
            'roles_id' => $role,
304
            'notes' => substr($notes, 0, 255),
305
            'invites' => $invites,
306
            'movieview' => $movieview,
307
            'musicview' => $musicview,
308
            'gameview' => $gameview,
309
            'xxxview' => $xxxview,
310
            'consoleview' => $consoleview,
311
            'bookview' => $bookview,
312
            'style' => $style,
313
            'queuetype'  => $queueType,
314
            'nzbgeturl' => $nzbgetURL,
315
            'nzbgetusername' => $nzbgetUsername,
316
            'nzbgetpassword' => $nzbgetPassword,
317
            'saburl' => $saburl,
318
            'sabapikey' => $sabapikey,
319
            'sabapikeytype' => $sabapikeytype,
320
            'sabpriority' => $sabpriority,
321
            'nzbvortex_server_url' => $nzbvortexServerUrl,
322
            'nzbvortex_api_key' => $nzbvortexApiKey,
323
            'cp_url' => $cp_url,
324
            'cp_api' => $cp_api,
325
            'rate_limit' => $rateLimit ? $rateLimit['rate_limit'] : 60,
326
        ];
327
328
        if (! empty($email)) {
329
            $email = trim($email);
330
            $sql += ['email' => $email];
331
        }
332
333
        self::whereId($id)->update($sql);
334
335
        $user = self::find($id);
336
        $user->syncRoles([$rateLimit['name']]);
337
338
        return self::SUCCESS;
339
    }
340
341
    /**
342
     * @param string $userName
343
     * @return \Illuminate\Database\Eloquent\Model|null|static
344
     */
345
    public static function getByUsername(string $userName)
346
    {
347
        return self::whereUsername($userName)->first();
348
    }
349
350
    /**
351
     * @param string $email
352
     *
353
     * @return \Illuminate\Database\Eloquent\Model|static
354
     * @throws \Illuminate\Database\Eloquent\ModelNotFoundException
355
     */
356
    public static function getByEmail(string $email)
357
    {
358
        return self::whereEmail($email)->first();
359
    }
360
361
    /**
362
     * @param int $uid
363
     * @param int $role
364
     * @return int
365
     */
366
    public static function updateUserRole(int $uid, int $role): int
367
    {
368
        return self::whereId($uid)->update(['roles_id' => $role]);
369
    }
370
371
    /**
372
     * @param $uid
373
     * @param $date
374
     * @return int
375
     */
376
    public static function updateUserRoleChangeDate($uid, $date): int
377
    {
378
        return self::whereId($uid)->update(['rolechangedate' => $date]);
379
    }
380
381
    /**
382
     * @return int
383
     */
384
    public static function updateExpiredRoles(): int
385
    {
386
        $data = self::query()->whereDate('rolechangedate', '<', now())->get();
387
388
        foreach ($data as $u) {
389
            $user = self::find($u['id']);
390
            $user->update(['roles_id' => self::ROLE_USER, 'rolechangedate' => null]);
391
            $user->syncRoles('User');
392
            SendAccountExpiredEmail::dispatch($user);
393
        }
394
395
        return self::SUCCESS;
396
    }
397
398
    /**
399
     * @param        $start
400
     * @param        $offset
401
     * @param        $orderBy
402
     * @param string $userName
403
     * @param string $email
404
     * @param string $host
405
     * @param string $role
406
     * @param bool   $apiRequests
407
     *
408
     * @return array
409
     * @throws \Throwable
410
     */
411
    public static function getRange($start, $offset, $orderBy, $userName = '', $email = '', $host = '', $role = '', $apiRequests = false): array
412
    {
413
        if ($apiRequests) {
414
            UserRequest::clearApiRequests(false);
415
            $query = "
416
				SELECT users.*, roles.name AS rolename, COUNT(user_requests.id) AS apirequests
417
				FROM users
418
				INNER JOIN roles ON roles.id = users.roles_id
419
				LEFT JOIN user_requests ON user_requests.users_id = users.id
420
				WHERE users.id != 0 %s %s %s %s
421
				AND email != '[email protected]'
422
				GROUP BY users.id
423
				ORDER BY %s %s %s ";
424
        } else {
425
            $query = '
426
				SELECT users.*, roles.name AS rolename,
427
				FROM users
428
				INNER JOIN roles ON roles.id = users.roles_id
429
				WHERE 1=1 %s %s %s %s
430
				ORDER BY %s %s %s';
431
        }
432
        $order = self::getBrowseOrder($orderBy);
433
434
        return DB::select(
435
            sprintf(
436
                $query,
437
                ! empty($userName) ? 'AND users.username '.'LIKE '.escapeString('%'.$userName.'%') : '',
438
                ! empty($email) ? 'AND users.email '.'LIKE '.escapeString('%'.$email.'%') : '',
439
                ! empty($host) ? 'AND users.host '.'LIKE '.escapeString('%'.$host.'%') : '',
440
                (! empty($role) ? ('AND users.roles_id = '.$role) : ''),
441
                $order[0],
442
                $order[1],
443
                ($start === false ? '' : ('LIMIT '.$offset.' OFFSET '.$start))
444
            )
445
        );
446
    }
447
448
    /**
449
     * Get sort types for sorting users on the web page user list.
450
     *
451
     * @param $orderBy
452
     *
453
     * @return string[]
454
     */
455
    public static function getBrowseOrder($orderBy): array
456
    {
457
        $order = (empty($orderBy) ? 'username_desc' : $orderBy);
458
        $orderArr = explode('_', $order);
459
        switch ($orderArr[0]) {
460
            case 'username':
461
                $orderField = 'username';
462
                break;
463
            case 'email':
464
                $orderField = 'email';
465
                break;
466
            case 'host':
467
                $orderField = 'host';
468
                break;
469
            case 'createdat':
470
                $orderField = 'created_at';
471
                break;
472
            case 'lastlogin':
473
                $orderField = 'lastlogin';
474
                break;
475
            case 'apiaccess':
476
                $orderField = 'apiaccess';
477
                break;
478
            case 'grabs':
479
                $orderField = 'grabs';
480
                break;
481
            case 'role':
482
                $orderField = 'rolename';
483
                break;
484
            case 'rolechangedate':
485
                $orderField = 'rolechangedate';
486
                break;
487
            case 'verification':
488
                $orderField = 'verified';
489
                break;
490
            default:
491
                $orderField = 'username';
492
                break;
493
        }
494
        $orderSort = (isset($orderArr[1]) && preg_match('/^asc|desc$/i', $orderArr[1])) ? $orderArr[1] : 'desc';
495
496
        return [$orderField, $orderSort];
497
    }
498
499
    /**
500
     * Verify a password against a hash.
501
     *
502
     * Automatically update the hash if it needs to be.
503
     *
504
     * @param string $password Password to check against hash.
505
     * @param string|bool $hash     Hash to check against password.
506
     * @param int    $userID   ID of the user.
507
     *
508
     * @return bool
509
     */
510
    public static function checkPassword($password, $hash, $userID = -1): bool
511
    {
512
        if (Hash::check($password, $hash) === false) {
513
            return false;
514
        }
515
516
        // Update the hash if it needs to be.
517
        if (is_numeric($userID) && $userID > 0 && Hash::needsRehash($hash)) {
518
            $hash = self::hashPassword($password);
519
520
            if ($hash !== false) {
0 ignored issues
show
introduced by
The condition $hash !== false is always true.
Loading history...
521
                self::whereId($userID)->update(['password' => $hash]);
522
            }
523
        }
524
525
        return true;
526
    }
527
528
    /**
529
     * @param $uid
530
     *
531
     * @return int
532
     */
533
    public static function updateRssKey($uid): int
534
    {
535
        self::whereId($uid)->update(['api_token' => md5(Password::getRepository()->createNewToken())]);
536
537
        return self::SUCCESS;
538
    }
539
540
    /**
541
     * @param $id
542
     * @param $guid
543
     *
544
     * @return int
545
     */
546
    public static function updatePassResetGuid($id, $guid): int
547
    {
548
        self::whereId($id)->update(['resetguid' => $guid]);
549
550
        return self::SUCCESS;
551
    }
552
553
    /**
554
     * @param int    $id
555
     * @param string $password
556
     *
557
     * @return int
558
     */
559
    public static function updatePassword(int $id, string $password): int
560
    {
561
        self::whereId($id)->update(['password' => self::hashPassword($password), 'userseed' => md5(Str::uuid()->toString())]);
562
563
        return self::SUCCESS;
564
    }
565
566
    /**
567
     * @param $password
568
     * @return mixed
569
     */
570
    public static function hashPassword($password)
571
    {
572
        return Hash::make($password);
573
    }
574
575
    /**
576
     * @param $guid
577
     *
578
     * @return \Illuminate\Database\Eloquent\Model|static
579
     * @throws \Illuminate\Database\Eloquent\ModelNotFoundException
580
     */
581
    public static function getByPassResetGuid(string $guid)
582
    {
583
        return self::whereResetguid($guid)->first();
584
    }
585
586
    /**
587
     * @param     $id
588
     * @param int $num
589
     */
590
    public static function incrementGrabs(int $id, $num = 1): void
591
    {
592
        self::whereId($id)->increment('grabs', $num);
593
    }
594
595
    /**
596
     * Check if the user is in the database, and if their API key is good, return user data if so.
597
     *
598
     *
599
     * @param $userID
600
     * @param $rssToken
601
     *
602
     * @return bool|\Illuminate\Database\Eloquent\Model|null|static
603
     */
604
    public static function getByIdAndRssToken($userID, $rssToken)
605
    {
606
        $user = self::query()->where(['id' => $userID, 'api_token' => $rssToken])->first();
607
        if ($user === null) {
608
            return false;
609
        }
610
611
        return $user;
612
    }
613
614
    /**
615
     * @param string $rssToken
616
     * @return \Illuminate\Database\Eloquent\Model|null|static
617
     */
618
    public static function getByRssToken(string $rssToken)
619
    {
620
        return self::whereApiToken($rssToken)->first();
621
    }
622
623
    /**
624
     * @param $url
625
     *
626
     * @return bool
627
     */
628
    public static function isValidUrl($url): bool
629
    {
630
        return (! preg_match('/^(http|https|ftp):\/\/([A-Z0-9][A-Z0-9_-]*(?:\.[A-Z0-9][A-Z0-9_-]*)+):?(\d+)?\/?/i', $url)) ? false : true;
631
    }
632
633
    /**
634
     * Generate a random username.
635
     *
636
     *
637
     * @return string
638
     */
639
    public static function generateUsername(): string
640
    {
641
        return Str::random();
642
    }
643
644
    /**
645
     * @param int $length
646
     *
647
     * @return string
648
     * @throws \Exception
649
     */
650
    public static function generatePassword($length = 15): string
651
    {
652
        return \Token::random($length, true);
0 ignored issues
show
Bug introduced by
The type Token was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
653
    }
654
655
    /**
656
     * Register a new user.
657
     *
658
     * @param        $userName
659
     * @param        $password
660
     * @param        $email
661
     * @param        $host
662
     * @param int    $role
663
     * @param        $notes
664
     * @param int    $invites
665
     * @param string $inviteCode
666
     * @param bool   $forceInviteMode
667
     *
668
     * @return bool|int
669
     * @throws \Exception
670
     * @throws \Illuminate\Database\Eloquent\ModelNotFoundException
671
     */
672
    public static function signUp($userName, $password, $email, $host, $notes, $invites = Invitation::DEFAULT_INVITES, $inviteCode = '', $forceInviteMode = false, $role = self::ROLE_USER)
673
    {
674
        $user = [
675
            'username' => trim($userName),
676
            'password' => trim($password),
677
            'email' => trim($email),
678
        ];
679
680
        $validator = Validator::make($user, [
681
            'username' => ['required', 'string', 'min:5', 'max:255', 'unique:users'],
682
            'email' => ['required', 'string', 'email', 'max:255', 'unique:users', 'indisposable'],
683
            'password' => ['required', 'string', 'min:8', 'confirmed', 'regex:/^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$/'],
684
        ]);
685
686
        if ($validator->fails()) {
687
            (new ColorCLI())->error(implode('', array_collapse($validator->errors()->toArray())));
688
        }
689
690
        // Make sure this is the last check, as if a further validation check failed, the invite would still have been used up.
691
        $invitedBy = 0;
692
        if (! $forceInviteMode && (int) Settings::settingValue('..registerstatus') === Settings::REGISTER_STATUS_INVITE) {
693
            if ($inviteCode === '') {
694
                return self::ERR_SIGNUP_BADINVITECODE;
695
            }
696
697
            $invitedBy = self::checkAndUseInvite($inviteCode);
698
            if ($invitedBy < 0) {
699
                return self::ERR_SIGNUP_BADINVITECODE;
700
            }
701
        }
702
703
        return self::add($user['userName'], $user['password'], $user['email'], $role, $notes, $host, $invites, $invitedBy);
704
    }
705
706
    /**
707
     * If a invite is used, decrement the person who invited's invite count.
708
     *
709
     * @param string $inviteCode
710
     *
711
     * @return int
712
     */
713
    public static function checkAndUseInvite(string $inviteCode): int
714
    {
715
        $invite = Invitation::getInvite($inviteCode);
716
        if (! $invite) {
717
            return -1;
718
        }
719
720
        self::query()->where('id', $invite['users_id'])->decrement('invites');
721
        Invitation::deleteInvite($inviteCode);
722
723
        return $invite['users_id'];
724
    }
725
726
    /**
727
     * Add a new user.
728
     *
729
     * @param string    $userName
730
     * @param  string   $password
731
     * @param  string   $email
732
     * @param int    $role
733
     * @param string    $notes
734
     * @param string    $host
735
     * @param int $invites
736
     * @param int $invitedBy
737
     *
738
     * @return bool|int
739
     * @throws \Exception
740
     */
741
    public static function add($userName, $password, $email, $role, $notes, $host, $invites = Invitation::DEFAULT_INVITES, $invitedBy = 0)
742
    {
743
        $password = self::hashPassword($password);
744
        if (! $password) {
745
            return false;
746
        }
747
748
        $roleData = Role::query()->where('id', $role);
749
        $rateLimit = $roleData->value('rate_limit');
750
        $roleName = $roleData->value('name');
751
752
        $storeips = (int) Settings::settingValue('..storeuserips') === 1 ? $host : '';
753
754
        $user = self::create(
755
            [
756
                'username' => $userName,
757
                'password' => $password,
758
                'email' => $email,
759
                'host' => $storeips,
760
                'roles_id' => $role,
761
                'api_token' => md5(Password::getRepository()->createNewToken()),
762
                'invites' => $invites,
763
                'invitedby' => (int) $invitedBy === 0 ? null : $invitedBy,
764
                'userseed' => md5(Str::uuid()->toString()),
765
                'notes' => $notes,
766
                'rate_limit' => $rateLimit,
767
            ]
768
        );
769
770
        $user->assignRole($roleName);
771
772
        return $user->id;
773
    }
774
775
    /**
776
     * When a user logs in, update the last time they logged in.
777
     *
778
     * @param int    $userID ID of the user.
779
     * @param string $host
780
     */
781
    public static function updateSiteAccessed($userID, $host = ''): void
782
    {
783
        self::whereId($userID)->update(
784
            [
785
                'lastlogin' => now(),
786
                'host' => $host,
787
            ]
788
        );
789
    }
790
791
    /**
792
     * @param $uid
793
     */
794
    public static function updateApiAccessed($uid): void
795
    {
796
        self::whereId($uid)->update(['apiaccess' => date('Y-m-d h:m:s')]);
797
    }
798
799
    /**
800
     * Get the list of categories the user has excluded.
801
     *
802
     * @param int $userID ID of the user.
803
     *
804
     * @return array
805
     * @throws \Exception
806
     */
807
    public static function getCategoryExclusionById($userID): array
808
    {
809
        $ret = [];
810
811
        $user = self::find($userID);
812
813
        $userAllowed = $user->getDirectPermissions()->pluck('name')->toArray();
814
        $roleAllowed = $user->getAllPermissions()->pluck('name')->toArray();
815
816
        $allowed = array_intersect($roleAllowed, $userAllowed);
817
818
        $cats = ['view console', 'view movies', 'view audio', 'view tv', 'view pc', 'view adult', 'view books', 'view other'];
819
820
        if (! empty($allowed)) {
821
            foreach ($cats as $cat) {
822
                if (! \in_array($cat, $allowed, false)) {
823
                    switch ($cat) {
824
                        case 'view console':
825
                            $ret[] = 1000;
826
                            continue 2;
827
                        case 'view movies':
828
                            $ret[] = 2000;
829
                            continue 2;
830
                        case 'view audio':
831
                            $ret[] = 3000;
832
                            continue 2;
833
                        case 'view tv':
834
                            $ret[] = 4000;
835
                            continue 2;
836
                        case 'view pc':
837
                            $ret[] = 5000;
838
                            continue 2;
839
                        case 'view adult':
840
                            $ret[] = 6000;
841
                            continue 2;
842
                        case 'view books':
843
                            $ret[] = 7000;
844
                            continue 2;
845
                        case 'view other':
846
                            $ret[] = 1;
847
848
                    }
849
                }
850
            }
851
        }
852
853
        $exclusion = Category::query()->whereIn('parentid', $ret)->pluck('id')->toArray();
854
855
        return $exclusion;
856
    }
857
858
    /**
859
     * @param \Illuminate\Http\Request $request
860
     * @return array
861
     * @throws \Exception
862
     */
863
    public static function getCategoryExclusionForApi(Request $request): array
864
    {
865
        $user = self::getByRssToken($request->input('api_token'));
866
        return self::getCategoryExclusionById($user->id);
867
    }
868
869
    /**
870
     * @return \Illuminate\Database\Eloquent\Collection|\Illuminate\Support\Collection|static[]
871
     */
872
    public static function getTopGrabbers()
873
    {
874
        return self::query()->selectRaw('id, username, SUM(grabs) as grabs')->groupBy('id', 'username')->having('grabs', '>', 0)->orderBy('grabs', 'desc')->limit(10)->get();
875
    }
876
877
    /**
878
     * @return \Illuminate\Database\Eloquent\Collection|\Illuminate\Support\Collection|static[]
879
     */
880
    public static function getUsersByMonth()
881
    {
882
        return self::query()->whereNotNull('created_at')->where('created_at', '<>', '0000-00-00 00:00:00')->selectRaw("DATE_FORMAT(created_at, '%M %Y') as mth, COUNT(id) as num")->groupBy(['mth'])->orderBy('created_at', 'desc')->get();
883
    }
884
885
    /**
886
     * @param $serverUrl
887
     * @param $uid
888
     * @param $emailTo
889
     *
890
     * @return string
891
     * @throws \Exception
892
     */
893
    public static function sendInvite($serverUrl, $uid, $emailTo): string
894
    {
895
        $token = \Token::randomString(40);
896
        $url = $serverUrl.'register?invitecode='.$token;
897
898
        Invitation::addInvite($uid, $token);
899
        SendInviteEmail::dispatch($emailTo, $uid, $url);
900
901
        return $url;
902
    }
903
904
    /**
905
     * Deletes old rows FROM the user_requests and user_downloads tables.
906
     * if site->userdownloadpurgedays SET to 0 then all release history is removed but
907
     * the download/request rows must remain for at least one day to allow the role based
908
     * limits to apply.
909
     *
910
     * @param int $days
911
     */
912
    public static function pruneRequestHistory($days = 0): void
913
    {
914
        if ($days === 0) {
915
            $days = 1;
916
            UserDownload::query()->update(['releases_id' => null]);
917
        }
918
919
        UserRequest::query()->where('timestamp', '<', now()->subDays($days))->delete();
920
        UserDownload::query()->where('timestamp', '<', now()->subDays($days))->delete();
921
    }
922
923
    /**
924
     * Deletes users that have not verified their accounts for 3 or more days.
925
     */
926
    public static function deleteUnVerified(): void
927
    {
928
        static::whereVerified(0)->where('created_at', '<', now()->subDays(3))->delete();
929
    }
930
}
931