Completed
Pull Request — master (#125)
by Joas
04:07
created

APIv2::get()   C

Complexity

Conditions 16
Paths 11

Size

Total Lines 65
Code Lines 42

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 40
CRAP Score 16

Importance

Changes 0
Metric Value
dl 0
loc 65
ccs 40
cts 40
cp 1
rs 5.9197
c 0
b 0
f 0
cc 16
eloc 42
nc 11
nop 7
crap 16

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Joas Schilling <[email protected]>
6
 *
7
 * @license AGPL-3.0
8
 *
9
 * This code is free software: you can redistribute it and/or modify
10
 * it under the terms of the GNU Affero General Public License, version 3,
11
 * as published by the Free Software Foundation.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
 * GNU Affero General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Affero General Public License, version 3,
19
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
20
 *
21
 */
22
23
namespace OCA\Activity\Controller;
24
25
26
use OC\Files\View;
27
use OCA\Activity\Data;
28
use OCA\Activity\Exception\InvalidFilterException;
29
use OCA\Activity\GroupHelper;
30
use OCA\Activity\UserSettings;
31
use OCA\Activity\ViewInfoCache;
32
use OCP\AppFramework\Http;
33
use OCP\AppFramework\Http\DataResponse;
34
use OCP\AppFramework\OCSController;
35
use OCP\Files\FileInfo;
36
use OCP\Files\IMimeTypeDetector;
37
use OCP\IPreview;
38
use OCP\IRequest;
39
use OCP\IURLGenerator;
40
use OCP\IUser;
41
use OCP\IUserSession;
42
43
class APIv2 extends OCSController {
44
45
	/** @var string */
46
	protected $filter;
47
48
	/** @var int */
49
	protected $since;
50
51
	/** @var int */
52
	protected $limit;
53
54
	/** @var string */
55
	protected $sort;
56
57
	/** @var string */
58
	protected $objectType;
59
60
	/** @var int */
61
	protected $objectId;
62
63
	/** @var string */
64
	protected $user;
65
66
	/** @var bool */
67
	protected $loadPreviews;
68
69
70
	/** @var Data */
71
	protected $data;
72
73
	/** @var GroupHelper */
74
	protected $helper;
75
76
	/** @var UserSettings */
77
	protected $settings;
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 string $appName
101
	 * @param IRequest $request
102
	 * @param Data $data
103
	 * @param GroupHelper $helper
104
	 * @param UserSettings $settings
105
	 * @param IURLGenerator $urlGenerator
106
	 * @param IUserSession $userSession
107
	 * @param IPreview $preview
108
	 * @param IMimeTypeDetector $mimeTypeDetector
109
	 * @param View $view
110
	 * @param ViewInfoCache $infoCache
111
	 */
112 65
	public function __construct($appName,
113
								IRequest $request,
114
								Data $data,
115
								GroupHelper $helper,
116
								UserSettings $settings,
117
								IURLGenerator $urlGenerator,
118
								IUserSession $userSession,
119
								IPreview $preview,
120
								IMimeTypeDetector $mimeTypeDetector,
121
								View $view,
122
								ViewInfoCache $infoCache) {
123 65
		parent::__construct($appName, $request);
124 65
		$this->data = $data;
125 65
		$this->helper = $helper;
126 65
		$this->settings = $settings;
127 65
		$this->urlGenerator = $urlGenerator;
128 65
		$this->userSession = $userSession;
129 65
		$this->preview = $preview;
130 65
		$this->mimeTypeDetector = $mimeTypeDetector;
131 65
		$this->view = $view;
132 65
		$this->infoCache = $infoCache;
133 65
	}
134
135
	/**
136
	 * @param string $filter
137
	 * @param int $since
138
	 * @param int $limit
139
	 * @param bool $previews
140
	 * @param string $objectType
141
	 * @param int $objectId
142
	 * @param string $sort
143
	 * @throws InvalidFilterException when the filter is invalid
144
	 * @throws \OutOfBoundsException when no user is given
145
	 */
146 22
	protected function validateParameters($filter, $since, $limit, $previews, $objectType, $objectId, $sort) {
147 22
		$this->filter = is_string($filter) ? $filter : 'all';
148 22
		if ($this->filter !== $this->data->validateFilter($this->filter)) {
149 2
			throw new InvalidFilterException();
150
		}
151 20
		$this->since = (int) $since;
152 20
		$this->limit = (int) $limit;
153 20
		$this->loadPreviews = (bool) $previews;
154 20
		$this->objectType = (string) $objectType;
155 20
		$this->objectId = (int) $objectId;
156 20
		$this->sort = in_array($sort, ['asc', 'desc'], true) ? $sort : 'desc';
157
158 20
		if (($this->objectType !== '' && $this->objectId === 0) || ($this->objectType === '' && $this->objectId !== 0)) {
159
			// Only allowed together
160 2
			$this->objectType = '';
161 2
			$this->objectId = 0;
162
		}
163
164 20
		$user = $this->userSession->getUser();
165 20
		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...
166 19
			$this->user = $user->getUID();
167
		} else {
168
			// No user logged in
169 1
			throw new \OutOfBoundsException();
170
		}
171 19
	}
172
173
	/**
174
	 * @NoAdminRequired
175
	 *
176
	 * @param int $since
177
	 * @param int $limit
178
	 * @param bool $previews
179
	 * @param string $object_type
180
	 * @param int $object_id
181
	 * @param string $sort
182
	 * @return DataResponse
183
	 */
184 2
	public function getDefault($since = 0, $limit = 50, $previews = false, $object_type = '', $object_id = 0, $sort = 'desc') {
185 2
		return $this->get('all', $since, $limit, $previews, $object_type, $object_id, $sort);
186
	}
187
188
	/**
189
	 * @NoAdminRequired
190
	 *
191
	 * @param string $filter
192
	 * @param int $since
193
	 * @param int $limit
194
	 * @param bool $previews
195
	 * @param string $object_type
196
	 * @param int $object_id
197
	 * @param string $sort
198
	 * @return DataResponse
199
	 */
200 2
	public function getFilter($filter, $since = 0, $limit = 50, $previews = false, $object_type = '', $object_id = 0, $sort = 'desc') {
201 2
		return $this->get($filter, $since, $limit, $previews, $object_type, $object_id, $sort);
202
	}
203
204
	/**
205
	 * @param string $filter
206
	 * @param int $since
207
	 * @param int $limit
208
	 * @param bool $previews
209
	 * @param string $filterObjectType
210
	 * @param int $filterObjectId
211
	 * @param string $sort
212
	 * @return DataResponse
213
	 */
214 11
	protected function get($filter, $since, $limit, $previews, $filterObjectType, $filterObjectId, $sort) {
215
		try {
216 11
			$this->validateParameters($filter, $since, $limit, $previews, $filterObjectType, $filterObjectId, $sort);
217 2
		} catch (InvalidFilterException $e) {
218 1
			return new DataResponse(null, Http::STATUS_NOT_FOUND);
219 1
		} catch (\OutOfBoundsException $e) {
220 1
			return new DataResponse(null, Http::STATUS_FORBIDDEN);
221
		}
222
223
		try {
224 9
			$response = $this->data->get(
225 9
				$this->helper,
226 9
				$this->settings,
227 9
				$this->user,
228
229 9
				$this->since,
230 9
				$this->limit,
231 9
				$this->sort,
232
233 9
				$this->filter,
234 9
				$this->objectType,
235 9
				$this->objectId
236
			);
237 2
		} catch (\OutOfBoundsException $e) {
238
			// Invalid since argument
239 1
			return new DataResponse(null, Http::STATUS_FORBIDDEN);
240 1
		} catch (\BadMethodCallException $e) {
241
			// No activity settings enabled
242 1
			return new DataResponse(null, Http::STATUS_NO_CONTENT);
243
		}
244
245 7
		$headers = $this->generateHeaders($response['headers'], $response['has_more'], $response['data']);
246 7
		if (empty($response['data']) || $this->request->getHeader('If-None-Match') === $headers['ETag']) {
247 3
			return new DataResponse([], Http::STATUS_NOT_MODIFIED, $headers);
248
		}
249
250 4
		$preparedActivities = [];
251 4
		foreach ($response['data'] as $activity) {
252 4
			$activity['datetime'] = date(\DateTime::ATOM, $activity['timestamp']);
253 4
			unset($activity['timestamp']);
254
255 4
			if ($this->loadPreviews) {
256 3
				$activity['previews'] = [];
257 3
				if ($activity['object_type'] === 'files') {
258 2
					if (!empty($activity['objects']) && is_array($activity['objects'])) {
259 1
						foreach ($activity['objects'] as $objectId => $objectName) {
260 1
							if (((int) $objectId) === 0 || $objectName === '') {
261
								// No file, no preview
262 1
								continue;
263
							}
264
265 1
							$activity['previews'][] = $this->getPreview($activity['affecteduser'], (int) $objectId, $objectName);
266
						}
267 1
					} else if ($activity['object_id']) {
268 1
						$activity['previews'][] = $this->getPreview($activity['affecteduser'], (int) $activity['object_id'], $activity['object_name']);
269
					}
270
				}
271
			}
272
273 4
			unset($activity['affecteduser']);
274 4
			$preparedActivities[] = $activity;
275
		}
276
277 4
		return new DataResponse($preparedActivities, Http::STATUS_OK, $headers);
278
	}
279
280
	/**
281
	 * @param array $headers
282
	 * @param bool $hasMoreActivities
283
	 * @param array $data
284
	 * @return array
285
	 */
286 6
	protected function generateHeaders(array $headers, $hasMoreActivities, array $data) {
287 6
		if ($hasMoreActivities && isset($headers['X-Activity-Last-Given'])) {
288
			// Set the "Link" header for the next page
289
			$nextPageParameters = [
290 3
				'since' => $headers['X-Activity-Last-Given'],
291 3
				'limit' => $this->limit,
292 3
				'sort' => $this->sort,
293
			];
294 3
			if ($this->objectType && $this->objectId) {
295 1
				$nextPageParameters['object_type'] = $this->objectType;
296 1
				$nextPageParameters['object_id'] = $this->objectId;
297
			}
298 3
			if ($this->request->getParam('format') !== null) {
299 1
				$nextPageParameters['format'] = $this->request->getParam('format');
300
			}
301
302 3
			$nextPage = $this->request->getServerProtocol(); # http
303 3
			$nextPage .= '://' . $this->request->getServerHost(); # localhost
304 3
			$nextPage .= $this->request->getScriptName(); # /ocs/v2.php
305 3
			$nextPage .= $this->request->getPathInfo(); # /apps/activity/api/v2/activity
306 3
			$nextPage .= '?' . http_build_query($nextPageParameters);
307 3
			$headers['Link'] = '<' . $nextPage . '>; rel="next"';
308
		}
309
310 6
		$ids = [];
311 6
		foreach ($data as $activity) {
312 2
			$ids[] = $activity['activity_id'];
313
		}
314 6
		$headers['ETag'] = md5(json_encode($ids));
315
316 6
		return $headers;
317
	}
318
319
	/**
320
	 * @param string $owner
321
	 * @param int $fileId
322
	 * @param string $filePath
323
	 * @return array
324
	 */
325 7
	protected function getPreview($owner, $fileId, $filePath) {
326 7
		$info = $this->infoCache->getInfoById($owner, $fileId, $filePath);
327
328 7
		if (!$info['exists'] || $info['view'] !== '') {
329 3
			return $this->getPreviewFromPath($filePath, $info);
330
		}
331
332
		$preview = [
333 4
			'link'			=> $this->getPreviewLink($info['path'], $info['is_dir'], $info['view']),
334 4
			'source'		=> '',
335
			'isMimeTypeIcon' => true,
336
		];
337
338
		// show a preview image if the file still exists
339 4
		if ($info['is_dir']) {
340 1
			$preview['source'] = $this->getPreviewPathFromMimeType('dir');
341
		} else {
342 3
			$this->view->chroot('/' . $owner . '/files');
343 3
			$fileInfo = $this->view->getFileInfo($info['path']);
344 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...
345 1
				$pathPreview = $this->getPreviewFromPath($filePath, $info);
346 1
				$preview['source'] = $pathPreview['source'];
347 2
			} else if ($this->preview->isAvailable($fileInfo)) {
348 1
				$preview['isMimeTypeIcon'] = false;
349 1
				$preview['source'] = $this->urlGenerator->linkToRouteAbsolute('core.Preview.getPreview', [
350 1
					'file' => $info['path'],
351 1
					'c' => $this->view->getETag($info['path']),
352 1
					'x' => 150,
353 1
					'y' => 150,
354
				]);
355
			} else {
356 1
				$preview['source'] = $this->getPreviewPathFromMimeType($fileInfo->getMimetype());
357
			}
358
		}
359
360 4
		return $preview;
361
	}
362
363
	/**
364
	 * @param string $filePath
365
	 * @param array $info
366
	 * @return array
367
	 */
368 3
	protected function getPreviewFromPath($filePath, $info) {
369 3
		$mimeType = $this->mimeTypeDetector->detectPath($filePath);
370
		$preview = [
371 3
			'link'			=> $this->getPreviewLink($info['path'], $info['is_dir'], $info['view']),
372 3
			'source'		=> $this->getPreviewPathFromMimeType($mimeType),
373
			'isMimeTypeIcon' => true,
374
		];
375
376 3
		return $preview;
377
	}
378
379
	/**
380
	 * @param string $mimeType
381
	 * @return string
382
	 */
383 3
	protected function getPreviewPathFromMimeType($mimeType) {
384 3
		$mimeTypeIcon = $this->mimeTypeDetector->mimeTypeIcon($mimeType);
385 3
		if (substr($mimeTypeIcon, -4) === '.png') {
386 1
			$mimeTypeIcon = substr($mimeTypeIcon, 0, -4) . '.svg';
387
		}
388
389 3
		return $this->urlGenerator->getAbsoluteURL($mimeTypeIcon);
390
	}
391
392
	/**
393
	 * @param string $path
394
	 * @param bool $isDir
395
	 * @param string $view
396
	 * @return string
397
	 */
398 6
	protected function getPreviewLink($path, $isDir, $view) {
399
		$params = [
400 6
			'dir' => $path,
401
		];
402 6
		if (!$isDir) {
403 3
			$params['dir'] = (substr_count($path, '/') === 1) ? '/' : dirname($path);
404 3
			$params['scrollto'] = basename($path);
405
		}
406 6
		if ($view !== '') {
407 2
			$params['view'] = $view;
408
		}
409 6
		return $this->urlGenerator->linkToRouteAbsolute('files.view.index', $params);
410
	}
411
}
412