1<?php
2
3declare(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 <maxence@artificial-owl.com>
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
32namespace OCA\Circles\Model;
33
34use ArtificialOwl\MySmallPhpTools\Db\Nextcloud\nc22\INC22QueryRow;
35use ArtificialOwl\MySmallPhpTools\Exceptions\InvalidItemException;
36use ArtificialOwl\MySmallPhpTools\IDeserializable;
37use ArtificialOwl\MySmallPhpTools\Traits\Nextcloud\nc22\TNC22Deserialize;
38use ArtificialOwl\MySmallPhpTools\Traits\TArrayTools;
39use DateTime;
40use JsonSerializable;
41use OC;
42use OC\Files\Cache\Cache;
43use OC\Share20\Share;
44use OCA\Circles\AppInfo\Application;
45use OCA\Circles\ShareByCircleProvider;
46use OCP\Files\IRootFolder;
47use OCP\IURLGenerator;
48use OCP\IUserManager;
49use OCP\Share\Exceptions\IllegalIDChangeException;
50use OCP\Share\IShare;
51
52/**
53 * Class ShareWrapper
54 *
55 * @package OCA\Circles\Model
56 */
57class ShareWrapper extends ManagedModel implements IDeserializable, INC22QueryRow, JsonSerializable {
58	use TArrayTools;
59	use TNC22Deserialize;
60
61
62	/** @var string */
63	private $id = '';
64
65	/** @var int */
66	private $permissions = 0;
67
68	/** @var string */
69	private $itemType = '';
70
71	/** @var int */
72	private $itemSource = 0;
73
74	/** @var string */
75	private $itemTarget = '';
76
77	/** @var int */
78	private $fileSource = 0;
79
80	/** @var string */
81	private $fileTarget = '';
82
83	/** @var string */
84	private $token = '';
85
86	/** @var int */
87	private $status = 0;
88
89	/** @var string */
90	private $providerId = '';
91
92	/** @var DateTime */
93	private $shareTime = '';
94
95	/** @var string */
96	private $sharedWith = '';
97
98	/** @var string */
99	private $sharedBy = '';
100
101	/** @var string */
102	private $shareOwner = '';
103
104	/** @var int */
105	private $shareType = 0;
106
107	/** @var Circle */
108	private $circle;
109
110	/** @var int */
111	private $childId = 0;
112
113	/** @var string */
114	private $childFileTarget = '';
115
116	/** @var int */
117	private $childPermissions = 0;
118
119	/** @var FileCacheWrapper */
120	private $fileCache;
121
122	/** @var Member */
123	private $initiator;
124
125	/** @var Member */
126	private $owner;
127
128	/** @var ShareToken */
129	private $shareToken;
130
131
132	/**
133	 * @param string $id
134	 *
135	 * @return ShareWrapper
136	 */
137	public function setId(string $id): self {
138		$this->id = $id;
139
140		return $this;
141	}
142
143	/**
144	 * @return string
145	 */
146	public function getId(): string {
147		return $this->id;
148	}
149
150
151	/**
152	 * @param int $permissions
153	 *
154	 * @return ShareWrapper
155	 */
156	public function setPermissions(int $permissions): self {
157		$this->permissions = $permissions;
158
159		return $this;
160	}
161
162	/**
163	 * @return int
164	 */
165	public function getPermissions(): int {
166		return $this->permissions;
167	}
168
169
170	/**
171	 * @param string $itemType
172	 *
173	 * @return ShareWrapper
174	 */
175	public function setItemType(string $itemType): self {
176		$this->itemType = $itemType;
177
178		return $this;
179	}
180
181	/**
182	 * @return string
183	 */
184	public function getItemType(): string {
185		return $this->itemType;
186	}
187
188
189	/**
190	 * @param int $itemSource
191	 *
192	 * @return ShareWrapper
193	 */
194	public function setItemSource(int $itemSource): self {
195		$this->itemSource = $itemSource;
196
197		return $this;
198	}
199
200	/**
201	 * @return int
202	 */
203	public function getItemSource(): int {
204		return $this->itemSource;
205	}
206
207
208	/**
209	 * @param string $itemTarget
210	 *
211	 * @return ShareWrapper
212	 */
213	public function setItemTarget(string $itemTarget): self {
214		$this->itemTarget = $itemTarget;
215
216		return $this;
217	}
218
219	/**
220	 * @return string
221	 */
222	public function getItemTarget(): string {
223		return $this->itemTarget;
224	}
225
226
227	/**
228	 * @param int $fileSource
229	 *
230	 * @return ShareWrapper
231	 */
232	public function setFileSource(int $fileSource): self {
233		$this->fileSource = $fileSource;
234
235		return $this;
236	}
237
238	/**
239	 * @return int
240	 */
241	public function getFileSource(): int {
242		return $this->fileSource;
243	}
244
245
246	/**
247	 * @param string $fileTarget
248	 *
249	 * @return ShareWrapper
250	 */
251	public function setFileTarget(string $fileTarget): self {
252		$this->fileTarget = $fileTarget;
253
254		return $this;
255	}
256
257	/**
258	 * @return string
259	 */
260	public function getFileTarget(): string {
261		return $this->fileTarget;
262	}
263
264
265	/**
266	 * @param string $token
267	 *
268	 * @return ShareWrapper
269	 */
270	public function setToken(string $token): self {
271		$this->token = $token;
272
273		return $this;
274	}
275
276	/**
277	 * @return string
278	 */
279	public function getToken(): string {
280		return $this->token;
281	}
282
283
284	/**
285	 * @param int $status
286	 *
287	 * @return ShareWrapper
288	 */
289	public function setStatus(int $status): self {
290		$this->status = $status;
291
292		return $this;
293	}
294
295	/**
296	 * @return int
297	 */
298	public function getStatus(): int {
299		return $this->status;
300	}
301
302
303	/**
304	 * @param string $providerId
305	 *
306	 * @return $this
307	 */
308	public function setProviderId(string $providerId): self {
309		$this->providerId = $providerId;
310
311		return $this;
312	}
313
314	/**
315	 * @return string
316	 */
317	public function getProviderId(): string {
318		return $this->providerId;
319	}
320
321
322	/**
323	 * @param DateTime $shareTime
324	 *
325	 * @return ShareWrapper
326	 */
327	public function setShareTime(DateTime $shareTime): self {
328		$this->shareTime = $shareTime;
329
330		return $this;
331	}
332
333	/**
334	 * @return DateTime
335	 */
336	public function getShareTime(): DateTime {
337		return $this->shareTime;
338	}
339
340
341	/**
342	 * @param string $sharedWith
343	 *
344	 * @return ShareWrapper
345	 */
346	public function setSharedWith(string $sharedWith): self {
347		$this->sharedWith = $sharedWith;
348
349		return $this;
350	}
351
352	/**
353	 * @return string
354	 */
355	public function getSharedWith(): string {
356		return $this->sharedWith;
357	}
358
359	/**
360	 * @param string $sharedBy
361	 *
362	 * @return ShareWrapper
363	 */
364	public function setSharedBy(string $sharedBy): self {
365		$this->sharedBy = $sharedBy;
366
367		return $this;
368	}
369
370	/**
371	 * @return string
372	 */
373	public function getSharedBy(): string {
374		return $this->sharedBy;
375	}
376
377
378	/**
379	 * @param string $shareOwner
380	 *
381	 * @return ShareWrapper
382	 */
383	public function setShareOwner(string $shareOwner): self {
384		$this->shareOwner = $shareOwner;
385
386		return $this;
387	}
388
389	/**
390	 * @return string
391	 */
392	public function getShareOwner(): string {
393		return $this->shareOwner;
394	}
395
396
397	/**
398	 * @param int $shareType
399	 *
400	 * @return ShareWrapper
401	 */
402	public function setShareType(int $shareType): self {
403		$this->shareType = $shareType;
404
405		return $this;
406	}
407
408	/**
409	 * @return int
410	 */
411	public function getShareType(): int {
412		return $this->shareType;
413	}
414
415
416	/**
417	 * @param Circle $circle
418	 *
419	 * @return ShareWrapper
420	 */
421	public function setCircle(Circle $circle): self {
422		$this->circle = $circle;
423
424		return $this;
425	}
426
427	/**
428	 * @return Circle
429	 */
430	public function getCircle(): Circle {
431		return $this->circle;
432	}
433
434	/**
435	 * @return bool
436	 */
437	public function hasCircle(): bool {
438		return (!is_null($this->circle));
439	}
440
441
442	/**
443	 * @param int $childId
444	 *
445	 * @return ShareWrapper
446	 */
447	public function setChildId(int $childId): self {
448		$this->childId = $childId;
449
450		return $this;
451	}
452
453	/**
454	 * @return int
455	 */
456	public function getChildId(): int {
457		return $this->childId;
458	}
459
460
461	/**
462	 * @param string $childFileTarget
463	 *
464	 * @return ShareWrapper
465	 */
466	public function setChildFileTarget(string $childFileTarget): self {
467		$this->childFileTarget = $childFileTarget;
468
469		return $this;
470	}
471
472	/**
473	 * @return string
474	 */
475	public function getChildFileTarget(): string {
476		return $this->childFileTarget;
477	}
478
479
480	/**
481	 * @param int $childPermissions
482	 *
483	 * @return ShareWrapper
484	 */
485	public function setChildPermissions(int $childPermissions): self {
486		$this->childPermissions = $childPermissions;
487
488		return $this;
489	}
490
491	/**
492	 * @return int
493	 */
494	public function getChildPermissions(): int {
495		return $this->childPermissions;
496	}
497
498
499	/**
500	 * @param FileCacheWrapper $fileCache
501	 *
502	 * @return $this
503	 */
504	public function setFileCache(FileCacheWrapper $fileCache): self {
505		$this->fileCache = $fileCache;
506
507		return $this;
508	}
509
510	/**
511	 * @return FileCacheWrapper
512	 */
513	public function getFileCache(): FileCacheWrapper {
514		return $this->fileCache;
515	}
516
517	/**
518	 * @return bool
519	 */
520	public function hasFileCache(): bool {
521		return (!is_null($this->fileCache));
522	}
523
524
525	/**
526	 * @param Member $initiator
527	 *
528	 * @return ShareWrapper
529	 */
530	public function setInitiator(Member $initiator): self {
531		$this->initiator = $initiator;
532
533		return $this;
534	}
535
536	/**
537	 * @return Member
538	 */
539	public function getInitiator(): Member {
540		return $this->initiator;
541	}
542
543	/**
544	 * @return bool
545	 */
546	public function hasInitiator(): bool {
547		return (!is_null($this->initiator));
548	}
549
550
551	/**
552	 * @param Member $owner
553	 *
554	 * @return ShareWrapper
555	 */
556	public function setOwner(Member $owner): self {
557		$this->owner = $owner;
558
559		return $this;
560	}
561
562	/**
563	 * @return Member
564	 */
565	public function getOwner(): Member {
566		return $this->owner;
567	}
568
569	/**
570	 * @return bool
571	 */
572	public function hasOwner(): bool {
573		return (!is_null($this->owner));
574	}
575
576
577	/**
578	 * @param ShareToken $shareToken
579	 *
580	 * @return ShareWrapper
581	 */
582	public function setShareToken(ShareToken $shareToken): self {
583		$this->shareToken = $shareToken;
584
585		return $this;
586	}
587
588	/**
589	 * @return ShareToken
590	 */
591	public function getShareToken(): ShareToken {
592		return $this->shareToken;
593	}
594
595	/**
596	 * @return bool
597	 */
598	public function hasShareToken(): bool {
599		return !is_null($this->shareToken);
600	}
601
602
603	/**
604	 * @param IRootFolder $rootFolder
605	 * @param IUserManager $userManager
606	 * @param IURLGenerator $urlGenerator
607	 * @param bool $nullOnMissingFileCache
608	 *
609	 * @return IShare
610	 * @throws IllegalIDChangeException
611	 */
612	public function getShare(
613		IRootFolder $rootFolder,
614		IUserManager $userManager,
615		IURLGenerator $urlGenerator,
616		bool $nullOnMissingFileCache = false
617	): ?IShare {
618		$share = new Share($rootFolder, $userManager);
619		$share->setId($this->getId());
620		$share->setPermissions($this->getPermissions());
621		$share->setNodeType($this->getItemType());
622		$share->setNodeId($this->getFileSource());
623		$share->setTarget($this->getFileTarget());
624		$share->setProviderId($this->getProviderId());
625		$share->setStatus($this->getStatus());
626
627		$share->setShareTime($this->getShareTime())
628			  ->setSharedWith($this->getSharedWith())
629			  ->setSharedBy($this->getSharedBy())
630			  ->setShareOwner($this->getShareOwner())
631			  ->setShareType($this->getShareType());
632
633		if ($this->getChildId() > 0) {
634			$share->setTarget($this->getChildFileTarget());
635			if ($this->getChildPermissions() < $this->getPermissions()) {
636				$share->setPermissions($this->getChildPermissions());
637			}
638		}
639
640		$this->setShareDisplay($share, $urlGenerator);
641
642		if ($this->hasFileCache()) {
643			if (!$this->getFileCache()->isAccessible()) {
644				return null;
645			}
646			$share->setNodeCacheEntry(
647				Cache::cacheEntryFromData($this->getFileCache()->toCache(), OC::$server->getMimeTypeLoader())
648			);
649		} elseif ($nullOnMissingFileCache) {
650			return null;
651		}
652
653		return $share;
654	}
655
656
657	/**
658	 * @param IShare $share
659	 * @param IURLGenerator $urlGenerator
660	 */
661	private function setShareDisplay(IShare $share, IURLGenerator $urlGenerator) {
662		if (!$this->hasCircle()) {
663			return;
664		}
665
666		$circle = $this->getCircle();
667		if ($circle->isConfig(Circle::CFG_PERSONAL)
668			&& $this->hasInitiator()
669			&& $circle->getOwner()->getSingleId() !== $this->getInitiator()->getSingleId()) {
670			$share->setSharedWithDisplayName(' ');
671
672			return;
673		}
674
675		$display = $circle->getDisplayName();
676		if ($circle->getSource() === Member::TYPE_CIRCLE) {
677			$display .= ' (Circle owned by ' . $circle->getOwner()->getDisplayName() . ')';
678		} else {
679			$display .= ' (' . Circle::$DEF_SOURCE[$circle->getSource()] . ')';
680		}
681
682		$share->setSharedWithDisplayName($display);
683
684		$icon = $urlGenerator->getAbsoluteURL(
685			$urlGenerator->imagePath(Application::APP_ID, 'circles.svg')
686		);
687		$share->setSharedWithAvatar($icon);
688
689
690//		if (array_key_exists('circle_type', $data)
691//			&& method_exists($share, 'setSharedWithDisplayName')) {
692//			$name = $data['circle_name'];
693//			if ($data['circle_alt_name'] !== '') {
694//				$name = $data['circle_alt_name'];
695//			}
696//
697//			$share->setSharedWithAvatar(CirclesService::getCircleIcon($data['circle_type']))
698//				  ->setSharedWithDisplayName(
699//					  sprintf(
700//						  ' % s(%s, %s)', $name,
701//						  $this->l10n->t(DeprecatedCircle::TypeLongString($data['circle_type'])),
702//						  $this->miscService->getDisplayName($data['circle_owner'], true)
703//					  )
704//				  );
705//		}
706	}
707
708
709	/**
710	 * @param array $data
711	 *
712	 * @return IDeserializable
713	 * @throws InvalidItemException
714	 */
715	public function import(array $data): IDeserializable {
716		if ($this->getInt('id', $data) === 0) {
717			throw new InvalidItemException();
718		}
719
720		$shareTime = new DateTime();
721		$shareTime->setTimestamp($this->getInt('shareTime', $data));
722
723		$this->setId($this->get('id', $data))
724			 ->setShareType($this->getInt('shareType', $data))
725			 ->setPermissions($this->getInt('permissions', $data))
726			 ->setItemType($this->get('itemType', $data))
727			 ->setItemSource($this->getInt('itemSource', $data))
728			 ->setItemTarget($this->get('itemTarget', $data))
729			 ->setFileSource($this->getInt('fileSource', $data))
730			 ->setFileTarget($this->get('fileTarget', $data))
731			 ->setSharedWith($this->get('sharedWith', $data))
732			 ->setSharedBy($this->get('uidInitiator', $data))
733			 ->setShareOwner($this->get('uidOwner', $data))
734			 ->setToken($this->get('token', $data))
735			 ->setShareTime($shareTime);
736
737		$this->setChildId($this->getInt('childId', $data))
738			 ->setChildFileTarget($this->get('childFileTarget', $data))
739			 ->setChildPermissions($this->getInt('childPermissions', $data))
740			 ->setProviderId(ShareByCircleProvider::IDENTIFIER)
741			 ->setStatus(Ishare::STATUS_ACCEPTED);
742
743		try {
744			$circle = new Circle();
745			$this->setCircle($circle->import($this->getArray('circle', $data)));
746		} catch (InvalidItemException $e) {
747		}
748
749		try {
750			$fileCache = new FileCacheWrapper();
751			$this->setFileCache($fileCache->import($this->getArray('fileCache', $data)));
752		} catch (InvalidItemException $e) {
753		}
754
755		try {
756			$owner = new Member();
757			$this->setOwner($owner->import($this->getArray('owner', $data)));
758		} catch (InvalidItemException $e) {
759		}
760
761		try {
762			$member = new Member();
763			$this->setInitiator($member->import($this->getArray('viewer', $data)));
764		} catch (InvalidItemException $e) {
765		}
766
767		try {
768			$shareToken = new ShareToken();
769			$this->setShareToken($shareToken->import($this->getArray('shareToken', $data)));
770		} catch (InvalidItemException $e) {
771		}
772
773		return $this;
774	}
775
776
777	/**
778	 * @param array $data
779	 * @param string $prefix
780	 *
781	 * @return INC22QueryRow
782	 */
783	public function importFromDatabase(array $data, string $prefix = ''): INC22QueryRow {
784		$shareTime = new DateTime();
785		$shareTime->setTimestamp($this->getInt($prefix . 'stime', $data));
786
787		$this->setId($this->get($prefix . 'id', $data))
788			 ->setShareType($this->getInt($prefix . 'share_type', $data))
789			 ->setPermissions($this->getInt($prefix . 'permissions', $data))
790			 ->setItemType($this->get($prefix . 'item_type', $data))
791			 ->setItemSource($this->getInt($prefix . 'item_source', $data))
792			 ->setItemTarget($this->get($prefix . 'item_target', $data))
793			 ->setFileSource($this->getInt($prefix . 'file_source', $data))
794			 ->setFileTarget($this->get($prefix . 'file_target', $data))
795			 ->setSharedWith($this->get($prefix . 'share_with', $data))
796			 ->setSharedBy($this->get($prefix . 'uid_initiator', $data))
797			 ->setShareOwner($this->get($prefix . 'uid_owner', $data))
798			 ->setToken($this->get($prefix . 'token', $data))
799			 ->setShareTime($shareTime);
800
801//		if (($password = $this->get('personal_password', $data, '')) !== '') {
802//			$share->setPassword($this->get('personal_password', $data, ''));
803//		} else if (($password = $this->get('password', $data, '')) !== '') {
804//			$share->setPassword($this->get('password', $data, ''));
805//		}
806
807		$this->setChildId($this->getInt($prefix . 'child_id', $data))
808			 ->setChildFileTarget($this->get($prefix . 'child_file_target', $data))
809			 ->setChildPermissions($this->getInt($prefix . 'child_permissions', $data))
810			 ->setProviderId(ShareByCircleProvider::IDENTIFIER)
811			 ->setStatus(Ishare::STATUS_ACCEPTED);
812
813		$this->getManager()->manageImportFromDatabase($this, $data, $prefix);
814
815		return $this;
816	}
817
818
819	/**
820	 * @return string[]
821	 */
822	public function jsonSerialize(): array {
823		$arr = [
824			'id' => $this->getId(),
825			'shareType' => $this->getShareType(),
826			'providerId' => $this->getProviderId(),
827			'permissions' => $this->getPermissions(),
828			'itemType' => $this->getItemType(),
829			'itemSource' => $this->getItemSource(),
830			'itemTarget' => $this->getItemTarget(),
831			'fileSource' => $this->getFileSource(),
832			'fileTarget' => $this->getFileTarget(),
833			'status' => $this->getStatus(),
834			'shareTime' => $this->getShareTime()->getTimestamp(),
835			'sharedWith' => $this->getSharedWith(),
836			'sharedBy' => $this->getSharedBy(),
837			'shareOwner' => $this->getShareOwner(),
838			'token' => $this->getToken(),
839			'childId' => $this->getChildId(),
840			'childFileTarget' => $this->getChildFileTarget(),
841			'childPermissions' => $this->getChildPermissions()
842		];
843
844		if ($this->hasOwner()) {
845			$arr['owner'] = $this->getOwner();
846		}
847
848		if ($this->hasCircle()) {
849			$arr['circle'] = $this->getCircle();
850		}
851
852		if ($this->hasInitiator()) {
853			$arr['viewer'] = $this->getInitiator();
854		}
855
856		if ($this->hasFileCache()) {
857			$arr['fileCache'] = $this->getFileCache();
858		}
859
860		if ($this->hasShareToken()) {
861			$arr['shareToken'] = $this->getShareToken();
862		}
863
864		return $arr;
865	}
866}
867