Completed
Push — master ( ce24c1...6d98ad )
by Maxence
24:46
created

FilesService::isDocumentUpToDate()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 20
rs 9.6
c 0
b 0
f 0
cc 4
nc 4
nop 1
1
<?php
2
declare(strict_types=1);
3
4
5
/**
6
 * Files_FullTextSearch - Index the content of your files
7
 *
8
 * This file is licensed under the Affero General Public License version 3 or
9
 * later. See the COPYING file.
10
 *
11
 * @author Maxence Lange <[email protected]>
12
 * @copyright 2018
13
 * @license GNU AGPL version 3 or any later version
14
 *
15
 * This program is free software: you can redistribute it and/or modify
16
 * it under the terms of the GNU Affero General Public License as
17
 * published by the Free Software Foundation, either version 3 of the
18
 * License, or (at your option) any later version.
19
 *
20
 * This program is distributed in the hope that it will be useful,
21
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
 * GNU Affero General Public License for more details.
24
 *
25
 * You should have received a copy of the GNU Affero General Public License
26
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
27
 *
28
 */
29
30
31
namespace OCA\Files_FullTextSearch\Service;
32
33
34
use daita\MySmallPhpTools\Traits\TPathTools;
35
use Exception;
36
use OCA\Files_FullTextSearch\Exceptions\EmptyUserException;
37
use OCA\Files_FullTextSearch\Exceptions\FileIsNotIndexableException;
38
use OCA\Files_FullTextSearch\Exceptions\FilesNotFoundException;
39
use OCA\Files_FullTextSearch\Exceptions\KnownFileMimeTypeException;
40
use OCA\Files_FullTextSearch\Exceptions\KnownFileSourceException;
41
use OCA\Files_FullTextSearch\Model\FilesDocument;
42
use OCA\Files_FullTextSearch\Provider\FilesProvider;
43
use OCP\App\IAppManager;
44
use OCP\AppFramework\IAppContainer;
45
use OCP\Files\File;
46
use OCP\Files\FileInfo;
47
use OCP\Files\Folder;
48
use OCP\Files\InvalidPathException;
49
use OCP\Files\IRootFolder;
50
use OCP\Files\Node;
51
use OCP\Files\NotFoundException;
52
use OCP\Files\NotPermittedException;
53
use OCP\Files\StorageNotAvailableException;
54
use OCP\FullTextSearch\Model\IIndex;
55
use OCP\FullTextSearch\Model\IIndexOptions;
56
use OCP\FullTextSearch\Model\IndexDocument;
57
use OCP\FullTextSearch\Model\IRunner;
58
use OCP\IUserManager;
59
use OCP\Share\IManager;
60
use Throwable;
61
62
63
/**
64
 * Class FilesService
65
 *
66
 * @package OCA\Files_FullTextSearch\Service
67
 */
68
class FilesService {
69
70
71
	use TPathTools;
72
73
74
	const MIMETYPE_TEXT = 'files_text';
75
	const MIMETYPE_PDF = 'files_pdf';
76
	const MIMETYPE_OFFICE = 'files_office';
77
	const MIMETYPE_ZIP = 'files_zip';
78
	const MIMETYPE_IMAGE = 'files_image';
79
	const MIMETYPE_AUDIO = 'files_audio';
80
81
82
	/** @var IAppContainer */
83
	private $container;
84
85
	/** @var IRootFolder */
86
	private $rootFolder;
87
88
	/** @var IUserManager */
89
	private $userManager;
90
91
	/** @var IAppManager */
92
	private $appManager;
93
94
	/** @var IManager */
95
	private $shareManager;
96
97
	/** @var ConfigService */
98
	private $configService;
99
100
	/** @var LocalFilesService */
101
	private $localFilesService;
102
103
	/** @var ExternalFilesService */
104
	private $externalFilesService;
105
106
	/** @var GroupFoldersService */
107
	private $groupFoldersService;
108
109
	/** @var ExtensionService */
110
	private $extensionService;
111
112
	/** @var MiscService */
113
	private $miscService;
114
115
116
	/** @var IRunner */
117
	private $runner;
118
119
	/** @var int */
120
	private $sumDocuments;
121
122
123
	/**
124
	 * FilesService constructor.
125
	 *
126
	 * @param IAppContainer $container
127
	 * @param IRootFolder $rootFolder
128
	 * @param IAppManager $appManager
129
	 * @param IUserManager $userManager
130
	 * @param IManager $shareManager
131
	 * @param ConfigService $configService
132
	 * @param LocalFilesService $localFilesService
133
	 * @param ExternalFilesService $externalFilesService
134
	 * @param GroupFoldersService $groupFoldersService
135
	 * @param ExtensionService $extensionService
136
	 * @param MiscService $miscService
137
	 *
138
	 * @internal param IProviderFactory $factory
139
	 */
140
	public function __construct(
141
		IAppContainer $container, IRootFolder $rootFolder, IAppManager $appManager,
142
		IUserManager $userManager, IManager $shareManager,
143
		ConfigService $configService, LocalFilesService $localFilesService,
144
		ExternalFilesService $externalFilesService, GroupFoldersService $groupFoldersService,
145
		ExtensionService $extensionService, MiscService $miscService
146
	) {
147
		$this->container = $container;
148
		$this->rootFolder = $rootFolder;
149
		$this->appManager = $appManager;
150
		$this->userManager = $userManager;
151
		$this->shareManager = $shareManager;
152
153
		$this->configService = $configService;
154
		$this->localFilesService = $localFilesService;
155
		$this->externalFilesService = $externalFilesService;
156
		$this->groupFoldersService = $groupFoldersService;
157
		$this->extensionService = $extensionService;
158
159
		$this->miscService = $miscService;
160
	}
161
162
163
	/**
164
	 * @param IRunner $runner
165
	 */
166
	public function setRunner(IRunner $runner) {
167
		$this->runner = $runner;
168
	}
169
170
171
	/**
172
	 * @param string $userId
173
	 * @param IIndexOptions $indexOptions
174
	 *
175
	 * @return FilesDocument[]
176
	 * @throws InvalidPathException
177
	 * @throws NotFoundException
178
	 */
179
	public function getFilesFromUser(string $userId, IIndexOptions $indexOptions): array {
180
181
		$this->initFileSystems($userId);
182
		$this->sumDocuments = 0;
183
184
		/** @var Folder $files */
185
		$files = $this->rootFolder->getUserFolder($userId)
186
								  ->get($indexOptions->getOption('path', '/'));
187
		if ($files instanceof Folder) {
0 ignored issues
show
Bug introduced by
The class OCP\Files\Folder does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
188
			$result = $this->getFilesFromDirectory($userId, $files);
189
		} else {
190
			$result = [];
191
			try {
192
				$result[] = $this->generateFilesDocumentFromFile($userId, $files);
193
			} catch (FileIsNotIndexableException $e) {
194
				/** we do nothin' */
195
			}
196
		}
197
198
		return $result;
199
	}
200
201
202
	/**
203
	 * @param string $userId
204
	 */
205
	private function initFileSystems(string $userId) {
206
		if ($userId === '') {
207
			return;
208
		}
209
210
		$this->externalFilesService->initExternalFilesForUser($userId);
211
		$this->groupFoldersService->initGroupSharesForUser($userId);
212
	}
213
214
215
	/**
216
	 * @param string $userId
217
	 * @param Folder $node
218
	 *
219
	 * @return FilesDocument[]
220
	 * @throws InvalidPathException
221
	 * @throws NotFoundException
222
	 * @throws Exception
223
	 */
224
	public function getFilesFromDirectory(string $userId, Folder $node): array {
225
		$documents = [];
226
227
		$this->updateRunnerAction('generateIndexFiles', true);
228
		$this->updateRunnerInfo(
229
			[
230
				'info'          => $node->getPath(),
231
				'documentTotal' => $this->sumDocuments
232
			]
233
		);
234
235
		try {
236
			if ($node->nodeExists('.noindex')) {
237
				return $documents;
238
			}
239
		} catch (StorageNotAvailableException $e) {
0 ignored issues
show
Bug introduced by
The class OCP\Files\StorageNotAvailableException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
240
			return $documents;
241
		}
242
243
		$files = $node->getDirectoryListing();
244
		foreach ($files as $file) {
245
246
			try {
247
				$documents[] = $this->generateFilesDocumentFromFile($userId, $file);
248
				$this->sumDocuments++;
249
			} catch (FileIsNotIndexableException $e) {
250
				continue;
251
			}
252
253
			if ($file->getType() === FileInfo::TYPE_FOLDER) {
254
				/** @var $file Folder */
255
				$documents =
256
					array_merge($documents, $this->getFilesFromDirectory($userId, $file));
257
			}
258
		}
259
260
		return $documents;
261
	}
262
263
264
	/**
265
	 * @param string $viewerId
266
	 * @param Node $file
267
	 *
268
	 * @return FilesDocument
269
	 * @throws FileIsNotIndexableException
270
	 * @throws InvalidPathException
271
	 * @throws NotFoundException
272
	 * @throws Exception
273
	 */
274
	private function generateFilesDocumentFromFile(string $viewerId, Node $file): FilesDocument {
275
276
		$source = $this->getFileSource($file);
277
		$document = new FilesDocument(FilesProvider::FILES_PROVIDER_ID, (string)$file->getId());
278
279
		if ($file->getId() === -1) {
280
			throw new FileIsNotIndexableException();
281
		}
282
283
		$ownerId = '';
284
		if ($file->getOwner() !== null) {
285
			$ownerId = $file->getOwner()
286
							->getUID();
287
		}
288
		$document->setType($file->getType())
289
				 ->setOwnerId($ownerId)
290
				 ->setPath($this->getPathFromViewerId($file->getId(), $viewerId))
291
				 ->setViewerId($viewerId)
292
				 ->setMimetype($file->getMimetype());
293
		$document->setModifiedTime($file->getMTime())
294
				 ->setSource($source);
295
296
		return $document;
297
	}
298
299
300
	/**
301
	 * @param Node $file
302
	 *
303
	 * @return string
304
	 * @throws FileIsNotIndexableException
305
	 */
306
	private function getFileSource(Node $file): string {
307
		$source = '';
308
309
		try {
310
			$this->localFilesService->getFileSource($file, $source);
311
			$this->externalFilesService->getFileSource($file, $source);
312
			$this->groupFoldersService->getFileSource($file, $source);
313
		} catch (KnownFileSourceException $e) {
314
			/** we know the source, just leave. */
315
		}
316
317
		return $source;
318
	}
319
320
321
	/**
322
	 * @param string $userId
323
	 * @param string $path
324
	 *
325
	 * @return Node
326
	 * @throws NotFoundException
327
	 */
328
	public function getFileFromPath(string $userId, string $path): Node {
329
		return $this->rootFolder->getUserFolder($userId)
330
								->get($path);
331
	}
332
333
334
	/**
335
	 * @param string $userId
336
	 * @param int $fileId
337
	 *
338
	 * @return Node
339
	 * @throws FilesNotFoundException
340
	 * @throws EmptyUserException
341
	 */
342
	public function getFileFromId(string $userId, int $fileId): Node {
343
344
		if ($userId === '') {
345
			throw new EmptyUserException();
346
		}
347
348
		$files = $this->rootFolder->getUserFolder($userId)
349
								  ->getById($fileId);
350
		if (sizeof($files) === 0) {
351
			throw new FilesNotFoundException();
352
		}
353
354
		$file = array_shift($files);
355
356
		return $file;
357
	}
358
359
360
	/**
361
	 * @param IIndex $index
362
	 *
363
	 * @return Node
364
	 * @throws EmptyUserException
365
	 * @throws FilesNotFoundException
366
	 */
367
	public function getFileFromIndex(IIndex $index): Node {
368
		$this->impersonateOwner($index);
369
370
		return $this->getFileFromId($index->getOwnerId(), (int)$index->getDocumentId());
371
	}
372
373
374
	/**
375
	 * @param int $fileId
376
	 * @param string $viewerId
377
	 *
378
	 * @throws Exception
379
	 * @return string
380
	 */
381
	private function getPathFromViewerId(int $fileId, string $viewerId): string {
382
383
		$viewerFiles = $this->rootFolder->getUserFolder($viewerId)
384
										->getById($fileId);
385
386
		if (sizeof($viewerFiles) === 0) {
387
			return '';
388
		}
389
390
		$file = array_shift($viewerFiles);
391
392
		// TODO: better way to do this : we remove the '/userid/files/'
393
		$path = $this->withoutEndSlash(substr($file->getPath(), 8 + strlen($viewerId)));
394
395
		return $path;
396
	}
397
398
399
	/**
400
	 * @param FilesDocument $document
401
	 */
402
	public function generateDocument(FilesDocument $document) {
403
404
		try {
405
			$this->updateFilesDocument($document);
406
		} catch (Exception $e) {
407
			// TODO - update $document with a error status instead of just ignore !
408
			$document->getIndex()
409
					 ->setStatus(IIndex::INDEX_IGNORE);
410
			echo 'Exception: ' . json_encode($e->getTrace()) . ' - ' . $e->getMessage()
411
				 . "\n";
412
		}
413
	}
414
415
416
	/**
417
	 * @param IIndex $index
418
	 *
419
	 * @return FilesDocument
420
	 * @throws FileIsNotIndexableException
421
	 * @throws InvalidPathException
422
	 * @throws NotFoundException
423
	 */
424
	private function generateDocumentFromIndex(IIndex $index): FilesDocument {
425
426
		try {
427
			$file = $this->getFileFromIndex($index);
428
		} catch (Exception $e) {
429
			$index->setStatus(IIndex::INDEX_REMOVE);
430
			$document = new FilesDocument($index->getProviderId(), $index->getDocumentId());
431
			$document->setIndex($index);
432
433
			return $document;
434
		}
435
436
		$document = $this->generateFilesDocumentFromFile($index->getOwnerId(), $file);
437
		$document->setIndex($index);
438
439
		$this->updateFilesDocumentFromFile($document, $file);
440
441
		return $document;
442
	}
443
444
445
	/**
446
	 * @param IndexDocument $document
447
	 *
448
	 * @return bool
449
	 */
450
	public function isDocumentUpToDate(IndexDocument $document): bool {
451
		$index = $document->getIndex();
452
453
		if (!$this->configService->compareIndexOptions($index)) {
454
			$index->setStatus(IIndex::INDEX_CONTENT);
455
			$document->setIndex($index);
456
457
			return false;
458
		}
459
460
		if ($index->getStatus() !== IIndex::INDEX_OK) {
461
			return false;
462
		}
463
464
		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...
465
			return true;
466
		}
467
468
		return false;
469
	}
470
471
472
	/**
473
	 * @param IIndex $index
474
	 *
475
	 * @return FilesDocument
476
	 * @throws InvalidPathException
477
	 * @throws NotFoundException
478
	 * @throws NotPermittedException
479
	 * @throws FileIsNotIndexableException
480
	 */
481
	public function updateDocument(IIndex $index): FilesDocument {
482
		$this->impersonateOwner($index);
483
		$this->initFileSystems($index->getOwnerId());
484
485
		return $this->generateDocumentFromIndex($index);
486
	}
487
488
489
	/**
490
	 * @param FilesDocument $document
491
	 *
492
	 * @throws NotFoundException
493
	 */
494
	private function updateFilesDocument(FilesDocument $document) {
495
		$userFolder = $this->rootFolder->getUserFolder($document->getViewerId());
496
		$file = $userFolder->get($document->getPath());
497
498
		try {
499
			$this->updateFilesDocumentFromFile($document, $file);
500
		} catch (FileIsNotIndexableException $e) {
501
			$document->getIndex()
502
					 ->setStatus(IIndex::INDEX_IGNORE);
503
		}
504
	}
505
506
507
	/**
508
	 * @param FilesDocument $document
509
	 * @param Node $file
510
	 */
511
	private function updateFilesDocumentFromFile(FilesDocument $document, Node $file) {
512
513
		$document->getIndex()
514
				 ->setSource($document->getSource());
515
516
		$this->updateDocumentAccess($document, $file);
517
		$this->updateContentFromFile($document, $file);
518
519
		$document->addMetaTag($document->getSource());
520
	}
521
522
523
	/**
524
	 * @param FilesDocument $document
525
	 * @param Node $file
526
	 */
527
	private function updateDocumentAccess(FilesDocument $document, Node $file) {
528
529
		$index = $document->getIndex();
530
531
		if (!$index->isStatus(IIndex::INDEX_FULL)
532
			&& !$index->isStatus(FilesDocument::STATUS_FILE_ACCESS)) {
533
			return;
534
		}
535
536
		$this->localFilesService->updateDocumentAccess($document, $file);
537
		$this->externalFilesService->updateDocumentAccess($document, $file);
538
		$this->groupFoldersService->updateDocumentAccess($document, $file);
539
540
		$this->updateShareNames($document, $file);
541
	}
542
543
544
	/**
545
	 * @param FilesDocument $document
546
	 * @param Node $file
547
	 */
548
	private function updateContentFromFile(FilesDocument $document, Node $file) {
549
550
		$document->setTitle($document->getPath());
551
552
		if (!$document->getIndex()
553
					  ->isStatus(IIndex::INDEX_CONTENT)
554
			|| $file->getType() !== FileInfo::TYPE_FILE) {
555
			return;
556
		}
557
558
		try {
559
			/** @var File $file */
560
			if ($file->getSize() <
561
				($this->configService->getAppValue(ConfigService::FILES_SIZE) * 1024 * 1024)) {
562
				$this->extractContentFromFileText($document, $file);
563
				$this->extractContentFromFileOffice($document, $file);
564
				$this->extractContentFromFilePDF($document, $file);
565
				$this->extractContentFromFileZip($document, $file);
566
567
				$this->extensionService->fileIndexing($document, $file);
568
			}
569
		} catch (Throwable $t) {
0 ignored issues
show
Bug introduced by
The class Throwable does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
570
			$this->manageContentErrorException($document, $t);
571
		}
572
573
		if ($document->getContent() === null) {
574
			$document->getIndex()
575
					 ->unsetStatus(IIndex::INDEX_CONTENT);
576
		}
577
	}
578
579
580
	/**
581
	 * @param FilesDocument $document
582
	 * @param Node $file
583
	 *
584
	 * @return array
585
	 */
586
	private function updateShareNames(FilesDocument $document, Node $file): array {
587
588
		$users = [];
589
590
		$this->localFilesService->getShareUsersFromFile($file, $users);
591
		$this->externalFilesService->getShareUsers($document, $users);
592
		$this->groupFoldersService->getShareUsers($document, $users);
593
594
		$shareNames = [];
595
		foreach ($users as $username) {
596
			try {
597
				$user = $this->userManager->get($username);
598
				if ($user === null || $user->getLastLogin() === 0) {
599
					continue;
600
				}
601
602
				$path = $this->getPathFromViewerId($file->getId(), $username);
603
				$shareNames[$this->miscService->secureUsername($username)] =
604
					(!is_string($path)) ? $path = '' : $path;
605
606
			} catch (Exception $e) {
607
				$this->miscService->log(
608
					'Issue while getting information on documentId:' . $document->getId(), 0
609
				);
610
			}
611
		}
612
613
		$document->setInfoArray('share_names', $shareNames);
614
615
		return $shareNames;
616
	}
617
618
619
	/**
620
	 * @param string $mimeType
621
	 * @param string $extension
622
	 *
623
	 * @return string
624
	 */
625
	private function parseMimeType(string $mimeType, string $extension): string {
626
627
		$parsed = '';
628
		try {
629
			$this->parseMimeTypeText($mimeType, $extension, $parsed);
630
			$this->parseMimeTypePDF($mimeType, $parsed);
631
			$this->parseMimeTypeOffice($mimeType, $parsed);
632
			$this->parseMimeTypeZip($mimeType, $parsed);
633
		} catch (KnownFileMimeTypeException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
634
		}
635
636
		return $parsed;
637
	}
638
639
640
	/**
641
	 * @param string $mimeType
642
	 * @param string $extension
643
	 * @param string $parsed
644
	 *
645
	 * @throws KnownFileMimeTypeException
646
	 */
647
	private function parseMimeTypeText(string $mimeType, string $extension, string &$parsed) {
648
649
		if (substr($mimeType, 0, 5) === 'text/') {
650
			$parsed = self::MIMETYPE_TEXT;
651
			throw new KnownFileMimeTypeException();
652
		}
653
654
		$textMimes = [
655
			'application/epub+zip'
656
		];
657
658 View Code Duplication
		foreach ($textMimes as $mime) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
659
			if (strpos($mimeType, $mime) === 0) {
660
				$parsed = self::MIMETYPE_TEXT;
661
				throw new KnownFileMimeTypeException();
662
			}
663
		}
664
665
		$this->parseMimeTypeTextByExtension($mimeType, $extension, $parsed);
666
	}
667
668
669
	/**
670
	 * @param string $mimeType
671
	 * @param string $extension
672
	 * @param string $parsed
673
	 *
674
	 * @throws KnownFileMimeTypeException
675
	 */
676
	private function parseMimeTypeTextByExtension(
677
		string $mimeType, string $extension, string &$parsed
678
	) {
679
		$textMimes = [
680
			'application/octet-stream'
681
		];
682
		$textExtension = [
683
		];
684
685
		foreach ($textMimes as $mime) {
686
			if (strpos($mimeType, $mime) === 0
687
				&& in_array(
688
					strtolower($extension), $textExtension
689
				)) {
690
				$parsed = self::MIMETYPE_TEXT;
691
				throw new KnownFileMimeTypeException();
692
			}
693
		}
694
	}
695
696
697
	/**
698
	 * @param string $mimeType
699
	 * @param string $parsed
700
	 *
701
	 * @throws KnownFileMimeTypeException
702
	 */
703
	private function parseMimeTypePDF(string $mimeType, string &$parsed) {
704
705
		if ($mimeType === 'application/pdf') {
706
			$parsed = self::MIMETYPE_PDF;
707
			throw new KnownFileMimeTypeException();
708
		}
709
	}
710
711
712
	/**
713
	 * @param string $mimeType
714
	 * @param string $parsed
715
	 *
716
	 * @throws KnownFileMimeTypeException
717
	 */
718
	private function parseMimeTypeZip(string $mimeType, string &$parsed) {
719
		if ($mimeType === 'application/zip') {
720
			$parsed = self::MIMETYPE_ZIP;
721
			throw new KnownFileMimeTypeException();
722
		}
723
	}
724
725
726
	/**
727
	 * @param string $mimeType
728
	 * @param string $parsed
729
	 *
730
	 * @throws KnownFileMimeTypeException
731
	 */
732
	private function parseMimeTypeOffice(string $mimeType, string &$parsed) {
733
734
		$officeMimes = [
735
			'application/msword',
736
			'application/vnd.oasis.opendocument',
737
			'application/vnd.sun.xml',
738
			'application/vnd.openxmlformats-officedocument',
739
			'application/vnd.ms-word',
740
			'application/vnd.ms-powerpoint',
741
			'application/vnd.ms-excel'
742
		];
743
744 View Code Duplication
		foreach ($officeMimes as $mime) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
745
			if (strpos($mimeType, $mime) === 0) {
746
				$parsed = self::MIMETYPE_OFFICE;
747
				throw new KnownFileMimeTypeException();
748
			}
749
		}
750
	}
751
752
753
	/**
754
	 * @param FilesDocument $document
755
	 * @param File $file
756
	 *
757
	 * @throws NotPermittedException
758
	 */
759
	private function extractContentFromFileText(FilesDocument $document, File $file) {
760
		if ($this->parseMimeType($document->getMimeType(), $file->getExtension())
761
			!== self::MIMETYPE_TEXT) {
762
			return;
763
		}
764
765
		if (!$this->isSourceIndexable($document)) {
766
			return;
767
		}
768
769
		$document->setContent(
770
			base64_encode($file->getContent()), IndexDocument::ENCODED_BASE64
771
		);
772
	}
773
774
775
	/**
776
	 * @param FilesDocument $document
777
	 * @param File $file
778
	 *
779
	 * @throws NotPermittedException
780
	 */
781 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...
782
		if ($this->parseMimeType($document->getMimeType(), $file->getExtension())
783
			!== self::MIMETYPE_PDF) {
784
			return;
785
		}
786
787
		$this->configService->setDocumentIndexOption($document, ConfigService::FILES_PDF);
788
		if (!$this->isSourceIndexable($document)) {
789
			return;
790
		}
791
792
		if ($this->configService->getAppValue(ConfigService::FILES_PDF) !== '1') {
793
			$document->setContent('');
794
795
			return;
796
		}
797
798
		$document->setContent(
799
			base64_encode($file->getContent()), IndexDocument::ENCODED_BASE64
800
		);
801
	}
802
803
804
	/**
805
	 * @param FilesDocument $document
806
	 * @param File $file
807
	 *
808
	 * @throws NotPermittedException
809
	 */
810 View Code Duplication
	private function extractContentFromFileZip(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...
811
		if ($this->parseMimeType($document->getMimeType(), $file->getExtension())
812
			!== self::MIMETYPE_ZIP) {
813
			return;
814
		}
815
816
		$this->configService->setDocumentIndexOption($document, ConfigService::FILES_ZIP);
817
		if (!$this->isSourceIndexable($document)) {
818
			return;
819
		}
820
821
		if ($this->configService->getAppValue(ConfigService::FILES_ZIP) !== '1') {
822
			$document->setContent('');
823
824
			return;
825
		}
826
827
		$document->setContent(
828
			base64_encode($file->getContent()), IndexDocument::ENCODED_BASE64
829
		);
830
	}
831
832
833
	/**
834
	 * @param FilesDocument $document
835
	 * @param File $file
836
	 *
837
	 * @throws NotPermittedException
838
	 */
839 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...
840
		if ($this->parseMimeType($document->getMimeType(), $file->getExtension())
841
			!== self::MIMETYPE_OFFICE) {
842
			return;
843
		}
844
845
		$this->configService->setDocumentIndexOption($document, ConfigService::FILES_OFFICE);
846
		if (!$this->isSourceIndexable($document)) {
847
			return;
848
		}
849
850
		if ($this->configService->getAppValue(ConfigService::FILES_OFFICE) !== '1') {
851
			$document->setContent('');
852
853
			return;
854
		}
855
856
		$document->setContent(
857
			base64_encode($file->getContent()), IndexDocument::ENCODED_BASE64
858
		);
859
	}
860
861
862
	/**
863
	 * @param FilesDocument $document
864
	 *
865
	 * @return bool
866
	 */
867
	private function isSourceIndexable(FilesDocument $document): bool {
868
		$this->configService->setDocumentIndexOption($document, $document->getSource());
869
		if ($this->configService->getAppValue($document->getSource()) !== '1') {
870
			$document->setContent('');
871
872
			return false;
873
		}
874
875
		return true;
876
	}
877
878
879
	/**
880
	 * @param IIndex $index
881
	 */
882
	private function impersonateOwner(IIndex $index) {
883
		if ($index->getOwnerId() !== '') {
884
			return;
885
		}
886
887
		$this->groupFoldersService->impersonateOwner($index);
888
		$this->externalFilesService->impersonateOwner($index);
889
	}
890
891
892
	/**
893
	 * @param $action
894
	 * @param bool $force
895
	 *
896
	 * @throws Exception
897
	 */
898
	private function updateRunnerAction(string $action, bool $force = false) {
899
		if ($this->runner === null) {
900
			return;
901
		}
902
903
		$this->runner->updateAction($action, $force);
904
	}
905
906
907
	/**
908
	 * @param array $data
909
	 */
910
	private function updateRunnerInfo($data) {
911
		if ($this->runner === null) {
912
			return;
913
		}
914
915
		$this->runner->setInfoArray($data);
916
	}
917
918
	/**
919
	 * @param IndexDocument $document
920
	 * @param Throwable $t
921
	 */
922
	private function manageContentErrorException(IndexDocument $document, Throwable $t) {
923
		$document->getIndex()
924
				 ->addError(
925
					 'Error while getting file content', $t->getMessage(), IIndex::ERROR_SEV_3
926
				 );
927
		$this->updateNewIndexError(
928
			$document->getIndex(), 'Error while getting file content', $t->getMessage(),
929
			IIndex::ERROR_SEV_3
930
		);
931
		$this->miscService->log(json_encode($t->getTrace()), 0);
932
	}
933
934
935
	/**
936
	 * @param IIndex $index
937
	 * @param string $message
938
	 * @param string $exception
939
	 * @param int $sev
940
	 */
941
	private function updateNewIndexError(IIndex $index, string $message, string $exception, int $sev
942
	) {
943
		if ($this->runner === null) {
944
			return;
945
		}
946
947
		$this->runner->newIndexError($index, $message, $exception, $sev);
948
	}
949
}
950
951