Completed
Push — master ( c17b1b...8f13d8 )
by Olivier
13:31 queued 09:59
created

Environment::getResourceFromFolderAndId()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 9
ccs 5
cts 5
cp 1
rs 9.6666
cc 2
eloc 5
nc 2
nop 2
crap 2
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\Share\IShare;
20
use OCP\ILogger;
21
use OCP\Files\IRootFolder;
22
use OCP\Files\Folder;
23
use OCP\Files\Node;
24
use OCP\Files\File;
25
use OCP\Files\NotFoundException;
26
27
/**
28
 * Builds the environment so that the services have access to the files and folders' owner
29
 *
30
 * @package OCA\GalleryPlus\Environment
31
 */
32
class Environment {
33
34
	/**
35
	 * @var string
36
	 */
37
	private $appName;
38
	/**
39
	 * The userId of the logged-in user or the person sharing a folder publicly
40
	 *
41
	 * @var string
42
	 */
43
	private $userId;
44
	/**
45
	 * The userFolder of the logged-in user or the ORIGINAL owner of the files which are shared
46
	 * publicly
47
	 *
48
	 * A share needs to be tracked back to its original owner in order to be able to access the
49
	 * resource
50
	 *
51
	 * @var Folder|null
52
	 */
53
	private $userFolder;
54
	/**
55
	 * @var IUserManager
56
	 */
57
	private $userManager;
58
	/**
59
	 * @var int
60
	 */
61
	private $sharedNodeId;
62
	/**
63
	 * @var File|Folder
64
	 */
65
	private $sharedNode;
66
	/**
67
	 * @var IRootFolder
68
	 */
69
	private $rootFolder;
70
	/**
71
	 * @var ILogger
72
	 */
73
	private $logger;
74
	/**
75
	 * The path to the userFolder for users with accounts: /userId/files
76
	 *
77
	 * For public folders, it's the path from the shared folder to the root folder in the original
78
	 * owner's filesystem: /userId/files/parent_folder/shared_folder
79
	 *
80
	 * @var string
81
	 */
82
	private $fromRootToFolder;
83
	/**
84
	 * The name of the shared folder
85
	 *
86
	 * @var string
87
	 */
88
	private $folderName;
89
	/**
90
	 * @var string|null
91
	 */
92
	private $sharePassword;
93
94
	/***
95
	 * Constructor
96
	 *
97
	 * @param string $appName
98
	 * @param string|null $userId
99
	 * @param Folder|null $userFolder
100
	 * @param IUserManager $userManager
101
	 * @param IRootFolder $rootFolder
102
	 * @param ILogger $logger
103
	 */
104 59
	public function __construct(
105
		$appName,
106
		$userId,
107
		$userFolder,
108
		IUserManager $userManager,
109
		IRootFolder $rootFolder,
110
		ILogger $logger
111
	) {
112 59
		$this->appName = $appName;
113 59
		$this->userId = $userId;
114 59
		$this->userFolder = $userFolder;
115 59
		$this->userManager = $userManager;
116 59
		$this->rootFolder = $rootFolder;
117 59
		$this->logger = $logger;
118 59
	}
119
120
	/**
121
	 * Creates the environment based on the share the token links to
122
	 *
123
	 * @param IShare $share
124
	 */
125 21
	public function setTokenBasedEnv($share) {
126 21
		$origShareOwnerId = $share->getShareOwner();
127 21
		$this->userFolder = $this->rootFolder->getUserFolder($origShareOwnerId);
128
129 21
		$this->sharedNodeId = $share->getNodeId();
130 21
		$this->sharedNode = $share->getNode();
131 21
		$this->fromRootToFolder = $this->buildFromRootToFolder($this->sharedNodeId);
132
133 21
		$this->folderName = $share->getTarget();
134 21
		$this->userId = $origShareOwnerId;
135 21
		$this->sharePassword = $share->getPassword();
136 21
	}
137
138
	/**
139
	 * Creates the environment for a logged-in user
140
	 *
141
	 * userId and userFolder are already known, we define fromRootToFolder
142
	 * so that the services can use one method to have access to resources
143
	 * without having to know whether they're private or public
144
	 */
145 29
	public function setStandardEnv() {
146 29
		$this->fromRootToFolder = $this->userFolder->getPath() . '/';
147 29
	}
148
149
	/**
150
	 * Returns true if the environment has been setup using a token
151
	 *
152
	 * @return bool
153
	 */
154 43
	public function isTokenBasedEnv() {
155 43
		return !empty($this->sharedNodeId);
156
	}
157
158
	/**
159
	 * Returns the Node based on a path starting from the virtual root
160
	 *
161
	 * @param string $subPath
162
	 *
163
	 * @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...
164
	 */
165 8
	public function getNodeFromVirtualRoot($subPath) {
166 8
		$relativePath = $this->getRelativePath($this->fromRootToFolder);
167 8
		$path = $relativePath . '/' . $subPath;
168 8
		$node = $this->getNodeFromUserFolder($path);
169
170 8
		return $this->getResourceFromId($node->getId());
171
	}
172
173
	/**
174
	 * Returns the Node based on a path starting from the files' owner user folder
175
	 *
176
	 * When logged in, this is the current user's user folder
177
	 * When visiting a link, this is the sharer's user folder
178
	 *
179
	 * @param string $path
180
	 *
181
	 * @return File|Folder
182
	 *
183
	 * @throws NotFoundEnvException
184
	 */
185 11
	public function getNodeFromUserFolder($path) {
186 11
		$folder = $this->userFolder;
187 11
		if ($folder === null) {
188 1
			throw new NotFoundEnvException("Could not access the user's folder");
189
		} else {
190
			try {
191 10
				$node = $folder->get($path);
192 2
			} catch (NotFoundException $exception) {
193 2
				$message = 'Could not find anything at: ' . $exception->getMessage();
194 2
				throw new NotFoundEnvException($message);
195
			}
196
		}
197
198 10
		return $node;
199
	}
200
201
	/**
202
	 * Returns the resource identified by the given ID
203
	 *
204
	 * @param int $resourceId
205
	 *
206
	 * @return Node
207
	 *
208
	 * @throws NotFoundEnvException
209
	 */
210 37
	public function getResourceFromId($resourceId) {
211 37
		if ($this->isTokenBasedEnv()) {
212 21
			if ($this->sharedNode->getType() === 'dir') {
213 16
				$resource = $this->getResourceFromFolderAndId($this->sharedNode, $resourceId);
214
			} else {
215 21
				$resource = $this->sharedNode;
216
			}
217
		} else {
218 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...
219
		}
220
221 34
		return $resource;
222
	}
223
224
	/**
225
	 * Returns the shared node
226
	 *
227
	 * @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...
228
	 */
229 8
	public function getSharedNode() {
230 8
		return $this->getResourceFromId($this->sharedNodeId);
231
	}
232
233
	/**
234
	 * Returns the virtual root where the user lands after logging in or when following a link
235
	 *
236
	 * @return Folder
237
	 * @throws NotFoundEnvException
238
	 */
239 14
	public function getVirtualRootFolder() {
240 14
		$rootFolder = $this->userFolder;
241 14
		if ($this->isTokenBasedEnv()) {
242 4
			$node = $this->getSharedNode();
243 4
			$nodeType = $node->getType();
244 4
			if ($nodeType === 'dir') {
245 3
				$rootFolder = $node;
246
			} else {
247 1
				throw new NotFoundEnvException($node->getPath() . ' is not a folder');
248
			}
249
		}
250
251 13
		return $rootFolder;
252
	}
253
254
	/**
255
	 * Returns the userId of the currently logged-in user or the sharer
256
	 *
257
	 * @return string
258
	 */
259 9
	public function getUserId() {
260 9
		return $this->userId;
261
	}
262
263
	/**
264
	 * Returns the name of the user sharing files publicly
265
	 *
266
	 * @return string
267
	 * @throws NotFoundEnvException
268
	 */
269 2
	public function getDisplayName() {
270 2
		$user = null;
271 2
		$userId = $this->userId;
272
273 2
		if (isset($userId)) {
274 1
			$user = $this->userManager->get($userId);
275
		}
276 2
		if ($user === null) {
277 1
			throw new NotFoundEnvException('Could not find user');
278
		}
279
280 1
		return $user->getDisplayName();
281
	}
282
283
	/**
284
	 * Returns the name of shared folder
285
	 *
286
	 * @return string
287
	 */
288 1
	public function getSharedFolderName() {
289 1
		return trim($this->folderName, '//');
290
	}
291
292
	/**
293
	 * Returns the password for the share, if there is one
294
	 *
295
	 * @return string|null
296
	 */
297 1
	public function getSharePassword() {
298 1
		return $this->sharePassword;
299
	}
300
301
	/**
302
	 * Returns the path which goes from the file, up to the user folder, based on a node:
303
	 * parent_folder/current_folder/my_file
304
	 *
305
	 * This is used for the preview system, which needs a full path
306
	 *
307
	 * getPath() on the file produces a path like:
308
	 * '/userId/files/my_folder/my_sub_folder/my_file'
309
	 *
310
	 * So we substract the path to the folder, giving us a relative path
311
	 * 'my_folder/my_sub_folder/my_file'
312
	 *
313
	 * @param Node $file
314
	 *
315
	 * @return string
316
	 */
317 9
	public function getPathFromUserFolder($file) {
318 9
		$path = $file->getPath();
319
320 9
		return $this->getRelativePath($path);
321
	}
322
323
	/**
324
	 * Returns the path which goes from the file, up to the root folder of the Gallery:
325
	 * current_folder/my_file
326
	 *
327
	 * That root folder changes when folders are shared publicly
328
	 *
329
	 * @param File|Folder|Node $node
330
	 *
331
	 * @return string
332
	 */
333 10
	public function getPathFromVirtualRoot($node) {
334 10
		$path = $node->getPath();
335 10
		$nodeType = $node->getType();
336
337
		// Needed because fromRootToFolder always ends with a slash
338 10
		if ($nodeType === 'dir') {
339 8
			$path .= '/';
340
		}
341
342 10
		$path = str_replace($this->fromRootToFolder, '', $path);
343 10
		$path = rtrim($path, '/');
344
345 10
		return $path;
346
	}
347
348
	/**
349
	 * Returns the resource found in a specific folder and identified by the given ID
350
	 *
351
	 * @param Folder $folder
352
	 * @param int $resourceId
353
	 *
354
	 * @return Node
355
	 * @throws NotFoundEnvException
356
	 */
357 33
	private function getResourceFromFolderAndId($folder, $resourceId) {
358 33
		$resourcesArray = $folder->getById($resourceId);
359
360 33
		if ($resourcesArray[0] === null) {
361 3
			throw new NotFoundEnvException('Could not locate node linked to ID: ' . $resourceId);
362
		}
363
364 30
		return $resourcesArray[0];
365
	}
366
367
	/**
368
	 * Returns the path from the shared folder to the root folder in the original
369
	 * owner's filesystem: /userId/files/parent_folder/shared_folder
370
	 *
371
	 * This cannot be calculated with paths and IDs, the share's file source is required
372
	 *
373
	 * @param string $fileSource
374
	 *
375
	 * @return string
376
	 */
377 21
	private function buildFromRootToFolder($fileSource) {
378 21
		$resource = $this->getResourceFromId($fileSource);
379 21
		$fromRootToFolder = $resource->getPath() . '/';
380
381 21
		return $fromRootToFolder;
382
	}
383
384
	/**
385
	 * Returns the path which goes from the file, up to the user folder, based on a path:
386
	 * parent_folder/current_folder/my_file
387
	 *
388
	 * getPath() on the file produces a path like:
389
	 * '/userId/files/my_folder/my_sub_folder/my_file'
390
	 *
391
	 * So we substract the path to the user folder, giving us a relative path
392
	 * 'my_folder/my_sub_folder'
393
	 *
394
	 * @param string $fullPath
395
	 *
396
	 * @return string
397
	 */
398 17
	private function getRelativePath($fullPath) {
399 17
		$folderPath = $this->userFolder->getPath() . '/';
400 17
		$origShareRelPath = str_replace($folderPath, '', $fullPath);
401
402 17
		return $origShareRelPath;
403
	}
404
405
}
406