Completed
Push — dev ( d9c7ba...33e29e )
by Darko
09:16
created

User::signUp()   B

Complexity

Conditions 7
Paths 9

Size

Total Lines 35
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 0
Metric Value
eloc 20
dl 0
loc 35
ccs 0
cts 10
cp 0
rs 8.6666
c 0
b 0
f 0
cc 7
nc 9
nop 10
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\Support\Arr;
7
use Illuminate\Support\Str;
8
use Illuminate\Http\Request;
9
use App\Jobs\SendInviteEmail;
10
use Illuminate\Support\Carbon;
11
use Spatie\Permission\Models\Role;
12
use Illuminate\Support\Facades\Hash;
13
use App\Jobs\SendAccountExpiredEmail;
14
use Spatie\Permission\Traits\HasRoles;
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
     * @return int
391
     */
392
    public static function updateExpiredRoles(): int
393
    {
394
        $data = self::query()->whereDate('rolechangedate', '<', now())->get();
395
396
        foreach ($data as $u) {
397
            $user = self::find($u['id']);
398
            $user->update(['roles_id' => self::ROLE_USER, 'rolechangedate' => null]);
399
            $user->syncRoles('User');
400
            SendAccountExpiredEmail::dispatch($user);
401
        }
402
403
        return self::SUCCESS;
404
    }
405
406
    /**
407
     * @param        $start
408
     * @param        $offset
409
     * @param        $orderBy
410
     * @param string $userName
411
     * @param string $email
412
     * @param string $host
413
     * @param string $role
414
     * @param bool   $apiRequests
415
     *
416
     * @return \Illuminate\Database\Eloquent\Collection
417
     * @throws \Throwable
418
     */
419
    public static function getRange($start, $offset, $orderBy, $userName = '', $email = '', $host = '', $role = '', $apiRequests = false)
420
    {
421
        if ($apiRequests) {
422
            UserRequest::clearApiRequests(false);
423
            $query = "
424
				SELECT users.*, roles.name AS rolename, COUNT(user_requests.id) AS apirequests
425
				FROM users
426
				INNER JOIN roles ON roles.id = users.roles_id
427
				LEFT JOIN user_requests ON user_requests.users_id = users.id
428
				WHERE users.id != 0 %s %s %s %s
429
				AND email != '[email protected]'
430
				GROUP BY users.id
431
				ORDER BY %s %s %s ";
432
        } else {
433
            $query = '
434
				SELECT users.*, roles.name AS rolename
435
				FROM users
436
				INNER JOIN roles ON roles.id = users.roles_id
437
				WHERE 1=1 %s %s %s %s
438
				ORDER BY %s %s %s';
439
        }
440
        $order = self::getBrowseOrder($orderBy);
441
442
        return self::fromQuery(
443
            sprintf(
444
                $query,
445
                ! empty($userName) ? 'AND users.username '.'LIKE '.escapeString('%'.$userName.'%') : '',
446
                ! empty($email) ? 'AND users.email '.'LIKE '.escapeString('%'.$email.'%') : '',
447
                ! empty($host) ? 'AND users.host '.'LIKE '.escapeString('%'.$host.'%') : '',
448
                (! empty($role) ? ('AND users.roles_id = '.$role) : ''),
449
                $order[0],
450
                $order[1],
451
                ($start === false ? '' : ('LIMIT '.$offset.' OFFSET '.$start))
452
            )
453
        );
454
    }
455
456
    /**
457
     * Get sort types for sorting users on the web page user list.
458
     *
459
     * @param $orderBy
460
     *
461
     * @return string[]
462
     */
463
    public static function getBrowseOrder($orderBy): array
464
    {
465
        $order = (empty($orderBy) ? 'username_desc' : $orderBy);
466
        $orderArr = explode('_', $order);
467
        switch ($orderArr[0]) {
468
            case 'username':
469
                $orderField = 'username';
470
                break;
471
            case 'email':
472
                $orderField = 'email';
473
                break;
474
            case 'host':
475
                $orderField = 'host';
476
                break;
477
            case 'createdat':
478
                $orderField = 'created_at';
479
                break;
480
            case 'lastlogin':
481
                $orderField = 'lastlogin';
482
                break;
483
            case 'apiaccess':
484
                $orderField = 'apiaccess';
485
                break;
486
            case 'grabs':
487
                $orderField = 'grabs';
488
                break;
489
            case 'role':
490
                $orderField = 'rolename';
491
                break;
492
            case 'rolechangedate':
493
                $orderField = 'rolechangedate';
494
                break;
495
            case 'verification':
496
                $orderField = 'verified';
497
                break;
498
            default:
499
                $orderField = 'username';
500
                break;
501
        }
502
        $orderSort = (isset($orderArr[1]) && preg_match('/^asc|desc$/i', $orderArr[1])) ? $orderArr[1] : 'desc';
503
504
        return [$orderField, $orderSort];
505
    }
506
507
    /**
508
     * Verify a password against a hash.
509
     *
510
     * Automatically update the hash if it needs to be.
511
     *
512
     * @param string $password Password to check against hash.
513
     * @param string|bool $hash     Hash to check against password.
514
     * @param int    $userID   ID of the user.
515
     *
516
     * @return bool
517
     */
518
    public static function checkPassword($password, $hash, $userID = -1): bool
519
    {
520
        if (Hash::check($password, $hash) === false) {
521
            return false;
522
        }
523
524
        // Update the hash if it needs to be.
525
        if (is_numeric($userID) && $userID > 0 && Hash::needsRehash($hash)) {
526
            $hash = self::hashPassword($password);
527
528
            if ($hash !== false) {
0 ignored issues
show
introduced by
The condition $hash !== false is always true.
Loading history...
529
                self::find($userID)->update(['password' => $hash]);
530
            }
531
        }
532
533
        return true;
534
    }
535
536
    /**
537
     * @param $uid
538
     *
539
     * @return int
540
     */
541
    public static function updateRssKey($uid): int
542
    {
543
        self::find($uid)->update(['api_token' => md5(Password::getRepository()->createNewToken())]);
544
545
        return self::SUCCESS;
546
    }
547
548
    /**
549
     * @param $id
550
     * @param $guid
551
     *
552
     * @return int
553
     */
554
    public static function updatePassResetGuid($id, $guid): int
555
    {
556
        self::find($id)->update(['resetguid' => $guid]);
557
558
        return self::SUCCESS;
559
    }
560
561
    /**
562
     * @param int    $id
563
     * @param string $password
564
     *
565
     * @return int
566
     */
567
    public static function updatePassword(int $id, string $password): int
568
    {
569
        self::find($id)->update(['password' => self::hashPassword($password), 'userseed' => md5(Str::uuid()->toString())]);
570
571
        return self::SUCCESS;
572
    }
573
574
    /**
575
     * @param $password
576
     * @return mixed
577
     */
578
    public static function hashPassword($password)
579
    {
580
        return Hash::make($password);
581
    }
582
583
    /**
584
     * @param $guid
585
     *
586
     * @return \Illuminate\Database\Eloquent\Model|static
587
     * @throws \Illuminate\Database\Eloquent\ModelNotFoundException
588
     */
589
    public static function getByPassResetGuid(string $guid)
590
    {
591
        return self::whereResetguid($guid)->first();
592
    }
593
594
    /**
595
     * @param     $id
596
     * @param int $num
597
     */
598
    public static function incrementGrabs(int $id, $num = 1): void
599
    {
600
        self::find($id)->increment('grabs', $num);
601
    }
602
603
    /**
604
     * Check if the user is in the database, and if their API key is good, return user data if so.
605
     *
606
     *
607
     * @param $userID
608
     * @param $rssToken
609
     *
610
     * @return bool|\Illuminate\Database\Eloquent\Model|null|static
611
     */
612
    public static function getByIdAndRssToken($userID, $rssToken)
613
    {
614
        $user = self::query()->where(['id' => $userID, 'api_token' => $rssToken])->first();
615
        if ($user === null) {
616
            return false;
617
        }
618
619
        return $user;
620
    }
621
622
    /**
623
     * @param string $rssToken
624
     * @return \Illuminate\Database\Eloquent\Model|null|static
625
     */
626
    public static function getByRssToken(string $rssToken)
627
    {
628
        return self::whereApiToken($rssToken)->first();
629
    }
630
631
    /**
632
     * @param $url
633
     *
634
     * @return bool
635
     */
636
    public static function isValidUrl($url): bool
637
    {
638
        return (! preg_match('/^(http|https|ftp):\/\/([A-Z0-9][A-Z0-9_-]*(?:\.[A-Z0-9][A-Z0-9_-]*)+):?(\d+)?\/?/i', $url)) ? false : true;
639
    }
640
641
    /**
642
     * Generate a random username.
643
     *
644
     *
645
     * @return string
646
     */
647
    public static function generateUsername(): string
648
    {
649
        return Str::random();
650
    }
651
652
    /**
653
     * @param int $length
654
     *
655
     * @return string
656
     * @throws \Exception
657
     */
658
    public static function generatePassword($length = 15): string
659
    {
660
        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...
661
    }
662
663
    /**
664
     * Register a new user.
665
     *
666
     * @param        $userName
667
     * @param        $password
668
     * @param        $email
669
     * @param        $host
670
     * @param        $notes
671
     * @param int $invites
672
     * @param string $inviteCode
673
     * @param bool $forceInviteMode
674
     *
675
     * @param int $role
676
     * @param bool $validate
677
     * @return bool|int
678
     * @throws \Exception
679
     */
680
    public static function signUp($userName, $password, $email, $host, $notes, $invites = Invitation::DEFAULT_INVITES, $inviteCode = '', $forceInviteMode = false, $role = self::ROLE_USER, $validate = true)
681
    {
682
        $user = [
683
            'username' => trim($userName),
684
            'password' => trim($password),
685
            'email' => trim($email),
686
        ];
687
688
        if ($validate) {
689
            $validator = Validator::make($user, [
690
                'username' => ['required', 'string', 'min:5', 'max:255', 'unique:users'],
691
                'email' => ['required', 'string', 'email', 'max:255', 'unique:users', 'indisposable'],
692
                'password' => ['required', 'string', 'min:8', 'confirmed', 'regex:/^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$/'],
693
            ]);
694
695
            if ($validator->fails()) {
696
                $error = implode('', Arr::collapse($validator->errors()->toArray()));
697
                return $error;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $error returns the type string which is incompatible with the documented return type boolean|integer.
Loading history...
698
            }
699
        }
700
701
        // Make sure this is the last check, as if a further validation check failed, the invite would still have been used up.
702
        $invitedBy = 0;
703
        if (! $forceInviteMode && (int) Settings::settingValue('..registerstatus') === Settings::REGISTER_STATUS_INVITE) {
704
            if ($inviteCode === '') {
705
                return self::ERR_SIGNUP_BADINVITECODE;
706
            }
707
708
            $invitedBy = self::checkAndUseInvite($inviteCode);
709
            if ($invitedBy < 0) {
710
                return self::ERR_SIGNUP_BADINVITECODE;
711
            }
712
        }
713
714
        return self::add($user['username'], $user['password'], $user['email'], $role, $notes, $host, $invites, $invitedBy);
715
    }
716
717
    /**
718
     * If a invite is used, decrement the person who invited's invite count.
719
     *
720
     * @param string $inviteCode
721
     *
722
     * @return int
723
     */
724
    public static function checkAndUseInvite(string $inviteCode): int
725
    {
726
        $invite = Invitation::getInvite($inviteCode);
727
        if (! $invite) {
728
            return -1;
729
        }
730
731
        self::query()->where('id', $invite['users_id'])->decrement('invites');
732
        Invitation::deleteInvite($inviteCode);
733
734
        return $invite['users_id'];
735
    }
736
737
    /**
738
     * Add a new user.
739
     *
740
     * @param string    $userName
741
     * @param  string   $password
742
     * @param  string   $email
743
     * @param int    $role
744
     * @param string    $notes
745
     * @param string    $host
746
     * @param int $invites
747
     * @param int $invitedBy
748
     *
749
     * @return bool|int
750
     * @throws \Exception
751
     */
752
    public static function add($userName, $password, $email, $role, $notes = '', $host = '', $invites = Invitation::DEFAULT_INVITES, $invitedBy = 0)
753
    {
754
        $password = self::hashPassword($password);
755
        if (! $password) {
756
            return false;
757
        }
758
759
        $storeips = (int) Settings::settingValue('..storeuserips') === 1 ? $host : '';
760
761
        $user = self::create(
762
            [
763
                'username' => $userName,
764
                'password' => $password,
765
                'email' => $email,
766
                'host' => $storeips,
767
                'roles_id' => $role,
768
                'invites' => $invites,
769
                'invitedby' => (int) $invitedBy === 0 ? null : $invitedBy,
770
                'notes' => $notes,
771
            ]
772
        );
773
774
        return $user->id;
775
    }
776
777
    /**
778
     * Get the list of categories the user has excluded.
779
     *
780
     * @param int $userID ID of the user.
781
     *
782
     * @return array
783
     * @throws \Exception
784
     */
785
    public static function getCategoryExclusionById($userID): array
786
    {
787
        $ret = [];
788
789
        $user = self::find($userID);
790
791
        $userAllowed = $user->getDirectPermissions()->pluck('name')->toArray();
792
        $roleAllowed = $user->getAllPermissions()->pluck('name')->toArray();
793
794
        $allowed = array_intersect($roleAllowed, $userAllowed);
795
796
        $cats = ['view console', 'view movies', 'view audio', 'view tv', 'view pc', 'view adult', 'view books', 'view other'];
797
798
        if (! empty($allowed)) {
799
            foreach ($cats as $cat) {
800
                if (! \in_array($cat, $allowed, false)) {
801
                    switch ($cat) {
802
                        case 'view console':
803
                            $ret[] = 1000;
804
                            continue 2;
805
                        case 'view movies':
806
                            $ret[] = 2000;
807
                            continue 2;
808
                        case 'view audio':
809
                            $ret[] = 3000;
810
                            continue 2;
811
                        case 'view pc':
812
                            $ret[] = 4000;
813
                            continue 2;
814
                        case 'view tv':
815
                            $ret[] = 5000;
816
                            continue 2;
817
                        case 'view adult':
818
                            $ret[] = 6000;
819
                            continue 2;
820
                        case 'view books':
821
                            $ret[] = 7000;
822
                            continue 2;
823
                        case 'view other':
824
                            $ret[] = 1;
825
826
                    }
827
                }
828
            }
829
        }
830
831
        $exclusion = Category::query()->whereIn('root_categories_id', $ret)->pluck('id')->toArray();
832
833
        return $exclusion;
834
    }
835
836
    /**
837
     * @param \Illuminate\Http\Request $request
838
     * @return array
839
     * @throws \Exception
840
     */
841
    public static function getCategoryExclusionForApi(Request $request): array
842
    {
843
        $apiToken = $request->has('api_token') ? $request->input('api_token') : $request->input('apikey');
844
        $user = self::getByRssToken($apiToken);
845
846
        return self::getCategoryExclusionById($user->id);
847
    }
848
849
    /**
850
     * @return \Illuminate\Database\Eloquent\Collection|\Illuminate\Support\Collection|static[]
851
     */
852
    public static function getTopGrabbers()
853
    {
854
        return self::query()->selectRaw('id, username, SUM(grabs) as grabs')->groupBy('id', 'username')->having('grabs', '>', 0)->orderBy('grabs', 'desc')->limit(10)->get();
855
    }
856
857
    /**
858
     * @return \Illuminate\Database\Eloquent\Collection|\Illuminate\Support\Collection|static[]
859
     */
860
    public static function getUsersByMonth()
861
    {
862
        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();
863
    }
864
865
    /**
866
     * @param $serverUrl
867
     * @param $uid
868
     * @param $emailTo
869
     *
870
     * @return string
871
     * @throws \Exception
872
     */
873
    public static function sendInvite($serverUrl, $uid, $emailTo): string
874
    {
875
        $token = \Token::randomString(40);
876
        $url = $serverUrl.'register?invitecode='.$token;
877
878
        Invitation::addInvite($uid, $token);
879
        SendInviteEmail::dispatch($emailTo, $uid, $url);
880
881
        return $url;
882
    }
883
884
    /**
885
     * Deletes old rows FROM the user_requests and user_downloads tables.
886
     * if site->userdownloadpurgedays SET to 0 then all release history is removed but
887
     * the download/request rows must remain for at least one day to allow the role based
888
     * limits to apply.
889
     *
890
     * @param int $days
891
     */
892
    public static function pruneRequestHistory($days = 0): void
893
    {
894
        if ($days === 0) {
895
            $days = 1;
896
            UserDownload::query()->update(['releases_id' => null]);
897
        }
898
899
        UserRequest::query()->where('timestamp', '<', now()->subDays($days))->delete();
900
        UserDownload::query()->where('timestamp', '<', now()->subDays($days))->delete();
901
    }
902
903
    /**
904
     * Deletes users that have not verified their accounts for 3 or more days.
905
     */
906
    public static function deleteUnVerified(): void
907
    {
908
        static::whereVerified(0)->where('created_at', '<', now()->subDays(3))->delete();
909
    }
910
}
911