Passed
Push — dev ( 423950...40e723 )
by Darko
08:40
created

UsenetGroup::purge()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 27
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 17
dl 0
loc 27
rs 9.7
c 0
b 0
f 0
cc 4
nc 8
nop 1
1
<?php
2
3
namespace App\Models;
4
5
use Blacklight\NZB;
6
use Blacklight\NNTP;
7
use Blacklight\ColorCLI;
8
use Blacklight\Releases;
9
use Blacklight\ReleaseImage;
10
use Illuminate\Support\Facades\DB;
11
use Illuminate\Database\Eloquent\Model;
12
13
/**
14
 * App\Models\Group.
15
 *
16
 * @property int $id
17
 * @property string $name
18
 * @property int $backfill_target
19
 * @property int $first_record
20
 * @property string|null $first_record_postdate
21
 * @property int $last_record
22
 * @property string|null $last_record_postdate
23
 * @property string|null $last_updated
24
 * @property int|null $minfilestoformrelease
25
 * @property int|null $minsizetoformrelease
26
 * @property bool $active
27
 * @property bool $backfill
28
 * @property string|null $description
29
 * @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\Release[] $release
30
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\UsenetGroup whereActive($value)
31
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\UsenetGroup whereBackfill($value)
32
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\UsenetGroup whereBackfillTarget($value)
33
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\UsenetGroup whereDescription($value)
34
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\UsenetGroup whereFirstRecord($value)
35
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\UsenetGroup whereFirstRecordPostdate($value)
36
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\UsenetGroup whereId($value)
37
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\UsenetGroup whereLastRecord($value)
38
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\UsenetGroup whereLastRecordPostdate($value)
39
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\UsenetGroup whereLastUpdated($value)
40
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\UsenetGroup whereMinfilestoformrelease($value)
41
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\UsenetGroup whereMinsizetoformrelease($value)
42
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\UsenetGroup whereName($value)
43
 * @mixin \Eloquent
44
 */
45
class UsenetGroup extends Model
46
{
47
    /**
48
     * @var bool
49
     */
50
    protected $dateFormat = false;
51
52
    /**
53
     * @var bool
54
     */
55
    public $timestamps = false;
56
57
    /**
58
     * @var array
59
     */
60
    protected $guarded = [];
61
62
    /**
63
     * @var array
64
     */
65
    protected static $cbpm = ['collections', 'binaries', 'parts', 'missed_parts'];
66
67
    /**
68
     * @var array
69
     */
70
    protected static $cbppTableNames;
71
72
    /**
73
     * @var bool
74
     */
75
    protected $allasmgr;
76
77
    /**
78
     * Group constructor.
79
     *
80
     * @throws \Exception
81
     */
82
    public function __construct()
83
    {
84
        parent::__construct();
85
        $this->allasmgr = (int) Settings::settingValue('..allasmgr') === 1;
86
    }
87
88
    /**
89
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
90
     */
91
    public function release()
92
    {
93
        return $this->hasMany(Release::class, 'groups_id');
94
    }
95
96
    /**
97
     * Returns an associative array of groups for list selection.
98
     *
99
     *
100
     * @return array
101
     */
102
    public static function getGroupsForSelect(): array
103
    {
104
        $groups = self::getActive();
105
106
        $temp_array = [];
107
        $temp_array[-1] = '--Please Select--';
108
109
        foreach ($groups as $group) {
110
            $temp_array[$group['name']] = $group['name'];
111
        }
112
113
        return $temp_array;
114
    }
115
116
    /**
117
     * Get all properties of a single group by its ID.
118
     *
119
     *
120
     * @param $id
121
     * @return \Illuminate\Database\Eloquent\Model|null|static
122
     */
123
    public static function getGroupByID($id)
124
    {
125
        return self::query()->where('id', $id)->first();
126
    }
127
128
    /**
129
     * @return \Illuminate\Database\Eloquent\Collection|static[]
130
     */
131
    public static function getActive()
132
    {
133
        return self::query()->where('active', '=', 1)->orderBy('name')->get();
134
    }
135
136
    /**
137
     * Get active backfill groups ordered by name ascending.
138
     *
139
     *
140
     * @param $order
141
     * @return array|\Illuminate\Database\Eloquent\Collection|static[]
142
     */
143
    public static function getActiveBackfill($order)
144
    {
145
        switch ($order) {
146
            case '':
147
            case 'normal':
148
                return self::query()->where('backfill', '=', 1)->where('last_record', '<>', 0)->orderBy('name')->get();
149
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
150
            case 'date':
151
                return self::query()->where('backfill', '=', 1)->where('last_record', '<>', 0)->orderBy('first_record_postdate', 'DESC')->get();
152
                break;
153
            default:
154
                return [];
155
        }
156
    }
157
158
    /**
159
     * Get all active group IDs.
160
     *
161
     *
162
     * @return \Illuminate\Database\Eloquent\Collection|static[]
163
     */
164
    public static function getActiveIDs()
165
    {
166
        return self::query()->where('active', '=', 1)->orderBy('name')->get(['id']);
167
    }
168
169
    /**
170
     * Get all group columns by Name.
171
     *
172
     *
173
     * @param $grp
174
     * @return \Illuminate\Database\Eloquent\Model|null|static
175
     */
176
    public static function getByName($grp)
177
    {
178
        return self::query()->where('name', $grp)->first();
179
    }
180
181
    /**
182
     * Get a group name using its ID.
183
     *
184
     * @param int|string $id The group ID.
185
     *
186
     * @return string Empty string on failure, groupName on success.
187
     */
188
    public static function getNameByID($id): string
189
    {
190
        $res = self::query()->where('id', $id)->first(['name']);
191
192
        return $res !== null ? $res->name : '';
193
    }
194
195
    /**
196
     * Get a group ID using its name.
197
     *
198
     * @param string $name The group name.
199
     *
200
     * @return false|int false on failure, groups_id on success.
201
     */
202
    public static function getIDByName($name)
203
    {
204
        $res = self::query()->where('name', $name)->first(['id']);
205
206
        return $res === null ? false : $res->id;
207
    }
208
209
    /**
210
     * Gets a count of all groups in the table limited by parameters.
211
     *
212
     * @param string $groupname Constrain query to specific group name
213
     * @param int    $active    Constrain query to active status
214
     *
215
     * @return mixed
216
     */
217
    public static function getGroupsCount($groupname = '', $active = -1)
218
    {
219
        $res = self::query();
220
221
        if ($groupname !== '') {
222
            $res->where('name', 'like', '%'.$groupname.'%');
223
        }
224
225
        if ($active > -1) {
226
            $res->where('active', $active);
227
        }
228
229
        return $res === null ? 0 : $res->count(['id']);
230
    }
231
232
    /**
233
     * @param string $groupname
234
     * @param null   $active
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $active is correct as it would always require null to be passed?
Loading history...
235
     *
236
     * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
237
     */
238
    public static function getGroupsRange($groupname = '', $active = null)
239
    {
240
        $groups = self::query()->groupBy('id')->orderBy('name');
241
242
        if ($groupname !== '') {
243
            $groups->where('name', 'like', '%'.$groupname.'%');
244
        }
245
246
        if ($active === true) {
0 ignored issues
show
introduced by
The condition $active === true is always false.
Loading history...
247
            $groups->where('active', '=', 1);
248
        } elseif ($active === false) {
0 ignored issues
show
introduced by
The condition $active === false is always true.
Loading history...
249
            $groups->where('active', '=', 0);
250
        }
251
252
        return $groups->paginate(config('nntmux.items_per_page'));
253
    }
254
255
    /**
256
     * Update an existing group.
257
     *
258
     *
259
     * @param $group
260
     *
261
     * @return int
262
     */
263
    public static function updateGroup($group)
264
    {
265
        return self::query()->where('id', $group['id'])->update(
266
            [
267
                'name' => trim($group['name']),
268
                'description' => trim($group['description']),
269
                'backfill_target' => $group['backfill_target'],
270
                'first_record' => $group['first_record'],
271
                'last_record' => $group['last_record'],
272
                'last_updated' => now(),
273
                'active' => $group['active'],
274
                'backfill' => $group['backfill'],
275
                'minsizetoformrelease' => $group['minsizetoformrelease'] === '' ? null : $group['minsizetoformrelease'],
276
                'minfilestoformrelease' => $group['minfilestoformrelease'] === '' ? null : $group['minfilestoformrelease'],
277
            ]
278
        );
279
    }
280
281
    /**
282
     * Checks group name is standard and replaces any shorthand prefixes.
283
     *
284
     * @param string $groupName The full name of the usenet group being evaluated
285
     *
286
     * @return string|bool The name of the group replacing shorthand prefix or false if groupname was malformed
287
     */
288
    public static function isValidGroup($groupName)
289
    {
290
        if (preg_match('/^([\w-]+\.)+[\w-]+$/i', $groupName)) {
291
            return preg_replace('/^a\.b\./i', 'alt.binaries.', $groupName, 1);
292
        }
293
294
        return false;
295
    }
296
297
    /**
298
     * Add a new group.
299
     *
300
     *
301
     * @param $group
302
     * @return int|mixed
303
     */
304
    public static function addGroup($group)
305
    {
306
        $checkOld = UsenetGroup::query()->where('name', trim($group['name']))->first();
307
        if (empty($checkOld)) {
308
            return self::query()->insertGetId([
309
                    'name' => trim($group['name']),
310
                    'description' => isset($group['description']) ? trim($group['description']) : '',
311
                    'backfill_target' => $group['backfill_target'] ?? 1,
312
                    'first_record' => $group['first_record'] ?? 0,
313
                    'last_record' => $group['last_record'] ?? 0,
314
                    'active' => $group['active'] ?? 0,
315
                    'backfill' => $group['backfill'] ?? 0,
316
                    'minsizetoformrelease' => $group['minsizetoformrelease'] ?? null,
317
                    'minfilestoformrelease' => $group['minfilestoformrelease'] ?? null,
318
                ]);
319
        }
320
321
        return $checkOld->id;
322
    }
323
324
    /**
325
     * Delete a group.
326
     *
327
     * @param int|string $id ID of the group.
328
     *
329
     * @return bool
330
     * @throws \Exception
331
     */
332
    public static function deleteGroup($id): bool
333
    {
334
        self::purge($id);
335
336
        return self::query()->where('id', $id)->delete();
0 ignored issues
show
Bug Best Practice introduced by
The expression return self::query()->where('id', $id)->delete() could return the type integer which is incompatible with the type-hinted return boolean. Consider adding an additional type-check to rule them out.
Loading history...
337
    }
338
339
    /**
340
     * Reset a group.
341
     *
342
     * @param string|int $id The group ID.
343
     *
344
     * @return bool
345
     * @throws \Exception
346
     */
347
    public static function reset($id): bool
348
    {
349
        // Remove rows from part repair.
350
        MissedPart::query()->where('groups_id', $id)->delete();
351
352
        foreach (self::$cbpm as $tablePrefix) {
353
            DB::statement(
354
                "DROP TABLE IF EXISTS {$tablePrefix}"
355
            );
356
        }
357
358
        // Reset the group stats.
359
        return self::query()->where('id', $id)->update(
0 ignored issues
show
Bug Best Practice introduced by
The expression return self::query()->wh...> null, 'active' => 0)) returns the type integer which is incompatible with the type-hinted return boolean.
Loading history...
360
            [
361
                'backfill_target' => 1,
362
                'first_record' => 0,
363
                'first_record_postdate' => null,
364
                'last_record' => 0,
365
                'last_record_postdate' => null,
366
                'last_updated' => null,
367
                'active' => 0,
368
            ]
369
        );
370
    }
371
372
    /**
373
     * Reset all groups.
374
     *
375
     * @return bool
376
     */
377
    public static function resetall(): bool
378
    {
379
        foreach (self::$cbpm as $tablePrefix) {
380
            DB::statement("TRUNCATE TABLE {$tablePrefix}");
381
        }
382
383
        // Reset the group stats.
384
385
        return self::query()->update(
0 ignored issues
show
Bug Best Practice introduced by
The expression return self::query()->up...> null, 'active' => 0)) returns the type integer which is incompatible with the type-hinted return boolean.
Loading history...
386
            [
387
                'backfill_target' => 1,
388
                'first_record' => 0,
389
                'first_record_postdate' => null,
390
                'last_record' => 0,
391
                'člast_record_postdate' => null,
392
                'last_updated' => null,
393
                'active' => 0,
394
            ]
395
        );
396
    }
397
398
    /**
399
     * Purge a single group or all groups.
400
     *
401
     * @param int|string|bool $id The group ID. If false, purge all groups.
402
     * @throws \Exception
403
     */
404
    public static function purge($id = false)
405
    {
406
        if ($id === false) {
407
            self::resetall();
408
        } else {
409
            self::reset($id);
0 ignored issues
show
Bug introduced by
It seems like $id can also be of type true; however, parameter $id of App\Models\UsenetGroup::reset() does only seem to accept integer|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

409
            self::reset(/** @scrutinizer ignore-type */ $id);
Loading history...
410
        }
411
412
        $res = Release::query()->select(['id', 'guid']);
413
414
        if ($id !== false) {
415
            $res->where('groups_id', $id);
416
        }
417
418
        $res->get();
419
420
        $releases = new Releases(['Groups' => self::class]);
421
        $nzb = new NZB();
422
        $releaseImage = new ReleaseImage();
423
        foreach ($res as $row) {
424
            $releases->deleteSingle(
425
                [
426
                        'g' => $row['guid'],
427
                        'i' => $row['id'],
428
                    ],
429
                $nzb,
430
                $releaseImage
431
                );
432
        }
433
    }
434
435
    /**
436
     * Adds new newsgroups based on a regular expression match against USP available.
437
     *
438
     * @param string $groupList
439
     * @param int $active
440
     * @param int $backfill
441
     *
442
     * @return array|string
443
     * @throws \Exception
444
     */
445
    public static function addBulk($groupList, $active = 1, $backfill = 1)
446
    {
447
        if (preg_match('/^\s*$/m', $groupList)) {
448
            $ret = 'No group list provided.';
449
        } else {
450
            $nntp = new NNTP(['Echo' => false]);
451
            if ($nntp->doConnect() !== true) {
452
                return 'Problem connecting to usenet.';
453
            }
454
            $groups = $nntp->getGroups();
455
            $nntp->doQuit();
456
457
            if ($nntp->isError($groups)) {
458
                return 'Problem fetching usenet_groups from usenet.';
459
            }
460
461
            $regFilter = '/'.$groupList.'/i';
462
463
            $ret = [];
464
465
            foreach ($groups as $group) {
466
                if (preg_match($regFilter, $group['group']) > 0) {
467
                    $res = self::getIDByName($group['group']);
468
                    if ($res === false) {
469
                        self::addGroup(
470
                            [
471
                                'name'        => $group['group'],
472
                                'active'      => $active,
473
                                'backfill'    => $backfill,
474
                                'description' => 'Added by bulkAdd',
475
                            ]
476
                        );
477
                        $ret[] = ['group' => $group['group'], 'msg' => 'Created'];
478
                    }
479
                }
480
            }
481
482
            if (\count($ret) === 0) {
483
                $ret[] = ['group' => '', 'msg' => 'No groups found with your regex or groups already exist in database, try again!'];
484
            }
485
        }
486
487
        return $ret;
488
    }
489
490
    /**
491
     * Updates the group active/backfill status.
492
     *
493
     * @param int    $id     Which group ID
494
     * @param string $column Which column active/backfill
495
     * @param int    $status Which status we are setting
496
     *
497
     * @return string
498
     */
499
    public static function updateGroupStatus($id, $column, $status = 0): string
500
    {
501
        self::query()->where('id', $id)->update(
502
            [
503
                $column => $status,
504
            ]
505
        );
506
507
        return "Group {$id} has been ".(($status === 0) ? 'deactivated' : 'activated').'.';
508
    }
509
510
    /**
511
     * Disable group that does not exist on USP server.
512
     *
513
     * @param int $id The Group ID to disable
514
     */
515
    public static function disableIfNotExist($id): void
516
    {
517
        self::updateGroupStatus($id, 'active');
518
        (new ColorCLI())->error('Group does not exist on server, disabling');
519
    }
520
}
521