Completed
Pull Request — stable8.2 (#49)
by Olivier
17:04 queued 04:12
created

Environment::getSharedFolderName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
/**
3
 * ownCloud - galleryplus
4
 *
5
 * This file is licensed under the Affero General Public License version 3 or
6
 * later. See the COPYING file.
7
 *
8
 * @author Olivier Paroz <[email protected]>
9
 * @author Authors of \OCA\Files_Sharing\Helper
10
 *
11
 * @copyright Olivier Paroz 2016
12
 * @copyright Authors of \OCA\Files_Sharing\Helper 2014-2016
13
 */
14
15
namespace OCA\GalleryPlus\Environment;
16
17
use OCP\IUserManager;
18
use OCP\Share;
19
use OCP\ILogger;
20
use OCP\Files\IRootFolder;
21
use OCP\Files\Folder;
22
use OCP\Files\Node;
23
use OCP\Files\File;
24
use OCP\Files\NotFoundException;
25
26
/**
27
 * Builds the environment so that the services have access to the files and folders' owner
28
 *
29
 * @package OCA\GalleryPlus\Environment
30
 */
31
class Environment {
32
33
	/**
34
	 * @var string
35
	 */
36
	private $appName;
37
	/**
38
	 * The userId of the logged-in user or the person sharing a folder publicly
39
	 *
40
	 * @var string
41
	 */
42
	private $userId;
43
	/**
44
	 * The userFolder of the logged-in user or the ORIGINAL owner of the files which are shared
45
	 * publicly
46
	 *
47
	 * A share needs to be tracked back to its original owner in order to be able to access the
48
	 * resource
49
	 *
50
	 * @var Folder|null
51
	 */
52
	private $userFolder;
53
	/**
54
	 * @var IUserManager
55
	 */
56
	private $userManager;
57
	/**
58
	 * @var int
59
	 */
60
	private $sharedNodeId;
61
	/**
62
	 * @var File|Folder
63
	 */
64
	private $sharedNode;
65
	/**
66
	 * @var IRootFolder
67
	 */
68
	private $rootFolder;
69
	/**
70
	 * @var ILogger
71
	 */
72
	private $logger;
73
	/**
74
	 * The path to the userFolder for users with accounts: /userId/files
75
	 *
76
	 * For public folders, it's the path from the shared folder to the root folder in the original
77
	 * owner's filesystem: /userId/files/parent_folder/shared_folder
78
	 *
79
	 * @var string
80
	 */
81
	private $fromRootToFolder;
82
	/**
83
	 * The name of the shared folder
84
	 *
85
	 * @var string
86
	 */
87
	private $folderName;
88
	/**
89
	 * @var string|null
90
	 */
91
	private $sharePassword;
92
93
	/***
94
	 * Constructor
95
	 *
96
	 * @param string $appName
97
	 * @param string|null $userId
98
	 * @param Folder|null $userFolder
99
	 * @param IUserManager $userManager
100
	 * @param IRootFolder $rootFolder
101
	 * @param ILogger $logger
102
	 */
103 59
	public function __construct(
104
		$appName,
105
		$userId,
106
		$userFolder,
107
		IUserManager $userManager,
108
		IRootFolder $rootFolder,
109
		ILogger $logger
110
	) {
111 59
		$this->appName = $appName;
112 59
		$this->userId = $userId;
113 59
		$this->userFolder = $userFolder;
114 59
		$this->userManager = $userManager;
115 59
		$this->rootFolder = $rootFolder;
116 59
		$this->logger = $logger;
117 59
	}
118
119
	/**
120
	 * Creates the environment based on the linkItem the token links to
121
	 *
122
	 * @param array $linkItem
123
	 */
124 21
	public function setTokenBasedEnv($linkItem) {
125
		// Resolves reshares down to the last real share
126 21
		$rootLinkItem = Share::resolveReShare($linkItem);
127 21
		$origShareOwner = $rootLinkItem['uid_owner'];
128 21
		$this->userFolder = $this->rootFolder->getUserFolder($origShareOwner);
129
130
		// This is actually the node ID
131 21
		$this->sharedNodeId = $linkItem['file_source'];
132 21
		$this->sharedNode =
133 21
			$this->getResourceFromFolderAndId($this->userFolder, $this->sharedNodeId);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->getResourceFromFo...r, $this->sharedNodeId) of type object<OCP\Files\Node> is incompatible with the declared type object<OCP\Files\File>|object<OCP\Files\Folder> of property $sharedNode.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
134 21
		$this->fromRootToFolder = $this->buildFromRootToFolder($this->sharedNodeId);
135
136 21
		$this->folderName = $linkItem['file_target'];
137 21
		$this->userId = $rootLinkItem['uid_owner'];
138 21
		$this->sharePassword = $linkItem['share_with'];
139 21
	}
140
141
	/**
142
	 * Creates the environment for a logged-in user
143
	 *
144
	 * userId and userFolder are already known, we define fromRootToFolder
145
	 * so that the services can use one method to have access to resources
146
	 * without having to know whether they're private or public
147
	 */
148 29
	public function setStandardEnv() {
149 29
		$this->fromRootToFolder = $this->userFolder->getPath() . '/';
150 29
	}
151
152
	/**
153
	 * Returns true if the environment has been setup using a token
154
	 *
155
	 * @return bool
156
	 */
157 43
	public function isTokenBasedEnv() {
158 43
		return !empty($this->sharedNodeId);
159
	}
160
161
	/**
162
	 * Returns the Node based on a path starting from the virtual root
163
	 *
164
	 * @param string $subPath
165
	 *
166
	 * @return File|Folder
0 ignored issues
show
Documentation introduced by
Should the return type not be Node?

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...
167
	 */
168 8
	public function getNodeFromVirtualRoot($subPath) {
169 8
		$relativePath = $this->getRelativePath($this->fromRootToFolder);
170 8
		$path = $relativePath . '/' . $subPath;
171 8
		$node = $this->getNodeFromUserFolder($path);
172
173 8
		return $this->getResourceFromId($node->getId());
174
	}
175
176
	/**
177
	 * Returns the Node based on a path starting from the files' owner user folder
178
	 *
179
	 * When logged in, this is the current user's user folder
180
	 * When visiting a link, this is the sharer's user folder
181
	 *
182
	 * @param string $path
183
	 *
184
	 * @return File|Folder
185
	 *
186
	 * @throws NotFoundEnvException
187
	 */
188 11
	public function getNodeFromUserFolder($path) {
189 11
		$folder = $this->userFolder;
190 11
		if ($folder === null) {
191 1
			throw new NotFoundEnvException("Could not access the user's folder");
192
		} else {
193
			try {
194 10
				$node = $folder->get($path);
195 2
			} catch (NotFoundException $exception) {
196 2
				$message = 'Could not find anything at: ' . $exception->getMessage();
197 2
				throw new NotFoundEnvException($message);
198
			}
199
		}
200
201 10
		return $node;
202
	}
203
204
	/**
205
	 * Returns the resource identified by the given ID
206
	 *
207
	 * @param int $resourceId
208
	 *
209
	 * @return Node
210
	 *
211
	 * @throws NotFoundEnvException
212
	 */
213 37
	public function getResourceFromId($resourceId) {
214 37
		if ($this->isTokenBasedEnv()) {
215 21
			if ($this->sharedNode->getType() === 'dir') {
216 16
				$resource = $this->getResourceFromFolderAndId($this->sharedNode, $resourceId);
217
			} else {
218 21
				$resource = $this->sharedNode;
219
			}
220
		} else {
221 17
			$resource = $this->getResourceFromFolderAndId($this->userFolder, $resourceId);
0 ignored issues
show
Bug introduced by
It seems like $this->userFolder can be null; however, getResourceFromFolderAndId() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
222
		}
223
224 34
		return $resource;
225
	}
226
227
	/**
228
	 * Returns the shared node
229
	 *
230
	 * @return File|Folder
0 ignored issues
show
Documentation introduced by
Should the return type not be Node?

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...
231
	 */
232 8
	public function getSharedNode() {
233 8
		return $this->getResourceFromId($this->sharedNodeId);
234
	}
235
236
	/**
237
	 * Returns the virtual root where the user lands after logging in or when following a link
238
	 *
239
	 * @return Folder
240
	 * @throws NotFoundEnvException
241
	 */
242 14
	public function getVirtualRootFolder() {
243 14
		$rootFolder = $this->userFolder;
244 14
		if ($this->isTokenBasedEnv()) {
245 4
			$node = $this->getSharedNode();
246 4
			$nodeType = $node->getType();
247 4
			if ($nodeType === 'dir') {
248 3
				$rootFolder = $node;
249
			} else {
250 1
				throw new NotFoundEnvException($node->getPath() . ' is not a folder');
251
			}
252
		}
253
254 13
		return $rootFolder;
255
	}
256
257
	/**
258
	 * Returns the userId of the currently logged-in user or the sharer
259
	 *
260
	 * @return string
261
	 */
262 9
	public function getUserId() {
263 9
		return $this->userId;
264
	}
265
266
	/**
267
	 * Returns the name of the user sharing files publicly
268
	 *
269
	 * @return string
270
	 * @throws NotFoundEnvException
271
	 */
272 2
	public function getDisplayName() {
273 2
		$user = null;
274 2
		$userId = $this->userId;
275
276 2
		if (isset($userId)) {
277 1
			$user = $this->userManager->get($userId);
278
		}
279 2
		if ($user === null) {
280 1
			throw new NotFoundEnvException('Could not find user');
281
		}
282
283 1
		return $user->getDisplayName();
284
	}
285
286
	/**
287
	 * Returns the name of shared folder
288
	 *
289
	 * @return string
290
	 */
291 1
	public function getSharedFolderName() {
292 1
		return trim($this->folderName, '//');
293
	}
294
295
	/**
296
	 * Returns the password for the share, if there is one
297
	 *
298
	 * @return string|null
299
	 */
300 1
	public function getSharePassword() {
301 1
		return $this->sharePassword;
302
	}
303
304
	/**
305
	 * Returns the path which goes from the file, up to the user folder, based on a node:
306
	 * parent_folder/current_folder/my_file
307
	 *
308
	 * This is used for the preview system, which needs a full path
309
	 *
310
	 * getPath() on the file produces a path like:
311
	 * '/userId/files/my_folder/my_sub_folder/my_file'
312
	 *
313
	 * So we substract the path to the folder, giving us a relative path
314
	 * 'my_folder/my_sub_folder/my_file'
315
	 *
316
	 * @param Node $file
317
	 *
318
	 * @return string
319
	 */
320 9
	public function getPathFromUserFolder($file) {
321 9
		$path = $file->getPath();
322
323 9
		return $this->getRelativePath($path);
324
	}
325
326
	/**
327
	 * Returns the path which goes from the file, up to the root folder of the Gallery:
328
	 * current_folder/my_file
329
	 *
330
	 * That root folder changes when folders are shared publicly
331
	 *
332
	 * @param File|Folder|N $node
333
	 *
334
	 * @return string
335
	 */
336 10
	public function getPathFromVirtualRoot($node) {
337 10
		$path = $node->getPath();
338 10
		$nodeType = $node->getType();
339
340
		// Needed because fromRootToFolder always ends with a slash
341 10
		if ($nodeType === 'dir') {
342 8
			$path .= '/';
343
		}
344
345 10
		$path = str_replace($this->fromRootToFolder, '', $path);
346 10
		$path = rtrim($path, '/');
347
348 10
		return $path;
349
	}
350
351
	/**
352
	 * Returns the resource found in a specific folder and identified by the given ID
353
	 *
354
	 * @param Folder $folder
355
	 * @param int $resourceId
356
	 *
357
	 * @return Node
358
	 * @throws NotFoundEnvException
359
	 */
360 37
	private function getResourceFromFolderAndId($folder, $resourceId) {
361 37
		$resourcesArray = $folder->getById($resourceId);
362
363 37
		if ($resourcesArray[0] === null) {
364 3
			throw new NotFoundEnvException('Could not locate node linked to ID: ' . $resourceId);
365
		}
366
367 34
		return $resourcesArray[0];
368
	}
369
370
	/**
371
	 * Returns the path from the shared folder to the root folder in the original
372
	 * owner's filesystem: /userId/files/parent_folder/shared_folder
373
	 *
374
	 * This cannot be calculated with paths and IDs, the linkitem's file source is required
375
	 *
376
	 * @param string $fileSource
377
	 *
378
	 * @return string
379
	 */
380 21
	private function buildFromRootToFolder($fileSource) {
381 21
		$resource = $this->getResourceFromId($fileSource);
382 21
		$fromRootToFolder = $resource->getPath() . '/';
383
384 21
		return $fromRootToFolder;
385
	}
386
387
	/**
388
	 * Returns the path which goes from the file, up to the user folder, based on a path:
389
	 * parent_folder/current_folder/my_file
390
	 *
391
	 * getPath() on the file produces a path like:
392
	 * '/userId/files/my_folder/my_sub_folder/my_file'
393
	 *
394
	 * So we substract the path to the user folder, giving us a relative path
395
	 * 'my_folder/my_sub_folder'
396
	 *
397
	 * @param string $fullPath
398
	 *
399
	 * @return string
400
	 */
401 17
	private function getRelativePath($fullPath) {
402 17
		$folderPath = $this->userFolder->getPath() . '/';
403 17
		$origShareRelPath = str_replace($folderPath, '', $fullPath);
404
405 17
		return $origShareRelPath;
406
	}
407
408
}
409