Completed
Push — dev ( 0c8160...357043 )
by Darko
08:50
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
ccs 0
cts 7
cp 0
crap 56
rs 8.8333
c 0
b 0
f 0

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 Illuminate\Support\Arr;
6
use Illuminate\Support\Str;
7
use Illuminate\Http\Request;
8
use App\Jobs\SendInviteEmail;
9
use Illuminate\Support\Carbon;
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 App\Jobs\SendAccountWillExpireEmail;
15
use Illuminate\Notifications\Notifiable;
16
use Illuminate\Support\Facades\Password;
17
use Illuminate\Support\Facades\Validator;
18
use Jrean\UserVerification\Traits\UserVerification;
19
use Illuminate\Foundation\Auth\User as Authenticatable;
20
21
/**
22
 * App\Models\User.
23
 *
24
 * @property int $id
25
 * @property string $username
26
 * @property string|null $firstname
27
 * @property string|null $lastname
28
 * @property string $email
29
 * @property string $password
30
 * @property int $user_roles_id FK to roles.id
31
 * @property string|null $host
32
 * @property int $grabs
33
 * @property string $rsstoken
34
 * @property \Carbon\Carbon|null $created_at
35
 * @property \Carbon\Carbon|null $updated_at
36
 * @property string|null $resetguid
37
 * @property string|null $lastlogin
38
 * @property string|null $apiaccess
39
 * @property int $invites
40
 * @property int|null $invitedby
41
 * @property int $movieview
42
 * @property int $xxxview
43
 * @property int $musicview
44
 * @property int $consoleview
45
 * @property int $bookview
46
 * @property int $gameview
47
 * @property string|null $saburl
48
 * @property string|null $sabapikey
49
 * @property bool|null $sabapikeytype
50
 * @property bool|null $sabpriority
51
 * @property bool $queuetype Type of queue, Sab or NZBGet
52
 * @property string|null $nzbgeturl
53
 * @property string|null $nzbgetusername
54
 * @property string|null $nzbgetpassword
55
 * @property string|null $nzbvortex_api_key
56
 * @property string|null $nzbvortex_server_url
57
 * @property string $userseed
58
 * @property string $notes
59
 * @property string|null $cp_url
60
 * @property string|null $cp_api
61
 * @property string|null $style
62
 * @property string|null $rolechangedate When does the role expire
63
 * @property string|null $remember_token
64
 * @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\ReleaseComment[] $comment
65
 * @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\UserDownload[] $download
66
 * @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\DnzbFailure[] $failedRelease
67
 * @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\Invitation[] $invitation
68
 * @property-read \Illuminate\Notifications\DatabaseNotificationCollection|\Illuminate\Notifications\DatabaseNotification[] $notifications
69
 * @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\UsersRelease[] $release
70
 * @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\UserRequest[] $request
71
 * @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\UserSerie[] $series
72
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereApiaccess($value)
73
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereBookview($value)
74
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereConsoleview($value)
75
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereCpApi($value)
76
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereCpUrl($value)
77
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereCreatedAt($value)
78
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereEmail($value)
79
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereFirstname($value)
80
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereGameview($value)
81
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereGrabs($value)
82
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereHost($value)
83
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereId($value)
84
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereInvitedby($value)
85
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereInvites($value)
86
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereLastlogin($value)
87
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereLastname($value)
88
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereMovieview($value)
89
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereMusicview($value)
90
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereNotes($value)
91
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereNzbgetpassword($value)
92
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereNzbgeturl($value)
93
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereNzbgetusername($value)
94
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereNzbvortexApiKey($value)
95
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereNzbvortexServerUrl($value)
96
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User wherePassword($value)
97
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereQueuetype($value)
98
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereRememberToken($value)
99
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereResetguid($value)
100
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereRolechangedate($value)
101
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereRsstoken($value)
102
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereSabapikey($value)
103
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereSabapikeytype($value)
104
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereSabpriority($value)
105
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereSaburl($value)
106
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereStyle($value)
107
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereUpdatedAt($value)
108
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereUserRolesId($value)
109
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereUsername($value)
110
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereUserseed($value)
111
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereXxxview($value)
112
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereVerified($value)
113
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereApiToken($value)
114
 * @mixin \Eloquent
115
 */
116
class User extends Authenticatable
117
{
118
    use Notifiable, UserVerification, HasRoles;
0 ignored issues
show
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...
Bug introduced by
The trait Illuminate\Notifications\Notifiable requires the property $phone_number which is not provided by App\Models\User.
Loading history...
119
120
    public const ERR_SIGNUP_BADUNAME = -1;
121
    public const ERR_SIGNUP_BADPASS = -2;
122
    public const ERR_SIGNUP_BADEMAIL = -3;
123
    public const ERR_SIGNUP_UNAMEINUSE = -4;
124
    public const ERR_SIGNUP_EMAILINUSE = -5;
125
    public const ERR_SIGNUP_BADINVITECODE = -6;
126
    public const ERR_SIGNUP_BADCAPTCHA = -7;
127
    public const SUCCESS = 1;
128
129
    public const ROLE_USER = 1;
130
    public const ROLE_ADMIN = 2;
131
    public const ROLE_DISABLED = 3;
132
    public const ROLE_MODERATOR = 4;
133
134
    /**
135
     * Users SELECT queue type.
136
     */
137
    public const QUEUE_NONE = 0;
138
    public const QUEUE_SABNZBD = 1;
139
    public const QUEUE_NZBGET = 2;
140
141
    /**
142
     * @var string
143
     */
144
    protected $table = 'users';
145
146
    /**
147
     * @var bool
148
     */
149
    protected $dateFormat = false;
150
151
    /**
152
     * @var array
153
     */
154
    protected $hidden = ['remember_token', 'password'];
155
156
    /**
157
     * @var array
158
     */
159
    protected $guarded = [];
160
161
    /**
162
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
163
     */
164
    public function role()
165
    {
166
        return $this->belongsTo(Role::class, 'roles_id');
167
    }
168
169
    /**
170
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
171
     */
172
    public function request()
173
    {
174
        return $this->hasMany(UserRequest::class, 'users_id');
175
    }
176
177
    /**
178
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
179
     */
180
    public function download()
181
    {
182
        return $this->hasMany(UserDownload::class, 'users_id');
183
    }
184
185
    /**
186
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
187
     */
188
    public function release()
189
    {
190
        return $this->hasMany(UsersRelease::class, 'users_id');
191
    }
192
193
    /**
194
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
195
     */
196
    public function series()
197
    {
198
        return $this->hasMany(UserSerie::class, 'users_id');
199
    }
200
201
    /**
202
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
203
     */
204
    public function invitation()
205
    {
206
        return $this->hasMany(Invitation::class, 'users_id');
207
    }
208
209
    /**
210
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
211
     */
212
    public function failedRelease()
213
    {
214
        return $this->hasMany(DnzbFailure::class, 'users_id');
215
    }
216
217
    /**
218
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
219
     */
220
    public function comment()
221
    {
222
        return $this->hasMany(ReleaseComment::class, 'users_id');
223
    }
224
225
    /**
226
     * @param $id
227
     * @throws \Exception
228
     */
229
    public static function deleteUser($id): void
230
    {
231
        self::find($id)->delete();
232
    }
233
234
    /**
235
     * @param string $role
236
     * @param string $username
237
     * @param string $host
238
     * @param string $email
239
     * @return int
240
     */
241
    public static function getCount($role = '', $username = '', $host = '', $email = ''): int
242
    {
243
        $res = self::query()->where('email', '<>', '[email protected]');
244
245
        if ($role !== '') {
246
            $res->where('roles_id', $role);
247
        }
248
249
        if ($username !== '') {
250
            $res->where('username', 'like', '%'.$username.'%');
251
        }
252
253
        if ($host !== '') {
254
            $res->where('host', 'like', '%'.$host.'%');
255
        }
256
257
        if ($email !== '') {
258
            $res->where('email', 'like', '%'.$email.'%');
259
        }
260
261
        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...
262
    }
263
264
    /**
265
     * @param  int      $id
266
     * @param  string      $userName
267
     * @param  string      $email
268
     * @param  int     $grabs
269
     * @param  int     $role
270
     * @param  string    $notes
271
     * @param  int     $invites
272
     * @param  int     $movieview
273
     * @param  int    $musicview
274
     * @param  int   $gameview
275
     * @param  int    $xxxview
276
     * @param  int    $consoleview
277
     * @param  int    $bookview
278
     * @param string $queueType
279
     * @param string $nzbgetURL
280
     * @param string $nzbgetUsername
281
     * @param string $nzbgetPassword
282
     * @param string $saburl
283
     * @param string $sabapikey
284
     * @param string $sabpriority
285
     * @param string $sabapikeytype
286
     * @param bool   $nzbvortexServerUrl
287
     * @param bool   $nzbvortexApiKey
288
     * @param bool   $cp_url
289
     * @param bool   $cp_api
290
     * @param string $style
291
     *
292
     * @return int
293
     * @throws \Illuminate\Database\Eloquent\ModelNotFoundException
294
     */
295
    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
296
    {
297
        $userName = trim($userName);
298
299
        $rateLimit = Role::query()->where('id', $role)->first();
300
301
        $sql = [
302
            'username' => $userName,
303
            'grabs' => $grabs,
304
            'roles_id' => $role,
305
            'notes' => substr($notes, 0, 255),
306
            'invites' => $invites,
307
            'movieview' => $movieview,
308
            'musicview' => $musicview,
309
            'gameview' => $gameview,
310
            'xxxview' => $xxxview,
311
            'consoleview' => $consoleview,
312
            'bookview' => $bookview,
313
            'style' => $style,
314
            'queuetype'  => $queueType,
315
            'nzbgeturl' => $nzbgetURL,
316
            'nzbgetusername' => $nzbgetUsername,
317
            'nzbgetpassword' => $nzbgetPassword,
318
            'saburl' => $saburl,
319
            'sabapikey' => $sabapikey,
320
            'sabapikeytype' => $sabapikeytype,
321
            'sabpriority' => $sabpriority,
322
            'nzbvortex_server_url' => $nzbvortexServerUrl,
323
            'nzbvortex_api_key' => $nzbvortexApiKey,
324
            'cp_url' => $cp_url,
325
            'cp_api' => $cp_api,
326
            'rate_limit' => $rateLimit ? $rateLimit['rate_limit'] : 60,
327
        ];
328
329
        if (! empty($email)) {
330
            $email = trim($email);
331
            $sql += ['email' => $email];
332
        }
333
334
        $user = self::find($id);
335
        $user->update($sql);
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
     *
365
     * @return bool
366
     */
367
    public static function updateUserRole(int $uid, int $role)
368
    {
369
        return self::find($uid)->update(['roles_id' => $role]);
370
    }
371
372
    /**
373
     * @param int $uid
374
     * @param $date
375
     * @param int $addYear
376
     */
377
    public static function updateUserRoleChangeDate($uid, $date = '', $addYear = 0): void
378
    {
379
        $user = self::find($uid);
380
        $currRoleExp = $user::select(['rolechangedate'])->first();
381
        if (! empty($date)) {
382
            $user->update(['rolechangedate' => $date]);
383
        }
384
        if (empty($date) && ! empty($addYear)) {
385
            $user->update(['rolechangedate' => Carbon::createFromDate($currRoleExp['rolechangedate'])->addYears($addYear)]);
386
        }
387
    }
388
389
    /**
390
     * @param int|null $period
391
     */
392
    public static function updateExpiredRoles(int $period = null): void
393
    {
394
        $now = now();
395
        $endDate = $now->addDays($period);
396
        $query = self::query()->whereDate('rolechangedate', '>', now())->whereDate('rolechangedate', '<=', $endDate);
397
        if ($period === null) {
398
            $endDate = $now;
399
            $query = self::query()->whereDate('rolechangedate', '>', $endDate);
400
        }
401
402
        $usersCheck = $query->get();
403
404
        foreach ($usersCheck as $userCheck) {
405
            $emailCheckQuery = RoleExpirationEmail::query()->where('users_id', $userCheck->id)->get();
406
            if ($period === null) {
407
                $userCheck->update(['roles_id' => self::ROLE_USER, 'rolechangedate' => null]);
408
                $userCheck->syncRoles('User');
409
                SendAccountExpiredEmail::dispatch($userCheck);
410
            } else {
411
                if ($emailCheckQuery->isNotEmpty()) {
412
                    $booleans = [
413
                        'day' => $period === 1 && $emailCheckQuery->day === false,
414
                        'week' => $period === 7 && $emailCheckQuery->week === false,
415
                        'month' => $period === 30 && $emailCheckQuery->month === false,
416
                    ];
417
                    RoleExpirationEmail::query()->where('users_id', '=', $userCheck->id)->update($booleans);
418
                } else {
419
                    $booleans = [
420
                        'day' => $period === 1,
421
                        'week' => $period === 7,
422
                        'month' => $period === 30,
423
                    ];
424
                    $userId = [
425
                        'users_id' => $userCheck->id,
426
                    ];
427
                    $booleans += $userId;
428
429
                    RoleExpirationEmail::create($booleans);
430
                }
431
432
                SendAccountWillExpireEmail::dispatch($userCheck, $period);
433
            }
434
        }
435
    }
436
437
    /**
438
     * @param        $start
439
     * @param        $offset
440
     * @param        $orderBy
441
     * @param string $userName
442
     * @param string $email
443
     * @param string $host
444
     * @param string $role
445
     * @param bool   $apiRequests
446
     *
447
     * @return \Illuminate\Database\Eloquent\Collection
448
     * @throws \Throwable
449
     */
450
    public static function getRange($start, $offset, $orderBy, $userName = '', $email = '', $host = '', $role = '', $apiRequests = false)
451
    {
452
        if ($apiRequests) {
453
            UserRequest::clearApiRequests(false);
454
            $query = "
455
				SELECT users.*, roles.name AS rolename, COUNT(user_requests.id) AS apirequests
456
				FROM users
457
				INNER JOIN roles ON roles.id = users.roles_id
458
				LEFT JOIN user_requests ON user_requests.users_id = users.id
459
				WHERE users.id != 0 %s %s %s %s
460
				AND email != '[email protected]'
461
				GROUP BY users.id
462
				ORDER BY %s %s %s ";
463
        } else {
464
            $query = '
465
				SELECT users.*, roles.name AS rolename
466
				FROM users
467
				INNER JOIN roles ON roles.id = users.roles_id
468
				WHERE 1=1 %s %s %s %s
469
				ORDER BY %s %s %s';
470
        }
471
        $order = self::getBrowseOrder($orderBy);
472
473
        return self::fromQuery(
474
            sprintf(
475
                $query,
476
                ! empty($userName) ? 'AND users.username '.'LIKE '.escapeString('%'.$userName.'%') : '',
477
                ! empty($email) ? 'AND users.email '.'LIKE '.escapeString('%'.$email.'%') : '',
478
                ! empty($host) ? 'AND users.host '.'LIKE '.escapeString('%'.$host.'%') : '',
479
                (! empty($role) ? ('AND users.roles_id = '.$role) : ''),
480
                $order[0],
481
                $order[1],
482
                ($start === false ? '' : ('LIMIT '.$offset.' OFFSET '.$start))
483
            )
484
        );
485
    }
486
487
    /**
488
     * Get sort types for sorting users on the web page user list.
489
     *
490
     * @param $orderBy
491
     *
492
     * @return string[]
493
     */
494
    public static function getBrowseOrder($orderBy): array
495
    {
496
        $order = (empty($orderBy) ? 'username_desc' : $orderBy);
497
        $orderArr = explode('_', $order);
498
        switch ($orderArr[0]) {
499
            case 'username':
500
                $orderField = 'username';
501
                break;
502
            case 'email':
503
                $orderField = 'email';
504
                break;
505
            case 'host':
506
                $orderField = 'host';
507
                break;
508
            case 'createdat':
509
                $orderField = 'created_at';
510
                break;
511
            case 'lastlogin':
512
                $orderField = 'lastlogin';
513
                break;
514
            case 'apiaccess':
515
                $orderField = 'apiaccess';
516
                break;
517
            case 'grabs':
518
                $orderField = 'grabs';
519
                break;
520
            case 'role':
521
                $orderField = 'rolename';
522
                break;
523
            case 'rolechangedate':
524
                $orderField = 'rolechangedate';
525
                break;
526
            case 'verification':
527
                $orderField = 'verified';
528
                break;
529
            default:
530
                $orderField = 'username';
531
                break;
532
        }
533
        $orderSort = (isset($orderArr[1]) && preg_match('/^asc|desc$/i', $orderArr[1])) ? $orderArr[1] : 'desc';
534
535
        return [$orderField, $orderSort];
536
    }
537
538
    /**
539
     * Verify a password against a hash.
540
     *
541
     * Automatically update the hash if it needs to be.
542
     *
543
     * @param string $password Password to check against hash.
544
     * @param string|bool $hash     Hash to check against password.
545
     * @param int    $userID   ID of the user.
546
     *
547
     * @return bool
548
     */
549
    public static function checkPassword($password, $hash, $userID = -1): bool
550
    {
551
        if (Hash::check($password, $hash) === false) {
552
            return false;
553
        }
554
555
        // Update the hash if it needs to be.
556
        if (is_numeric($userID) && $userID > 0 && Hash::needsRehash($hash)) {
557
            $hash = self::hashPassword($password);
558
559
            if ($hash !== false) {
0 ignored issues
show
introduced by
The condition $hash !== false is always true.
Loading history...
560
                self::find($userID)->update(['password' => $hash]);
561
            }
562
        }
563
564
        return true;
565
    }
566
567
    /**
568
     * @param $uid
569
     *
570
     * @return int
571
     */
572
    public static function updateRssKey($uid): int
573
    {
574
        self::find($uid)->update(['api_token' => md5(Password::getRepository()->createNewToken())]);
575
576
        return self::SUCCESS;
577
    }
578
579
    /**
580
     * @param $id
581
     * @param $guid
582
     *
583
     * @return int
584
     */
585
    public static function updatePassResetGuid($id, $guid): int
586
    {
587
        self::find($id)->update(['resetguid' => $guid]);
588
589
        return self::SUCCESS;
590
    }
591
592
    /**
593
     * @param int    $id
594
     * @param string $password
595
     *
596
     * @return int
597
     */
598
    public static function updatePassword(int $id, string $password): int
599
    {
600
        self::find($id)->update(['password' => self::hashPassword($password), 'userseed' => md5(Str::uuid()->toString())]);
601
602
        return self::SUCCESS;
603
    }
604
605
    /**
606
     * @param $password
607
     * @return mixed
608
     */
609
    public static function hashPassword($password)
610
    {
611
        return Hash::make($password);
612
    }
613
614
    /**
615
     * @param $guid
616
     *
617
     * @return \Illuminate\Database\Eloquent\Model|static
618
     * @throws \Illuminate\Database\Eloquent\ModelNotFoundException
619
     */
620
    public static function getByPassResetGuid(string $guid)
621
    {
622
        return self::whereResetguid($guid)->first();
623
    }
624
625
    /**
626
     * @param     $id
627
     * @param int $num
628
     */
629
    public static function incrementGrabs(int $id, $num = 1): void
630
    {
631
        self::find($id)->increment('grabs', $num);
632
    }
633
634
    /**
635
     * Check if the user is in the database, and if their API key is good, return user data if so.
636
     *
637
     *
638
     * @param $userID
639
     * @param $rssToken
640
     *
641
     * @return bool|\Illuminate\Database\Eloquent\Model|null|static
642
     */
643
    public static function getByIdAndRssToken($userID, $rssToken)
644
    {
645
        $user = self::query()->where(['id' => $userID, 'api_token' => $rssToken])->first();
646
        if ($user === null) {
647
            return false;
648
        }
649
650
        return $user;
651
    }
652
653
    /**
654
     * @param string $rssToken
655
     * @return \Illuminate\Database\Eloquent\Model|null|static
656
     */
657
    public static function getByRssToken(string $rssToken)
658
    {
659
        return self::whereApiToken($rssToken)->first();
660
    }
661
662
    /**
663
     * @param $url
664
     *
665
     * @return bool
666
     */
667
    public static function isValidUrl($url): bool
668
    {
669
        return (! preg_match('/^(http|https|ftp):\/\/([A-Z0-9][A-Z0-9_-]*(?:\.[A-Z0-9][A-Z0-9_-]*)+):?(\d+)?\/?/i', $url)) ? false : true;
670
    }
671
672
    /**
673
     * Generate a random username.
674
     *
675
     *
676
     * @return string
677
     */
678
    public static function generateUsername(): string
679
    {
680
        return Str::random();
681
    }
682
683
    /**
684
     * @param int $length
685
     *
686
     * @return string
687
     * @throws \Exception
688
     */
689
    public static function generatePassword($length = 15): string
690
    {
691
        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...
692
    }
693
694
    /**
695
     * Register a new user.
696
     *
697
     * @param        $userName
698
     * @param        $password
699
     * @param        $email
700
     * @param        $host
701
     * @param        $notes
702
     * @param int $invites
703
     * @param string $inviteCode
704
     * @param bool $forceInviteMode
705
     *
706
     * @param int $role
707
     * @param bool $validate
708
     * @return bool|int|string
709
     * @throws \Exception
710
     */
711
    public static function signUp($userName, $password, $email, $host, $notes, $invites = Invitation::DEFAULT_INVITES, $inviteCode = '', $forceInviteMode = false, $role = self::ROLE_USER, $validate = true)
712
    {
713
        $user = [
714
            'username' => trim($userName),
715
            'password' => trim($password),
716
            'email' => trim($email),
717
        ];
718
719
        if ($validate) {
720
            $validator = Validator::make($user, [
721
                'username' => ['required', 'string', 'min:5', 'max:255', 'unique:users'],
722
                'email' => ['required', 'string', 'email', 'max:255', 'unique:users', 'indisposable'],
723
                'password' => ['required', 'string', 'min:8', 'confirmed', 'regex:/^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$/'],
724
            ]);
725
726
            if ($validator->fails()) {
727
                $error = implode('', Arr::collapse($validator->errors()->toArray()));
728
729
                return $error;
730
            }
731
        }
732
733
        // Make sure this is the last check, as if a further validation check failed, the invite would still have been used up.
734
        $invitedBy = 0;
735
        if (! $forceInviteMode && (int) Settings::settingValue('..registerstatus') === Settings::REGISTER_STATUS_INVITE) {
736
            if ($inviteCode === '') {
737
                return self::ERR_SIGNUP_BADINVITECODE;
738
            }
739
740
            $invitedBy = self::checkAndUseInvite($inviteCode);
741
            if ($invitedBy < 0) {
742
                return self::ERR_SIGNUP_BADINVITECODE;
743
            }
744
        }
745
746
        return self::add($user['username'], $user['password'], $user['email'], $role, $notes, $host, $invites, $invitedBy);
747
    }
748
749
    /**
750
     * If a invite is used, decrement the person who invited's invite count.
751
     *
752
     * @param string $inviteCode
753
     *
754
     * @return int
755
     */
756
    public static function checkAndUseInvite(string $inviteCode): int
757
    {
758
        $invite = Invitation::getInvite($inviteCode);
759
        if (! $invite) {
760
            return -1;
761
        }
762
763
        self::query()->where('id', $invite['users_id'])->decrement('invites');
764
        Invitation::deleteInvite($inviteCode);
765
766
        return $invite['users_id'];
767
    }
768
769
    /**
770
     * Add a new user.
771
     *
772
     * @param string    $userName
773
     * @param  string   $password
774
     * @param  string   $email
775
     * @param int    $role
776
     * @param string    $notes
777
     * @param string    $host
778
     * @param int $invites
779
     * @param int $invitedBy
780
     *
781
     * @return bool|int
782
     * @throws \Exception
783
     */
784
    public static function add($userName, $password, $email, $role, $notes = '', $host = '', $invites = Invitation::DEFAULT_INVITES, $invitedBy = 0)
785
    {
786
        $password = self::hashPassword($password);
787
        if (! $password) {
788
            return false;
789
        }
790
791
        $storeips = (int) Settings::settingValue('..storeuserips') === 1 ? $host : '';
792
793
        $user = self::create(
794
            [
795
                'username' => $userName,
796
                'password' => $password,
797
                'email' => $email,
798
                'host' => $storeips,
799
                'roles_id' => $role,
800
                'invites' => $invites,
801
                'invitedby' => (int) $invitedBy === 0 ? null : $invitedBy,
802
                'notes' => $notes,
803
            ]
804
        );
805
806
        return $user->id;
807
    }
808
809
    /**
810
     * Get the list of categories the user has excluded.
811
     *
812
     * @param int $userID ID of the user.
813
     *
814
     * @return array
815
     * @throws \Exception
816
     */
817
    public static function getCategoryExclusionById($userID): array
818
    {
819
        $ret = [];
820
821
        $user = self::find($userID);
822
823
        $userAllowed = $user->getDirectPermissions()->pluck('name')->toArray();
824
        $roleAllowed = $user->getAllPermissions()->pluck('name')->toArray();
825
826
        $allowed = array_intersect($roleAllowed, $userAllowed);
827
828
        $cats = ['view console', 'view movies', 'view audio', 'view tv', 'view pc', 'view adult', 'view books', 'view other'];
829
830
        if (! empty($allowed)) {
831
            foreach ($cats as $cat) {
832
                if (! \in_array($cat, $allowed, false)) {
833
                    switch ($cat) {
834
                        case 'view console':
835
                            $ret[] = 1000;
836
                            continue 2;
837
                        case 'view movies':
838
                            $ret[] = 2000;
839
                            continue 2;
840
                        case 'view audio':
841
                            $ret[] = 3000;
842
                            continue 2;
843
                        case 'view pc':
844
                            $ret[] = 4000;
845
                            continue 2;
846
                        case 'view tv':
847
                            $ret[] = 5000;
848
                            continue 2;
849
                        case 'view adult':
850
                            $ret[] = 6000;
851
                            continue 2;
852
                        case 'view books':
853
                            $ret[] = 7000;
854
                            continue 2;
855
                        case 'view other':
856
                            $ret[] = 1;
857
858
                    }
859
                }
860
            }
861
        }
862
863
        $exclusion = Category::query()->whereIn('root_categories_id', $ret)->pluck('id')->toArray();
864
865
        return $exclusion;
866
    }
867
868
    /**
869
     * @param \Illuminate\Http\Request $request
870
     * @return array
871
     * @throws \Exception
872
     */
873
    public static function getCategoryExclusionForApi(Request $request): array
874
    {
875
        $apiToken = $request->has('api_token') ? $request->input('api_token') : $request->input('apikey');
876
        $user = self::getByRssToken($apiToken);
877
878
        return self::getCategoryExclusionById($user->id);
879
    }
880
881
    /**
882
     * @return \Illuminate\Database\Eloquent\Collection|\Illuminate\Support\Collection|static[]
883
     */
884
    public static function getTopGrabbers()
885
    {
886
        return self::query()->selectRaw('id, username, SUM(grabs) as grabs')->groupBy('id', 'username')->having('grabs', '>', 0)->orderBy('grabs', 'desc')->limit(10)->get();
887
    }
888
889
    /**
890
     * @return \Illuminate\Database\Eloquent\Collection|\Illuminate\Support\Collection|static[]
891
     */
892
    public static function getUsersByMonth()
893
    {
894
        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();
895
    }
896
897
    /**
898
     * @param $serverUrl
899
     * @param $uid
900
     * @param $emailTo
901
     *
902
     * @return string
903
     * @throws \Exception
904
     */
905
    public static function sendInvite($serverUrl, $uid, $emailTo): string
906
    {
907
        $token = \Token::randomString(40);
908
        $url = $serverUrl.'register?invitecode='.$token;
909
910
        Invitation::addInvite($uid, $token);
911
        SendInviteEmail::dispatch($emailTo, $uid, $url);
912
913
        return $url;
914
    }
915
916
    /**
917
     * Deletes old rows FROM the user_requests and user_downloads tables.
918
     * if site->userdownloadpurgedays SET to 0 then all release history is removed but
919
     * the download/request rows must remain for at least one day to allow the role based
920
     * limits to apply.
921
     *
922
     * @param int $days
923
     */
924
    public static function pruneRequestHistory($days = 0): void
925
    {
926
        if ($days === 0) {
927
            $days = 1;
928
            UserDownload::query()->update(['releases_id' => null]);
929
        }
930
931
        UserRequest::query()->where('timestamp', '<', now()->subDays($days))->delete();
932
        UserDownload::query()->where('timestamp', '<', now()->subDays($days))->delete();
933
    }
934
935
    /**
936
     * Deletes users that have not verified their accounts for 3 or more days.
937
     */
938
    public static function deleteUnVerified(): void
939
    {
940
        static::whereVerified(0)->where('created_at', '<', now()->subDays(3))->delete();
941
    }
942
}
943