Completed
Push — master ( 160a90...29891d )
by Joas
13:59
created

OCSEndPoint::getDefault()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 5
ccs 4
cts 4
cp 1
rs 9.4285
cc 1
eloc 3
nc 1
nop 1
crap 1
1
<?php
2
/**
3
 * @author Joas Schilling <[email protected]>
4
 *
5
 * @copyright Copyright (c) 2015, 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\IMimeTypeDetector;
33
use OCP\IPreview;
34
use OCP\IRequest;
35
use OCP\IURLGenerator;
36
use OCP\IUser;
37
use OCP\IUserSession;
38
39
class OCSEndPoint {
40
41
	/** @var string */
42
	protected $filter;
43
44
	/** @var int */
45
	protected $since;
46
47
	/** @var int */
48
	protected $limit;
49
50
	/** @var string */
51
	protected $sort;
52
53
	/** @var string */
54
	protected $objectType;
55
56
	/** @var int */
57
	protected $objectId;
58
59
	/** @var string */
60
	protected $user;
61
62
	/** @var bool */
63
	protected $loadPreviews;
64
65
66
	/** @var Data */
67
	protected $data;
68
69
	/** @var GroupHelper */
70
	protected $helper;
71
72
	/** @var UserSettings */
73
	protected $settings;
74
75
	/** @var IRequest */
76
	protected $request;
77
78
	/** @var IURLGenerator */
79
	protected $urlGenerator;
80
81
	/** @var IUserSession */
82
	protected $userSession;
83
84
	/** @var IPreview */
85
	protected $preview;
86
87
	/** @var IMimeTypeDetector */
88
	protected $mimeTypeDetector;
89
90
	/** @var View */
91
	protected $view;
92
93
	/** @var ViewInfoCache */
94
	protected $infoCache;
95
96
	/**
97
	 * OCSEndPoint constructor.
98
	 *
99
	 * @param Data $data
100
	 * @param GroupHelper $helper
101
	 * @param UserSettings $settings
102
	 * @param IRequest $request
103
	 * @param IURLGenerator $urlGenerator
104
	 * @param IUserSession $userSession
105
	 * @param IPreview $preview
106
	 * @param IMimeTypeDetector $mimeTypeDetector
107
	 * @param View $view
108
	 * @param ViewInfoCache $infoCache
109
	 */
110 61
	public function __construct(Data $data,
111
								GroupHelper $helper,
112
								UserSettings $settings,
113
								IRequest $request,
114
								IURLGenerator $urlGenerator,
115
								IUserSession $userSession,
116
								IPreview $preview,
117
								IMimeTypeDetector $mimeTypeDetector,
118
								View $view,
119
								ViewInfoCache $infoCache) {
120 61
		$this->data = $data;
121 61
		$this->helper = $helper;
122 61
		$this->settings = $settings;
123 61
		$this->request = $request;
124 61
		$this->urlGenerator = $urlGenerator;
125 61
		$this->userSession = $userSession;
126 61
		$this->preview = $preview;
127 61
		$this->mimeTypeDetector = $mimeTypeDetector;
128 61
		$this->view = $view;
129 61
		$this->infoCache = $infoCache;
130 61
	}
131
132
	/**
133
	 * @param array $parameters
134
	 * @throws InvalidFilterException when the filter is invalid
135
	 * @throws \OutOfBoundsException when no user is given
136
	 */
137 23
	protected function readParameters(array $parameters) {
138 23
		$this->filter = isset($parameters['filter']) && is_string($parameters['filter']) ? (string) $parameters['filter'] : 'all';
139 23
		if ($this->filter !== $this->data->validateFilter($this->filter)) {
140 2
			throw new InvalidFilterException();
141
		}
142 21
		$this->since = (int) $this->request->getParam('since', 0);
143 21
		$this->limit = (int) $this->request->getParam('limit', 50);
144 21
		$this->loadPreviews = $this->request->getParam('previews', 'false') === 'true';
145 21
		$this->objectType = (string) $this->request->getParam('object_type', '');
146 21
		$this->objectId = (int) $this->request->getParam('object_id', 0);
147 21
		$this->sort = (string) $this->request->getParam('sort', '');
148 21
		$this->sort = in_array($this->sort, ['asc', 'desc']) ? $this->sort : 'desc';
149
150 21
		if ($this->objectType !== '' && $this->objectId === 0 || $this->objectType === '' && $this->objectId !== 0) {
151
			// Only allowed together
152 2
			$this->objectType = '';
153 2
			$this->objectId = 0;
154 2
		}
155
156 21
		$user = $this->userSession->getUser();
157 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...
158 20
			$this->user = $user->getUID();
159 20
		} else {
160
			// No user logged in
161 1
			throw new \OutOfBoundsException();
162
		}
163 20
	}
164
165
	/**
166
	 * @param array $parameters
167
	 * @return \OC_OCS_Result
168
	 */
169 3
	public function getDefault(array $parameters) {
170 3
		return $this->get(array_merge($parameters, [
171 3
			'filter' => 'all',
172 3
		]));
173
	}
174
175
	/**
176
	 * @param array $parameters
177
	 * @return \OC_OCS_Result
178
	 */
179 3
	public function getFilter(array $parameters) {
180 3
		return $this->get($parameters);
181
	}
182
183
	/**
184
	 * @param array $parameters
185
	 * @return \OC_OCS_Result
186
	 */
187 9
	protected function get(array $parameters) {
188
		try {
189 9
			$this->readParameters($parameters);
190 9
		} catch (InvalidFilterException $e) {
191 1
			return new \OC_OCS_Result(null, Http::STATUS_NOT_FOUND);
192 1
		} catch (\OutOfBoundsException $e) {
193 1
			return new \OC_OCS_Result(null, Http::STATUS_FORBIDDEN);
194
		}
195
196
		try {
197 7
			$response = $this->data->get(
198 7
				$this->helper,
199 7
				$this->settings,
200 7
				$this->user,
201
202 7
				$this->since,
203 7
				$this->limit,
204 7
				$this->sort,
205
206 7
				$this->filter,
207 7
				$this->objectType,
208 7
				$this->objectId
209 7
			);
210 7
		} catch (\OutOfBoundsException $e) {
211
			// Invalid since argument
212 1
			return new \OC_OCS_Result(null, Http::STATUS_FORBIDDEN);
213 1
		} catch (\BadMethodCallException $e) {
214
			// No activity settings enabled
215 1
			return new \OC_OCS_Result(null, Http::STATUS_NO_CONTENT);
216
		}
217
218 5
		$headers = $this->generateHeaders($response['headers'], $response['has_more']);
219 5
		if (empty($response['data'])) {
220 1
			return new \OC_OCS_Result([], Http::STATUS_NOT_MODIFIED, null, $headers);
221
		}
222
223 4
		$preparedActivities = [];
224 4
		foreach ($response['data'] as $activity) {
225 4
			$activity['datetime'] = date('c', $activity['timestamp']);
226 4
			unset($activity['timestamp']);
227
228 4
			if ($this->loadPreviews) {
229 3
				$activity['previews'] = [];
230 3
				if ($activity['object_type'] === 'files' && !empty($activity['files'])) {
231 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...
232 1
						if (((int) $objectId) === 0 || $objectName === '') {
233
							// No file, no preview
234 1
							continue;
235
						}
236
237 1
						$activity['previews'][] = $this->getPreview($activity['affecteduser'], (int) $objectId, $objectName);
238 1
					}
239 3
				} else if ($activity['object_type'] === 'files' && $activity['object_id']) {
240 1
					$activity['previews'][] = $this->getPreview($activity['affecteduser'], (int) $activity['object_id'], $activity['file']);
241 1
				}
242 3
			}
243
244 4
			$preparedActivities[] = $activity;
245 4
		}
246
247 4
		return new \OC_OCS_Result($preparedActivities, 100, null, $headers);
248
	}
249
250
	/**
251
	 * @param array $headers
252
	 * @param bool $hasMoreActivities
253
	 * @return array
254
	 */
255 4
	protected function generateHeaders(array $headers, $hasMoreActivities) {
256 4
		if ($hasMoreActivities && isset($headers['X-Activity-Last-Given'])) {
257
			// Set the "Link" header for the next page
258
			$nextPageParameters = [
259 3
				'since' => $headers['X-Activity-Last-Given'],
260 3
				'limit' => $this->limit,
261 3
				'sort' => $this->sort,
262 3
			];
263 3
			if ($this->objectType && $this->objectId) {
264 1
				$nextPageParameters['object_type'] = $this->objectType;
265 1
				$nextPageParameters['object_id'] = $this->objectId;
266 1
			}
267 3
			if ($this->request->getParam('format') !== null) {
268 1
				$nextPageParameters['format'] = $this->request->getParam('format');
269 1
			}
270
271 3
			$nextPage = $this->request->getServerProtocol(); # http
272 3
			$nextPage .= '://' . $this->request->getServerHost(); # localhost
273 3
			$nextPage .= $this->request->getScriptName(); # /ocs/v2.php
274 3
			$nextPage .= $this->request->getPathInfo(); # /apps/activity/api/v2/activity
275 3
			$nextPage .= '?' . http_build_query($nextPageParameters);
276 3
			$headers['Link'] = '<' . $nextPage . '>; rel="next"';
277 3
		}
278
279 4
		return $headers;
280
	}
281
282
	/**
283
	 * @param string $owner
284
	 * @param int $fileId
285
	 * @param string $filePath
286
	 * @return array
287
	 */
288 6
	protected function getPreview($owner, $fileId, $filePath) {
289 6
		$info = $this->infoCache->getInfoById($owner, $fileId, $filePath);
290
291 6
		if (!$info['exists'] || $info['view'] !== '') {
292 3
			return $this->getPreviewFromPath($filePath);
293
		}
294
295
		$preview = [
296 3
			'link'			=> $this->getPreviewLink($info['path'], $info['is_dir']),
297 3
			'source'		=> '',
298 3
			'isMimeTypeIcon' => true,
299 3
		];
300
301
		// show a preview image if the file still exists
302 3
		if ($info['is_dir']) {
303 1
			$preview['source'] = $this->getPreviewPathFromMimeType('dir');
304 1
		} else {
305 2
			$this->view->chroot('/' . $owner . '/files');
306 2
			$fileInfo = $this->view->getFileInfo($info['path']);
307 2
			if ($this->preview->isAvailable($fileInfo)) {
308 1
				$preview['isMimeTypeIcon'] = false;
309 1
				$preview['source'] = $this->urlGenerator->linkToRoute('core_ajax_preview', [
310 1
					'file' => $info['path'],
311 1
					'c' => $this->view->getETag($info['path']),
312 1
					'x' => 150,
313 1
					'y' => 150,
314 1
				]);
315 1
			} else {
316 1
				$preview['source'] = $this->getPreviewPathFromMimeType($fileInfo->getMimetype());
317
			}
318
		}
319
320 3
		return $preview;
321
	}
322
323
	/**
324
	 * @param string $filePath
325
	 * @return array
326
	 */
327 3
	protected function getPreviewFromPath($filePath) {
328 3
		$mimeType = $this->mimeTypeDetector->detectPath($filePath);
329
		$preview = [
330 3
			'link'			=> $this->getPreviewLink($filePath, false),
331 3
			'source'		=> $this->getPreviewPathFromMimeType($mimeType),
332 3
			'isMimeTypeIcon' => true,
333 3
		];
334
335 3
		return $preview;
336
	}
337
338
	/**
339
	 * @param string $mimeType
340
	 * @return string
341
	 */
342 3
	protected function getPreviewPathFromMimeType($mimeType) {
343 3
		$mimeTypeIcon = $this->mimeTypeDetector->mimeTypeIcon($mimeType);
344 3
		if (substr($mimeTypeIcon, -4) === '.png') {
345 1
			$mimeTypeIcon = substr($mimeTypeIcon, 0, -4) . '.svg';
346 1
		}
347
348 3
		return $mimeTypeIcon;
349
	}
350
351
	/**
352
	 * @param string $path
353
	 * @param bool $isDir
354
	 * @return string
355
	 */
356 6
	protected function getPreviewLink($path, $isDir) {
357 6
		if ($isDir) {
358 3
			return $this->urlGenerator->linkTo('files', 'index.php', array('dir' => $path));
359
		} else {
360 3
			$parentDir = (substr_count($path, '/') === 1) ? '/' : dirname($path);
361 3
			$fileName = basename($path);
362 3
			return $this->urlGenerator->linkTo('files', 'index.php', array(
363 3
				'dir' => $parentDir,
364 3
				'scrollto' => $fileName,
365 3
			));
366
		}
367
	}
368
}
369