Completed
Pull Request — master (#551)
by Maxence
02:35
created

Member::importFromDatabase()   B

Complexity

Conditions 6
Paths 17

Size

Total Lines 38

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 38
rs 8.6897
c 0
b 0
f 0
cc 6
nc 17
nop 2
1
<?php
2
3
declare(strict_types=1);
4
5
6
/**
7
 * Circles - Bring cloud-users closer together.
8
 *
9
 * This file is licensed under the Affero General Public License version 3 or
10
 * later. See the COPYING file.
11
 *
12
 * @author Maxence Lange <[email protected]>
13
 * @copyright 2021
14
 * @license GNU AGPL version 3 or any later version
15
 *
16
 * This program is free software: you can redistribute it and/or modify
17
 * it under the terms of the GNU Affero General Public License as
18
 * published by the Free Software Foundation, either version 3 of the
19
 * License, or (at your option) any later version.
20
 *
21
 * This program is distributed in the hope that it will be useful,
22
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24
 * GNU Affero General Public License for more details.
25
 *
26
 * You should have received a copy of the GNU Affero General Public License
27
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
28
 *
29
 */
30
31
32
namespace OCA\Circles\Model;
33
34
use daita\MySmallPhpTools\Db\Nextcloud\nc21\INC21QueryRow;
35
use daita\MySmallPhpTools\Exceptions\InvalidItemException;
36
use daita\MySmallPhpTools\IDeserializable;
37
use daita\MySmallPhpTools\Traits\Nextcloud\nc21\TNC21Deserialize;
38
use daita\MySmallPhpTools\Traits\TArrayTools;
39
use DateTime;
40
use JsonSerializable;
41
use OCA\Circles\Exceptions\MemberLevelException;
42
use OCA\Circles\Exceptions\MemberNotFoundException;
43
use OCA\Circles\Exceptions\UserTypeNotFoundException;
44
use OCA\Circles\IFederatedUser;
45
46
47
/**
48
 * Class Member
49
 *
50
 * @package OCA\Circles\Model
51
 */
52
class Member extends ManagedModel implements IFederatedUser, IDeserializable, INC21QueryRow, JsonSerializable {
53
54
55
	use TArrayTools;
56
	use TNC21Deserialize;
57
58
59
	const LEVEL_NONE = 0;
60
	const LEVEL_MEMBER = 1;
61
	const LEVEL_MODERATOR = 4;
62
	const LEVEL_ADMIN = 8;
63
	const LEVEL_OWNER = 9;
64
65
	const TYPE_CIRCLE = 16;
66
	const TYPE_USER = 1;
67
	const TYPE_GROUP = 2;
68
	const TYPE_MAIL = 3;
69
	const TYPE_CONTACT = 4;
70
71
	const STATUS_NONMEMBER = 'Unknown';
72
	const STATUS_INVITED = 'Invited';
73
	const STATUS_REQUEST = 'Requesting';
74
	const STATUS_MEMBER = 'Member';
75
	const STATUS_BLOCKED = 'Blocked';
76
	const STATUS_KICKED = 'Kicked';
77
78
	public static $DEF_LEVEL = [
79
		1 => 'Member',
80
		4 => 'Moderator',
81
		8 => 'Admin',
82
		9 => 'Owner'
83
	];
84
85
	public static $DEF_TYPE = [
86
		1  => 'local',
87
		16 => 'circle',
88
		3  => 'mail',
89
		4  => 'contact',
90
	];
91
92
	/** @var string */
93
	private $id = '';
94
95
	/** @var string */
96
	private $circleId = '';
97
98
	/** @var string */
99
	private $singleId = '';
100
101
	/** @var string */
102
	private $userId = '';
103
104
	/** @var int */
105
	private $userType = self::TYPE_USER;
106
107
	/** @var string */
108
	private $instance = '';
109
110
	/** @var int */
111
	private $level = 0;
112
113
	/** @var string */
114
	private $status = 'Unknown';
115
116
	/** @var string */
117
	private $note = '';
118
119
	/** @var string */
120
	private $cachedName = '';
121
122
	/** @var int */
123
	private $cachedUpdate = 0;
124
125
	/** @var string */
126
	private $contactId = '';
127
128
	/** @var string */
129
	private $contactMeta = '';
130
131
	/** @var Circle */
132
	private $circle;
133
134
135
	/** @var int */
136
	private $joined = 0;
137
138
139
	/**
140
	 * Member constructor.
141
	 */
142
	public function __construct() {
143
	}
144
145
146
	/**
147
	 * @param string $id
148
	 *
149
	 * @return $this
150
	 */
151
	public function setId(string $id): self {
152
		$this->id = $id;
153
154
		return $this;
155
	}
156
157
	/**
158
	 * @return string
159
	 */
160
	public function getId(): string {
161
		return $this->id;
162
	}
163
164
165
	/**
166
	 * @param string $circleId
167
	 *
168
	 * @return Member
169
	 */
170
	public function setCircleId(string $circleId): self {
171
		$this->circleId = $circleId;
172
173
		return $this;
174
	}
175
176
	/**
177
	 * @return string
178
	 */
179
	public function getCircleId(): string {
180
		return $this->circleId;
181
	}
182
183
184
	/**
185
	 * This should replace user_id, user_type and instance; and will use the data from Circle with
186
	 * Config=CFG_SINGLE
187
	 *
188
	 * @param string $singleId
189
	 *
190
	 * @return $this
191
	 */
192
	public function setSingleId(string $singleId): self {
193
		$this->singleId = $singleId;
194
195
		return $this;
196
	}
197
198
	/**
199
	 * @return string
200
	 */
201
	public function getSingleId(): string {
202
		return $this->singleId;
203
	}
204
205
206
	/**
207
	 * @param string $userId
208
	 *
209
	 * @return Member
210
	 */
211
	public function setUserId(string $userId): self {
212
		$this->userId = $userId;
213
214
		return $this;
215
	}
216
217
	/**
218
	 * @return string
219
	 */
220
	public function getUserId(): string {
221
		return $this->userId;
222
	}
223
224
225
	/**
226
	 * @param int $userType
227
	 *
228
	 * @return Member
229
	 */
230
	public function setUserType(int $userType): self {
231
		$this->userType = $userType;
232
233
		return $this;
234
	}
235
236
	/**
237
	 * @return int
238
	 */
239
	public function getUserType(): int {
240
		return $this->userType;
241
	}
242
243
244
	/**
245
	 * @param string $instance
246
	 *
247
	 * @return Member
248
	 */
249
	public function setInstance(string $instance): self {
250
		$this->instance = $instance;
251
252
		return $this;
253
	}
254
255
	/**
256
	 * @return string
257
	 */
258
	public function getInstance(): string {
259
		return $this->instance;
260
	}
261
262
263
	/**
264
	 * @param int $level
265
	 *
266
	 * @return Member
267
	 */
268
	public function setLevel(int $level): self {
269
		$this->level = $level;
270
271
		return $this;
272
	}
273
274
	/**
275
	 * @return int
276
	 */
277
	public function getLevel(): int {
278
		return $this->level;
279
	}
280
281
282
	/**
283
	 * @param string $status
284
	 *
285
	 * @return Member
286
	 */
287
	public function setStatus(string $status): self {
288
		$this->status = $status;
289
290
		return $this;
291
	}
292
293
	/**
294
	 * @return string
295
	 */
296
	public function getStatus(): string {
297
		return $this->status;
298
	}
299
300
301
	/**
302
	 * @param string $note
303
	 *
304
	 * @return Member
305
	 */
306
	public function setNote(string $note): self {
307
		$this->note = $note;
308
309
		return $this;
310
	}
311
312
	/**
313
	 * @return string
314
	 */
315
	public function getNote(): string {
316
		return $this->note;
317
	}
318
319
320
	/**
321
	 * @param string $cachedName
322
	 *
323
	 * @return Member
324
	 */
325
	public function setCachedName(string $cachedName): self {
326
		$this->cachedName = $cachedName;
327
328
		return $this;
329
	}
330
331
332
	/**
333
	 * @param int $cachedUpdate
334
	 *
335
	 * @return Member
336
	 */
337
	public function setCachedUpdate(int $cachedUpdate): self {
338
		$this->cachedUpdate = $cachedUpdate;
339
340
		return $this;
341
	}
342
343
	/**
344
	 * @return int
345
	 */
346
	public function getCachedUpdate(): int {
347
		return $this->cachedUpdate;
348
	}
349
350
351
	/**
352
	 * @return string
353
	 */
354
	public function getCachedName(): string {
355
		return $this->cachedName;
356
	}
357
358
359
	/**
360
	 * @param string $contactId
361
	 *
362
	 * @return Member
363
	 */
364
	public function setContactId(string $contactId): self {
365
		$this->contactId = $contactId;
366
367
		return $this;
368
	}
369
370
	/**
371
	 * @return string
372
	 */
373
	public function getContactId(): string {
374
		return $this->contactId;
375
	}
376
377
378
	/**
379
	 * @param string $contactMeta
380
	 *
381
	 * @return Member
382
	 */
383
	public function setContactMeta(string $contactMeta): self {
384
		$this->contactMeta = $contactMeta;
385
386
		return $this;
387
	}
388
389
	/**
390
	 * @return string
391
	 */
392
	public function getContactMeta(): string {
393
		return $this->contactMeta;
394
	}
395
396
397
	/**
398
	 * @param Circle $circle
399
	 *
400
	 * @return self
401
	 */
402
	public function setCircle(Circle $circle): self {
403
		$this->circle = $circle;
404
405
		return $this;
406
	}
407
408
	/**
409
	 * @return Circle
410
	 */
411
	public function getCircle(): Circle {
412
		return $this->circle;
413
	}
414
415
	/**
416
	 * @return bool
417
	 */
418
	public function hasCircle(): bool {
419
		return (!is_null($this->circle));
420
	}
421
422
423
	/**
424
	 * @param int $joined
425
	 *
426
	 * @return Member
427
	 */
428
	public function setJoined(int $joined): self {
429
		$this->joined = $joined;
430
431
		return $this;
432
	}
433
434
	/**
435
	 * @return int
436
	 */
437
	public function getJoined(): int {
438
		return $this->joined;
439
	}
440
441
442
	/**
443
	 * @return bool
444
	 */
445
	public function isMember(): bool {
446
		return ($this->level > 0);
447
	}
448
449
450
	/**
451
	 * @param Member $member
452
	 * @param bool $full
453
	 *
454
	 * @return bool
455
	 */
456
	public function compareWith(Member $member, bool $full = true): bool {
457
		if ($this->getId() !== $member->getId()
458
			|| $this->getCircleId() !== $member->getCircleId()
459
			|| $this->getSingleId() !== $member->getSingleId()
460
			|| $this->getUserId() !== $member->getUserId()
461
			|| $this->getUserType() <> $member->getUserType()
462
			|| $this->getInstance() !== $member->getInstance()) {
463
			return false;
464
		}
465
466
		if ($full
0 ignored issues
show
Unused Code introduced by
This if statement, and the following return statement can be replaced with return !($full && ($this...$member->getStatus()));.
Loading history...
467
			&& ($this->getLevel() <> $member->getLevel()
468
				|| $this->getStatus() !== $member->getStatus())) {
469
			return false;
470
		}
471
472
		return true;
473
	}
474
475
476
	/**
477
	 * @param array $data
478
	 *
479
	 * @return $this
480
	 * @throws InvalidItemException
481
	 */
482
	public function import(array $data): IDeserializable {
483
		if ($this->get('user_id', $data) === '') {
484
			throw new InvalidItemException();
485
		}
486
487
		$this->setId($this->get('id', $data));
488
		$this->setCircleId($this->get('circle_id', $data));
489
		$this->setSingleId($this->get('single_id', $data));
490
		$this->setUserId($this->get('user_id', $data));
491
		$this->setUserType($this->getInt('user_type', $data));
492
		$this->setInstance($this->get('instance', $data));
493
		$this->setLevel($this->getInt('level', $data));
494
		$this->setStatus($this->get('status', $data));
495
		$this->setCachedName($this->get('cached_name', $data));
496
		$this->setCachedUpdate($this->getInt('cached_update', $data));
497
		$this->setNote($this->get('note', $data));
498
		$this->setContactId($this->get('contact_id', $data));
499
		$this->setContactMeta($this->get('contact_meta', $data));
500
		$this->setJoined($this->getInt('joined', $data));
501
502
		try {
503
			/** @var Circle $circle */
504
			$circle = $this->deserialize($this->getArray('circle', $data), Circle::class);
505
			$this->setCircle($circle);
506
		} catch (InvalidItemException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
507
		}
508
509
		return $this;
510
	}
511
512
513
	/**
514
	 * @return string[]
515
	 */
516
	public function jsonSerialize(): array {
517
		$arr = array_filter(
518
			[
519
				'id'            => $this->getId(),
520
				'circle_id'     => $this->getCircleId(),
521
				'single_id'     => $this->getSingleId(),
522
				'user_id'       => $this->getUserId(),
523
				'user_type'     => $this->getUserType(),
524
				'instance'      => $this->getInstance(),
525
				'level'         => $this->getLevel(),
526
				'status'        => $this->getStatus(),
527
				'cached_name'   => $this->getCachedName(),
528
				'cached_update' => $this->getCachedUpdate(),
529
				'note'          => $this->getNote(),
530
				'contact_id'    => $this->getContactId(),
531
				'contact_meta'  => $this->getContactMeta(),
532
				'joined'        => $this->getJoined()
533
			]
534
		);
535
536
		if ($this->hasCircle()) {
537
			$arr['circle'] = $this->getCircle();
538
		}
539
540
		return $arr;
541
	}
542
543
544
	/**
545
	 * @param array $data
546
	 * @param string $prefix
547
	 *
548
	 * @return INC21QueryRow
549
	 * @throws MemberNotFoundException
550
	 */
551
	public function importFromDatabase(array $data, string $prefix = ''): INC21QueryRow {
552
		if (!array_key_exists($prefix . 'member_id', $data)) {
553
			throw new MemberNotFoundException();
554
		}
555
556
		$this->setId($this->get($prefix . 'member_id', $data));
557
		$this->setCircleId($this->get($prefix . 'circle_id', $data));
558
		$this->setSingleId($this->get($prefix . 'single_id', $data));
559
		$this->setUserId($this->get($prefix . 'user_id', $data));
560
		$this->setUserType($this->getInt($prefix . 'user_type', $data));
561
		$this->setInstance($this->get($prefix . 'instance', $data));
562
		$this->setLevel($this->getInt($prefix . 'level', $data));
563
		$this->setStatus($this->get($prefix . 'status', $data));
564
		$this->setCachedName($this->get($prefix . 'cached_name', $data));
565
		$this->setNote($this->get($prefix . 'note', $data));
566
		$this->setContactId($this->get($prefix . 'contact_id', $data));
567
		$this->setContactMeta($this->get($prefix . 'contact_meta', $data));
568
569
		$cachedUpdate = $this->get($prefix . 'cached_update', $data);
570
		if ($cachedUpdate !== '') {
571
			$this->setCachedUpdate(DateTime::createFromFormat('Y-m-d H:i:s', $cachedUpdate)->getTimestamp());
572
		}
573
574
		$joined = $this->get($prefix . 'joined', $data);
575
		if ($joined !== '') {
576
			$this->setJoined(DateTime::createFromFormat('Y-m-d H:i:s', $joined)->getTimestamp());
577
		}
578
579
		if ($this->getInstance() === '') {
580
			$this->setInstance($this->get('_params.local', $data));
581
		}
582
583
		if ($prefix === '') {
584
			$this->getManager()->importCircleFromDatabase($this, $data);
585
		}
586
587
		return $this;
588
	}
589
590
591
	/**
592
	 * @param string $levelString
593
	 *
594
	 * @return int
595
	 * @throws MemberLevelException
596
	 */
597 View Code Duplication
	public static function parseLevelString(string $levelString): int {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
598
		$levelString = ucfirst(strtolower($levelString));
599
		$level = array_search($levelString, Member::$DEF_LEVEL);
600
601
		if (!$level) {
602
			$all = implode(', ', array_values(self::$DEF_LEVEL));
603
			throw new MemberLevelException('Available levels: ' . $all);
604
		}
605
606
		return (int)$level;
607
	}
608
609
	/**
610
	 * @param string $typeString
611
	 *
612
	 * @return int
613
	 * @throws UserTypeNotFoundException
614
	 */
615 View Code Duplication
	public static function parseTypeString(string $typeString): int {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
616
		$typeString = strtolower($typeString);
617
		$type = array_search($typeString, Member::$DEF_TYPE);
618
619
		if (!$type) {
620
			$all = implode(', ', array_values(self::$DEF_TYPE));
621
			throw new UserTypeNotFoundException('Available types: ' . $all);
622
		}
623
624
		return (int)$type;
625
	}
626
627
}
628
629