Passed
Push — master ( ff58cd...f7cca5 )
by John
17:34 queued 12s
created

ApiController::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 19
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 9
nc 1
nop 10
dl 0
loc 19
rs 9.9666
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Christoph Wurst <[email protected]>
6
 * @author Daniel Kesselberg <[email protected]>
7
 * @author Felix Nüsse <[email protected]>
8
 * @author fnuesse <[email protected]>
9
 * @author fnuesse <[email protected]>
10
 * @author Joas Schilling <[email protected]>
11
 * @author John Molakvoæ <[email protected]>
12
 * @author Julius Härtl <[email protected]>
13
 * @author Lukas Reschke <[email protected]>
14
 * @author Max Kovalenko <[email protected]>
15
 * @author Morris Jobke <[email protected]>
16
 * @author Nina Pypchenko <[email protected]>
17
 * @author Richard Steinmetz <[email protected]>
18
 * @author Robin Appelman <[email protected]>
19
 * @author Roeland Jago Douma <[email protected]>
20
 * @author Tobias Kaminsky <[email protected]>
21
 * @author Vincent Petry <[email protected]>
22
 *
23
 * @license AGPL-3.0
24
 *
25
 * This code is free software: you can redistribute it and/or modify
26
 * it under the terms of the GNU Affero General Public License, version 3,
27
 * as published by the Free Software Foundation.
28
 *
29
 * This program is distributed in the hope that it will be useful,
30
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32
 * GNU Affero General Public License for more details.
33
 *
34
 * You should have received a copy of the GNU Affero General Public License, version 3,
35
 * along with this program. If not, see <http://www.gnu.org/licenses/>
36
 *
37
 */
38
namespace OCA\Files\Controller;
39
40
use OC\Files\Node\Node;
41
use OCA\Files\Service\TagService;
42
use OCA\Files\Service\UserConfig;
43
use OCA\Files\Service\ViewConfig;
44
use OCP\AppFramework\Controller;
45
use OCP\AppFramework\Http;
46
use OCP\AppFramework\Http\ContentSecurityPolicy;
47
use OCP\AppFramework\Http\DataResponse;
48
use OCP\AppFramework\Http\FileDisplayResponse;
49
use OCP\AppFramework\Http\JSONResponse;
50
use OCP\AppFramework\Http\Response;
51
use OCP\AppFramework\Http\StreamResponse;
52
use OCP\Files\File;
53
use OCP\Files\Folder;
54
use OCP\Files\NotFoundException;
55
use OCP\IConfig;
56
use OCP\IPreview;
57
use OCP\IRequest;
58
use OCP\IUserSession;
59
use OCP\Share\IManager;
60
use OCP\Share\IShare;
61
62
/**
63
 * Class ApiController
64
 *
65
 * @package OCA\Files\Controller
66
 */
67
class ApiController extends Controller {
68
	private TagService $tagService;
69
	private IManager $shareManager;
70
	private IPreview $previewManager;
71
	private IUserSession $userSession;
72
	private IConfig $config;
73
	private Folder $userFolder;
74
	private UserConfig $userConfig;
75
	private ViewConfig $viewConfig;
76
77
	/**
78
	 * @param string $appName
79
	 * @param IRequest $request
80
	 * @param IUserSession $userSession
81
	 * @param TagService $tagService
82
	 * @param IPreview $previewManager
83
	 * @param IManager $shareManager
84
	 * @param IConfig $config
85
	 * @param Folder $userFolder
86
	 */
87
	public function __construct($appName,
88
								IRequest $request,
89
								IUserSession $userSession,
90
								TagService $tagService,
91
								IPreview $previewManager,
92
								IManager $shareManager,
93
								IConfig $config,
94
								Folder $userFolder,
95
								UserConfig $userConfig,
96
								ViewConfig $viewConfig) {
97
		parent::__construct($appName, $request);
98
		$this->userSession = $userSession;
99
		$this->tagService = $tagService;
100
		$this->previewManager = $previewManager;
101
		$this->shareManager = $shareManager;
102
		$this->config = $config;
103
		$this->userFolder = $userFolder;
104
		$this->userConfig = $userConfig;
105
		$this->viewConfig = $viewConfig;
106
	}
107
108
	/**
109
	 * Gets a thumbnail of the specified file
110
	 *
111
	 * @since API version 1.0
112
	 *
113
	 * @NoAdminRequired
114
	 * @NoCSRFRequired
115
	 * @StrictCookieRequired
116
	 *
117
	 * @param int $x
118
	 * @param int $y
119
	 * @param string $file URL-encoded filename
120
	 * @return DataResponse|FileDisplayResponse
121
	 */
122
	public function getThumbnail($x, $y, $file) {
123
		if ($x < 1 || $y < 1) {
124
			return new DataResponse(['message' => 'Requested size must be numeric and a positive value.'], Http::STATUS_BAD_REQUEST);
125
		}
126
127
		try {
128
			$file = $this->userFolder->get($file);
129
			if ($file instanceof Folder) {
130
				throw new NotFoundException();
131
			}
132
133
			/** @var File $file */
134
			$preview = $this->previewManager->getPreview($file, $x, $y, true);
135
136
			return new FileDisplayResponse($preview, Http::STATUS_OK, ['Content-Type' => $preview->getMimeType()]);
137
		} catch (NotFoundException $e) {
138
			return new DataResponse(['message' => 'File not found.'], Http::STATUS_NOT_FOUND);
139
		} catch (\Exception $e) {
140
			return new DataResponse([], Http::STATUS_BAD_REQUEST);
141
		}
142
	}
143
144
	/**
145
	 * Updates the info of the specified file path
146
	 * The passed tags are absolute, which means they will
147
	 * replace the actual tag selection.
148
	 *
149
	 * @NoAdminRequired
150
	 *
151
	 * @param string $path path
152
	 * @param array|string $tags array of tags
153
	 * @return DataResponse
154
	 */
155
	public function updateFileTags($path, $tags = null) {
156
		$result = [];
157
		// if tags specified or empty array, update tags
158
		if (!is_null($tags)) {
159
			try {
160
				$this->tagService->updateFileTags($path, $tags);
161
			} catch (\OCP\Files\NotFoundException $e) {
162
				return new DataResponse([
163
					'message' => $e->getMessage()
164
				], Http::STATUS_NOT_FOUND);
165
			} catch (\OCP\Files\StorageNotAvailableException $e) {
166
				return new DataResponse([
167
					'message' => $e->getMessage()
168
				], Http::STATUS_SERVICE_UNAVAILABLE);
169
			} catch (\Exception $e) {
170
				return new DataResponse([
171
					'message' => $e->getMessage()
172
				], Http::STATUS_NOT_FOUND);
173
			}
174
			$result['tags'] = $tags;
175
		}
176
		return new DataResponse($result);
177
	}
178
179
	/**
180
	 * @param \OCP\Files\Node[] $nodes
181
	 * @return array
182
	 */
183
	private function formatNodes(array $nodes) {
184
		$shareTypesForNodes = $this->getShareTypesForNodes($nodes);
185
		return array_values(array_map(function (Node $node) use ($shareTypesForNodes) {
186
			$shareTypes = $shareTypesForNodes[$node->getId()] ?? [];
187
			$file = \OCA\Files\Helper::formatFileInfo($node->getFileInfo());
188
			$file['hasPreview'] = $this->previewManager->isAvailable($node);
189
			$parts = explode('/', dirname($node->getPath()), 4);
190
			if (isset($parts[3])) {
191
				$file['path'] = '/' . $parts[3];
192
			} else {
193
				$file['path'] = '/';
194
			}
195
			if (!empty($shareTypes)) {
196
				$file['shareTypes'] = $shareTypes;
197
			}
198
			return $file;
199
		}, $nodes));
200
	}
201
202
	/**
203
	 * Get the share types for each node
204
	 *
205
	 * @param \OCP\Files\Node[] $nodes
206
	 * @return array<int, int[]> list of share types for each fileid
207
	 */
208
	private function getShareTypesForNodes(array $nodes): array {
209
		$userId = $this->userSession->getUser()->getUID();
210
		$requestedShareTypes = [
211
			IShare::TYPE_USER,
212
			IShare::TYPE_GROUP,
213
			IShare::TYPE_LINK,
214
			IShare::TYPE_REMOTE,
215
			IShare::TYPE_EMAIL,
216
			IShare::TYPE_ROOM,
217
			IShare::TYPE_DECK,
218
			IShare::TYPE_SCIENCEMESH,
219
		];
220
		$shareTypes = [];
221
222
		$nodeIds = array_map(function (Node $node) {
223
			return $node->getId();
224
		}, $nodes);
225
226
		foreach ($requestedShareTypes as $shareType) {
227
			$nodesLeft = array_combine($nodeIds, array_fill(0, count($nodeIds), true));
228
			$offset = 0;
229
230
			// fetch shares until we've either found shares for all nodes or there are no more shares left
231
			while (count($nodesLeft) > 0) {
232
				$shares = $this->shareManager->getSharesBy($userId, $shareType, null, false, 100, $offset);
233
				foreach ($shares as $share) {
234
					$fileId = $share->getNodeId();
235
					if (isset($nodesLeft[$fileId])) {
236
						if (!isset($shareTypes[$fileId])) {
237
							$shareTypes[$fileId] = [];
238
						}
239
						$shareTypes[$fileId][] = $shareType;
240
						unset($nodesLeft[$fileId]);
241
					}
242
				}
243
244
				if (count($shares) < 100) {
245
					break;
246
				} else {
247
					$offset += count($shares);
248
				}
249
			}
250
		}
251
		return $shareTypes;
252
	}
253
254
	/**
255
	 * Returns a list of recently modified files.
256
	 *
257
	 * @NoAdminRequired
258
	 *
259
	 * @return DataResponse
260
	 */
261
	public function getRecentFiles() {
262
		$nodes = $this->userFolder->getRecent(100);
263
		$files = $this->formatNodes($nodes);
264
		return new DataResponse(['files' => $files]);
265
	}
266
267
268
	/**
269
	 * Returns the current logged-in user's storage stats.
270
	 *
271
	 * @NoAdminRequired
272
	 *
273
	 * @param ?string $dir the directory to get the storage stats from
274
	 * @return JSONResponse
275
	 */
276
	public function getStorageStats($dir = '/'): JSONResponse {
277
		$storageInfo = \OC_Helper::getStorageInfo($dir ?: '/');
278
		return new JSONResponse(['message' => 'ok', 'data' => $storageInfo]);
279
	}
280
281
	/**
282
	 * Set a user view config
283
	 *
284
	 * @NoAdminRequired
285
	 *
286
	 * @param string $view
287
	 * @param string $key
288
	 * @param string|bool $value
289
	 * @return JSONResponse
290
	 */
291
	public function setViewConfig(string $view, string $key, $value): JSONResponse {
292
		try {
293
			$this->viewConfig->setConfig($view, $key, (string)$value);
294
		} catch (\InvalidArgumentException $e) {
295
			return new JSONResponse(['message' => $e->getMessage()], Http::STATUS_BAD_REQUEST);
296
		}
297
298
		return new JSONResponse(['message' => 'ok', 'data' => $this->viewConfig->getConfig($view)]);
299
	}
300
301
302
	/**
303
	 * Get the user view config
304
	 *
305
	 * @NoAdminRequired
306
	 *
307
	 * @return JSONResponse
308
	 */
309
	public function getViewConfigs(): JSONResponse {
310
		return new JSONResponse(['message' => 'ok', 'data' => $this->viewConfig->getConfigs()]);
311
	}
312
313
	/**
314
	 * Set a user config
315
	 *
316
	 * @NoAdminRequired
317
	 *
318
	 * @param string $key
319
	 * @param string|bool $value
320
	 * @return JSONResponse
321
	 */
322
	public function setConfig(string $key, $value): JSONResponse {
323
		try {
324
			$this->userConfig->setConfig($key, (string)$value);
325
		} catch (\InvalidArgumentException $e) {
326
			return new JSONResponse(['message' => $e->getMessage()], Http::STATUS_BAD_REQUEST);
327
		}
328
329
		return new JSONResponse(['message' => 'ok', 'data' => ['key' => $key, 'value' => $value]]);
330
	}
331
332
333
	/**
334
	 * Get the user config
335
	 *
336
	 * @NoAdminRequired
337
	 *
338
	 * @return JSONResponse
339
	 */
340
	public function getConfigs(): JSONResponse {
341
		return new JSONResponse(['message' => 'ok', 'data' => $this->userConfig->getConfigs()]);
342
	}
343
344
	/**
345
	 * Toggle default for showing/hiding hidden files
346
	 *
347
	 * @NoAdminRequired
348
	 *
349
	 * @param bool $value
350
	 * @return Response
351
	 * @throws \OCP\PreConditionNotMetException
352
	 */
353
	public function showHiddenFiles(bool $value): Response {
354
		$this->config->setUserValue($this->userSession->getUser()->getUID(), 'files', 'show_hidden', $value ? '1' : '0');
355
		return new Response();
356
	}
357
358
	/**
359
	 * Toggle default for cropping preview images
360
	 *
361
	 * @NoAdminRequired
362
	 *
363
	 * @param bool $value
364
	 * @return Response
365
	 * @throws \OCP\PreConditionNotMetException
366
	 */
367
	public function cropImagePreviews(bool $value): Response {
368
		$this->config->setUserValue($this->userSession->getUser()->getUID(), 'files', 'crop_image_previews', $value ? '1' : '0');
369
		return new Response();
370
	}
371
372
	/**
373
	 * Toggle default for files grid view
374
	 *
375
	 * @NoAdminRequired
376
	 *
377
	 * @param bool $show
378
	 * @return Response
379
	 * @throws \OCP\PreConditionNotMetException
380
	 */
381
	public function showGridView(bool $show): Response {
382
		$this->config->setUserValue($this->userSession->getUser()->getUID(), 'files', 'show_grid', $show ? '1' : '0');
383
		return new Response();
384
	}
385
386
	/**
387
	 * Get default settings for the grid view
388
	 *
389
	 * @NoAdminRequired
390
	 */
391
	public function getGridView() {
392
		$status = $this->config->getUserValue($this->userSession->getUser()->getUID(), 'files', 'show_grid', '0') === '1';
393
		return new JSONResponse(['gridview' => $status]);
394
	}
395
396
	/**
397
	 * Get sorting-order for custom sorting
398
	 *
399
	 * @NoAdminRequired
400
	 *
401
	 * @param string $folderpath
402
	 * @return string
403
	 * @throws \OCP\Files\NotFoundException
404
	 */
405
	public function getNodeType($folderpath) {
406
		$node = $this->userFolder->get($folderpath);
407
		return $node->getType();
408
	}
409
	
410
	/**
411
	 * @NoAdminRequired
412
	 * @NoCSRFRequired
413
	 */
414
	public function serviceWorker(): StreamResponse {
415
		$response = new StreamResponse(__DIR__ . '/../../../../dist/preview-service-worker.js');
416
		$response->setHeaders([
417
			'Content-Type' => 'application/javascript',
418
			'Service-Worker-Allowed' => '/'
419
		]);
420
		$policy = new ContentSecurityPolicy();
421
		$policy->addAllowedWorkerSrcDomain("'self'");
422
		$policy->addAllowedScriptDomain("'self'");
423
		$policy->addAllowedConnectDomain("'self'");
424
		$response->setContentSecurityPolicy($policy);
425
		return $response;
426
	}
427
}
428