User::signUp()   B
last analyzed

Complexity

Conditions 7
Paths 9

Size

Total Lines 34
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 19
dl 0
loc 34
rs 8.8333
c 0
b 0
f 0
cc 7
nc 9
nop 10

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 Carbon\CarbonImmutable;
8
use Illuminate\Database\Eloquent\Builder;
9
use Illuminate\Database\Eloquent\Collection;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, App\Models\Collection. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
10
use Illuminate\Database\Eloquent\Model;
11
use Illuminate\Database\Eloquent\ModelNotFoundException;
12
use Illuminate\Database\Eloquent\Relations\BelongsTo;
13
use Illuminate\Database\Eloquent\Relations\HasMany;
14
use Illuminate\Database\Eloquent\Relations\HasOne;
15
use Illuminate\Database\Eloquent\SoftDeletes;
16
use Illuminate\Foundation\Auth\User as Authenticatable;
17
use Illuminate\Http\Request;
18
use Illuminate\Notifications\Notifiable;
19
use Illuminate\Support\Arr;
20
use Illuminate\Support\Carbon;
21
use Illuminate\Support\Facades\Hash;
22
use Illuminate\Support\Facades\Password;
23
use Illuminate\Support\Facades\Validator;
24
use Illuminate\Support\Str;
25
use Jrean\UserVerification\Traits\UserVerification;
26
use Spatie\Permission\Models\Role;
27
use Spatie\Permission\Traits\HasRoles;
0 ignored issues
show
Bug introduced by
The type Spatie\Permission\Traits\HasRoles 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...
28
29
/**
30
 * App\Models\User.
31
 *
32
 * App\Models\User.
33
 *
34
 * @property int $id
35
 * @property string $username
36
 * @property string|null $firstname
37
 * @property string|null $lastname
38
 * @property string $email
39
 * @property string $password
40
 * @property int $user_roles_id FK to roles.id
41
 * @property string|null $host
42
 * @property int $grabs
43
 * @property string $rsstoken
44
 * @property \Carbon\Carbon|null $created_at
45
 * @property \Carbon\Carbon|null $updated_at
46
 * @property string|null $resetguid
47
 * @property string|null $lastlogin
48
 * @property string|null $apiaccess
49
 * @property int $invites
50
 * @property int|null $invitedby
51
 * @property int $movieview
52
 * @property int $xxxview
53
 * @property int $musicview
54
 * @property int $consoleview
55
 * @property int $bookview
56
 * @property int $gameview
57
 * @property string|null $saburl
58
 * @property string|null $sabapikey
59
 * @property bool|null $sabapikeytype
60
 * @property bool|null $sabpriority
61
 * @property string|null $nzbgeturl
62
 * @property string|null $nzbgetusername
63
 * @property string|null $nzbgetpassword
64
 * @property string|null $nzbvortex_api_key
65
 * @property string|null $nzbvortex_server_url
66
 * @property string $notes
67
 * @property string|null $cp_url
68
 * @property string|null $cp_api
69
 * @property string|null $style
70
 * @property string|null $rolechangedate When does the role expire
71
 * @property string|null $remember_token
72
 * @property-read Collection|\App\Models\ReleaseComment[] $comment
73
 * @property-read Collection|\App\Models\UserDownload[] $download
74
 * @property-read Collection|\App\Models\DnzbFailure[] $failedRelease
75
 * @property-read Collection|\App\Models\Invitation[] $invitation
76
 * @property-read \Illuminate\Notifications\DatabaseNotificationCollection|\Illuminate\Notifications\DatabaseNotification[] $notifications
77
 * @property-read Collection|\App\Models\UsersRelease[] $release
78
 * @property-read Collection|\App\Models\UserRequest[] $request
79
 * @property-read Collection|\App\Models\UserSerie[] $series
80
 *
81
 * @method static Builder|\App\Models\User whereApiaccess($value)
82
 * @method static Builder|\App\Models\User whereBookview($value)
83
 * @method static Builder|\App\Models\User whereConsoleview($value)
84
 * @method static Builder|\App\Models\User whereCpApi($value)
85
 * @method static Builder|\App\Models\User whereCpUrl($value)
86
 * @method static Builder|\App\Models\User whereCreatedAt($value)
87
 * @method static Builder|\App\Models\User whereEmail($value)
88
 * @method static Builder|\App\Models\User whereFirstname($value)
89
 * @method static Builder|\App\Models\User whereGameview($value)
90
 * @method static Builder|\App\Models\User whereGrabs($value)
91
 * @method static Builder|\App\Models\User whereHost($value)
92
 * @method static Builder|\App\Models\User whereId($value)
93
 * @method static Builder|\App\Models\User whereInvitedby($value)
94
 * @method static Builder|\App\Models\User whereInvites($value)
95
 * @method static Builder|\App\Models\User whereLastlogin($value)
96
 * @method static Builder|\App\Models\User whereLastname($value)
97
 * @method static Builder|\App\Models\User whereMovieview($value)
98
 * @method static Builder|\App\Models\User whereMusicview($value)
99
 * @method static Builder|\App\Models\User whereNotes($value)
100
 * @method static Builder|\App\Models\User whereNzbgetpassword($value)
101
 * @method static Builder|\App\Models\User whereNzbgeturl($value)
102
 * @method static Builder|\App\Models\User whereNzbgetusername($value)
103
 * @method static Builder|\App\Models\User whereNzbvortexApiKey($value)
104
 * @method static Builder|\App\Models\User whereNzbvortexServerUrl($value)
105
 * @method static Builder|\App\Models\User wherePassword($value)
106
 * @method static Builder|\App\Models\User whereRememberToken($value)
107
 * @method static Builder|\App\Models\User whereResetguid($value)
108
 * @method static Builder|\App\Models\User whereRolechangedate($value)
109
 * @method static Builder|\App\Models\User whereRsstoken($value)
110
 * @method static Builder|\App\Models\User whereSabapikey($value)
111
 * @method static Builder|\App\Models\User whereSabapikeytype($value)
112
 * @method static Builder|\App\Models\User whereSabpriority($value)
113
 * @method static Builder|\App\Models\User whereSaburl($value)
114
 * @method static Builder|\App\Models\User whereStyle($value)
115
 * @method static Builder|\App\Models\User whereUpdatedAt($value)
116
 * @method static Builder|\App\Models\User whereUserRolesId($value)
117
 * @method static Builder|\App\Models\User whereUsername($value)
118
 * @method static Builder|\App\Models\User whereXxxview($value)
119
 * @method static Builder|\App\Models\User whereVerified($value)
120
 * @method static Builder|\App\Models\User whereApiToken($value)
121
 *
122
 * @mixin \Eloquent
123
 *
124
 * @property int $roles_id FK to roles.id
125
 * @property string $api_token
126
 * @property int $rate_limit
127
 * @property string|null $email_verified_at
128
 * @property int $verified
129
 * @property string|null $verification_token
130
 * @property-read Collection|\Junaidnasir\Larainvite\Models\LaraInviteModel[] $invitationPending
131
 * @property-read Collection|\Junaidnasir\Larainvite\Models\LaraInviteModel[] $invitationSuccess
132
 * @property-read Collection|\Junaidnasir\Larainvite\Models\LaraInviteModel[] $invitations
133
 * @property-read Collection|\Spatie\Permission\Models\Permission[] $permissions
134
 * @property-read Role $role
135
 * @property-read Collection|\Spatie\Permission\Models\Role[] $roles
136
 *
137
 * @method static Builder|\App\Models\User newModelQuery()
138
 * @method static Builder|\App\Models\User newQuery()
139
 * @method static Builder|\App\Models\User permission($permissions)
140
 * @method static Builder|\App\Models\User query()
141
 * @method static Builder|\App\Models\User whereEmailVerifiedAt($value)
142
 * @method static Builder|\App\Models\User whereRateLimit($value)
143
 * @method static Builder|\App\Models\User whereRolesId($value)
144
 * @method static Builder|\App\Models\User whereVerificationToken($value)
145
 */
146
class User extends Authenticatable
147
{
148
    use HasRoles, Notifiable, SoftDeletes, UserVerification;
149
150
    public const ERR_SIGNUP_BADUNAME = -1;
151
152
    public const ERR_SIGNUP_BADPASS = -2;
153
154
    public const ERR_SIGNUP_BADEMAIL = -3;
155
156
    public const ERR_SIGNUP_UNAMEINUSE = -4;
157
158
    public const ERR_SIGNUP_EMAILINUSE = -5;
159
160
    public const ERR_SIGNUP_BADINVITECODE = -6;
161
162
    public const SUCCESS = 1;
163
164
    public const ROLE_USER = 1;
165
166
    public const ROLE_ADMIN = 2;
167
168
    /**
169
     * Users SELECT queue type.
170
     */
171
    public const QUEUE_NONE = 0;
172
173
    public const QUEUE_SABNZBD = 1;
174
175
    public const QUEUE_NZBGET = 2;
176
177
    /**
178
     * @var string
179
     */
180
181
    /**
182
     * @var bool
183
     */
184
    protected $dateFormat = false;
185
186
    /**
187
     * @var array
188
     */
189
    protected $hidden = ['remember_token', 'password'];
190
191
    /**
192
     * @var array
193
     */
194
    protected $guarded = [];
195
196
    protected function getDefaultGuardName(): string
197
    {
198
        return 'web';
199
    }
200
201
    public function role(): BelongsTo
202
    {
203
        return $this->belongsTo(Role::class, 'roles_id');
204
    }
205
206
    public function request(): HasMany
207
    {
208
        return $this->hasMany(UserRequest::class, 'users_id');
209
    }
210
211
    public function download(): HasMany
212
    {
213
        return $this->hasMany(UserDownload::class, 'users_id');
214
    }
215
216
    public function release(): HasMany
217
    {
218
        return $this->hasMany(UsersRelease::class, 'users_id');
219
    }
220
221
    public function series(): HasMany
222
    {
223
        return $this->hasMany(UserSerie::class, 'users_id');
224
    }
225
226
    public function invitation(): HasMany
227
    {
228
        return $this->hasMany(Invitation::class, 'invited_by');
229
    }
230
231
    public function failedRelease(): HasMany
232
    {
233
        return $this->hasMany(DnzbFailure::class, 'users_id');
234
    }
235
236
    public function comment(): HasMany
237
    {
238
        return $this->hasMany(ReleaseComment::class, 'users_id');
239
    }
240
241
    /**
242
     * @throws \Exception
243
     */
244
    public static function deleteUser($id): void
245
    {
246
        self::find($id)->delete();
247
    }
248
249
    public static function getCount(?string $role = null, ?string $username = '', ?string $host = '', ?string $email = ''): int
250
    {
251
        $res = self::query()->where('email', '<>', '[email protected]');
252
253
        if (! empty($role)) {
254
            $res->where('roles_id', $role);
255
        }
256
257
        if ($username !== '') {
258
            $res->where('username', 'like', '%'.$username.'%');
259
        }
260
261
        if ($host !== '') {
262
            $res->where('host', 'like', '%'.$host.'%');
263
        }
264
265
        if ($email !== '') {
266
            $res->where('email', 'like', '%'.$email.'%');
267
        }
268
269
        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...
270
    }
271
272
    public static function updateUser(int $id, string $userName, ?string $email, int $grabs, int $role, ?string $notes, int $invites, int $movieview, int $musicview, int $gameview, int $xxxview, int $consoleview, int $bookview, string $style = 'None'): int
273
    {
274
        $userName = trim($userName);
275
276
        $rateLimit = Role::query()->where('id', $role)->first();
277
278
        $sql = [
279
            'username' => $userName,
280
            'grabs' => $grabs,
281
            'roles_id' => $role,
282
            'notes' => substr($notes, 0, 255),
0 ignored issues
show
Bug introduced by
It seems like $notes can also be of type null; however, parameter $string of substr() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

282
            'notes' => substr(/** @scrutinizer ignore-type */ $notes, 0, 255),
Loading history...
283
            'invites' => $invites,
284
            'movieview' => $movieview,
285
            'musicview' => $musicview,
286
            'gameview' => $gameview,
287
            'xxxview' => $xxxview,
288
            'consoleview' => $consoleview,
289
            'bookview' => $bookview,
290
            'style' => $style,
291
            'rate_limit' => $rateLimit ? $rateLimit['rate_limit'] : 60,
292
        ];
293
294
        if (! empty($email)) {
295
            $email = trim($email);
296
            $sql += ['email' => $email];
297
        }
298
299
        $user = self::find($id);
300
        $user->update($sql);
301
        $user->syncRoles([$rateLimit['name']]);
302
303
        return self::SUCCESS;
304
    }
305
306
    /**
307
     * @return User|Builder|Model|object|null
308
     */
309
    public static function getByUsername(string $userName)
310
    {
311
        return self::whereUsername($userName)->first();
312
    }
313
314
    /**
315
     * @return Model|static
316
     *
317
     * @throws ModelNotFoundException
318
     */
319
    public static function getByEmail(string $email)
320
    {
321
        return self::whereEmail($email)->first();
322
    }
323
324
    public static function updateUserRole(int $uid, int|string $role): bool
325
    {
326
        if (is_int($role)) {
327
            $roleQuery = Role::query()->where('id', $role)->first();
328
        } else {
329
            $roleQuery = Role::query()->where('name', $role)->first();
330
        }
331
        $roleName = $roleQuery->name;
332
333
        $user = self::find($uid);
334
        $user->syncRoles([$roleName]);
335
336
        return self::find($uid)->update(['roles_id' => $roleQuery->id]);
337
    }
338
339
    public static function updateUserRoleChangeDate(int $uid, $date = '', int $addYear = 0): void
340
    {
341
        $user = self::find($uid);
342
        $currRoleExp = $user->rolechangedate ?? now()->toDateTimeString();
343
        if (! empty($date)) {
344
            $user->update(['rolechangedate' => $date]);
345
        }
346
        if (empty($date) && ! empty($addYear)) {
347
            $user->update(['rolechangedate' => Carbon::createFromDate($currRoleExp)->addYears($addYear)]);
348
        }
349
    }
350
351
    public static function updateExpiredRoles(): void
352
    {
353
        $now = CarbonImmutable::now();
354
        $period = [
355
            'day' => $now->addDay(),
356
            'week' => $now->addWeek(),
357
            'month' => $now->addMonth(),
358
        ];
359
360
        foreach ($period as $value) {
361
            $users = self::query()->whereDate('rolechangedate', '=', $value)->get();
362
            $days = $now->diffInDays($value, true);
363
            foreach ($users as $user) {
364
                SendAccountWillExpireEmail::dispatch($user, $days)->onQueue('emails');
365
            }
366
        }
367
        foreach (self::query()->whereDate('rolechangedate', '<', $now)->get() as $expired) {
368
            $expired->update(['roles_id' => self::ROLE_USER, 'rolechangedate' => null]);
369
            $expired->syncRoles(['User']);
370
            SendAccountExpiredEmail::dispatch($expired)->onQueue('emails');
371
        }
372
    }
373
374
    /**
375
     * @throws \Throwable
376
     */
377
    public static function getRange($start, $offset, $orderBy, ?string $userName = '', ?string $email = '', ?string $host = '', ?string $role = '', bool $apiRequests = false): Collection
378
    {
379
        if ($apiRequests) {
380
            UserRequest::clearApiRequests(false);
381
            $query = "
382
				SELECT users.*, roles.name AS rolename, COUNT(user_requests.id) AS apirequests
383
				FROM users
384
				INNER JOIN roles ON roles.id = users.roles_id
385
				LEFT JOIN user_requests ON user_requests.users_id = users.id
386
				WHERE users.id != 0 %s %s %s %s
387
				AND email != '[email protected]'
388
				GROUP BY users.id
389
				ORDER BY %s %s %s ";
390
        } else {
391
            $query = '
392
				SELECT users.*, roles.name AS rolename
393
				FROM users
394
				INNER JOIN roles ON roles.id = users.roles_id
395
				WHERE 1=1 %s %s %s %s
396
				ORDER BY %s %s %s';
397
        }
398
        $order = self::getBrowseOrder($orderBy);
399
400
        return self::fromQuery(
401
            sprintf(
402
                $query,
403
                ! empty($userName) ? 'AND users.username '.'LIKE '.escapeString('%'.$userName.'%') : '',
404
                ! empty($email) ? 'AND users.email '.'LIKE '.escapeString('%'.$email.'%') : '',
405
                ! empty($host) ? 'AND users.host '.'LIKE '.escapeString('%'.$host.'%') : '',
406
                (! empty($role) ? ('AND users.roles_id = '.$role) : ''),
407
                $order[0],
408
                $order[1],
409
                ($start === false ? '' : ('LIMIT '.$offset.' OFFSET '.$start))
410
            )
411
        );
412
    }
413
414
    /**
415
     * Get sort types for sorting users on the web page user list.
416
     *
417
     * @return string[]
418
     */
419
    public static function getBrowseOrder($orderBy): array
420
    {
421
        $order = (empty($orderBy) ? 'username_desc' : $orderBy);
422
        $orderArr = explode('_', $order);
423
        $orderField = match ($orderArr[0]) {
424
            'email' => 'email',
425
            'host' => 'host',
426
            'createdat' => 'created_at',
427
            'lastlogin' => 'lastlogin',
428
            'apiaccess' => 'apiaccess',
429
            'grabs' => 'grabs',
430
            'role' => 'rolename',
431
            'rolechangedate' => 'rolechangedate',
432
            'verification' => 'verified',
433
            default => 'username',
434
        };
435
        $orderSort = (isset($orderArr[1]) && preg_match('/^asc|desc$/i', $orderArr[1])) ? $orderArr[1] : 'desc';
436
437
        return [$orderField, $orderSort];
438
    }
439
440
    /**
441
     * Verify a password against a hash.
442
     *
443
     * Automatically update the hash if it needs to be.
444
     *
445
     * @param  string  $password  Password to check against hash.
446
     * @param  bool|string  $hash  Hash to check against password.
447
     * @param  int  $userID  ID of the user.
448
     */
449
    public static function checkPassword(string $password, bool|string $hash, int $userID = -1): bool
450
    {
451
        if (Hash::check($password, $hash) === false) {
452
            return false;
453
        }
454
455
        // Update the hash if it needs to be.
456
        if (is_numeric($userID) && $userID > 0 && Hash::needsRehash($hash)) {
457
            $hash = self::hashPassword($password);
458
459
            if ($hash !== false) {
0 ignored issues
show
introduced by
The condition $hash !== false is always true.
Loading history...
460
                self::find($userID)->update(['password' => $hash]);
461
            }
462
        }
463
464
        return true;
465
    }
466
467
    public static function updateRssKey($uid): int
468
    {
469
        self::find($uid)->update(['api_token' => md5(Password::getRepository()->createNewToken())]);
0 ignored issues
show
Bug introduced by
The method createNewToken() does not exist on Illuminate\Auth\Passwords\TokenRepositoryInterface. Did you maybe mean create()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

469
        self::find($uid)->update(['api_token' => md5(Password::getRepository()->/** @scrutinizer ignore-call */ createNewToken())]);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
470
471
        return self::SUCCESS;
472
    }
473
474
    public static function updatePassResetGuid($id, $guid): int
475
    {
476
        self::find($id)->update(['resetguid' => $guid]);
477
478
        return self::SUCCESS;
479
    }
480
481
    public static function updatePassword(int $id, string $password): int
482
    {
483
        self::find($id)->update(['password' => self::hashPassword($password)]);
484
485
        return self::SUCCESS;
486
    }
487
488
    public static function hashPassword($password): string
489
    {
490
        return Hash::make($password);
491
    }
492
493
    /**
494
     * @return Model|static
495
     *
496
     * @throws ModelNotFoundException
497
     */
498
    public static function getByPassResetGuid(string $guid)
499
    {
500
        return self::whereResetguid($guid)->first();
501
    }
502
503
    public static function incrementGrabs(int $id, int $num = 1): void
504
    {
505
        self::find($id)->increment('grabs', $num);
506
    }
507
508
    /**
509
     * @return Model|null|static
510
     */
511
    public static function getByRssToken(string $rssToken)
512
    {
513
        return self::whereApiToken($rssToken)->first();
514
    }
515
516
    public static function isValidUrl($url): bool
517
    {
518
        return (! preg_match('/^(http|https|ftp):\/\/([A-Z0-9][A-Z0-9_-]*(?:\.[A-Z0-9][A-Z0-9_-]*)+):?(\d+)?\/?/i', $url)) ? false : true;
519
    }
520
521
    /**
522
     * @throws \Exception
523
     */
524
    public static function generatePassword(int $length = 15): string
525
    {
526
        return Str::password($length);
527
    }
528
529
    /**
530
     * @throws \Exception
531
     */
532
    public static function signUp($userName, $password, $email, $host, $notes, int $invites = Invitation::DEFAULT_INVITES, string $inviteCode = '', bool $forceInviteMode = false, int $role = self::ROLE_USER, bool $validate = true): bool|int|string
533
    {
534
        $user = [
535
            'username' => trim($userName),
536
            'password' => trim($password),
537
            'email' => trim($email),
538
        ];
539
540
        if ($validate) {
541
            $validator = Validator::make($user, [
542
                'username' => ['required', 'string', 'min:5', 'max:255', 'unique:users'],
543
                'email' => ['required', 'string', 'email', 'max:255', 'unique:users', 'indisposable'],
544
                'password' => ['required', 'string', 'min:8', 'confirmed', 'regex:/^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$/'],
545
            ]);
546
547
            if ($validator->fails()) {
548
                return implode('', Arr::collapse($validator->errors()->toArray()));
549
            }
550
        }
551
552
        // Make sure this is the last check, as if a further validation check failed, the invite would still have been used up.
553
        $invitedBy = 0;
554
        if (! $forceInviteMode && (int) Settings::settingValue('registerstatus') === Settings::REGISTER_STATUS_INVITE) {
555
            if ($inviteCode === '') {
556
                return self::ERR_SIGNUP_BADINVITECODE;
557
            }
558
559
            $invitedBy = self::checkAndUseInvite($inviteCode);
560
            if ($invitedBy < 0) {
561
                return self::ERR_SIGNUP_BADINVITECODE;
562
            }
563
        }
564
565
        return self::add($user['username'], $user['password'], $user['email'], $role, $notes, $host, $invites, $invitedBy);
566
    }
567
568
    /**
569
     * If a invite is used, decrement the person who invited's invite count.
570
     */
571
    public static function checkAndUseInvite(string $inviteCode): int
572
    {
573
        $invite = Invitation::findValidByToken($inviteCode);
574
        if (! $invite) {
575
            return -1;
576
        }
577
578
        self::query()->where('id', $invite->invited_by)->decrement('invites');
579
        $invite->markAsUsed(0); // Will be updated with actual user ID later
580
581
        return $invite->invited_by;
582
    }
583
584
    /**
585
     * @return false|int|mixed
586
     */
587
    public static function add(string $userName, string $password, string $email, int $role, ?string $notes = '', string $host = '', int $invites = Invitation::DEFAULT_INVITES, int $invitedBy = 0)
588
    {
589
        $password = self::hashPassword($password);
590
        if (! $password) {
591
            return false;
592
        }
593
594
        $storeips = config('nntmux:settings.store_user_ip') === true ? $host : '';
595
596
        $user = self::create(
597
            [
598
                'username' => $userName,
599
                'password' => $password,
600
                'email' => $email,
601
                'host' => $storeips,
602
                'roles_id' => $role,
603
                'invites' => $invites,
604
                'invitedby' => (int) $invitedBy === 0 ? null : $invitedBy,
605
                'notes' => $notes,
606
            ]
607
        );
608
609
        return $user->id;
610
    }
611
612
    /**
613
     * Get the list of categories the user has excluded.
614
     *
615
     * @param  int  $userID  ID of the user.
616
     *
617
     * @throws \Exception
618
     */
619
    public static function getCategoryExclusionById(int $userID): array
620
    {
621
        $ret = [];
622
623
        $user = self::find($userID);
624
625
        $userAllowed = $user->getDirectPermissions()->pluck('name')->toArray();
626
        $roleAllowed = $user->getAllPermissions()->pluck('name')->toArray();
627
628
        $allowed = array_intersect($roleAllowed, $userAllowed);
629
630
        $cats = ['view console', 'view movies', 'view audio', 'view tv', 'view pc', 'view adult', 'view books', 'view other'];
631
632
        if (! empty($allowed)) {
633
            foreach ($cats as $cat) {
634
                if (! \in_array($cat, $allowed, false)) {
635
                    $ret[] = match ($cat) {
636
                        'view console' => 1000,
637
                        'view movies' => 2000,
638
                        'view audio' => 3000,
639
                        'view pc' => 4000,
640
                        'view tv' => 5000,
641
                        'view adult' => 6000,
642
                        'view books' => 7000,
643
                        'view other' => 1,
644
                    };
645
                }
646
            }
647
        }
648
649
        return Category::query()->whereIn('root_categories_id', $ret)->pluck('id')->toArray();
650
    }
651
652
    /**
653
     * @throws \Exception
654
     */
655
    public static function getCategoryExclusionForApi(Request $request): array
656
    {
657
        $apiToken = $request->has('api_token') ? $request->input('api_token') : $request->input('apikey');
658
        $user = self::getByRssToken($apiToken);
659
660
        return self::getCategoryExclusionById($user->id);
661
    }
662
663
    /**
664
     * @throws \Exception
665
     */
666
    public static function sendInvite($serverUrl, $uid, $emailTo): string
667
    {
668
        $user = self::find($uid);
669
670
        // Create invitation using our custom system
671
        $invitation = Invitation::createInvitation($emailTo, $user->id);
672
        $url = $serverUrl.'/register?token='.$invitation->token;
673
674
        // Send invitation email
675
        $invitationService = app(InvitationService::class);
0 ignored issues
show
Bug introduced by
The type App\Models\InvitationService 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...
676
        $invitationService->sendInvitationEmail($invitation);
677
678
        return $url;
679
    }
680
681
    /**
682
     * Deletes users that have not verified their accounts for 3 or more days.
683
     */
684
    public static function deleteUnVerified(): void
685
    {
686
        static::whereVerified(0)->where('created_at', '<', now()->subDays(3))->delete();
687
    }
688
689
    public function passwordSecurity(): HasOne
690
    {
691
        return $this->hasOne(PasswordSecurity::class);
692
    }
693
}
694