Passed
Push — master ( 8eb950...2e6e15 )
by John
17:12 queued 12s
created

ApiController::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 17
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

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

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 OCP\AppFramework\Controller;
44
use OCP\AppFramework\Http;
45
use OCP\AppFramework\Http\ContentSecurityPolicy;
46
use OCP\AppFramework\Http\DataResponse;
47
use OCP\AppFramework\Http\FileDisplayResponse;
48
use OCP\AppFramework\Http\JSONResponse;
49
use OCP\AppFramework\Http\Response;
50
use OCP\AppFramework\Http\StreamResponse;
51
use OCP\Files\File;
52
use OCP\Files\Folder;
53
use OCP\Files\NotFoundException;
54
use OCP\IConfig;
55
use OCP\IPreview;
56
use OCP\IRequest;
57
use OCP\IUserSession;
58
use OCP\Share\IManager;
59
use OCP\Share\IShare;
60
61
/**
62
 * Class ApiController
63
 *
64
 * @package OCA\Files\Controller
65
 */
66
class ApiController extends Controller {
67
	private TagService $tagService;
68
	private IManager $shareManager;
69
	private IPreview $previewManager;
70
	private IUserSession $userSession;
71
	private IConfig $config;
72
	private Folder $userFolder;
73
	private UserConfig $userConfig;
74
75
	/**
76
	 * @param string $appName
77
	 * @param IRequest $request
78
	 * @param IUserSession $userSession
79
	 * @param TagService $tagService
80
	 * @param IPreview $previewManager
81
	 * @param IManager $shareManager
82
	 * @param IConfig $config
83
	 * @param Folder $userFolder
84
	 */
85
	public function __construct($appName,
86
								IRequest $request,
87
								IUserSession $userSession,
88
								TagService $tagService,
89
								IPreview $previewManager,
90
								IManager $shareManager,
91
								IConfig $config,
92
								Folder $userFolder,
93
								UserConfig $userConfig) {
94
		parent::__construct($appName, $request);
95
		$this->userSession = $userSession;
96
		$this->tagService = $tagService;
97
		$this->previewManager = $previewManager;
98
		$this->shareManager = $shareManager;
99
		$this->config = $config;
100
		$this->userFolder = $userFolder;
101
		$this->userConfig = $userConfig;
102
	}
103
104
	/**
105
	 * Gets a thumbnail of the specified file
106
	 *
107
	 * @since API version 1.0
108
	 *
109
	 * @NoAdminRequired
110
	 * @NoCSRFRequired
111
	 * @StrictCookieRequired
112
	 *
113
	 * @param int $x
114
	 * @param int $y
115
	 * @param string $file URL-encoded filename
116
	 * @return DataResponse|FileDisplayResponse
117
	 */
118
	public function getThumbnail($x, $y, $file) {
119
		if ($x < 1 || $y < 1) {
120
			return new DataResponse(['message' => 'Requested size must be numeric and a positive value.'], Http::STATUS_BAD_REQUEST);
121
		}
122
123
		try {
124
			$file = $this->userFolder->get($file);
125
			if ($file instanceof Folder) {
126
				throw new NotFoundException();
127
			}
128
129
			/** @var File $file */
130
			$preview = $this->previewManager->getPreview($file, $x, $y, true);
131
132
			return new FileDisplayResponse($preview, Http::STATUS_OK, ['Content-Type' => $preview->getMimeType()]);
133
		} catch (NotFoundException $e) {
134
			return new DataResponse(['message' => 'File not found.'], Http::STATUS_NOT_FOUND);
135
		} catch (\Exception $e) {
136
			return new DataResponse([], Http::STATUS_BAD_REQUEST);
137
		}
138
	}
139
140
	/**
141
	 * Updates the info of the specified file path
142
	 * The passed tags are absolute, which means they will
143
	 * replace the actual tag selection.
144
	 *
145
	 * @NoAdminRequired
146
	 *
147
	 * @param string $path path
148
	 * @param array|string $tags array of tags
149
	 * @return DataResponse
150
	 */
151
	public function updateFileTags($path, $tags = null) {
152
		$result = [];
153
		// if tags specified or empty array, update tags
154
		if (!is_null($tags)) {
155
			try {
156
				$this->tagService->updateFileTags($path, $tags);
157
			} catch (\OCP\Files\NotFoundException $e) {
158
				return new DataResponse([
159
					'message' => $e->getMessage()
160
				], Http::STATUS_NOT_FOUND);
161
			} catch (\OCP\Files\StorageNotAvailableException $e) {
162
				return new DataResponse([
163
					'message' => $e->getMessage()
164
				], Http::STATUS_SERVICE_UNAVAILABLE);
165
			} catch (\Exception $e) {
166
				return new DataResponse([
167
					'message' => $e->getMessage()
168
				], Http::STATUS_NOT_FOUND);
169
			}
170
			$result['tags'] = $tags;
171
		}
172
		return new DataResponse($result);
173
	}
174
175
	/**
176
	 * @param \OCP\Files\Node[] $nodes
177
	 * @return array
178
	 */
179
	private function formatNodes(array $nodes) {
180
		$shareTypesForNodes = $this->getShareTypesForNodes($nodes);
181
		return array_values(array_map(function (Node $node) use ($shareTypesForNodes) {
182
			$shareTypes = $shareTypesForNodes[$node->getId()] ?? [];
183
			$file = \OCA\Files\Helper::formatFileInfo($node->getFileInfo());
184
			$file['hasPreview'] = $this->previewManager->isAvailable($node);
185
			$parts = explode('/', dirname($node->getPath()), 4);
186
			if (isset($parts[3])) {
187
				$file['path'] = '/' . $parts[3];
188
			} else {
189
				$file['path'] = '/';
190
			}
191
			if (!empty($shareTypes)) {
192
				$file['shareTypes'] = $shareTypes;
193
			}
194
			return $file;
195
		}, $nodes));
196
	}
197
198
	/**
199
	 * Get the share types for each node
200
	 *
201
	 * @param \OCP\Files\Node[] $nodes
202
	 * @return array<int, int[]> list of share types for each fileid
203
	 */
204
	private function getShareTypesForNodes(array $nodes): array {
205
		$userId = $this->userSession->getUser()->getUID();
206
		$requestedShareTypes = [
207
			IShare::TYPE_USER,
208
			IShare::TYPE_GROUP,
209
			IShare::TYPE_LINK,
210
			IShare::TYPE_REMOTE,
211
			IShare::TYPE_EMAIL,
212
			IShare::TYPE_ROOM,
213
			IShare::TYPE_DECK,
214
			IShare::TYPE_SCIENCEMESH,
215
		];
216
		$shareTypes = [];
217
218
		$nodeIds = array_map(function (Node $node) {
219
			return $node->getId();
220
		}, $nodes);
221
222
		foreach ($requestedShareTypes as $shareType) {
223
			$nodesLeft = array_combine($nodeIds, array_fill(0, count($nodeIds), true));
224
			$offset = 0;
225
226
			// fetch shares until we've either found shares for all nodes or there are no more shares left
227
			while (count($nodesLeft) > 0) {
228
				$shares = $this->shareManager->getSharesBy($userId, $shareType, null, false, 100, $offset);
229
				foreach ($shares as $share) {
230
					$fileId = $share->getNodeId();
231
					if (isset($nodesLeft[$fileId])) {
232
						if (!isset($shareTypes[$fileId])) {
233
							$shareTypes[$fileId] = [];
234
						}
235
						$shareTypes[$fileId][] = $shareType;
236
						unset($nodesLeft[$fileId]);
237
					}
238
				}
239
240
				if (count($shares) < 100) {
241
					break;
242
				} else {
243
					$offset += count($shares);
244
				}
245
			}
246
		}
247
		return $shareTypes;
248
	}
249
250
	/**
251
	 * Returns a list of recently modified files.
252
	 *
253
	 * @NoAdminRequired
254
	 *
255
	 * @return DataResponse
256
	 */
257
	public function getRecentFiles() {
258
		$nodes = $this->userFolder->getRecent(100);
259
		$files = $this->formatNodes($nodes);
260
		return new DataResponse(['files' => $files]);
261
	}
262
263
264
	/**
265
	 * Returns the current logged-in user's storage stats.
266
	 *
267
	 * @NoAdminRequired
268
	 *
269
	 * @param ?string $dir the directory to get the storage stats from
270
	 * @return JSONResponse
271
	 */
272
	public function getStorageStats($dir = '/'): JSONResponse {
273
		$storageInfo = \OC_Helper::getStorageInfo($dir ?: '/');
274
		return new JSONResponse(['message' => 'ok', 'data' => $storageInfo]);
275
	}
276
277
	/**
278
	 * Change the default sort mode
279
	 *
280
	 * @NoAdminRequired
281
	 *
282
	 * @param string $mode
283
	 * @param string $direction
284
	 * @return JSONResponse
285
	 * @throws \OCP\PreConditionNotMetException
286
	 */
287
	public function updateFileSorting($mode, string $direction = 'asc', string $view = 'files'): JSONResponse {
288
		$allowedDirection = ['asc', 'desc'];
289
		if (!in_array($direction, $allowedDirection)) {
290
			return  new JSONResponse(['message' => 'Invalid direction parameter'], Http::STATUS_UNPROCESSABLE_ENTITY);
291
		}
292
293
		$userId = $this->userSession->getUser()->getUID();
294
295
		$sortingJson = $this->config->getUserValue($userId, 'files', 'files_sorting_configs', '{}');
296
		$sortingConfig = json_decode($sortingJson, true) ?: [];
297
		$sortingConfig[$view] = [
298
			'mode' => $mode,
299
			'direction' => $direction,
300
		];
301
302
		$this->config->setUserValue($userId, 'files', 'files_sorting_configs', json_encode($sortingConfig));
303
		return new JSONResponse([
304
			'message' => 'ok',
305
			'data' => $sortingConfig,
306
		]);
307
	}
308
309
	/**
310
	 * Toggle default files user config
311
	 *
312
	 * @NoAdminRequired
313
	 *
314
	 * @param string $key
315
	 * @param string|bool $value
316
	 * @return JSONResponse
317
	 */
318
	public function setConfig(string $key, $value): JSONResponse {
319
		try {
320
			$this->userConfig->setConfig($key, (string)$value);
321
		} catch (\InvalidArgumentException $e) {
322
			return new JSONResponse(['message' => $e->getMessage()], Http::STATUS_BAD_REQUEST);
323
		}
324
325
		return new JSONResponse(['message' => 'ok', 'data' => ['key' => $key, 'value' => $value]]);
326
	}
327
328
329
	/**
330
	 * Get the user config
331
	 *
332
	 * @NoAdminRequired
333
	 *
334
	 * @return JSONResponse
335
	 */
336
	public function getConfigs(): JSONResponse {
337
		return new JSONResponse(['message' => 'ok', 'data' => $this->userConfig->getConfigs()]);
338
	}
339
340
	/**
341
	 * Toggle default for showing/hiding hidden files
342
	 *
343
	 * @NoAdminRequired
344
	 *
345
	 * @param bool $value
346
	 * @return Response
347
	 * @throws \OCP\PreConditionNotMetException
348
	 */
349
	public function showHiddenFiles(bool $value): Response {
350
		$this->config->setUserValue($this->userSession->getUser()->getUID(), 'files', 'show_hidden', $value ? '1' : '0');
351
		return new Response();
352
	}
353
354
	/**
355
	 * Toggle default for cropping preview images
356
	 *
357
	 * @NoAdminRequired
358
	 *
359
	 * @param bool $value
360
	 * @return Response
361
	 * @throws \OCP\PreConditionNotMetException
362
	 */
363
	public function cropImagePreviews(bool $value): Response {
364
		$this->config->setUserValue($this->userSession->getUser()->getUID(), 'files', 'crop_image_previews', $value ? '1' : '0');
365
		return new Response();
366
	}
367
368
	/**
369
	 * Toggle default for files grid view
370
	 *
371
	 * @NoAdminRequired
372
	 *
373
	 * @param bool $show
374
	 * @return Response
375
	 * @throws \OCP\PreConditionNotMetException
376
	 */
377
	public function showGridView(bool $show): Response {
378
		$this->config->setUserValue($this->userSession->getUser()->getUID(), 'files', 'show_grid', $show ? '1' : '0');
379
		return new Response();
380
	}
381
382
	/**
383
	 * Get default settings for the grid view
384
	 *
385
	 * @NoAdminRequired
386
	 */
387
	public function getGridView() {
388
		$status = $this->config->getUserValue($this->userSession->getUser()->getUID(), 'files', 'show_grid', '0') === '1';
389
		return new JSONResponse(['gridview' => $status]);
390
	}
391
392
	/**
393
	 * Toggle default for showing/hiding xxx folder
394
	 *
395
	 * @NoAdminRequired
396
	 *
397
	 * @param int $show
398
	 * @param string $key the key of the folder
399
	 *
400
	 * @return Response
401
	 * @throws \OCP\PreConditionNotMetException
402
	 */
403
	public function toggleShowFolder(int $show, string $key): Response {
404
		if ($show !== 0 && $show !== 1) {
405
			return new DataResponse([
406
				'message' => 'Invalid show value. Only 0 and 1 are allowed.'
407
			], Http::STATUS_BAD_REQUEST);
408
		}
409
410
		$userId = $this->userSession->getUser()->getUID();
411
412
		// Set the new value and return it
413
		// Using a prefix prevents the user from setting arbitrary keys
414
		$this->config->setUserValue($userId, 'files', 'show_' . $key, (string)$show);
415
		return new JSONResponse([$key => $show]);
416
	}
417
418
	/**
419
	 * Get sorting-order for custom sorting
420
	 *
421
	 * @NoAdminRequired
422
	 *
423
	 * @param string $folderpath
424
	 * @return string
425
	 * @throws \OCP\Files\NotFoundException
426
	 */
427
	public function getNodeType($folderpath) {
428
		$node = $this->userFolder->get($folderpath);
429
		return $node->getType();
430
	}
431
	
432
	/**
433
	 * @NoAdminRequired
434
	 * @NoCSRFRequired
435
	 */
436
	public function serviceWorker(): StreamResponse {
437
		$response = new StreamResponse(__DIR__ . '/../../../../dist/preview-service-worker.js');
438
		$response->setHeaders([
439
			'Content-Type' => 'application/javascript',
440
			'Service-Worker-Allowed' => '/'
441
		]);
442
		$policy = new ContentSecurityPolicy();
443
		$policy->addAllowedWorkerSrcDomain("'self'");
444
		$policy->addAllowedScriptDomain("'self'");
445
		$policy->addAllowedConnectDomain("'self'");
446
		$response->setContentSecurityPolicy($policy);
447
		return $response;
448
	}
449
}
450