Completed
Push — master ( cdcc19...a26468 )
by
unknown
02:40
created

OCSEndPoint::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 21
ccs 12
cts 12
cp 1
rs 9.584
c 0
b 0
f 0
cc 1
nc 1
nop 10
crap 1

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
 * @author Joas Schilling <[email protected]>
4
 *
5
 * @copyright Copyright (c) 2016, ownCloud, Inc.
6
 * @license AGPL-3.0
7
 *
8
 * This code is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Affero General Public License, version 3,
10
 * as published by the Free Software Foundation.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
 * GNU Affero General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Affero General Public License, version 3,
18
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
19
 *
20
 */
21
22
namespace OCA\Activity\Controller;
23
24
25
use OC\Files\View;
26
use OCA\Activity\Data;
27
use OCA\Activity\Exception\InvalidFilterException;
28
use OCA\Activity\GroupHelper;
29
use OCA\Activity\UserSettings;
30
use OCA\Activity\ViewInfoCache;
31
use OCP\AppFramework\Http;
32
use OCP\Files\FileInfo;
33
use OCP\Files\IMimeTypeDetector;
34
use OCP\IPreview;
35
use OCP\IRequest;
36
use OCP\IURLGenerator;
37
use OCP\IUser;
38
use OCP\IUserSession;
39
40
class OCSEndPoint {
41
42
	/** @var string */
43
	protected $filter;
44
45
	/** @var int */
46
	protected $since;
47
48
	/** @var int */
49
	protected $limit;
50
51
	/** @var string */
52
	protected $sort;
53
54
	/** @var string */
55
	protected $objectType;
56
57
	/** @var int */
58
	protected $objectId;
59
60
	/** @var string */
61
	protected $user;
62
63
	/** @var bool */
64
	protected $loadPreviews;
65
66
67
	/** @var Data */
68
	protected $data;
69
70
	/** @var GroupHelper */
71
	protected $helper;
72
73
	/** @var UserSettings */
74
	protected $settings;
75
76
	/** @var IRequest */
77
	protected $request;
78
79
	/** @var IURLGenerator */
80
	protected $urlGenerator;
81
82
	/** @var IUserSession */
83
	protected $userSession;
84
85
	/** @var IPreview */
86
	protected $preview;
87
88
	/** @var IMimeTypeDetector */
89
	protected $mimeTypeDetector;
90
91
	/** @var View */
92
	protected $view;
93
94
	/** @var ViewInfoCache */
95
	protected $infoCache;
96
97
	/**
98
	 * OCSEndPoint constructor.
99
	 *
100
	 * @param Data $data
101
	 * @param GroupHelper $helper
102
	 * @param UserSettings $settings
103
	 * @param IRequest $request
104
	 * @param IURLGenerator $urlGenerator
105
	 * @param IUserSession $userSession
106
	 * @param IPreview $preview
107
	 * @param IMimeTypeDetector $mimeTypeDetector
108
	 * @param View $view
109
	 * @param ViewInfoCache $infoCache
110
	 */
111 61
	public function __construct(Data $data,
112
								GroupHelper $helper,
113
								UserSettings $settings,
114
								IRequest $request,
115
								IURLGenerator $urlGenerator,
116
								IUserSession $userSession,
117
								IPreview $preview,
118
								IMimeTypeDetector $mimeTypeDetector,
119
								View $view,
120
								ViewInfoCache $infoCache) {
121 61
		$this->data = $data;
122 61
		$this->helper = $helper;
123 61
		$this->settings = $settings;
124 61
		$this->request = $request;
125 61
		$this->urlGenerator = $urlGenerator;
126 61
		$this->userSession = $userSession;
127 61
		$this->preview = $preview;
128 61
		$this->mimeTypeDetector = $mimeTypeDetector;
129 61
		$this->view = $view;
130 61
		$this->infoCache = $infoCache;
131 61
	}
132
133
	/**
134
	 * @param array $parameters
135
	 * @throws InvalidFilterException when the filter is invalid
136
	 * @throws \OutOfBoundsException when no user is given
137
	 */
138 23
	protected function readParameters(array $parameters) {
139 23
		$this->filter = isset($parameters['filter']) && is_string($parameters['filter']) ? (string) $parameters['filter'] : 'all';
140 23
		if ($this->filter !== $this->data->validateFilter($this->filter)) {
141 2
			throw new InvalidFilterException();
142
		}
143 21
		$this->since = (int) $this->request->getParam('since', 0);
144 21
		$this->limit = (int) $this->request->getParam('limit', 50);
145 21
		$this->loadPreviews = $this->request->getParam('previews', 'false') === 'true';
146 21
		$this->objectType = (string) $this->request->getParam('object_type', '');
147 21
		$this->objectId = (int) $this->request->getParam('object_id', 0);
148 21
		$this->sort = (string) $this->request->getParam('sort', '');
149 21
		$this->sort = in_array($this->sort, ['asc', 'desc']) ? $this->sort : 'desc';
150
151 21
		if ($this->objectType !== '' && $this->objectId === 0 || $this->objectType === '' && $this->objectId !== 0) {
152
			// Only allowed together
153 2
			$this->objectType = '';
154 2
			$this->objectId = 0;
155
		}
156
157 21
		$user = $this->userSession->getUser();
158 21
		if ($user instanceof IUser) {
0 ignored issues
show
Bug introduced by
The class OCP\IUser does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
159 20
			$this->user = $user->getUID();
160
		} else {
161
			// No user logged in
162 1
			throw new \OutOfBoundsException();
163
		}
164 20
	}
165
166
	/**
167
	 * @param array $parameters
168
	 * @return \OC_OCS_Result
169
	 */
170 3
	public function getDefault(array $parameters) {
171 3
		return $this->get(array_merge($parameters, [
172 3
			'filter' => 'all',
173
		]));
174
	}
175
176
	/**
177
	 * @param array $parameters
178
	 * @return \OC_OCS_Result
179
	 */
180 3
	public function getFilter(array $parameters) {
181 3
		return $this->get($parameters);
182
	}
183
184
	/**
185
	 * @param array $parameters
186
	 * @return \OC_OCS_Result
187
	 */
188 9
	protected function get(array $parameters) {
189
		try {
190 9
			$this->readParameters($parameters);
191 2
		} catch (InvalidFilterException $e) {
192 1
			return new \OC_OCS_Result(null, Http::STATUS_NOT_FOUND);
193 1
		} catch (\OutOfBoundsException $e) {
194 1
			return new \OC_OCS_Result(null, Http::STATUS_FORBIDDEN);
195
		}
196
197
		try {
198 7
			$response = $this->data->get(
199 7
				$this->helper,
200 7
				$this->settings,
201 7
				$this->user,
202
203 7
				$this->since,
204 7
				$this->limit,
205 7
				$this->sort,
206
207 7
				$this->filter,
208 7
				$this->objectType,
209 7
				$this->objectId
210
			);
211 2
		} catch (\OutOfBoundsException $e) {
212
			// Invalid since argument
213 1
			return new \OC_OCS_Result(null, Http::STATUS_FORBIDDEN);
214 1
		} catch (\BadMethodCallException $e) {
215
			// No activity settings enabled
216 1
			return new \OC_OCS_Result(null, Http::STATUS_NO_CONTENT);
217
		}
218
219 5
		$headers = $this->generateHeaders($response['headers'], $response['has_more']);
220 5
		if (empty($response['data'])) {
221 1
			return new \OC_OCS_Result([], Http::STATUS_NOT_MODIFIED, null, $headers);
222
		}
223
224 4
		$preparedActivities = [];
225 4
		foreach ($response['data'] as $activity) {
226 4
			$activity['datetime'] = date('c', $activity['timestamp']);
227 4
			unset($activity['timestamp']);
228
229 4
			if ($this->loadPreviews) {
230 3
				$activity['previews'] = [];
231 3
				if ($activity['object_type'] === 'files' && !empty($activity['files'])) {
232 1
					foreach ($activity['files'] as $objectId => $objectName) {
0 ignored issues
show
Bug introduced by
The expression $activity['files'] of type string|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
233 1
						if (((int) $objectId) === 0 || $objectName === '') {
234
							// No file, no preview
235 1
							continue;
236
						}
237
238 1
						$activity['previews'][] = $this->getPreview($activity['affecteduser'], (int) $objectId, $objectName);
239
					}
240 2
				} else if ($activity['object_type'] === 'files' && $activity['object_id']) {
241 1
					$activity['previews'][] = $this->getPreview($activity['affecteduser'], (int) $activity['object_id'], $activity['object_name']);
242
				}
243
			}
244
245 4
			$preparedActivities[] = $activity;
246
		}
247
248 4
		return new \OC_OCS_Result($preparedActivities, 100, null, $headers);
249
	}
250
251
	/**
252
	 * @param array $headers
253
	 * @param bool $hasMoreActivities
254
	 * @return array
255
	 */
256 4
	protected function generateHeaders(array $headers, $hasMoreActivities) {
257 4
		if ($hasMoreActivities && isset($headers['X-Activity-Last-Given'])) {
258
			// Set the "Link" header for the next page
259
			$nextPageParameters = [
260 3
				'since' => $headers['X-Activity-Last-Given'],
261 3
				'limit' => $this->limit,
262 3
				'sort' => $this->sort,
263
			];
264 3
			if ($this->objectType && $this->objectId) {
265 1
				$nextPageParameters['object_type'] = $this->objectType;
266 1
				$nextPageParameters['object_id'] = $this->objectId;
267
			}
268 3
			if ($this->request->getParam('format') !== null) {
269 1
				$nextPageParameters['format'] = $this->request->getParam('format');
270
			}
271
272 3
			$nextPage = $this->request->getServerProtocol(); # http
273 3
			$nextPage .= '://' . $this->request->getServerHost(); # localhost
274 3
			$nextPage .= $this->request->getScriptName(); # /ocs/v2.php
275 3
			$nextPage .= $this->request->getPathInfo(); # /apps/activity/api/v2/activity
276 3
			$nextPage .= '?' . http_build_query($nextPageParameters);
277 3
			$headers['Link'] = '<' . $nextPage . '>; rel="next"';
278
		}
279
280 4
		return $headers;
281
	}
282
283
	/**
284
	 * @param string $owner
285
	 * @param int $fileId
286
	 * @param string $filePath
287
	 * @return array
288
	 */
289 7
	protected function getPreview($owner, $fileId, $filePath) {
290 7
		$info = $this->infoCache->getInfoById($owner, $fileId, $filePath);
291
292 7
		if (!$info['exists'] || $info['view'] !== '') {
293 3
			return $this->getPreviewFromPath($filePath, $info);
294
		}
295
296
		$preview = [
297 4
			'link'			=> $this->getPreviewLink($info['path'], $info['is_dir'], $info['view']),
298 4
			'source'		=> '',
299
			'isMimeTypeIcon' => true,
300
		];
301
302
		// show a preview image if the file still exists
303 4
		if ($info['is_dir']) {
304 1
			$preview['source'] = $this->getPreviewPathFromMimeType('dir');
305
		} else {
306 3
			$this->view->chroot('/' . $owner . '/files');
307 3
			$fileInfo = $this->view->getFileInfo($info['path']);
308 3
			if (!($fileInfo instanceof FileInfo)) {
0 ignored issues
show
Bug introduced by
The class OCP\Files\FileInfo does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
309 1
				$pathPreview = $this->getPreviewFromPath($filePath, $info);
310 1
				$preview['source'] = $pathPreview['source'];
311 2
			} else if ($this->preview->isAvailable($fileInfo)) {
312 1
				$preview['isMimeTypeIcon'] = false;
313 1
				if (\version_compare(\implode('.', \OCP\Util::getVersion()), '10.0.9', '>=')) {
314 1
					$query = \http_build_query([
315 1
						'preview' => 1,
316 1
						'c' => $this->view->getETag($info['path']),
317 1
						'x' => 150,
318 1
						'y' => 150
319 1
					], '', '&');
320
321 1
					$preview['source'] = $this->urlGenerator->linkTo('', 'remote.php')
322 1
						. '/dav/files/' . \rawurlencode($this->user) . \OCP\Util::encodePath($filePath)
323 1
						. "?$query";
324
				} else {
325
					$preview['source'] = $this->urlGenerator->linkToRoute('core_ajax_preview', [
326
						'file' => $info['path'],
327
						'c' => $this->view->getETag($info['path']),
328
						'x' => 150,
329 1
						'y' => 150,
330
					]);
331
				}
332
333
			} else {
334 1
				$preview['source'] = $this->getPreviewPathFromMimeType($fileInfo->getMimetype());
335
			}
336
		}
337
338 4
		return $preview;
339
	}
340
341
	/**
342
	 * @param string $filePath
343
	 * @param array $info
344
	 * @return array
345
	 */
346 3
	protected function getPreviewFromPath($filePath, $info) {
347 3
		$mimeType = $this->mimeTypeDetector->detectPath($filePath);
348
		$preview = [
349 3
			'link'			=> $this->getPreviewLink($info['path'], $info['is_dir'], $info['view']),
350 3
			'source'		=> $this->getPreviewPathFromMimeType($mimeType),
351
			'isMimeTypeIcon' => true,
352
		];
353
354 3
		return $preview;
355
	}
356
357
	/**
358
	 * @param string $mimeType
359
	 * @return string
360
	 */
361 3
	protected function getPreviewPathFromMimeType($mimeType) {
362 3
		$mimeTypeIcon = $this->mimeTypeDetector->mimeTypeIcon($mimeType);
363 3
		if (substr($mimeTypeIcon, -4) === '.png') {
364 1
			$mimeTypeIcon = substr($mimeTypeIcon, 0, -4) . '.svg';
365
		}
366
367 3
		return $mimeTypeIcon;
368
	}
369
370
	/**
371
	 * @param string $path
372
	 * @param bool $isDir
373
	 * @param string $view
374
	 * @return string
375
	 */
376 6
	protected function getPreviewLink($path, $isDir, $view) {
377
		$params = [
378 6
			'dir' => $path,
379
		];
380 6
		if (!$isDir) {
381 3
			$params['dir'] = (substr_count($path, '/') === 1) ? '/' : dirname($path);
382 3
			$params['scrollto'] = basename($path);
383
		}
384 6
		if ($view !== '') {
385 2
			$params['view'] = $view;
386
		}
387 6
		return $this->urlGenerator->linkToRoute('files.view.index', $params);
388
	}
389
}
390