UsenetGroup::getActiveBackfill()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 12
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 10
dl 0
loc 12
rs 9.9332
c 0
b 0
f 0
cc 4
nc 4
nop 1
1
<?php
2
3
namespace App\Models;
4
5
use Blacklight\ColorCLI;
6
use Blacklight\NNTP;
7
use Blacklight\NZB;
8
use Blacklight\ReleaseImage;
9
use Blacklight\Releases;
10
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
11
use Illuminate\Database\Eloquent\Model;
12
use Illuminate\Database\Eloquent\Relations\HasMany;
13
use Illuminate\Support\Facades\DB;
14
15
/**
16
 * App\Models\Group.
17
 *
18
 * @property int $id
19
 * @property string $name
20
 * @property int $backfill_target
21
 * @property int $first_record
22
 * @property string|null $first_record_postdate
23
 * @property int $last_record
24
 * @property string|null $last_record_postdate
25
 * @property string|null $last_updated
26
 * @property int|null $minfilestoformrelease
27
 * @property int|null $minsizetoformrelease
28
 * @property bool $active
29
 * @property bool $backfill
30
 * @property string|null $description
31
 * @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\Release[] $release
32
 *
33
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\UsenetGroup whereActive($value)
34
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\UsenetGroup whereBackfill($value)
35
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\UsenetGroup whereBackfillTarget($value)
36
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\UsenetGroup whereDescription($value)
37
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\UsenetGroup whereFirstRecord($value)
38
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\UsenetGroup whereFirstRecordPostdate($value)
39
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\UsenetGroup whereId($value)
40
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\UsenetGroup whereLastRecord($value)
41
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\UsenetGroup whereLastRecordPostdate($value)
42
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\UsenetGroup whereLastUpdated($value)
43
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\UsenetGroup whereMinfilestoformrelease($value)
44
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\UsenetGroup whereMinsizetoformrelease($value)
45
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\UsenetGroup whereName($value)
46
 *
47
 * @mixin \Eloquent
48
 *
49
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\UsenetGroup newModelQuery()
50
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\UsenetGroup newQuery()
51
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\UsenetGroup query()
52
 */
53
class UsenetGroup extends Model
54
{
55
    /**
56
     * @var bool
57
     */
58
    protected $dateFormat = false;
59
60
    /**
61
     * @var bool
62
     */
63
    public $timestamps = false;
64
65
    /**
66
     * @var array
67
     */
68
    protected $guarded = [];
69
70
    /**
71
     * @var array
72
     */
73
    protected static $cbpm = ['collections', 'binaries', 'parts', 'missed_parts'];
74
75
    /**
76
     * @var array
77
     */
78
    protected static $cbppTableNames;
79
80
    /**
81
     * @var bool
82
     */
83
    protected $allasmgr;
84
85
    /**
86
     * Group constructor.
87
     *
88
     * @throws \Exception
89
     */
90
    public function __construct()
91
    {
92
        parent::__construct();
93
    }
94
95
    public function release(): HasMany
96
    {
97
        return $this->hasMany(Release::class, 'groups_id');
98
    }
99
100
    /**
101
     * Returns an associative array of groups for list selection.
102
     */
103
    public static function getGroupsForSelect(): array
104
    {
105
        $groups = self::getActive();
106
107
        $temp_array = [];
108
        $temp_array[-1] = '--Please Select--';
109
110
        foreach ($groups as $group) {
111
            $temp_array[$group['name']] = $group['name'];
112
        }
113
114
        return $temp_array;
115
    }
116
117
    /**
118
     * Get all properties of a single group by its ID.
119
     *
120
     *
121
     * @return 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
     * @return array|\Illuminate\Database\Eloquent\Collection|static[]
141
     */
142
    public static function getActiveBackfill($order)
143
    {
144
        switch ($order) {
145
            case '':
146
            case 'normal':
147
                return self::query()->where('backfill', '=', 1)->where('last_record', '<>', 0)->orderBy('name')->get();
148
                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...
149
            case 'date':
150
                return self::query()->where('backfill', '=', 1)->where('last_record', '<>', 0)->orderByDesc('first_record_postdate')->get();
151
                break;
152
            default:
153
                return [];
154
        }
155
    }
156
157
    /**
158
     * Get all active group IDs.
159
     *
160
     *
161
     * @return \Illuminate\Database\Eloquent\Collection|static[]
162
     */
163
    public static function getActiveIDs()
164
    {
165
        return self::query()->where('active', '=', 1)->orderBy('name')->get(['id']);
166
    }
167
168
    /**
169
     * Get all group columns by Name.
170
     *
171
     *
172
     * @return Model|null|static
173
     */
174
    public static function getByName($grp)
175
    {
176
        return self::query()->where('name', $grp)->first();
177
    }
178
179
    /**
180
     * Get a group name using its ID.
181
     *
182
     * @param  int|string  $id  The group ID.
183
     * @return string Empty string on failure, groupName on success.
184
     */
185
    public static function getNameByID($id): string
186
    {
187
        $res = self::query()->where('id', $id)->first(['name']);
188
189
        return $res !== null ? $res->name : '';
190
    }
191
192
    /**
193
     * Get a group ID using its name.
194
     *
195
     * @param  string  $name  The group name.
196
     * @return false|int false on failure, groups_id on success.
197
     */
198
    public static function getIDByName(string $name)
199
    {
200
        $res = self::query()->where('name', $name)->first(['id']);
201
202
        return $res === null ? false : $res->id;
203
    }
204
205
    /**
206
     * Gets a count of all groups in the table limited by parameters.
207
     *
208
     * @param  string  $groupname  Constrain query to specific group name
209
     * @param  int  $active  Constrain query to active status
210
     * @return mixed
211
     */
212
    public static function getGroupsCount(string $groupname = '', int $active = -1)
213
    {
214
        $res = self::query();
215
216
        if ($groupname !== '') {
217
            $res->where('name', 'like', '%'.$groupname.'%');
218
        }
219
220
        if ($active > -1) {
221
            $res->where('active', $active);
222
        }
223
224
        return $res === null ? 0 : $res->count(['id']);
225
    }
226
227
    public static function getGroupsRange(string $groupname = '', $active = null): LengthAwarePaginator
228
    {
229
        $groups = self::query()->groupBy('id')->orderBy('name');
0 ignored issues
show
Bug introduced by
'name' of type string is incompatible with the type Closure|Illuminate\Datab...\Database\Query\Builder expected by parameter $column of Illuminate\Database\Query\Builder::orderBy(). ( Ignorable by Annotation )

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

229
        $groups = self::query()->groupBy('id')->orderBy(/** @scrutinizer ignore-type */ 'name');
Loading history...
230
231
        if ($groupname !== '') {
232
            $groups->where('name', 'like', '%'.$groupname.'%');
233
        }
234
235
        if ($active === true) {
236
            $groups->where('active', '=', 1);
237
        } elseif ($active === false) {
238
            $groups->where('active', '=', 0);
239
        }
240
241
        return $groups->paginate(config('nntmux.items_per_page'));
242
    }
243
244
    /**
245
     * Update an existing group.
246
     */
247
    public static function updateGroup($group): int
248
    {
249
        return self::query()->where('id', $group['id'])->update(
250
            [
251
                'name' => trim($group['name']),
252
                'description' => trim($group['description']),
253
                'backfill_target' => $group['backfill_target'],
254
                'first_record' => $group['first_record'],
255
                'last_record' => $group['last_record'],
256
                'last_updated' => now(),
257
                'active' => $group['active'],
258
                'backfill' => $group['backfill'],
259
                'minsizetoformrelease' => $group['minsizetoformrelease'] === '' ? null : $group['minsizetoformrelease'],
260
                'minfilestoformrelease' => $group['minfilestoformrelease'] === '' ? null : $group['minfilestoformrelease'],
261
            ]
262
        );
263
    }
264
265
    /**
266
     * Checks group name is standard and replaces any shorthand prefixes.
267
     *
268
     * @param  string  $groupName  The full name of the usenet group being evaluated
269
     * @return string|bool The name of the group replacing shorthand prefix or false if groupname was malformed
270
     */
271
    public static function isValidGroup(string $groupName)
272
    {
273
        if (preg_match('/^([\w\-]+\.)+[\w\-]+$/i', $groupName)) {
274
            return preg_replace('/^a\.b\./i', 'alt.binaries.', $groupName, 1);
275
        }
276
277
        return false;
278
    }
279
280
    /**
281
     * Add a new group.
282
     *
283
     *
284
     * @return int|mixed
285
     */
286
    public static function addGroup($group)
287
    {
288
        $checkOld = UsenetGroup::query()->where('name', trim($group['name']))->first();
289
        if (empty($checkOld)) {
290
            return self::query()->insertGetId([
291
                'name' => trim($group['name']),
292
                'description' => isset($group['description']) ? trim($group['description']) : '',
293
                'backfill_target' => $group['backfill_target'] ?? 1,
294
                'first_record' => $group['first_record'] ?? 0,
295
                'last_record' => $group['last_record'] ?? 0,
296
                'active' => $group['active'] ?? 0,
297
                'backfill' => $group['backfill'] ?? 0,
298
                'minsizetoformrelease' => $group['minsizetoformrelease'] ?? null,
299
                'minfilestoformrelease' => $group['minfilestoformrelease'] ?? null,
300
            ]);
301
        }
302
303
        return $checkOld->id;
304
    }
305
306
    /**
307
     * Delete a group.
308
     *
309
     * @param  int|string  $id  ID of the group.
310
     *
311
     * @throws \Exception
312
     */
313
    public static function deleteGroup($id): bool
314
    {
315
        self::purge($id);
316
317
        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...
318
    }
319
320
    /**
321
     * Reset a group.
322
     *
323
     * @param  string|int  $id  The group ID.
324
     *
325
     * @throws \Exception
326
     */
327
    public static function reset($id): bool
328
    {
329
        // Remove rows from part repair.
330
        MissedPart::query()->where('groups_id', $id)->delete();
331
332
        // Reset the group stats.
333
        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...
334
            [
335
                'backfill_target' => 1,
336
                'first_record' => 0,
337
                'first_record_postdate' => null,
338
                'last_record' => 0,
339
                'last_record_postdate' => null,
340
                'last_updated' => null,
341
                'active' => 0,
342
            ]
343
        );
344
    }
345
346
    /**
347
     * Reset all groups.
348
     */
349
    public static function resetall(): bool
350
    {
351
        foreach (self::$cbpm as $tablePrefix) {
352
            DB::statement("TRUNCATE TABLE {$tablePrefix}");
353
        }
354
355
        // Reset the group stats.
356
357
        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...
358
            [
359
                'backfill_target' => 1,
360
                'first_record' => 0,
361
                'first_record_postdate' => null,
362
                'last_record' => 0,
363
                'last_record_postdate' => null,
364
                'last_updated' => null,
365
                'active' => 0,
366
            ]
367
        );
368
    }
369
370
    /**
371
     * Purge a single group or all groups.
372
     *
373
     * @param  int|string|bool  $id  The group ID. If false, purge all groups.
374
     *
375
     * @throws \Exception
376
     */
377
    public static function purge($id = false)
378
    {
379
        if ($id === false) {
380
            self::resetall();
381
        } else {
382
            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

382
            self::reset(/** @scrutinizer ignore-type */ $id);
Loading history...
383
        }
384
385
        $res = Release::query()->select(['id', 'guid']);
386
387
        if ($id !== false) {
388
            $res->where('groups_id', $id);
389
        }
390
391
        $res->get();
392
393
        $releases = new Releases;
394
        $nzb = new NZB;
395
        $releaseImage = new ReleaseImage;
396
        foreach ($res as $row) {
397
            $releases->deleteSingle(
398
                [
399
                    'g' => $row['guid'],
400
                    'i' => $row['id'],
401
                ],
402
                $nzb,
403
                $releaseImage
404
            );
405
        }
406
    }
407
408
    /**
409
     * Adds new newsgroups based on a regular expression match against USP available.
410
     *
411
     * @return array|string
412
     *
413
     * @throws \Exception
414
     */
415
    public static function addBulk(string $groupList, int $active = 1, int $backfill = 1)
416
    {
417
        if (preg_match('/^\s*$/m', $groupList)) {
418
            $ret = 'No group list provided.';
419
        } else {
420
            $nntp = new NNTP(['Echo' => false]);
0 ignored issues
show
Unused Code introduced by
The call to Blacklight\NNTP::__construct() has too many arguments starting with array('Echo' => false). ( Ignorable by Annotation )

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

420
            $nntp = /** @scrutinizer ignore-call */ new NNTP(['Echo' => false]);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
421
            if ($nntp->doConnect() !== true) {
422
                return 'Problem connecting to usenet.';
423
            }
424
            $groups = $nntp->getGroups();
425
            $nntp->doQuit();
426
427
            if ($nntp->isError($groups)) {
428
                return 'Problem fetching usenet_groups from usenet.';
429
            }
430
431
            $regFilter = '/'.$groupList.'/i';
432
433
            $ret = [];
434
435
            foreach ($groups as $group) {
436
                if (preg_match($regFilter, $group['group']) > 0) {
437
                    $res = self::getIDByName($group['group']);
438
                    if ($res === false) {
439
                        self::addGroup(
440
                            [
441
                                'name' => $group['group'],
442
                                'active' => $active,
443
                                'backfill' => $backfill,
444
                                'description' => 'Added by bulkAdd',
445
                            ]
446
                        );
447
                        $ret[] = ['group' => $group['group'], 'msg' => 'Created'];
448
                    }
449
                }
450
            }
451
452
            if (\count($ret) === 0) {
453
                $ret[] = ['group' => '', 'msg' => 'No groups found with your regex or groups already exist in database, try again!'];
454
            }
455
        }
456
457
        return $ret;
458
    }
459
460
    /**
461
     * Updates the group active/backfill status.
462
     *
463
     * @param  int  $id  Which group ID
464
     * @param  string  $column  Which column active/backfill
465
     * @param  int  $status  Which status we are setting
466
     */
467
    public static function updateGroupStatus(int $id, string $column, int $status = 0): string
468
    {
469
        self::query()->where('id', $id)->update(
470
            [
471
                $column => $status,
472
            ]
473
        );
474
475
        return "Group {$id} has been ".(($status === 0) ? 'deactivated' : 'activated').'.';
476
    }
477
478
    /**
479
     * Disable group that does not exist on USP server.
480
     *
481
     * @param  int  $id  The Group ID to disable
482
     */
483
    public static function disableIfNotExist(int $id): void
484
    {
485
        self::updateGroupStatus($id, 'active');
486
        (new ColorCLI)->error('Group does not exist on server, disabling');
487
    }
488
}
489