FilesService   A
last analyzed

Complexity

Total Complexity 32

Size/Duplication

Total Lines 287
Duplicated Lines 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
eloc 85
dl 0
loc 287
rs 9.84
c 4
b 0
f 0
wmc 32

14 Methods

Rating   Name   Duplication   Size   Complexity  
A isExternalShareAllowed() 0 5 2
A getFolderData() 0 5 1
A recoverFromGetNodesError() 0 6 2
A getNodeData() 0 14 1
A isAllowedAndAvailable() 0 8 4
A isAvailable() 0 2 1
A isExternalShare() 0 8 2
A getNodes() 0 8 2
A isAllowed() 0 12 4
A formatNodeData() 0 12 1
A getNodeType() 0 8 2
A getOwnerData() 0 11 2
A isRootFolder() 0 12 3
A getAllowedSubFolder() 0 16 5
1
<?php
2
/**
3
 * Nextcloud - Gallery
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
 *
10
 * @copyright Olivier Paroz 2017
11
 */
12
13
namespace OCA\Gallery\Service;
14
15
use OCP\Files\File;
0 ignored issues
show
Bug introduced by
The type OCP\Files\File was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
16
use OCP\Files\Folder;
0 ignored issues
show
Bug introduced by
The type OCP\Files\Folder was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
17
use OCP\Files\Node;
0 ignored issues
show
Bug introduced by
The type OCP\Files\Node was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
18
use OCP\Files\StorageNotAvailableException;
0 ignored issues
show
Bug introduced by
The type OCP\Files\StorageNotAvailableException was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
19
20
/**
21
 * Contains various methods to retrieve information from the filesystem
22
 *
23
 * @package OCA\Gallery\Service
24
 */
25
abstract class FilesService extends Service {
26
27
	/** @var int */
28
	protected $virtualRootLevel = null;
29
	/** @var string[] */
30
	protected $features;
31
	/** @var string[] */
32
	protected $ignoreAlbumStrings = ['.nomedia', '.noimage'];
33
34
	/**
35
	 * Retrieves all files and sub-folders contained in a folder
36
	 *
37
	 * If we can't find anything in the current folder, we throw an exception as there is no point
38
	 * in doing any more work, but if we're looking at a sub-folder, we return an empty array so
39
	 * that it can be simply ignored
40
	 *
41
	 * @param Folder $folder
42
	 * @param int $subDepth
43
	 *
44
	 * @return array
45
	 */
46
	protected function getNodes($folder, $subDepth) {
47
		try {
48
			$nodes = $folder->getDirectoryListing();
49
		} catch (\Exception $exception) {
50
			$nodes = $this->recoverFromGetNodesError($subDepth, $exception);
51
		}
52
53
		return $nodes;
54
	}
55
56
	/**
57
	 * Determines if the files are hosted locally (shared or not) and can be used by the preview
58
	 * system
59
	 *
60
	 * isMounted() doesn't include externally hosted shares, so we need to exclude those from the
61
	 * non-mounted nodes
62
	 *
63
	 * @param Node $node
64
	 *
65
	 * @return bool
66
	 */
67
	protected function isAllowedAndAvailable($node) {
68
		try {
69
			return $node && $this->isAllowed($node) && $this->isAvailable($node);
70
		} catch (\Exception $exception) {
71
			$message = 'The folder is not available: ' . $exception->getMessage();
72
			$this->logger->error($message);
73
74
			return false;
75
		}
76
	}
77
78
	/**
79
	 * Returns the node type, either 'dir' or 'file'
80
	 *
81
	 * If there is a problem, we return an empty string so that the node can be ignored
82
	 *
83
	 * @param Node $node
84
	 *
85
	 * @return string
86
	 */
87
	protected function getNodeType($node) {
88
		try {
89
			$nodeType = $node->getType();
90
		} catch (\Exception $exception) {
91
			return '';
92
		}
93
94
		return $nodeType;
95
	}
96
97
	/**
98
	 * Returns various information about a node
99
	 *
100
	 * @param Node|File|Folder $node
101
	 *
102
	 * @return array<string,int|string|bool|array<string,int|string>>
103
	 */
104
	protected function getNodeData($node) {
105
		$imagePath = $this->environment->getPathFromVirtualRoot($node);
106
		$nodeId = $node->getId();
107
		$mTime = $node->getMTime();
108
		$etag = $node->getEtag();
109
		$size = $node->getSize();
110
		$sharedWithUser = $node->isShared();
111
		$ownerData = $this->getOwnerData($node);
112
		$permissions = $node->getPermissions();
113
114
		//$this->logger->debug("Image path : {var1}", ['var1' => $imagePath]);
115
116
		return $this->formatNodeData(
117
			$imagePath, $nodeId, $mTime, $etag, $size, $sharedWithUser, $ownerData, $permissions
118
		);
119
	}
120
121
	/**
122
	 * Returns various information about a folder
123
	 *
124
	 * @param Folder $node
125
	 *
126
	 * @return array<string,int|string|bool|array<string,int|string>>
127
	 */
128
	protected function getFolderData($node) {
129
		$folderData = $this->getNodeData($node);
130
		$folderData['freespace'] = $node->getFreeSpace();
131
132
		return $folderData;
133
	}
134
135
	/**
136
	 * Returns the node if it's a folder we have access to
137
	 *
138
	 * @param Folder $node
139
	 * @param string $nodeType
140
	 *
141
	 * @return array|Folder
142
	 */
143
	protected function getAllowedSubFolder($node, $nodeType) {
144
		if ($nodeType === 'dir') {
145
			/** @var Folder $node */
146
			try {
147
				foreach ($this->ignoreAlbumStrings as $ignoreAlbum) {
148
					if ($node->nodeExists($ignoreAlbum)) {
149
						return [];
150
					}
151
				}
152
				return [$node];
153
			} catch (StorageNotAvailableException $e) {
154
				return [];
155
			}
156
		}
157
158
		return [];
159
	}
160
161
	/**
162
	 * Determines if we've reached the root folder
163
	 *
164
	 * @param Folder $folder
165
	 * @param int $level
166
	 *
167
	 * @return bool
168
	 */
169
	protected function isRootFolder($folder, $level) {
170
		$isRootFolder = false;
171
		$rootFolder = $this->environment->getVirtualRootFolder();
172
		if (rtrim($folder->getPath(), '/') === rtrim($rootFolder->getPath(), '/')) {
173
			$isRootFolder = true;
174
		}
175
		$virtualRootFolder = $this->environment->getPathFromVirtualRoot($folder);
176
		if (empty($virtualRootFolder)) {
177
			$this->virtualRootLevel = $level;
178
		}
179
180
		return $isRootFolder;
181
	}
182
183
	/**
184
	 * Throws an exception if this problem occurs in the current folder, otherwise just ignores the
185
	 * sub-folder
186
	 *
187
	 * @param int $subDepth
188
	 * @param \Exception $exception
189
	 *
190
	 * @return array
191
	 * @throws NotFoundServiceException
192
	 */
193
	private function recoverFromGetNodesError($subDepth, $exception) {
194
		if ($subDepth === 0) {
195
			throw new NotFoundServiceException($exception->getMessage());
196
		}
197
198
		return [];
199
	}
200
201
	/**
202
	 * Determines if we can consider the node mounted locally or if it's been authorised to be
203
	 * scanned
204
	 *
205
	 * @param Node $node
206
	 *
207
	 * @return bool
208
	 */
209
	private function isAllowed($node) {
210
		$allowed = true;
211
		if ($this->isExternalShare($node)) {
212
			$allowed = $this->isExternalShareAllowed();
213
		}
214
215
		if ($node->isMounted()) {
216
			$mount = $node->getMountPoint();
217
			$allowed = $mount && $mount->getOption('previews', true);
218
		}
219
220
		return $allowed;
221
	}
222
223
	/**
224
	 * Determines if the node is available, as in readable
225
	 *
226
	 * @todo Test to see by how much using file_exists slows things down
227
	 *
228
	 * @param Node $node
229
	 *
230
	 * @return bool
231
	 */
232
	private function isAvailable($node) {
233
		return $node->isReadable();
234
	}
235
236
	/**
237
	 * Determines if the user has allowed the use of external shares
238
	 *
239
	 * @return bool
240
	 */
241
	private function isExternalShareAllowed() {
242
		$rootFolder = $this->environment->getVirtualRootFolder();
243
244
		return ($this->isExternalShare($rootFolder)
245
				|| in_array('external_shares', $this->features));
246
	}
247
248
	/**
249
	 * Determines if the node is a share which is hosted externally
250
	 *
251
	 *
252
	 * @param Node $node
253
	 *
254
	 * @return bool
255
	 */
256
	private function isExternalShare($node) {
257
		$sid = explode(
258
			':',
259
			$node->getStorage()
260
				 ->getId()
261
		);
262
263
		return ($sid[0] === 'shared' && $sid[2][0] !== '/');
264
	}
265
266
	/**
267
	 * Returns what we known about the owner of a node
268
	 *
269
	 * @param Node $node
270
	 *
271
	 * @return null|array<string,int|string>
272
	 */
273
	private function getOwnerData($node) {
274
		$owner = $node->getOwner();
275
		$ownerData = [];
276
		if ($owner) {
277
			$ownerData = [
278
				'uid'         => $owner->getUID(),
279
				'displayname' => $owner->getDisplayName()
280
			];
281
		}
282
283
		return $ownerData;
284
	}
285
286
	/**
287
	 * Returns an array containing information about a node
288
	 *
289
	 * @param string $imagePath
290
	 * @param int $nodeId
291
	 * @param int $mTime
292
	 * @param string $etag
293
	 * @param int $size
294
	 * @param bool $sharedWithUser
295
	 * @param array <string,int|string> $ownerData
0 ignored issues
show
Documentation Bug introduced by
The doc comment <string,int|string> at position 0 could not be parsed: Unknown type name '<' at position 0 in <string,int|string>.
Loading history...
296
	 * @param int $permissions
297
	 *
298
	 * @return array
299
	 */
300
	private function formatNodeData(
301
		$imagePath, $nodeId, $mTime, $etag, $size, $sharedWithUser, $ownerData, $permissions
302
	) {
303
		return [
304
			'path'           => $imagePath,
305
			'nodeid'         => $nodeId,
306
			'mtime'          => $mTime,
307
			'etag'           => $etag,
308
			'size'           => $size,
309
			'sharedwithuser' => $sharedWithUser,
310
			'owner'          => $ownerData,
311
			'permissions'    => $permissions
312
		];
313
	}
314
315
}
316