Completed
Pull Request — master (#125)
by Joas
02:16
created

APIv2::validateParameters()   D

Complexity

Conditions 9
Paths 18

Size

Total Lines 26
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 26
rs 4.909
c 0
b 0
f 0
cc 9
eloc 18
nc 18
nop 7
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
	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
		parent::__construct($appName, $request);
124
		$this->data = $data;
125
		$this->helper = $helper;
126
		$this->settings = $settings;
127
		$this->urlGenerator = $urlGenerator;
128
		$this->userSession = $userSession;
129
		$this->preview = $preview;
130
		$this->mimeTypeDetector = $mimeTypeDetector;
131
		$this->view = $view;
132
		$this->infoCache = $infoCache;
133
	}
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
	protected function validateParameters($filter, $since, $limit, $previews, $objectType, $objectId, $sort) {
147
		$this->filter = is_string($filter) ? $filter : 'all';
148
		if ($this->filter !== $this->data->validateFilter($this->filter)) {
149
			throw new InvalidFilterException();
150
		}
151
		$this->since = (int) $since;
152
		$this->limit = (int) $limit;
153
		$this->loadPreviews = (bool) $previews;
154
		$this->objectType = (string) $objectType;
155
		$this->objectId = (int) $objectId;
156
		$this->sort = in_array($sort, ['asc', 'desc'], true) ? $sort : 'desc';
157
158
		if (($this->objectType !== '' && $this->objectId === 0) || ($this->objectType === '' && $this->objectId !== 0)) {
159
			// Only allowed together
160
			$this->objectType = '';
161
			$this->objectId = 0;
162
		}
163
164
		$user = $this->userSession->getUser();
165
		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
			$this->user = $user->getUID();
167
		} else {
168
			// No user logged in
169
			throw new \OutOfBoundsException();
170
		}
171
	}
172
173
	/**
174
	 * @param int $since
175
	 * @param int $limit
176
	 * @param bool $previews
177
	 * @param string $object_type
178
	 * @param int $object_id
179
	 * @param string $sort
180
	 * @return DataResponse
181
	 */
182
	public function getDefault($since = 0, $limit = 50, $previews = false, $object_type = '', $object_id = 0, $sort = 'desc') {
183
		return $this->get('all', $since, $limit, $previews, $object_type, $object_id, $sort);
184
	}
185
186
	/**
187
	 * @param string $filter
188
	 * @param int $since
189
	 * @param int $limit
190
	 * @param bool $previews
191
	 * @param string $object_type
192
	 * @param int $object_id
193
	 * @param string $sort
194
	 * @return DataResponse
195
	 */
196
	public function getFilter($filter, $since = 0, $limit = 50, $previews = false, $object_type = '', $object_id = 0, $sort = 'desc') {
197
		return $this->get($filter, $since, $limit, $previews, $object_type, $object_id, $sort);
198
	}
199
200
	/**
201
	 * @param string $filter
202
	 * @param int $since
203
	 * @param int $limit
204
	 * @param bool $previews
205
	 * @param string $filterObjectType
206
	 * @param int $filterObjectId
207
	 * @param string $sort
208
	 * @return DataResponse
209
	 */
210
	protected function get($filter, $since, $limit, $previews, $filterObjectType, $filterObjectId, $sort) {
211
		try {
212
			$this->validateParameters($filter, $since, $limit, $previews, $filterObjectType, $filterObjectId, $sort);
213
		} catch (InvalidFilterException $e) {
214
			return new DataResponse(null, Http::STATUS_NOT_FOUND);
215
		} catch (\OutOfBoundsException $e) {
216
			return new DataResponse(null, Http::STATUS_FORBIDDEN);
217
		}
218
219
		try {
220
			$response = $this->data->get(
221
				$this->helper,
222
				$this->settings,
223
				$this->user,
224
225
				$this->since,
226
				$this->limit,
227
				$this->sort,
228
229
				$this->filter,
230
				$this->objectType,
231
				$this->objectId
232
			);
233
		} catch (\OutOfBoundsException $e) {
234
			// Invalid since argument
235
			return new DataResponse(null, Http::STATUS_FORBIDDEN);
236
		} catch (\BadMethodCallException $e) {
237
			// No activity settings enabled
238
			return new DataResponse(null, Http::STATUS_NO_CONTENT);
239
		}
240
241
		$headers = $this->generateHeaders($response['headers'], $response['has_more']);
242
		if (empty($response['data'])) {
243
			return new DataResponse([], Http::STATUS_NOT_MODIFIED, $headers);
244
		}
245
246
		$preparedActivities = [];
247
		foreach ($response['data'] as $activity) {
248
			$activity['datetime'] = date('c', $activity['timestamp']);
249
			unset($activity['timestamp']);
250
251
			if ($this->loadPreviews) {
252
				$activity['previews'] = [];
253
				if ($activity['object_type'] === 'files') {
254
					if (!empty($activity['objects']) && is_array($activity['objects'])) {
255
						foreach ($activity['objects'] as $objectId => $objectName) {
256
							if (((int) $objectId) === 0 || $objectName === '') {
257
								// No file, no preview
258
								continue;
259
							}
260
261
							$activity['previews'][] = $this->getPreview($activity['affecteduser'], (int) $objectId, $objectName);
262
						}
263
					} else if ($activity['object_id']) {
264
						$activity['previews'][] = $this->getPreview($activity['affecteduser'], (int) $activity['object_id'], $activity['object_name']);
265
					}
266
				}
267
			}
268
269
			$preparedActivities[] = $activity;
270
		}
271
272
		return new DataResponse($preparedActivities, Http::STATUS_OK, $headers);
273
	}
274
275
	/**
276
	 * @param array $headers
277
	 * @param bool $hasMoreActivities
278
	 * @return array
279
	 */
280
	protected function generateHeaders(array $headers, $hasMoreActivities) {
281
		if ($hasMoreActivities && isset($headers['X-Activity-Last-Given'])) {
282
			// Set the "Link" header for the next page
283
			$nextPageParameters = [
284
				'since' => $headers['X-Activity-Last-Given'],
285
				'limit' => $this->limit,
286
				'sort' => $this->sort,
287
			];
288
			if ($this->objectType && $this->objectId) {
289
				$nextPageParameters['object_type'] = $this->objectType;
290
				$nextPageParameters['object_id'] = $this->objectId;
291
			}
292
			if ($this->request->getParam('format') !== null) {
293
				$nextPageParameters['format'] = $this->request->getParam('format');
294
			}
295
296
			$nextPage = $this->request->getServerProtocol(); # http
297
			$nextPage .= '://' . $this->request->getServerHost(); # localhost
298
			$nextPage .= $this->request->getScriptName(); # /ocs/v2.php
299
			$nextPage .= $this->request->getPathInfo(); # /apps/activity/api/v2/activity
300
			$nextPage .= '?' . http_build_query($nextPageParameters);
301
			$headers['Link'] = '<' . $nextPage . '>; rel="next"';
302
		}
303
304
		return $headers;
305
	}
306
307
	/**
308
	 * @param string $owner
309
	 * @param int $fileId
310
	 * @param string $filePath
311
	 * @return array
312
	 */
313
	protected function getPreview($owner, $fileId, $filePath) {
314
		$info = $this->infoCache->getInfoById($owner, $fileId, $filePath);
315
316
		if (!$info['exists'] || $info['view'] !== '') {
317
			return $this->getPreviewFromPath($filePath, $info);
318
		}
319
320
		$preview = [
321
			'link'			=> $this->getPreviewLink($info['path'], $info['is_dir'], $info['view']),
322
			'source'		=> '',
323
			'isMimeTypeIcon' => true,
324
		];
325
326
		// show a preview image if the file still exists
327
		if ($info['is_dir']) {
328
			$preview['source'] = $this->getPreviewPathFromMimeType('dir');
329
		} else {
330
			$this->view->chroot('/' . $owner . '/files');
331
			$fileInfo = $this->view->getFileInfo($info['path']);
332
			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...
333
				$pathPreview = $this->getPreviewFromPath($filePath, $info);
334
				$preview['source'] = $pathPreview['source'];
335
			} else if ($this->preview->isAvailable($fileInfo)) {
336
				$preview['isMimeTypeIcon'] = false;
337
				$preview['source'] = $this->urlGenerator->linkToRouteAbsolute('core.Preview.getPreview', [
338
					'file' => $info['path'],
339
					'c' => $this->view->getETag($info['path']),
340
					'x' => 150,
341
					'y' => 150,
342
				]);
343
			} else {
344
				$preview['source'] = $this->getPreviewPathFromMimeType($fileInfo->getMimetype());
345
			}
346
		}
347
348
		return $preview;
349
	}
350
351
	/**
352
	 * @param string $filePath
353
	 * @param array $info
354
	 * @return array
355
	 */
356
	protected function getPreviewFromPath($filePath, $info) {
357
		$mimeType = $this->mimeTypeDetector->detectPath($filePath);
358
		$preview = [
359
			'link'			=> $this->getPreviewLink($info['path'], $info['is_dir'], $info['view']),
360
			'source'		=> $this->getPreviewPathFromMimeType($mimeType),
361
			'isMimeTypeIcon' => true,
362
		];
363
364
		return $preview;
365
	}
366
367
	/**
368
	 * @param string $mimeType
369
	 * @return string
370
	 */
371
	protected function getPreviewPathFromMimeType($mimeType) {
372
		$mimeTypeIcon = $this->mimeTypeDetector->mimeTypeIcon($mimeType);
373
		if (substr($mimeTypeIcon, -4) === '.png') {
374
			$mimeTypeIcon = substr($mimeTypeIcon, 0, -4) . '.svg';
375
		}
376
377
		return $this->urlGenerator->getAbsoluteURL($mimeTypeIcon);
378
	}
379
380
	/**
381
	 * @param string $path
382
	 * @param bool $isDir
383
	 * @param string $view
384
	 * @return string
385
	 */
386
	protected function getPreviewLink($path, $isDir, $view) {
387
		$params = [
388
			'dir' => $path,
389
		];
390
		if (!$isDir) {
391
			$params['dir'] = (substr_count($path, '/') === 1) ? '/' : dirname($path);
392
			$params['scrollto'] = basename($path);
393
		}
394
		if ($view !== '') {
395
			$params['view'] = $view;
396
		}
397
		return $this->urlGenerator->linkToRouteAbsolute('files.view.index', $params);
398
	}
399
}
400