Completed
Push — master ( 3f43c1...51db49 )
by Maxence
03:26
created

getRandomUserFromMountPoint()   B

Complexity

Conditions 5
Paths 7

Size

Total Lines 25
Code Lines 14

Duplication

Lines 7
Ratio 28 %

Importance

Changes 0
Metric Value
dl 7
loc 25
c 0
b 0
f 0
rs 8.439
cc 5
eloc 14
nc 7
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
/**
28
 * Created by PhpStorm.
29
 * User: maxence
30
 * Date: 12/13/17
31
 * Time: 4:11 PM
32
 */
33
34
namespace OCA\Files_FullTextSearch\Service;
35
36
37
use Exception;
38
use OCA\Files_External\Lib\StorageConfig;
39
use OCA\Files_External\Service\GlobalStoragesService;
40
use OCA\Files_FullTextSearch\Exceptions\ExternalMountNotFoundException;
41
use OCA\Files_FullTextSearch\Exceptions\ExternalMountWithNoViewerException;
42
use OCA\Files_FullTextSearch\Exceptions\FileIsNotIndexableException;
43
use OCA\Files_FullTextSearch\Exceptions\KnownFileSourceException;
44
use OCA\Files_FullTextSearch\Model\MountPoint;
45
use OCA\Files_FullTextSearch\Model\FilesDocument;
46
use OCA\FullTextSearch\Model\Index;
47
use OCP\App;
48
use OCP\Files\IRootFolder;
49
use OCP\Files\Node;
50
use OCP\Files\NotFoundException;
51
use OCP\IGroupManager;
52
use OCP\IUserManager;
53
use OCP\Share\IManager;
54
55
class ExternalFilesService {
56
57
58
	/** @var IRootFolder */
59
	private $rootFolder;
60
61
	/** @var IUserManager */
62
	private $userManager;
63
64
	/** @var IManager */
65
	private $shareManager;
66
67
	/** @var GlobalStoragesService */
68
	private $globalStoragesService;
69
70
	/** @var IGroupManager */
71
	private $groupManager;
72
73
	/** @var LocalFilesService */
74
	private $localFilesService;
75
76
	/** @var ConfigService */
77
	private $configService;
78
79
	/** @var MiscService */
80
	private $miscService;
81
82
83
	/** @var MountPoint[] */
84
	private $externalMounts = [];
85
86
87
	/**
88
	 * ExternalFilesService constructor.
89
	 *
90
	 * @param IRootFolder $rootFolder
91
	 * @param IUserManager $userManager
92
	 * @param IGroupManager $groupManager
93
	 * @param IManager $shareManager
94
	 * @param GlobalStoragesService $globalStoragesService
95
	 * @param LocalFilesService $localFilesService
96
	 * @param ConfigService $configService
97
	 * @param MiscService $miscService
98
	 */
99 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...
100
		IRootFolder $rootFolder, IUserManager $userManager, IGroupManager $groupManager,
101
		IManager $shareManager, GlobalStoragesService $globalStoragesService,
102
		LocalFilesService $localFilesService, ConfigService $configService, MiscService $miscService
103
	) {
104
		$this->rootFolder = $rootFolder;
105
		$this->userManager = $userManager;
106
		$this->groupManager = $groupManager;
107
		$this->shareManager = $shareManager;
108
		$this->globalStoragesService = $globalStoragesService;
109
110
		$this->localFilesService = $localFilesService;
111
112
		$this->configService = $configService;
113
		$this->miscService = $miscService;
114
	}
115
116
117
	/**
118
	 * @param string $userId
119
	 */
120
	public function initExternalFilesForUser($userId) {
121
		$this->externalMounts = [];
122
		if (!App::isEnabled('files_external')) {
123
			return;
124
		}
125
126
		$this->externalMounts = $this->getMountPoints($userId);
127
	}
128
129
130
	/**
131
	 * @param Node $file
132
	 *
133
	 * @param string $source
134
	 *
135
	 * @throws FileIsNotIndexableException
136
	 * @throws NotFoundException
137
	 * @throws KnownFileSourceException
138
	 */
139
	public function getFileSource(Node $file, &$source) {
140
		if ($file->getStorage()
141
				 ->isLocal() === true) {
142
			return;
143
		}
144
145
		$this->getMountPoint($file);
146
		$source = ConfigService::FILES_EXTERNAL;
147
148
		throw new KnownFileSourceException();
149
	}
150
151
152
	/**
153
	 * @param FilesDocument $document
154
	 * @param array $users
155
	 */
156
	public function getShareUsers(FilesDocument $document, &$users) {
157
		if ($document->getSource() !== ConfigService::FILES_EXTERNAL) {
158
			return;
159
		}
160
161
		$this->localFilesService->getSharedUsersFromAccess($document->getAccess(), $users);
162
	}
163
164
165
	/**
166
	 * @param FilesDocument $document
167
	 * @param Node $file
168
	 */
169
	public function updateDocumentAccess(FilesDocument &$document, Node $file) {
170
		try {
171
			$mount = $this->getMountPoint($file);
172
		} catch (FileIsNotIndexableException $e) {
173
			return;
174
		}
175
176
		$access = $document->getAccess();
177
178
		if ($this->isMountFullGlobal($mount)) {
179
			$access->addUsers(['__all']);
180
		} else {
181
			$access->addUsers($mount->getUsers());
182
			$access->addGroups($mount->getGroups());
183
//		 	$access->addCircles($mount->getCircles());
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
184
		}
185
186
		// twist 'n tweak.
187
		if (!$mount->isGlobal()) {
188
			$access->setOwnerId($mount->getUsers()[0]);
189
		}
190
191
		$document->getIndex()
192
				 ->addOption('external_mount_id', $mount->getId());
193
		$document->setAccess($access);
194
195
		$document->setAccess($access);
196
	}
197
198
199
	/**
200
	 * @param MountPoint $mount
201
	 *
202
	 * @return bool
203
	 */
204
	public function isMountFullGlobal(MountPoint $mount) {
205
		if (sizeof($mount->getGroups()) > 0) {
206
			return false;
207
		}
208
209
		if (sizeof($mount->getUsers()) !== 1) {
210
			return false;
211
		}
212
213
		if ($mount->getUsers()[0] === 'all') {
0 ignored issues
show
Unused Code introduced by
This if statement, and the following return statement can be replaced with return $mount->getUsers()[0] === 'all';.
Loading history...
214
			return true;
215
		}
216
217
		return false;
218
	}
219
220
221
	/**
222
	 * @param Node $file
223
	 *
224
	 * @return MountPoint
225
	 * @throws FileIsNotIndexableException
226
	 */
227 View Code Duplication
	private function getMountPoint(Node $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...
228
229
		foreach ($this->externalMounts as $mount) {
230
			if (strpos($file->getPath(), $mount->getPath()) === 0) {
231
				return $mount;
232
			}
233
		}
234
235
		throw new FileIsNotIndexableException();
236
	}
237
238
239
	/**
240
	 * @param $userId
241
	 *
242
	 * @return MountPoint[]
243
	 */
244
	private function getMountPoints($userId) {
245
246
		$mountPoints = [];
247
248
		// TODO: deprecated - use UserGlobalStoragesService::getStorages() and UserStoragesService::getStorages()
0 ignored issues
show
Unused Code Comprehensibility introduced by
37% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
Coding Style introduced by
This line exceeds maximum limit of 100 characters; contains 107 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
249
		$mounts = \OC_Mount_Config::getAbsoluteMountPoints($userId);
250
		foreach ($mounts as $path => $mount) {
251
			$mountPoint = new MountPoint();
252
			$mountPoint->setId($mount['id'])
253
					   ->setPath($path)
254
					   ->setGroups($mount['applicable']['groups'])
255
					   ->setUsers($mount['applicable']['users'])
256
					   ->setGlobal((!$mount['personal']));
257
			$mountPoints[] = $mountPoint;
258
		}
259
260
		return $mountPoints;
261
	}
262
263
264
	/**
265
	 * @param int $externalMountId
266
	 *
267
	 * @return MountPoint
268
	 * @throws ExternalMountNotFoundException
269
	 */
270
	private function getExternalMountById($externalMountId) {
271
		if ($externalMountId === 0) {
272
			throw new ExternalMountNotFoundException();
273
		}
274
275
		try {
276
			$mount = $this->globalStoragesService->getStorage($externalMountId);
277
			$mountPoint = new MountPoint();
278
			$mountPoint->setId($mount->getId())
279
					   ->setPath($mount->getMountPoint())
280
					   ->setGroups($mount->getApplicableGroups())
281
					   ->setUsers($mount->getApplicableUsers())
282
					   ->setGlobal(($mount->getType() === StorageConfig::MOUNT_TYPE_ADMIN));
283
		} catch (Exception $e) {
284
			throw new ExternalMountNotFoundException();
285
		}
286
287
		return $mountPoint;
288
	}
289
290
291
	/**
292
	 * @param Index $index
293
	 */
294
	public function impersonateOwner(Index $index) {
295
		if ($index->getSource() !== ConfigService::FILES_EXTERNAL) {
296
			return;
297
		}
298
299
		$groupFolderId = $index->getOption('external_mount_id', 0);
300
		try {
301
			$mount = $this->getExternalMountById($groupFolderId);
302
		} catch (ExternalMountNotFoundException $e) {
303
			return;
304
		}
305
306
		$this->miscService->log('========>>>>>> ' . json_encode($mount));
307
308
		try {
309
			$index->setOwnerId($this->getRandomUserFromMountPoint($mount));
310
		} catch (Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
311
		}
312
313
		$this->miscService->log(
314
			'======== ' . $index->getOwnerId() . ' >>>>>> ' . json_encode($mount)
315
		);
316
	}
317
318
319
	/**
320
	 * @param MountPoint $mount
321
	 *
322
	 * @return string
323
	 * @throws ExternalMountWithNoViewerException
324
	 */
325
	private function getRandomUserFromMountPoint(MountPoint $mount) {
326
327
		$users = $mount->getUsers();
328
		if (sizeof($users) > 0) {
329
			return $users[0];
330
		}
331
332
		$groups = $mount->getGroups();
333
		if (sizeof($groups) === 0) {
334
			$groups = ['admin'];
335
		}
336
337 View Code Duplication
		foreach ($groups as $groupName) {
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...
338
			$group = $this->groupManager->get($groupName);
339
			$users = $group->getUsers();
340
			if (sizeof($users) > 0) {
341
				return array_keys($users)[0];
342
			}
343
		}
344
345
		throw new ExternalMountWithNoViewerException(
346
			'cannot get a valid user for external mount'
347
		);
348
349
	}
350
351
}