Passed
Pull Request — dev (#1123)
by
unknown
06:52
created

User::add()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 23
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
eloc 14
c 0
b 0
f 0
dl 0
loc 23
ccs 0
cts 9
cp 0
rs 9.7998
cc 4
nc 3
nop 8
crap 20

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