Passed
Push — main ( e48c60...3aaa91 )
by Miaad
01:36
created

json::setUserDefaultData()   A

Complexity

Conditions 6
Paths 32

Size

Total Lines 16
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 6
eloc 11
c 1
b 0
f 1
nc 32
nop 0
dl 0
loc 16
rs 9.2222
1
<?php
2
3
namespace BPT\database;
4
5
use BPT\api\telegram;
6
use BPT\BPT;
7
use BPT\constants\chatMemberStatus;
8
use BPT\constants\chatType;
9
use BPT\constants\fields;
10
use BPT\database\json\groupUserInterface;
11
use BPT\database\json\userInterface;
12
use BPT\exception\bptException;
13
use BPT\settings;
14
use BPT\tools;
15
use BPT\types\callbackQuery;
16
use BPT\types\chatMemberUpdated;
17
use BPT\types\inlineQuery;
18
use BPT\types\message;
19
20
class json {
21
    /**
22
     * Global data will be loaded here automatically, And your changes will be saved automatically too
23
     *
24
     *  
25
     *
26
     * Always loaded when db started, no matter what
27
     */
28
    public static ?object $global = null;
29
    private static ?object $old_global = null;
30
31
    /**
32
     * User data will be loaded here automatically, And your changes will be saved automatically too
33
     *
34
     *  
35
     *
36
     * Will be loaded in Private chats. Will be loaded in Groups and SuperGroups if user started bot in private chat
37
     * @var userInterface $user
38
     */
39
    public static ?object $user = null;
40
    private static ?object $old_user = null;
41
    private static int $user_id;
42
43
    /**
44
     * Group data will be loaded here automatically, And your changes will be saved automatically too
45
     *
46
     *  
47
     *
48
     * Will be loaded in groups only.
49
     */
50
    public static ?object $group = null;
51
    private static ?object $old_group = null;
52
    private static int $group_id;
53
54
    /**
55
     * Supergroup data will be loaded here automatically, And your changes will be saved automatically too
56
     *
57
     *  
58
     *
59
     * Will be loaded in Supergroups only.
60
     */
61
    public static ?object $supergroup = null;
62
    private static ?object $old_supergroup = null;
63
    private static int $supergroup_id;
64
65
    /**
66
     * User data in group will be loaded here automatically, And your changes will be saved automatically too
67
     *
68
     *  
69
     *
70
     * Will be loaded in group and supergroups
71
     * @var groupUserInterface $group_user
72
     */
73
    public static ?object $group_user = null;
74
    private static ?object $old_group_user = null;
75
    private static int $group_user_id;
76
77
    /**
78
     * Channel data will be loaded here automatically, And your changes will be saved automatically too
79
     *
80
     *  
81
     *
82
     * Will be loaded in Channel only.
83
     */
84
    public static ?object $channel = null;
85
    private static ?object $old_channel = null;
86
    private static int $channel_id;
87
88
    private static string $folder = '';
89
90
    private static array $ids = [];
91
    private static array $old_ids = [];
92
93
    private static array $group_ids = [];
94
    private static array $old_group_ids = [];
95
96
    private static array $global_default_data = [];
97
    private static array $user_default_data = ['step' => 'none', 'value' => '', 'phone_number' => '', 'first_active' => 0, 'last_active' => 0, 'referral' => null];
98
    private static array $group_user_default_data = ['step' => 'none', 'value' => '', 'last_active' => 0, 'presence' => true, 'removed' => false, 'removed_by' => null, 'invite_link' => null, 'accepted_by' => null, 'invited_by' => null];
99
    private static array $group_default_data = [];
100
    private static array $supergroup_default_data = [];
101
    private static array $channel_default_data = [];
102
103
    /**
104
     * @internal Only for BPT self usage , Don't use it in your source!
105
     */
106
    public static function init (): void {
107
        self::$folder = settings::$name.'database';
108
        self::$global_default_data = settings::$db['global'] ?? self::$global_default_data;
109
        self::setUserDefaultData();
110
        self::setGroupUserDefaultData();
111
        self::$group_default_data = settings::$db['group'] ?? self::$group_default_data;
112
        self::$supergroup_default_data = settings::$db['supergroup'] ?? self::$supergroup_default_data;
113
        self::$channel_default_data = settings::$db['channel'] ?? self::$channel_default_data;
114
        self::create();
115
        self::load();
116
    }
117
118
    private static function setUserDefaultData (): void {
119
        self::$user_default_data = settings::$db['user'] ?? self::$user_default_data;
120
        if (!isset(self::$user_default_data['step'])) {
121
            self::$user_default_data['step'] = 'none';
122
        }
123
        if (!isset(self::$user_default_data['value'])) {
124
            self::$user_default_data['value'] = '';
125
        }
126
        if (!isset(self::$user_default_data['phone_number'])) {
127
            self::$user_default_data['phone_number'] = '';
128
        }
129
        if (!isset(self::$user_default_data['first_active'])) {
130
            self::$user_default_data['first_active'] = 0;
131
        }
132
        if (!isset(self::$user_default_data['last_active'])) {
133
            self::$user_default_data['last_active'] = 0;
134
        }
135
    }
136
137
    private static function setGroupUserDefaultData (): void {
138
        self::$group_user_default_data = settings::$db['group_user'] ?? self::$group_user_default_data;
139
        if (!isset(self::$group_user_default_data['step'])) {
140
            self::$group_user_default_data['step'] = 'none';
141
        }
142
        if (!isset(self::$group_user_default_data['value'])) {
143
            self::$group_user_default_data['value'] = '';
144
        }
145
    }
146
147
    private static function create(): void {
148
        if (!is_dir(self::$folder)) {
149
            mkdir(self::$folder);
150
        }
151
        if (!is_dir(self::$folder.'/privates')) {
152
            mkdir(self::$folder.'/privates');
153
        }
154
        if (!is_dir(self::$folder.'/groups')) {
155
            mkdir(self::$folder.'/groups');
156
        }
157
        if (!is_dir(self::$folder.'/supergroups')) {
158
            mkdir(self::$folder.'/supergroups');
159
        }
160
        if (!is_dir(self::$folder.'/channels')) {
161
            mkdir(self::$folder.'/channels');
162
        }
163
164
        if (!file_exists(self::$folder.'/global.json')) {
165
            file_put_contents(self::$folder.'/global.json',self::$global_default_data);
166
        }
167
        if (!file_exists(self::$folder.'/ids.json')) {
168
            file_put_contents(self::$folder.'/ids.json',json_encode([
169
                'privates' => [],
170
                'groups' => [],
171
                'supergroups' => [],
172
                'channels' => []
173
            ]));
174
        }
175
    }
176
177
    private static function load (): void {
178
        self::$global = json_decode(file_get_contents(self::$folder.'/global.json'));
179
        self::$old_global = clone self::$global;
180
        self::$ids = json_decode(file_get_contents(self::$folder.'/ids.json'),true);
181
        self::$old_ids = clone self::$ids;
182
    }
183
184
    private static function read (string $address) {
185
        return file_exists(self::$folder.'/'.$address.'.json') ? json_decode(file_get_contents(self::$folder.'/'.$address.'.json'), false) : null;
186
    }
187
188
    private static function write (string $address,string $data): void {
189
        file_put_contents(self::$folder.'/'.$address.'.json',$data);
190
    }
191
192
    /**
193
     * @internal Only for BPT self usage , Don't use it in your source!
194
     */
195
    public static function process (): void {
196
        if (isset(BPT::$update->message)) {
197
            self::processMessage(BPT::$update->message);
198
        }
199
        elseif (isset(BPT::$update->edited_message)) {
200
            self::processMessage(BPT::$update->edited_message);
201
        }
202
        elseif (isset(BPT::$update->callback_query)) {
203
            self::processCallbackQuery(BPT::$update->callback_query);
204
        }
205
        elseif (isset(BPT::$update->inline_query)) {
206
            self::processInlineQuery(BPT::$update->inline_query);
207
        }
208
        elseif (isset(BPT::$update->chat_member)) {
209
            self::processChatMember(BPT::$update->chat_member);
210
        }
211
    }
212
213
    /**
214
     * @internal Only for BPT self usage , Don't use it in your source!
215
     */
216
    public static function save(): void {
217
        if (self::$user !== self::$old_user && !empty(self::$user_id)) {
218
            self::write('privates/' . self::$user_id,json_encode(self::$user));
219
        }
220
        if (self::$group !== self::$old_group && !empty(self::$group_id)) {
221
            self::write('groups/' . self::$group_id,json_encode(self::$group));
222
        }
223
        if (self::$supergroup !== self::$old_supergroup && !empty(self::$supergroup_id)) {
224
            self::write('supergroups/' . self::$supergroup_id,json_encode(self::$supergroup));
225
        }
226
        if (self::$channel !== self::$old_channel && !empty(self::$channel_id)) {
227
            self::write('channels/' . self::$channel_id,json_encode(self::$channel));
228
        }
229
        if (self::$group_user !== self::$old_group_user && !empty(self::$group_user_id)) {
230
            if (empty(self::$group)) {
231
                $category = 'supergroups';
232
                $group_id = self::$supergroup_id;
233
            }
234
            else {
235
                $category = 'groups';
236
                $group_id = self::$group_id;
237
            }
238
            self::write($category . '/' . $group_id . '/' . self::$group_user_id,json_encode(self::$group_user));
239
        }
240
        if (self::$ids !== self::$old_ids) {
241
            self::write('ids',json_encode(self::$ids));
242
        }
243
        if (self::$global !== self::$old_global) {
244
            self::write('global',json_encode(self::$global));
245
        }
246
        if (self::$group_ids !== self::$old_group_ids) {
247
            if (empty(self::$group)) {
248
                $category = 'supergroups';
249
                $group_id = self::$supergroup_id;
250
            }
251
            else {
252
                $category = 'groups';
253
                $group_id = self::$group_id;
254
            }
255
            self::write($category . '/' . $group_id . '/users',json_encode(self::$group_user));
256
        }
257
    }
258
259
    private static function processMessage(message $update): void {
260
        $type = $update->chat->type;
261
        $category = $type . 's';
262
        if ($type === chatType::PRIVATE) {
263
            self::$user_id = $update->from->id;
264
            if (in_array(self::$user_id,self::$ids[$category])) {
265
                self::$user = self::read($category . '/' . self::$user_id);
266
                self::$old_user = clone self::$user;
267
                self::$user->last_active = time();
268
            }
269
            else {
270
                self::$ids[$category][] = self::$user_id;
271
                self::$user = (object) self::$user_default_data;
272
                self::$user->first_active = self::$user->last_active = time();
273
                if (isset($update->commend) && isset($update->commend_payload) && $update->commend === 'start' && str_starts_with($update->commend_payload,'ref_')) {
0 ignored issues
show
Bug introduced by
It seems like $update->commend_payload can also be of type null; however, parameter $haystack of str_starts_with() 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

273
                if (isset($update->commend) && isset($update->commend_payload) && $update->commend === 'start' && str_starts_with(/** @scrutinizer ignore-type */ $update->commend_payload,'ref_')) {
Loading history...
274
                    if (tools::isShorted(substr($update->commend_payload,4))) {
0 ignored issues
show
Bug introduced by
It seems like $update->commend_payload 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

274
                    if (tools::isShorted(substr(/** @scrutinizer ignore-type */ $update->commend_payload,4))) {
Loading history...
275
                        $referral = tools::shortDecode(substr($update->commend_payload,4));
276
                        if (in_array($referral,self::$ids[$category])) {
277
                            self::$user->referral = $referral;
278
                        }
279
                    }
280
                }
281
            }
282
        }
283
        elseif ($type === chatType::CHANNEL) {
284
            self::$channel_id = $update->chat->id;
285
            if (in_array(self::$channel_id,self::$ids[$category])) {
286
                self::$channel = self::read($category . '/' . self::$channel_id);
287
                self::$old_channel = clone self::$channel;
288
            }
289
            else {
290
                self::$ids[$category][] = self::$channel_id;
291
                self::$channel = (object) self::$channel_default_data;
292
            }
293
        }
294
        else {
295
            self::$user_id = $update->from->id;
296
            self::$group_user_id = self::$user_id;
297
            $chat_id = $update->chat->id;
298
            if ($type === chatType::SUPERGROUP) {
299
                self::$supergroup_id = $update->chat->id;
300
                if (in_array($chat_id,self::$ids[$category])) {
301
                    self::$supergroup = self::read($category . '/' . $chat_id);
302
                    self::$old_supergroup = clone self::$supergroup;
303
                    self::$group_ids = self::read($category . '/' . $chat_id . '/users');
304
                    self::$old_group_ids = clone self::$group_ids;
305
                }
306
                else {
307
                    self::$ids[$category][] = $chat_id;
308
                    self::$supergroup = (object) self::$supergroup_default_data;
309
                    self::$group_ids = [];
310
                }
311
            }
312
            else {
313
                self::$group_id = $update->chat->id;
314
                if (in_array($chat_id,self::$ids[$category])) {
315
                    self::$group = self::read($category . '/' . $chat_id);
316
                    self::$old_group = clone self::$group;
317
                    self::$group_ids = self::read($category . '/' . $chat_id . '/users');
318
                    self::$old_group_ids = clone self::$group_ids;
319
                }
320
                else {
321
                    self::$ids[$category][] = $chat_id;
322
                    self::$group = (object) self::$group_default_data;
323
                    self::$group_ids = [];
324
                }
325
            }
326
327
            if (in_array(self::$user_id,self::$group_ids)) {
328
                self::$group_user = self::read($category . '/' . $chat_id . '/' . self::$user_id);
329
                self::$old_group_user = clone self::$group_user;
330
            }
331
            else {
332
                self::$group_ids[] = self::$user_id;
333
                self::$group_user = (object) self::$group_user_default_data;
334
            }
335
336
            self::$user = self::read($category.'/'.self::$user_id);
337
            self::$old_user = clone self::$user;
338
            if (!empty(self::$user)) self::$user->last_active = time();
339
        }
340
    }
341
342
    private static function processCallbackQuery(callbackQuery $update): void {
343
        $type = $update->message->chat->type;
344
        $category = $type . 's';
345
        if ($type === chatType::PRIVATE) {
346
            self::$user_id = $update->from->id;
347
            if (in_array(self::$user_id,self::$ids[$category])) {
348
                self::$user = self::read($category . '/' . self::$user_id);
349
                self::$old_user = clone self::$user;
350
                self::$user->last_active = time();
351
            }
352
        }
353
        elseif ($type === chatType::CHANNEL) {
354
            self::$channel_id = $update->message->chat->id;
355
            if (in_array(self::$channel_id,self::$ids[$category])) {
356
                self::$channel = self::read($category . '/' . self::$channel_id);
357
                self::$old_channel = clone self::$channel;
358
            }
359
        }
360
        else {
361
            self::$user_id = $update->from->id;
362
            $chat_id = $update->message->chat->id;
363
            if (in_array($chat_id,self::$ids[$category])) {
364
                if ($type === chatType::SUPERGROUP) {
365
                    self::$supergroup_id = $update->message->chat->id;
366
                    self::$supergroup = self::read($category . '/' . $chat_id);
367
                    self::$old_supergroup = clone self::$supergroup;
368
                }
369
                else {
370
                    self::$group_id = $update->message->chat->id;
371
                    self::$group = self::read($category . '/' . $chat_id);
372
                    self::$old_group = clone self::$group;
373
                }
374
                self::$group_ids = self::read($category . '/' . $chat_id . '/users');
375
                self::$old_group_ids = clone self::$group_ids;
376
            }
377
378
            if (in_array(self::$user_id,self::$group_ids)) {
379
                self::$group_user = self::read($category . '/' . $chat_id . '/' . self::$user_id);
380
                self::$group_user_id = self::$user_id;
381
                self::$old_group_user = clone self::$group_user;
382
            }
383
384
            self::$user = self::read($category.'/'.self::$user_id);
385
            self::$old_user = clone self::$user;
386
            if (!empty(self::$user)) self::$user->last_active = time();
387
        }
388
    }
389
390
    private static function processInlineQuery(inlineQuery $update): void {
391
        $type = $update->chat_type;
392
        if ($type === chatType::PRIVATE || $type === chatType::SENDER) {
393
            $category = chatType::PRIVATE . 's';
394
            self::$user_id = $update->from->id;
395
            if (in_array(self::$user_id,self::$ids[$category])) {
396
                self::$user = self::read($category . '/' . self::$user_id);
397
                self::$old_user = clone self::$user;
398
                self::$user->last_active = time();
399
            }
400
        }
401
    }
402
403
    private static function processChatMember(chatMemberUpdated $update): void {
404
        $type = $update->chat->type;
405
406
        $category = $type . 's';
407
        if ($type === chatType::CHANNEL) {
408
            self::$channel_id = $update->chat->id;
409
            if (in_array(self::$channel_id,self::$ids[$category])) {
410
                self::$channel = self::read($category . '/' . self::$channel_id);
411
                self::$old_channel = clone self::$channel;
412
            }
413
            else {
414
                self::$ids[$category][] = self::$channel_id;
415
                self::$channel = (object) self::$channel_default_data;
416
            }
417
        }
418
        else {
419
            $chat_id = $update->chat->id;
420
            $by_id = $update->from->id;
421
            $old_user = $update->old_chat_member;
422
            $new_user = $update->new_chat_member;
423
            $user_id = $old_user->user->id;
424
            $invite_link = $update->invite_link;
425
426
427
            if ($type === chatType::SUPERGROUP) {
428
                self::$supergroup_id = $chat_id;
429
                if (in_array($chat_id,self::$ids[$category])) {
430
                    self::$supergroup = self::read($category . '/' . $chat_id);
431
                    self::$old_supergroup = clone self::$supergroup;
432
                    self::$group_ids = self::read($category . '/' . $chat_id . '/users');
433
                    self::$old_group_ids = clone self::$group_ids;
434
                }
435
                else {
436
                    self::$ids[$category][] = $chat_id;
437
                    self::$supergroup = (object) self::$supergroup_default_data;
438
                    self::$group_ids = [];
439
                }
440
            }
441
            elseif ($type === chatType::GROUP) {
442
                self::$group_id = $chat_id;
443
                if (in_array($chat_id,self::$ids[$category])) {
444
                    self::$group = self::read($category . '/' . $chat_id);
445
                    self::$old_group = clone self::$group;
446
                    self::$group_ids = self::read($category . '/' . $chat_id . '/users');
447
                    self::$old_group_ids = clone self::$group_ids;
448
                }
449
                else {
450
                    self::$ids[$category][] = $chat_id;
451
                    self::$group = (object) self::$group_default_data;
452
                    self::$group_ids = [];
453
                }
454
            }
455
456
            if (!in_array($user_id,self::$group_ids)) {
457
                self::$group_ids[] = $user_id;
458
                self::$group_user = (object) self::$group_user_default_data;
459
            }
460
            else {
461
                self::$group_user_id = $by_id == $user_id ? $user_id : $by_id;
462
                self::$group_user = self::read($category . '/' . $chat_id . '/' . self::$group_user_id);
463
            }
464
465
            if ($new_user->status === chatMemberStatus::LEFT || $new_user->status === chatMemberStatus::KICKED) {
466
                if ($old_user->status !== chatMemberStatus::LEFT && $old_user->status !== chatMemberStatus::KICKED) {
467
                    self::$group_user->presence = false;
468
                    self::$group_user->removed = $new_user->status === chatMemberStatus::KICKED;
469
                    if ($new_user->status === chatMemberStatus::KICKED) {
470
                        self::$group_user->removed_by = $by_id;
471
                    }
472
                }
473
            }
474
            else {
475
                if ($old_user->status === chatMemberStatus::LEFT || $old_user->status === chatMemberStatus::KICKED) {
476
                    self::$group_user->presence = true;
477
                    self::$group_user->removed = false;
478
                    self::$group_user->removed_by = null;
479
                    self::$group_user->invite_link = !empty($invite_link) ? $invite_link->invite_link : null;
480
                    if ($by_id !== $user_id) {
481
                        if (!empty($invite_link)) {
482
                            self::$group_user->accepted_by = $by_id;
483
                            self::$group_user->invited_by = null;
484
                        }
485
                        else {
486
                            self::$group_user->invited_by = $by_id;
487
                            self::$group_user->accepted_by = null;
488
                        }
489
                    }
490
                }
491
            }
492
        }
493
    }
494
495
    /**
496
     * delete user completely from database
497
     *
498
     * @param null|int $user_id
499
     *
500
     * @return bool
501
     * @throws bptException
502
     */
503
    public static function deleteUser (int $user_id = null): bool {
504
        if (empty($user_id)) $user_id = telegram::catchFields(fields::USER_ID);
505
        if (file_exists(self::$folder . '/privates/' . $user_id . '.json')) {
506
            unset(self::$ids['privates'][array_search($user_id, self::$ids['privates'])]);
507
            sort(self::$ids['privates']);
508
            if ($user_id === self::$user_id) {
509
                self::$user = self::$old_user = null;
510
            }
511
            return tools::delete(self::$folder . '/privates/' . $user_id . '.json');
512
        }
513
        return false;
514
    }
515
516
    /**
517
     * delete group and its user from database
518
     *
519
     * @param null|int $group_id
520
     *
521
     * @return bool
522
     * @throws bptException
523
     */
524
    public static function deleteGroup (int $group_id = null): bool {
525
        if (empty($group_id)) $group_id = telegram::catchFields(fields::CHAT_ID);
526
        if (file_exists(self::$folder . '/groups/' . $group_id . '.json')) {
527
            unset(self::$ids['groups'][array_search($group_id, self::$ids['groups'])]);
528
            sort(self::$ids['groups']);
529
            tools::delete(self::$folder . '/groups/' . $group_id);
530
            if ($group_id === self::$group_id) {
531
                self::$group = self::$old_group = null;
532
            }
533
            return tools::delete(self::$folder . '/groups/' . $group_id . '.json');
534
        }
535
        return false;
536
    }
537
538
    /**
539
     * delete supergroup and its user from database
540
     *
541
     * @param null|int $group_id
542
     *
543
     * @return bool
544
     * @throws bptException
545
     */
546
    public static function deleteSuperGroup (int $group_id = null): bool {
547
        if (empty($group_id)) $group_id = telegram::catchFields(fields::CHAT_ID);
548
        if (file_exists(self::$folder . '/supergroups/' . $group_id . '.json')) {
549
            unset(self::$ids['supergroups'][array_search($group_id, self::$ids['supergroups'])]);
550
            sort(self::$ids['supergroups']);
551
            tools::delete(self::$folder . '/supergroups/' . $group_id);
552
            if ($group_id === self::$supergroup_id) {
553
                self::$supergroup = self::$old_supergroup = null;
554
            }
555
            return tools::delete(self::$folder . '/supergroups/' . $group_id . '.json');
556
        }
557
        return false;
558
    }
559
560
    /**
561
     * delete channel from database
562
     *
563
     * @param null|int $channel_id
564
     *
565
     * @return bool
566
     * @throws bptException
567
     */
568
    public static function deleteChannel (int $channel_id = null): bool {
569
        if (empty($channel_id)) $channel_id = telegram::catchFields(fields::CHAT_ID);
570
        if (file_exists(self::$folder . '/channels/' . $channel_id . '.json')) {
571
            unset(self::$ids['channels'][array_search($channel_id, self::$ids['channels'])]);
572
            sort(self::$ids['channels']);
573
            if ($channel_id === self::$channel_id) {
574
                self::$channel = self::$old_channel = null;
575
            }
576
            return tools::delete(self::$folder . '/channels/' . $channel_id . '.json');
577
        }
578
        return false;
579
    }
580
581
    /**
582
     * get users list
583
     *
584
     * @return int[]
585
     */
586
    public static function getUsers (): array {
587
        return self::$ids['privates'] ?? [];
588
    }
589
590
    /**
591
     * get groups list
592
     *
593
     * @return int[]
594
     */
595
    public static function getGroups (): array {
596
        return self::$ids['groups'] ?? [];
597
    }
598
599
    /**
600
     * get supergroups list
601
     *
602
     * @return int[]
603
     */
604
    public static function getSuperGroups (): array {
605
        return self::$ids['supergroups'] ?? [];
606
    }
607
608
    /**
609
     * get channels list
610
     *
611
     * @return int[]
612
     */
613
    public static function getChannels (): array {
614
        return self::$ids['channels'] ?? [];
615
    }
616
}
617