Completed
Push — dev ( bc6315...df572a )
by Darko
06:54
created

User::signUp()   B

Complexity

Conditions 7
Paths 9

Size

Total Lines 36
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

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