Completed
Push — master ( d5da72...6387aa )
by Maxence
01:37
created

FilesService::isDocumentUpToDate()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 13
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 7
nc 3
nop 1
1
<?php
2
/**
3
 * Files_FullTextSearch - Index the content of your files
4
 *
5
 * This file is licensed under the Affero General Public License version 3 or
6
 * later. See the COPYING file.
7
 *
8
 * @author Maxence Lange <[email protected]>
9
 * @copyright 2018
10
 * @license GNU AGPL version 3 or any later version
11
 *
12
 * This program is free software: you can redistribute it and/or modify
13
 * it under the terms of the GNU Affero General Public License as
14
 * published by the Free Software Foundation, either version 3 of the
15
 * License, or (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU Affero General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU Affero General Public License
23
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
24
 *
25
 */
26
27
namespace OCA\Files_FullTextSearch\Service;
28
29
30
use Exception;
31
use OC\Share\Constants;
32
use OC\Share\Share;
33
use OCA\Files_FullTextSearch\Exceptions\FileIsNotIndexableException;
34
use OCA\Files_FullTextSearch\Model\FilesDocument;
35
use OCA\Files_FullTextSearch\Provider\FilesProvider;
36
use OCA\FullTextSearch\Exceptions\InterruptException;
37
use OCA\FullTextSearch\Exceptions\TickDoesNotExistException;
38
use OCA\FullTextSearch\Model\DocumentAccess;
39
use OCA\FullTextSearch\Model\Index;
40
use OCA\FullTextSearch\Model\IndexDocument;
41
use OCA\FullTextSearch\Model\Runner;
42
use OCP\Files\File;
43
use OCP\Files\FileInfo;
44
use OCP\Files\Folder;
45
use OCP\Files\InvalidPathException;
46
use OCP\Files\IRootFolder;
47
use OCP\Files\Node;
48
use OCP\Files\NotFoundException;
49
use OCP\Files\NotPermittedException;
50
use OCP\IUserManager;
51
use OCP\Share\IManager;
52
53
class FilesService {
54
55
	const DOCUMENT_TYPE = 'files';
56
57
	const MIMETYPE_TEXT = 'files_text';
58
	const MIMETYPE_PDF = 'files_pdf';
59
	const MIMETYPE_OFFICE = 'files_office';
60
	const MIMETYPE_IMAGE = 'files_image';
61
	const MIMETYPE_AUDIO = 'files_audio';
62
63
64
	/** @var IRootFolder */
65
	private $rootFolder;
66
67
	/** @var IUserManager */
68
	private $userManager;
69
70
	/** @var IManager */
71
	private $shareManager;
72
73
	/** @var ConfigService */
74
	private $configService;
75
76
	/** @var ExternalFilesService */
77
	private $externalFilesService;
78
79
	/** @var MiscService */
80
	private $miscService;
81
82
83
	/**
84
	 * FilesService constructor.
85
	 *
86
	 * @param IRootFolder $rootFolder
87
	 * @param IUserManager $userManager
88
	 * @param IManager $shareManager
89
	 * @param ConfigService $configService
90
	 * @param ExternalFilesService $externalFilesService
91
	 * @param MiscService $miscService
92
	 *
93
	 * @internal param IProviderFactory $factory
94
	 */
95 View Code Duplication
	public function __construct(
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...
96
		IRootFolder $rootFolder, IUserManager $userManager, IManager $shareManager,
97
		ConfigService $configService, ExternalFilesService $externalFilesService,
98
		MiscService $miscService
99
	) {
100
		$this->rootFolder = $rootFolder;
101
		$this->userManager = $userManager;
102
		$this->shareManager = $shareManager;
103
104
		$this->configService = $configService;
105
		$this->externalFilesService = $externalFilesService;
106
		$this->miscService = $miscService;
107
	}
108
109
110
	/**
111
	 * @param Runner $runner
112
	 * @param string $userId
113
	 *
114
	 * @return FilesDocument[]
115
	 * @throws InterruptException
116
	 * @throws InvalidPathException
117
	 * @throws NotFoundException
118
	 * @throws TickDoesNotExistException
119
	 */
120
	public function getFilesFromUser(Runner $runner, $userId) {
121
122
		$this->externalFilesService->initExternalFilesForUser($userId);
123
124
		/** @var Folder $files */
125
		$files = $this->rootFolder->getUserFolder($userId)
126
								  ->get('/');
127
		$result = $this->getFilesFromDirectory($runner, $userId, $files);
128
129
		return $result;
130
	}
131
132
133
	/**
134
	 * @param Runner $runner
135
	 * @param string $userId
136
	 * @param Folder $node
137
	 *
138
	 * @return FilesDocument[]
139
	 * @throws InterruptException
140
	 * @throws InvalidPathException
141
	 * @throws NotFoundException
142
	 * @throws TickDoesNotExistException
143
	 */
144
	public function getFilesFromDirectory(Runner $runner, $userId, Folder $node) {
145
		$documents = [];
146
147
		if ($node->nodeExists('.noindex')) {
148
			return $documents;
149
		}
150
151
		$files = $node->getDirectoryListing();
152
		foreach ($files as $file) {
153
			$runner->update('getFilesFromDirectory');
154
			try {
155
				$document = $this->generateFilesDocumentFromFile($file, $userId);
156
				$documents[] = $document;
157
			} catch (FileIsNotIndexableException $e) {
158
				/** goto next file */
159
			}
160
161
			if ($file->getType() === FileInfo::TYPE_FOLDER) {
162
				/** @var $file Folder */
163
				$documents =
164
					array_merge($documents, $this->getFilesFromDirectory($runner, $userId, $file));
165
			}
166
		}
167
168
		return $documents;
169
	}
170
171
172
	/**
173
	 * @param Node $file
174
	 *
175
	 * @param string $viewerId
176
	 *
177
	 * @return FilesDocument
178
	 * @throws FileIsNotIndexableException
179
	 * @throws InvalidPathException
180
	 * @throws NotFoundException
181
	 */
182
	private function generateFilesDocumentFromFile(Node $file, $viewerId = '') {
183
184
		$this->fileMustBeIndexable($file);
185
		$document = new FilesDocument(FilesProvider::FILES_PROVIDER_ID, $file->getId());
186
187
		$ownerId = $file->getOwner()
188
						->getUID();
189
190
		$document->setType($file->getType())
191
				 ->setOwnerId($ownerId)
192
				 ->setViewerId($viewerId)
193
				 ->setModifiedTime($file->getMTime())
194
				 ->setMimetype($file->getMimetype());
195
196
		return $document;
197
	}
198
199
200
	/**
201
	 * @param Node $file
202
	 *
203
	 * @throws FileIsNotIndexableException
204
	 * @throws NotFoundException
205
	 */
206
	private function fileMustBeIndexable(Node $file) {
207
		$this->externalFilesService->externalFileMustBeIndexable($file);
208
	}
209
210
211
	/**
212
	 * @param string $userId
213
	 * @param string $path
214
	 *
215
	 * @return Node
216
	 * @throws NotFoundException
217
	 */
218
	public function getFileFromPath($userId, $path) {
219
		return $this->rootFolder->getUserFolder($userId)
220
								->get($path);
221
	}
222
223
224
	/**
225
	 * @param string $userId
226
	 * @param int $fileId
227
	 *
228
	 * @return Node
229
	 */
230
	public function getFileFromId($userId, $fileId) {
231
232
		$files = $this->rootFolder->getUserFolder($userId)
233
								  ->getById($fileId);
234
235
		if (sizeof($files) === 0) {
236
			return null;
237
		}
238
239
		$file = array_shift($files);
240
241
		return $file;
242
	}
243
244
245
	/**
246
	 * @param int $fileId
247
	 * @param string $viewerId
248
	 *
249
	 * @return string
250
	 */
251
	private function getPathFromViewerId($fileId, $viewerId) {
252
253
		$viewerFiles = $this->rootFolder->getUserFolder($viewerId)
254
										->getById($fileId);
255
256
		if (sizeof($viewerFiles) === 0) {
257
			return '';
258
		}
259
260
		$file = array_shift($viewerFiles);
261
262
		// TODO: better way to do this : we remove the '/userid/files/'
263
		$path = MiscService::noEndSlash(substr($file->getPath(), 8 + strlen($viewerId)));
264
265
		return $path;
266
	}
267
268
269
	/**
270
	 * @param IndexDocument $document
271
	 */
272
	public function setDocumentInfo(IndexDocument $document) {
273
274
		$viewerId = $document->getAccess()
275
							 ->getViewerId();
276
277
		$viewerFiles = $this->rootFolder->getUserFolder($viewerId)
278
										->getById($document->getId());
279
280
		if (sizeof($viewerFiles) === 0) {
281
			return;
282
		}
283
		// we only take the first file
284
		$file = array_shift($viewerFiles);
285
286
		// TODO: better way to do this : we remove the '/userId/files/'
287
		$path = MiscService::noEndSlash(substr($file->getPath(), 7 + strlen($viewerId)));
288
		$document->setInfo('path', $path);
289
		$document->setInfo('filename', $file->getName());
290
	}
291
292
293
	/**
294
	 * @param IndexDocument $document
295
	 */
296
	public function setDocumentTitle(IndexDocument $document) {
297
		$document->setTitle($document->getInfo('path'));
298
	}
299
300
301
	/**
302
	 * @param IndexDocument $document
303
	 */
304
	public function setDocumentLink(IndexDocument $document) {
305
306
		$path = $document->getInfo('path');
307
		$dir = substr($path, 0, -strlen($document->getInfo('filename')));
308
		$filename = $document->getInfo('filename');
309
310
		$document->setLink('/index.php/apps/files/?dir=' . $dir . '&scrollto=' . $filename);
311
	}
312
313
314
	/**
315
	 * @param int $fileId
316
	 *
317
	 * @return string
318
	 */
319
	private function getWebdavId($fileId) {
320
		$instanceId = $this->configService->getSystemValue('instanceid');
321
322
		return sprintf("%08s", $fileId) . $instanceId;
323
	}
324
325
326
	/**
327
	 * @param IndexDocument $document
328
	 *
329
	 * @throws InvalidPathException
330
	 * @throws NotFoundException
331
	 */
332
	public function setDocumentMore(IndexDocument $document) {
333
334
		$access = $document->getAccess();
335
		$file = $this->getFileFromId($access->getViewerId(), $document->getId());
336
337
		if ($file === null) {
338
			return;
339
		}
340
341
		// TODO: better way to do this : we remove the '/userid/files/'
342
		$path = MiscService::noEndSlash(substr($file->getPath(), 7 + strlen($access->getViewerId())));
343
344
		$more = [
345
			'webdav'             => $this->getWebdavId($document->getId()),
346
			'path'               => $path,
347
			'timestamp'          => $file->getMTime(), // FIXME: get the creation date of the file
348
			'mimetype'           => $file->getMimetype(),
349
			'modified_timestamp' => $file->getMTime(),
350
			'etag'               => $file->getEtag(),
351
			'permissions'        => $file->getPermissions(),
352
			'size'               => $file->getSize(),
353
			'favorite'           => false // FIXME: get the favorite status
354
		];
355
356
		$document->setMore($more);
357
	}
358
359
360
	/**
361
	 * @param FilesDocument[] $documents
362
	 *
363
	 * @return FilesDocument[]
364
	 */
365
	public function generateDocuments($documents) {
366
367
		$index = [];
368
369
		foreach ($documents as $document) {
370
			if (!($document instanceof FilesDocument)) {
371
				continue;
372
			}
373
374
			$document->setPath($this->getPathFromViewerId($document->getId(), $document->getViewerId()));
375
376
			try {
377
				$this->updateDocumentFromFilesDocument($document);
378
			} catch (Exception $e) {
379
				// TODO - update $document with a error status instead of just ignore !
380
				$document->getIndex()
381
						 ->setStatus(Index::INDEX_IGNORE);
382
				echo 'Exception: ' . json_encode($e->getTrace()) . ' - ' . $e->getMessage() . "\n";
383
			}
384
385
			$index[] = $document;
386
		}
387
388
		return $index;
389
	}
390
391
392
	/**
393
	 * @param IndexDocument $document
394
	 *
395
	 * @return bool
396
	 */
397
	public function isDocumentUpToDate($document) {
398
		$index = $document->getIndex();
399
400
		if ($index->getStatus() !== Index::INDEX_OK) {
401
			return false;
402
		}
403
404
		if ($index->getLastIndex() >= $document->getModifiedTime()) {
0 ignored issues
show
Unused Code introduced by
This if statement, and the following return statement can be replaced with return $index->getLastIn...ent->getModifiedTime();.
Loading history...
405
			return true;
406
		}
407
408
		return false;
409
	}
410
411
412
	/**
413
	 * @param Index $index
414
	 *
415
	 * @return FilesDocument
0 ignored issues
show
Documentation introduced by
Should the return type not be FilesDocument|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
416
	 * @throws InvalidPathException
417
	 * @throws NotFoundException
418
	 * @throws NotPermittedException
419
	 */
420
	public function updateDocument(Index $index) {
421
		try {
422
			$document = $this->generateDocumentFromIndex($index);
423
424
			return $document;
425
		} catch (FileIsNotIndexableException $e) {
426
			return null;
427
		}
428
	}
429
430
431
	/**
432
	 * @param FilesDocument $document
433
	 *
434
	 * @throws InvalidPathException
435
	 * @throws NotFoundException
436
	 * @throws NotPermittedException
437
	 */
438
	private function updateDocumentFromFilesDocument(FilesDocument $document) {
439
		$userFolder = $this->rootFolder->getUserFolder($document->getViewerId());
440
		$file = $userFolder->get($document->getPath());
441
442
		try {
443
			$this->updateDocumentFromFile($document, $file);
444
		} catch (FileIsNotIndexableException $e) {
445
			$document->getIndex()
446
					 ->setStatus(Index::INDEX_IGNORE);
447
		}
448
449
	}
450
451
452
	/**
453
	 * @param FilesDocument $document
454
	 * @param Node $file
455
	 *
456
	 * @throws FileIsNotIndexableException
457
	 * @throws InvalidPathException
458
	 * @throws NotFoundException
459
	 * @throws NotPermittedException
460
	 */
461
	private function updateDocumentFromFile(FilesDocument $document, Node $file) {
462
		$this->updateAccessFromFile($document, $file);
463
		$this->updateContentFromFile($document, $file);
464
	}
465
466
467
	/**
468
	 * @param Index $index
469
	 *
470
	 * @return FilesDocument
471
	 * @throws FileIsNotIndexableException
472
	 * @throws InvalidPathException
473
	 * @throws NotFoundException
474
	 * @throws NotPermittedException
475
	 */
476
	private function generateDocumentFromIndex(Index $index) {
477
478
		$file = $this->getFileFromId($index->getOwnerId(), $index->getDocumentId());
479
		if ($file === null) {
480
			$index->setStatus(Index::INDEX_REMOVE);
481
			$document = new FilesDocument($index->getProviderId(), $index->getDocumentId());
482
			$document->setIndex($index);
483
484
			return $document;
485
		}
486
487
		$document = $this->generateFilesDocumentFromFile($file, $index->getOwnerId());
488
		$document->setIndex($index);
489
490
		$this->updateDocumentFromFile($document, $file);
491
492
		return $document;
493
	}
494
495
496
	/**
497
	 * @param FilesDocument $document
498
	 * @param Node $file
499
	 *
500
	 * @throws FileIsNotIndexableException
501
	 * @throws InvalidPathException
502
	 * @throws NotFoundException
503
	 */
504
	private function updateAccessFromFile(FilesDocument $document, Node $file) {
505
506
		$index = $document->getIndex();
507
		if (!$index->isStatus(Index::INDEX_FULL)
508
			&& !$index->isStatus(FilesDocument::STATUS_FILE_ACCESS)) {
509
			return;
510
		}
511
512
		$access = $this->getDocumentAccessFromFile($file);
513
		$document->setAccess($access);
514
		$document->setInfo('share_names', $this->getShareNamesFromFile($file, $access));
515
		$document->getIndex()
516
				 ->setOwnerId(
517
					 $document->getAccess()
518
							  ->getOwnerId()
519
				 );
520
521
		$this->updateDocumentWithLocalFiles($document, $file);
522
		$this->externalFilesService->updateDocumentWithExternalFiles($document, $file);
523
524
	}
525
526
527
	/**
528
	 * @param FilesDocument $document
529
	 * @param Node $file
530
	 *
531
	 * @throws NotFoundException
532
	 */
533
	private function updateDocumentWithLocalFiles(FilesDocument $document, Node $file) {
534
535
		if ($file->getStorage()
536
				 ->isLocal() === false) {
537
			return;
538
		}
539
540
		$document->addTag('local');
541
	}
542
543
544
	/**
545
	 * @param FilesDocument $document
546
	 * @param Node $file
547
	 *
548
	 * @throws NotPermittedException
549
	 */
550
	private function updateContentFromFile(FilesDocument $document, Node $file) {
551
552
		$document->setTitle($document->getPath());
553
554
		if (!$document->getIndex()
555
					  ->isStatus(Index::INDEX_CONTENT)
556
			|| $file->getType() !== FileInfo::TYPE_FILE) {
557
			return;
558
		}
559
560
		/** @var File $file */
561
		$this->extractContentFromFileText($document, $file);
562
		$this->extractContentFromFileOffice($document, $file);
563
		$this->extractContentFromFilePDF($document, $file);
564
565
		if ($document->getContent() === null) {
566
			$document->getIndex()
567
					 ->unsetStatus(Index::INDEX_CONTENT);
568
		}
569
	}
570
571
572
	/**
573
	 * @param string $mimeType
574
	 *
575
	 * @return string
576
	 */
577
	private function parseMimeType($mimeType) {
578
579
		if ($mimeType === 'application/octet-stream'
580
			|| substr($mimeType, 0, 5) === 'text/') {
581
			return self::MIMETYPE_TEXT;
582
		}
583
584
		if ($mimeType === 'application/pdf') {
585
			return self::MIMETYPE_PDF;
586
		}
587
588
		$officeMimes = [
589
			'application/msword',
590
			'application/vnd.oasis.opendocument',
591
			'application/vnd.sun.xml',
592
			'application/vnd.openxmlformats-officedocument',
593
			'application/vnd.ms-word',
594
			'application/vnd.ms-powerpoint',
595
			'application/vnd.ms-excel',
596
			'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
597
		];
598
599
		if (in_array($mimeType, $officeMimes)) {
600
			return self::MIMETYPE_OFFICE;
601
		}
602
603
		return '';
604
	}
605
606
607
	/**
608
	 * @param FilesDocument $document
609
	 * @param File $file
610
	 *
611
	 * @throws NotPermittedException
612
	 */
613
	private function extractContentFromFileText(FilesDocument $document, File $file) {
614
615
		if ($this->parseMimeType($document->getMimeType()) !== self::MIMETYPE_TEXT) {
616
			return;
617
		}
618
619
		// on simple text file, elastic search+attachment pipeline can still detect language, useful ?
620
//		$document->setContent($file->getContent(), IndexDocument::NOT_ENCODED);
621
622
		// We try to avoid error with some base encoding of the document:
623
		$document->setContent(base64_encode($file->getContent()), IndexDocument::ENCODED_BASE64);
624
	}
625
626
627
	/**
628
	 * @param FilesDocument $document
629
	 * @param File $file
630
	 *
631
	 * @throws NotPermittedException
632
	 */
633 View Code Duplication
	private function extractContentFromFilePDF(FilesDocument $document, File $file) {
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...
634
635
		if ($this->parseMimeType($document->getMimeType()) !== self::MIMETYPE_PDF) {
636
			return;
637
		}
638
639
		if ($this->configService->getAppValue('files_pdf') !== '1') {
640
			return;
641
		}
642
643
		$document->setContent(base64_encode($file->getContent()), IndexDocument::ENCODED_BASE64);
644
	}
645
646
647
	/**
648
	 * @param FilesDocument $document
649
	 * @param File $file
650
	 *
651
	 * @throws NotPermittedException
652
	 */
653 View Code Duplication
	private function extractContentFromFileOffice(FilesDocument $document, File $file) {
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...
654
655
		if ($this->configService->getAppValue('files_office') !== '1') {
656
			return;
657
		}
658
659
		if ($this->parseMimeType($document->getMimeType()) !== self::MIMETYPE_OFFICE) {
660
			return;
661
		}
662
663
		$document->setContent(base64_encode($file->getContent()), IndexDocument::ENCODED_BASE64);
664
	}
665
666
667
	/**
668
	 * @param Node $file
669
	 *
670
	 * @return DocumentAccess
671
	 * @throws InvalidPathException
672
	 * @throws NotFoundException
673
	 */
674
	private function getDocumentAccessFromFile(Node $file) {
675
676
		$access = new DocumentAccess(
677
			$file->getOwner()
678
				 ->getUID()
679
		);
680
681
		list($users, $groups, $circles, $links) = $this->getSharesFromFileId($file->getId());
682
		$access->setUsers($users);
683
		$access->setGroups($groups);
684
		$access->setCircles($circles);
685
		$access->setLinks($links);
686
687
		return $access;
688
	}
689
690
691
	/**
692
	 * @param Node $file
693
	 * @param DocumentAccess $access
694
	 *
695
	 * @return array
696
	 * @throws InvalidPathException
697
	 * @throws NotFoundException
698
	 */
699
	private function getShareNamesFromFile(Node $file, DocumentAccess $access) {
700
		$shareNames = [];
701
702
		if ($file->getStorage()
703
				 ->isLocal() === false) {
704
			$shares = $this->externalFilesService->getAllSharesFromExternalFile($access);
705
		} else {
706
			$shares = $this->getAllSharesFromFile($file);
707
		}
708
709
		foreach ($shares as $user) {
710
			$shareNames[$user] = $this->getPathFromViewerId($file->getId(), $user);
711
		}
712
713
		return $shareNames;
714
	}
715
716
717
	/**
718
	 * @param Node $file
719
	 *
720
	 * @return array
721
	 */
722
	private function getAllSharesFromFile(Node $file) {
723
		$result = [];
724
725
		$shares = $this->shareManager->getAccessList($file);
726
		if (!array_key_exists('users', $shares)) {
727
			return $result;
728
		}
729
730
		foreach ($shares['users'] as $user) {
731
			if (in_array($user, $result) || $this->userManager->get($user) === null) {
732
				continue;
733
			}
734
735
			array_push($result, $user);
736
		}
737
738
		return $result;
739
	}
740
741
742
	/**
743
	 * @param $fileId
744
	 *
745
	 * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array[].

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
746
	 */
747
	private function getSharesFromFileId($fileId) {
748
749
		$users = $groups = $circles = $links = [];
750
		$shares = Share::getAllSharesForFileId($fileId);
751
752
		foreach ($shares as $share) {
753
			if ($share['parent'] !== null) {
754
				continue;
755
			}
756
757
			$this->parseUsersShares($share, $users);
758
			$this->parseUsersGroups($share, $groups);
759
			$this->parseUsersCircles($share, $circles);
760
			$this->parseUsersLinks($share, $links);
761
		}
762
763
		return [$users, $groups, $circles, $links];
764
	}
765
766
767
	/**
768
	 * @param array $share
769
	 * @param array $users
770
	 */
771 View Code Duplication
	private function parseUsersShares($share, &$users) {
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...
772
		if ((int)$share['share_type'] !== Constants::SHARE_TYPE_USER) {
773
			return;
774
		}
775
776
		if (!in_array($share['share_with'], $users)) {
777
			$users[] = $share['share_with'];
778
		}
779
	}
780
781
782
	/**
783
	 * @param array $share
784
	 * @param array $groups
785
	 */
786 View Code Duplication
	private function parseUsersGroups($share, &$groups) {
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...
787
		if ((int)$share['share_type'] !== Constants::SHARE_TYPE_GROUP) {
788
			return;
789
		}
790
791
		if (!in_array($share['share_with'], $groups)) {
792
			$groups[] = $share['share_with'];
793
		}
794
	}
795
796
797
	/**
798
	 * @param array $share
799
	 * @param array $circles
800
	 */
801 View Code Duplication
	private function parseUsersCircles($share, &$circles) {
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...
802
		if ((int)$share['share_type'] !== Constants::SHARE_TYPE_CIRCLE) {
803
			return;
804
		}
805
806
		if (!in_array($share['share_with'], $circles)) {
807
			$circles[] = $share['share_with'];
808
		}
809
	}
810
811
812
	/**
813
	 * @param array $share
814
	 * @param array $links
815
	 */
816 View Code Duplication
	private function parseUsersLinks($share, &$links) {
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...
817
		if ((int)$share['share_type'] !== Constants::SHARE_TYPE_LINK) {
818
			return;
819
		}
820
821
		if (!in_array($share['share_with'], $links)) {
822
			$links[] = $share['share_with'];
823
		}
824
	}
825
826
827
}