Completed
Pull Request — master (#551)
by Maxence
84:52
created

Circle::setMemberOf()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
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\CircleNotFoundException;
42
use OCA\Circles\Exceptions\OwnerNotFoundException;
43
44
45
/**
46
 * Class Circle
47
 *
48
 * ** examples of use of bitwise flags for members management:
49
 *      CFG_OPEN, CFG_REQUEST, CFG_INVITE, CFG_FRIEND
50
 *
51
 * - CFG_OPEN                             => everyone can enter. moderator can add members.
52
 * - CFG_OPEN | CFG_REQUEST               => anyone can initiate a request to join the circle, moderator can
53
 *                                           add members
54
 * - CFG_OPEN | CFG_INVITE                => every one can enter, moderator must send invitation.
55
 * - CFG_OPEN | CFG_INVITE | CFG_REQUEST  => every one send a request, moderator must send invitation.
56
 * - CFG_OPEN | CFG_FRIEND                => useless
57
 * - CFG_OPEN | CFG_FRIEND | *            => useless
58
 *
59
 * - CFG_CIRCLE                           => no one can enter, moderator can add members.
60
 *                                           default config, this is only for code readability.
61
 * - CFG_INVITE                           => no one can enter, moderator must send invitation.
62
 * - CFG_FRIEND                           => no one can enter, but all members can add new member.
63
 * - CFG_REQUEST                          => useless (use CFG_OPEN | CFG_REQUEST)
64
 * - CFG_FRIEND | CFG_REQUEST             => no one can join the circle, but all members can request a
65
 *                                           moderator to accept new member
66
 * - CFG_FRIEND | CFG_INVITE              => no one can join the circle, but all members can add new member.
67
 *                                           An invitation will be generated
68
 * - CFG_FRIEND | CFG_INVITE | CFG_REQUEST  => no one can join the circle, but all members can request a
69
 *                                             moderator to accept new member. An invitation will be generated
70
 *
71
 * @package OCA\Circles\Model
72
 */
73
class Circle extends ManagedModel implements IDeserializable, INC21QueryRow, JsonSerializable {
74
75
76
	use TArrayTools;
77
	use TNC21Deserialize;
78
79
80
	// specific value
81
	const CFG_CIRCLE = 0;        // only for code readability. Circle is locked by default.
82
	const CFG_SINGLE = 1;        // Circle with only one single member.
83
	const CFG_PERSONAL = 2;      // Personal circle, only the owner can see it.
84
85
	// bitwise
86
	const CFG_VISIBLE = 8;        // Visible to everyone, if not visible, people have to know its name to be able to find it
87
	const CFG_OPEN = 16;          // Circle is open, people can join
88
	const CFG_INVITE = 32;        // Adding a member generate an invitation that needs to be accepted
89
	const CFG_REQUEST = 64;       // Request to join Circles needs to be confirmed by a moderator
90
	const CFG_FRIEND = 128;       // Members of the circle can invite their friends
91
	const CFG_PROTECTED = 256;    // Password protected to join/request
92
	const CFG_NO_OWNER = 512;     // no owner, only members
93
	const CFG_HIDDEN = 1024;      // hidden from listing, but available as a share entity
94
	const CFG_BACKEND = 2048;     // Fully hidden, only backend Circles
95
	const CFG_ROOT = 4096;        // Circle cannot be inside another Circle
96
	const CFG_FEDERATED = 8192;   // Federated
97
98
	static $DEF = [
99
		1 => 'S|Single',
100
101
		2    => 'P|Personal',
102
		8    => 'V|Visible',
103
		16   => 'O|Open',
104
		32   => 'I|Invite',
105
		64   => 'JR|Join Request',
106
		128  => 'F|Friends',
107
		256  => 'PP|Password Protected',
108
		512  => 'NO|No Owner',
109
		1024 => 'H|Hidden',
110
		2048 => 'T|Backend',
111
		4096 => 'T|Root',
112
		8192 => 'F|Federated'
113
	];
114
115
116
	/** @var string */
117
	private $id = '';
118
119
	/** @var int */
120
	private $config = 0;
121
122
	/** @var int */
123
	private $type = 0;
124
125
	/** @var string */
126
	private $name = '';
127
128
	/** @var string */
129
	private $altName = '';
130
131
	/** @var Member */
132
	private $owner;
133
134
	/** @var array */
135
	private $members = [];
136
137
	/** @var Member */
138
	private $initiator;
139
140
	/** @var array */
141
	private $settings = [];
142
143
	/** @var string */
144
	private $description = '';
145
146
	/** @var int */
147
	private $contactAddressBook = 0;
148
149
	/** @var string */
150
	private $contactGroupName = '';
151
152
	/** @var string */
153
	private $instance = '';
154
155
//	/** @var bool */
156
//	private $hidden = false;
157
158
	/** @var int */
159
	private $creation = 0;
160
161
162
	/** @var Circle[] */
163
	private $memberOf = null;
164
165
	private $completeJson = false;
166
167
168
	/**
169
	 * Circle constructor.
170
	 */
171
	public function __construct() {
172
	}
173
174
	/**
175
	 * @param string $id
176
	 *
177
	 * @return self
178
	 */
179
	public function setId(string $id): self {
180
		$this->id = $id;
181
182
		return $this;
183
	}
184
185
	/**
186
	 * @return string
187
	 */
188
	public function getId(): string {
189
		return $this->id;
190
	}
191
192
193
	/**
194
	 * @param int $config
195
	 *
196
	 * @return self
197
	 */
198
	public function setConfig(int $config): self {
199
		$this->config = $config;
200
201
//		$this->hidden = false;
202
//		foreach (array_keys(self::$DEF) as $def) {
203
//			if ($this->isType($def) && substr(self::$DEF[$def], 0, 1) === '*') {
204
//				$this->setHidden(true);
205
//				break;
206
//			}
207
//		}
208
209
		return $this;
210
	}
211
212
	/**
213
	 * @return int
214
	 */
215
	public function getConfig(): int {
216
		return $this->config;
217
	}
218
219
	/**
220
	 * @param int $flag
221
	 *
222
	 * @return bool
223
	 */
224
	public function isConfig(int $flag): bool {
225
		return (($this->getConfig() & $flag) !== 0);
226
	}
227
228
229
	/**
230
	 * @param string $name
231
	 *
232
	 * @return self
233
	 */
234
	public function setName(string $name): self {
235
		$this->name = $name;
236
237
		return $this;
238
	}
239
240
	/**
241
	 * @return string
242
	 */
243
	public function getName(): string {
244
		return $this->name;
245
	}
246
247
248
	/**
249
	 * @param string $altName
250
	 *
251
	 * @return self
252
	 */
253
	public function setAltName(string $altName): self {
254
		$this->altName = $altName;
255
256
		return $this;
257
	}
258
259
	/**
260
	 * @return string
261
	 */
262
	public function getAltName(): string {
263
		return $this->altName;
264
	}
265
266
267
	/**
268
	 * @param Member $owner
269
	 *
270
	 * @return self
271
	 */
272
	public function setOwner(Member $owner): self {
273
		$this->owner = $owner;
274
275
		return $this;
276
	}
277
278
	/**
279
	 * @return Member
280
	 */
281
	public function getOwner(): Member {
282
		return $this->owner;
283
	}
284
285
	/**
286
	 * @return bool
287
	 */
288
	public function hasOwner(): bool {
289
		return ($this->owner !== null);
290
	}
291
292
293
	/**
294
	 * @param array $members
295
	 *
296
	 * @return self
297
	 */
298
	public function setMembers(array $members): self {
299
		$this->members = $members;
300
301
		return $this;
302
	}
303
304
	/**
305
	 * @return array
306
	 */
307
	public function getMembers(): array {
308
		if (empty($this->members)) {
309
			$this->getManager()->getMembers($this);
310
		}
311
312
		return $this->members;
313
	}
314
315
316
	/**
317
	 * @param Member $initiator
318
	 *
319
	 * @return Circle
320
	 */
321
	public function setInitiator(Member $initiator): self {
322
		$this->initiator = $initiator;
323
324
		return $this;
325
	}
326
327
	/**
328
	 * @return Member
329
	 */
330
	public function getInitiator(): Member {
331
		return $this->initiator;
332
	}
333
334
	/**
335
	 * @return bool
336
	 */
337
	public function hasInitiator(): bool {
338
		return ($this->initiator !== null);
339
	}
340
341
	/**
342
	 * @param string $instance
343
	 *
344
	 * @return Circle
345
	 */
346
	public function setInstance(string $instance): self {
347
		if ($this->isConfig(self::CFG_NO_OWNER)) {
348
			$this->instance = $instance;
349
		}
350
351
		return $this;
352
	}
353
354
	/**
355
	 * @return string
356
	 * @throws OwnerNotFoundException
357
	 */
358
	public function getInstance(): string {
359
		if ($this->isConfig(self::CFG_NO_OWNER)) {
360
			return $this->instance;
361
		}
362
363
		if (!$this->hasOwner()) {
364
			throw new OwnerNotFoundException('circle has no owner, or not set to have no owner');
365
		}
366
367
		return $this->getOwner()->getInstance();
368
	}
369
370
371
	/**
372
	 * @param array $settings
373
	 *
374
	 * @return self
375
	 */
376
	public function setSettings(array $settings): self {
377
		$this->settings = $settings;
378
379
		return $this;
380
	}
381
382
	/**
383
	 * @return array
384
	 */
385
	public function getSettings(): array {
386
		return $this->settings;
387
	}
388
389
390
	/**
391
	 * @param string $description
392
	 *
393
	 * @return self
394
	 */
395
	public function setDescription(string $description): self {
396
		$this->description = $description;
397
398
		return $this;
399
	}
400
401
	/**
402
	 * @return string
403
	 */
404
	public function getDescription(): string {
405
		return $this->description;
406
	}
407
408
409
	/**
410
	 * @param int $contactAddressBook
411
	 *
412
	 * @return self
413
	 */
414
	public function setContactAddressBook(int $contactAddressBook): self {
415
		$this->contactAddressBook = $contactAddressBook;
416
417
		return $this;
418
	}
419
420
	/**
421
	 * @return int
422
	 */
423
	public function getContactAddressBook(): int {
424
		return $this->contactAddressBook;
425
	}
426
427
428
	/**
429
	 * @param string $contactGroupName
430
	 *
431
	 * @return self
432
	 */
433
	public function setContactGroupName(string $contactGroupName): self {
434
		$this->contactGroupName = $contactGroupName;
435
436
		return $this;
437
	}
438
439
	/**
440
	 * @return string
441
	 */
442
	public function getContactGroupName(): string {
443
		return $this->contactGroupName;
444
	}
445
446
447
//	/**
448
//	 * @param bool $hidden
449
//	 *
450
//	 * @return Circle
451
//	 */
452
//	public function setHidden(bool $hidden): self {
453
//		$this->hidden = $hidden;
454
//
455
//		return $this;
456
//	}
457
//
458
//	/**
459
//	 * @return bool
460
//	 */
461
//	public function isHidden(): bool {
462
//		return $this->hidden;
463
//	}
464
465
466
	/**
467
	 * @param array $memberOf
468
	 *
469
	 * @return $this
470
	 */
471
	public function setMemberOf(array $memberOf): self {
472
		$this->memberOf = $memberOf;
473
474
		return $this;
475
	}
476
477
	/**
478
	 * @return Circle[]
479
	 */
480
	public function memberOf(): array {
481
		if ($this->memberOf === null) {
482
			$this->getManager()->memberOf($this);
483
		}
484
485
		return $this->memberOf;
486
	}
487
488
489
	/**
490
	 * @param int $creation
491
	 *
492
	 * @return self
493
	 */
494
	public function setCreation(int $creation): self {
495
		$this->creation = $creation;
496
497
		return $this;
498
	}
499
500
	/**
501
	 * @return int
502
	 */
503
	public function getCreation(): int {
504
		return $this->creation;
505
	}
506
507
508
	/**
509
	 * @param array $data
510
	 *
511
	 * @return $this
512
	 * @throws InvalidItemException
513
	 */
514
	public function import(array $data): IDeserializable {
515
		if ($this->get('id', $data) === '') {
516
			throw new InvalidItemException();
517
		}
518
519
		$this->setId($this->get('id', $data))
520
			 ->setName($this->get('name', $data))
521
			 ->setAltName($this->get('alt_name', $data))
522
			 ->setConfig($this->getInt('config', $data))
523
			 ->setSettings($this->getArray('settings', $data))
524
//			 ->setContactAddressBook($this->get('contact_addressbook', $data))
525
//			 ->setContactGroupName($this->get('contact_groupname', $data))
526
			 ->setDescription($this->get('description', $data))
527
			 ->setCreation($this->getInt('creation', $data));
528
529
530
		try {
531
			/** @var Member $owner */
532
			$owner = $this->deserialize($this->getArray('owner', $data), Member::class);
533
			$this->setOwner($owner);
534
		} catch (InvalidItemException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
535
		}
536
537
		try {
538
			/** @var Member $initiator */
539
			$initiator = $this->deserialize($this->getArray('initiator', $data), Member::class);
540
			$this->setInitiator($initiator);
541
		} catch (InvalidItemException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
542
		}
543
544
		return $this;
545
	}
546
547
548
	/**
549
	 * @return array
550
	 */
551
	public function jsonSerialize(): array {
552
		$arr = [
553
			'id'          => $this->getId(),
554
			'name'        => $this->getName(),
555
			'alt_name'    => $this->getAltName(),
556
			'config'      => $this->getConfig(),
557
			'description' => $this->getDescription(),
558
			'settings'    => $this->getSettings(),
559
			//			'hidden'      => $this->isHidden(),
560
			'creation'    => $this->getCreation()
561
		];
562
563
		if ($this->hasOwner()) {
564
			$arr['owner'] = $this->getOwner();
565
		}
566
567
		if ($this->hasInitiator()) {
568
			$arr['initiator'] = $this->getInitiator();
569
		}
570
571
		if ($this->getManager()->isFullDetails()) {
572
			$arr['memberOf'] = $this->memberOf();
573
		}
574
575
		return array_filter($arr);
576
	}
577
578
579
	/**
580
	 * @param array $data
581
	 * @param string $prefix
582
	 *
583
	 * @return INC21QueryRow
584
	 * @throws CircleNotFoundException
585
	 */
586
	public function importFromDatabase(array $data, string $prefix = ''): INC21QueryRow {
587
		if (!array_key_exists($prefix . 'unique_id', $data)) {
588
			throw new CircleNotFoundException();
589
		}
590
591
		$this->setId($this->get($prefix . 'unique_id', $data))
592
			 ->setName($this->get($prefix . 'name', $data))
593
			 ->setAltName($this->get($prefix . 'alt_name', $data))
594
			 ->setConfig($this->getInt($prefix . 'config', $data))
595
			 ->setInstance($this->get($prefix . 'instance', $data))
596
			 ->setSettings($this->getArray($prefix . 'settings', $data))
597
			 ->setContactAddressBook($this->getInt($prefix . 'contact_addressbook', $data))
598
			 ->setContactGroupName($this->get($prefix . 'contact_groupname', $data))
599
			 ->setDescription($this->get($prefix . 'description', $data));
600
601
		$creation = $this->get($prefix . 'creation', $data);
602
		$this->setCreation(DateTime::createFromFormat('Y-m-d H:i:s', $creation)->getTimestamp());
603
604
		$this->getManager()->importOwnerFromDatabase($this, $data);
605
		$this->getManager()->importInitiatorFromDatabase($this, $data);
606
607
		return $this;
608
	}
609
610
611
	/**
612
	 * @param Circle $circle
613
	 *
614
	 * @return bool
615
	 * @throws OwnerNotFoundException
616
	 */
617
	public function compareWith(Circle $circle): bool {
618
		if ($this->getId() !== $circle->getId()
619
			|| $this->getInstance() !== $circle->getInstance()
620
			|| $this->getConfig() !== $circle->getConfig()) {
621
			return false;
622
		}
623
624
		if ($this->hasOwner()
625
			&& (!$circle->hasOwner()
626
				|| !$this->getOwner()->compareWith($circle->getOwner()))) {
627
			return false;
628
		}
629
630
		if ($this->hasInitiator()
0 ignored issues
show
Unused Code introduced by
This if statement, and the following return statement can be replaced with return !($this->hasIniti...cle->getInitiator())));.
Loading history...
631
			&& (!$circle->hasInitiator()
632
				|| !$this->getInitiator()->compareWith($circle->getInitiator()))) {
633
			return false;
634
		}
635
636
		return true;
637
	}
638
639
}
640
641