Completed
Push — master ( 4c884b...ad1c7c )
by Maxence
04:19
created

SearchService::searchQueryInOptions()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 17
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 17
rs 9.2
cc 4
eloc 10
nc 5
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 OCA\Files_FullTextSearch\Model\FilesDocument;
32
use OCA\FullTextSearch\Model\ExtendedTick;
33
use OCA\FullTextSearch\Model\Index;
34
use OCA\FullTextSearch\Model\SearchRequest;
35
use OCA\FullTextSearch\Model\SearchResult;
36
use OCP\Files\InvalidPathException;
37
use OCP\Files\Node;
38
use OCP\Files\NotFoundException;
39
40
class SearchService {
41
42
	/** @var string */
43
	private $userId;
44
45
	/** @var FilesService */
46
	private $filesService;
47
48
	/** @var ConfigService */
49
	private $configService;
50
51
	/** @var MiscService */
52
	private $miscService;
53
54
55
	/**
56
	 * SearchService constructor.
57
	 *
58
	 * @param string $userId
59
	 * @param FilesService $filesService
60
	 * @param ConfigService $configService
61
	 * @param MiscService $miscService
62
	 *
63
	 * @internal param IProviderFactory $factory
64
	 */
65
	public function __construct(
66
		$userId, FilesService $filesService, ConfigService $configService, MiscService $miscService
67
	) {
68
		$this->userId = $userId;
69
		$this->filesService = $filesService;
70
		$this->configService = $configService;
71
		$this->miscService = $miscService;
72
	}
73
74
75
	/**
76
	 * @param SearchRequest $request
77
	 */
78
	public function improveSearchRequest(SearchRequest $request) {
79
		$this->searchQueryShareNames($request);
80
		$this->searchQueryWithinDir($request);
81
		$this->searchQueryInOptions($request);
82
		$this->searchQueryFiltersExtension($request);
83
		$this->searchQueryFiltersSource($request);
84
	}
85
86
87
	/**
88
	 * @param SearchRequest $request
89
	 */
90
	private function searchQueryShareNames(SearchRequest $request) {
91
		$username = MiscService::secureUsername($request->getAuthor());
92
		$request->addField('share_names.' . $username);
93
94
		$request->addWildcardField('title');
95
		$request->addWildcardField('share_names.' . $username);
96
	}
97
98
99
	/**
100
	 * @param SearchRequest $request
101
	 */
102
	private function searchQueryWithinDir(SearchRequest $request) {
103
104
		$currentDir = $request->getOption('files_within_dir');
105
		if ($currentDir === '') {
106
			return;
107
		}
108
109
		$username = MiscService::secureUsername($request->getAuthor());
110
		$currentDir = MiscService::noBeginSlash(MiscService::endSlash($currentDir));
111
		$request->addRegexFilters(
112
			[
113
				['share_names.' . $username => $currentDir . '*'],
114
				['title' => $currentDir . '*']
115
			]
116
		);
117
	}
118
119
120
	/**
121
	 * @param SearchRequest $request
122
	 */
123
	private function searchQueryFiltersExtension(SearchRequest $request) {
124
		$extension = $request->getOption('files_extension');
125
		if ($extension === '') {
126
			return;
127
		}
128
129
		$username = MiscService::secureUsername($request->getAuthor());
130
		$request->addRegexFilters(
131
			[
132
				['share_names.' . $username => '.*\.' . $extension],
133
				['title' => '.*\.' . $extension]
134
			]
135
		);
136
	}
137
138
139
	/**
140
	 * @param SearchRequest $request
141
	 */
142
	private function searchQueryFiltersSource(SearchRequest $request) {
143
144
		$local = $request->getOption('files_local');
145
		$external = $request->getOption('files_external');
146
		$groupFolders = $request->getOption('files_group_folders');
147
		$federated = $request->getOption('files_federated');
0 ignored issues
show
Unused Code introduced by
$federated is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
148
149
		if (count(array_unique([$local, $external, $groupFolders])) === 1) {
150
			return;
151
		}
152
153
		$this->addTagToSearchRequest($request, 'files_local', $local);
154
		$this->addTagToSearchRequest($request, 'files_external', $external);
155
		$this->addTagToSearchRequest($request, 'files_group_folders', $groupFolders);
156
	}
157
158
159
	/**
160
	 * @param SearchRequest $request
161
	 */
162
	private function searchQueryInOptions(SearchRequest $request) {
163
		$in = $request->getOption('in');
164
165
		if (!is_array($in)) {
166
			return;
167
		}
168
169
		if (in_array('filename', $in)) {
170
			$username = MiscService::secureUsername($request->getAuthor());
171
			$request->limitToField('share_names.' . $username);
172
			$request->limitToField('title');
173
		}
174
175
		if (in_array('content', $in)) {
176
			$request->limitToField('content');
177
		}
178
	}
179
180
181
	/**
182
	 * @param SearchRequest $request
183
	 * @param string $tag
184
	 * @param mixed $cond
185
	 */
186
	private function addTagToSearchRequest(SearchRequest $request, $tag, $cond) {
187
		if ($cond === 1 || $cond === '1') {
188
			$request->addTag($tag);
189
		}
190
	}
191
192
193
	/**
194
	 * @param SearchResult $searchResult
195
	 */
196
	public function improveSearchResult(SearchResult $searchResult) {
197
		$indexDocuments = $searchResult->getDocuments();
198
		$filesDocuments = [];
199
		foreach ($indexDocuments as $indexDocument) {
200
201
			try {
202
				$filesDocument = FilesDocument::fromIndexDocument($indexDocument);
203
				$this->setDocumentInfo($filesDocument);
204
				$this->setDocumentTitle($filesDocument);
205
				$this->setDocumentLink($filesDocument);
206
207
				$filesDocuments[] = $filesDocument;
208
			} catch (Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
209
			}
210
		}
211
212
		$searchResult->setDocuments($filesDocuments);
213
	}
214
215
216
	/**
217
	 * @param FilesDocument $document
218
	 *
219
	 * @throws Exception
220
	 */
221
	private function setDocumentInfo(FilesDocument $document) {
222
		$index = new Index('files', $document->getId());
223
		$index->setOwnerId($this->userId);
224
225
		$document->setInfo('webdav', $this->getWebdavId($document->getId()));
226
227
		$file = $this->filesService->getFileFromIndex($index);
228
		$this->setDocumentInfoFromFile($document, $file);
229
	}
230
231
232
	/**
233
	 * @param FilesDocument $document
234
	 * @param Node $file
235
	 */
236
	private function setDocumentInfoFromFile(FilesDocument $document, Node $file) {
237
238
		// TODO: better way to do this : we remove the '/userId/files/'
239
		$path = MiscService::noEndSlash(substr($file->getPath(), 7 + strlen($this->userId)));
240
		$pathInfo = pathinfo($path);
241
242
		$document->setPath($path);
243
		$document->setInfo('type', $file->getType())
244
				 ->setInfo('file', $pathInfo['basename'])
245
				 ->setInfo('path', $pathInfo['dirname'])
246
				 ->setInfo('mime', $file->getMimetype())
247
				 ->setInfo('favorite', false); // FIXME: get the favorite status
248
249
		try {
250
			$document->setInfo('size', $file->getSize())
251
					 ->setInfo('mtime', $file->getMTime())
252
					 ->setInfo('etag', $file->getEtag())
253
					 ->setInfo('permissions', $file->getPermissions());
254
		} catch (Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
255
		}
256
	}
257
258
259
	/**
260
	 * @param FilesDocument $document
261
	 */
262
	private function setDocumentTitle(FilesDocument $document) {
263
		if (!is_null($document->getPath()) && $document->getPath() !== '') {
264
			$document->setTitle($document->getPath());
265
		} else {
266
			$document->setTitle('/' . $document->getTitle());
267
		}
268
	}
269
270
271
	/**
272
	 * @param FilesDocument $document
273
	 */
274
	private function setDocumentLink(FilesDocument $document) {
275
276
		$path = $document->getPath();
277
		$filename = $document->getInfo('file');
278
		$dir = substr($path, 0, -strlen($filename));
279
280
		$this->setDocumentLinkDir($document, $dir, $filename);
0 ignored issues
show
Unused Code introduced by
The call to SearchService::setDocumentLinkDir() has too many arguments starting with $filename.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
281
		$this->setDocumentLinkFile($document, $dir, $filename);
282
	}
283
284
285
	/**
286
	 * @param FilesDocument $document
287
	 * @param $dir
288
	 * @param $filename
289
	 */
290 View Code Duplication
	private function setDocumentLinkFile(FilesDocument $document, $dir, $filename) {
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...
291
		if ($document->getInfo('type') !== 'file') {
292
			return;
293
		}
294
295
		$document->setLink(
296
			\OC::$server->getURLGenerator()
297
						->linkToRoute(
298
							'files.view.index',
299
							[
300
								'dir'      => $dir,
301
								'scrollto' => $filename,
302
							]
303
						)
304
		);
305
	}
306
307
308
	/**
309
	 * @param FilesDocument $document
310
	 * @param $dir
311
	 */
312 View Code Duplication
	private function setDocumentLinkDir(FilesDocument $document, $dir) {
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...
313
		if ($document->getInfo('type') !== 'dir') {
314
			return;
315
		}
316
317
		$document->setLink(
318
			\OC::$server->getURLGenerator()
319
						->linkToRoute(
320
							'files.view.index',
321
							['dir' => $dir, 'fileid' => $document->getId()]
322
						)
323
		);
324
	}
325
326
	/**
327
	 * @param int $fileId
328
	 *
329
	 * @return string
330
	 */
331
	private function getWebdavId($fileId) {
332
		$instanceId = $this->configService->getSystemValue('instanceid');
333
334
		return sprintf("%08s", $fileId) . $instanceId;
335
	}
336
337
338
}