Passed
Push — master ( 49415e...22ff60 )
by Morris
13:58 queued 10s
created

AvatarController::postAvatar()   C

Complexity

Conditions 16
Paths 33

Size

Total Lines 91
Code Lines 63

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 16
eloc 63
nc 33
nop 1
dl 0
loc 91
rs 5.5666
c 0
b 0
f 0

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 Christoph Wurst <[email protected]>
6
 * @author Daniel Kesselberg <[email protected]>
7
 * @author Joas Schilling <[email protected]>
8
 * @author John Molakvoæ (skjnldsv) <[email protected]>
9
 * @author Lukas Reschke <[email protected]>
10
 * @author Morris Jobke <[email protected]>
11
 * @author Roeland Jago Douma <[email protected]>
12
 * @author Thomas Müller <[email protected]>
13
 * @author Vincent Petry <[email protected]>
14
 *
15
 * @license AGPL-3.0
16
 *
17
 * This code is free software: you can redistribute it and/or modify
18
 * it under the terms of the GNU Affero General Public License, version 3,
19
 * as published by the Free Software Foundation.
20
 *
21
 * This program is distributed in the hope that it will be useful,
22
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24
 * GNU Affero General Public License for more details.
25
 *
26
 * You should have received a copy of the GNU Affero General Public License, version 3,
27
 * along with this program. If not, see <http://www.gnu.org/licenses/>
28
 *
29
 */
30
31
namespace OC\Core\Controller;
32
33
use OC\AppFramework\Utility\TimeFactory;
34
use OCP\AppFramework\Controller;
35
use OCP\AppFramework\Http;
36
use OCP\AppFramework\Http\DataDisplayResponse;
37
use OCP\AppFramework\Http\FileDisplayResponse;
38
use OCP\AppFramework\Http\JSONResponse;
39
use OCP\Files\File;
40
use OCP\Files\IRootFolder;
41
use OCP\IAvatarManager;
42
use OCP\ICache;
43
use OCP\IL10N;
44
use OCP\ILogger;
45
use OCP\IRequest;
46
use OCP\IUserManager;
47
use OCP\IUserSession;
48
49
/**
50
 * Class AvatarController
51
 *
52
 * @package OC\Core\Controller
53
 */
54
class AvatarController extends Controller {
55
56
	/** @var IAvatarManager */
57
	protected $avatarManager;
58
59
	/** @var ICache */
60
	protected $cache;
61
62
	/** @var IL10N */
63
	protected $l;
64
65
	/** @var IUserManager */
66
	protected $userManager;
67
68
	/** @var IUserSession */
69
	protected $userSession;
70
71
	/** @var IRootFolder */
72
	protected $rootFolder;
73
74
	/** @var ILogger */
75
	protected $logger;
76
77
	/** @var string */
78
	protected $userId;
79
80
	/** @var TimeFactory */
81
	protected $timeFactory;
82
83
	public function __construct($appName,
84
								IRequest $request,
85
								IAvatarManager $avatarManager,
86
								ICache $cache,
87
								IL10N $l10n,
88
								IUserManager $userManager,
89
								IRootFolder $rootFolder,
90
								ILogger $logger,
91
								$userId,
92
								TimeFactory $timeFactory) {
93
		parent::__construct($appName, $request);
94
95
		$this->avatarManager = $avatarManager;
96
		$this->cache = $cache;
97
		$this->l = $l10n;
98
		$this->userManager = $userManager;
99
		$this->rootFolder = $rootFolder;
100
		$this->logger = $logger;
101
		$this->userId = $userId;
102
		$this->timeFactory = $timeFactory;
103
	}
104
105
106
	/**
107
	 * @NoAdminRequired
108
	 * @NoCSRFRequired
109
	 * @NoSameSiteCookieRequired
110
	 * @PublicPage
111
	 *
112
	 * @param string $userId
113
	 * @param int $size
114
	 * @return JSONResponse|FileDisplayResponse
115
	 */
116
	public function getAvatar($userId, $size) {
117
		// min/max size
118
		if ($size > 2048) {
119
			$size = 2048;
120
		} elseif ($size <= 0) {
121
			$size = 64;
122
		}
123
124
		try {
125
			$avatar = $this->avatarManager->getAvatar($userId);
126
			$avatarFile = $avatar->getFile($size);
127
			$response = new FileDisplayResponse(
128
				$avatarFile,
129
				Http::STATUS_OK,
130
				['Content-Type' => $avatarFile->getMimeType(), 'X-NC-IsCustomAvatar' => (int)$avatar->isCustomAvatar()]
131
			);
132
		} catch (\Exception $e) {
133
			return new JSONResponse([], Http::STATUS_NOT_FOUND);
134
		}
135
136
		// Cache for 1 day
137
		$response->cacheFor(60*60*24);
138
		return $response;
139
	}
140
141
	/**
142
	 * @NoAdminRequired
143
	 *
144
	 * @param string $path
145
	 * @return JSONResponse
146
	 */
147
	public function postAvatar($path) {
148
		$files = $this->request->getUploadedFile('files');
149
150
		if (isset($path)) {
151
			$path = stripslashes($path);
152
			$userFolder = $this->rootFolder->getUserFolder($this->userId);
153
			/** @var File $node */
154
			$node = $userFolder->get($path);
155
			if (!($node instanceof File)) {
0 ignored issues
show
introduced by
$node is always a sub-type of OCP\Files\File.
Loading history...
156
				return new JSONResponse(['data' => ['message' => $this->l->t('Please select a file.')]]);
157
			}
158
			if ($node->getSize() > 20*1024*1024) {
159
				return new JSONResponse(
160
					['data' => ['message' => $this->l->t('File is too big')]],
161
					Http::STATUS_BAD_REQUEST
162
				);
163
			}
164
165
			if ($node->getMimeType() !== 'image/jpeg' && $node->getMimeType() !== 'image/png') {
166
				return new JSONResponse(
167
					['data' => ['message' => $this->l->t('The selected file is not an image.')]],
168
					Http::STATUS_BAD_REQUEST
169
				);
170
			}
171
172
			try {
173
				$content = $node->getContent();
174
			} catch (\OCP\Files\NotPermittedException $e) {
175
				return new JSONResponse(
176
					['data' => ['message' => $this->l->t('The selected file cannot be read.')]],
177
					Http::STATUS_BAD_REQUEST
178
				);
179
			}
180
		} elseif (!is_null($files)) {
0 ignored issues
show
introduced by
The condition is_null($files) is always false.
Loading history...
181
			if (
182
				$files['error'][0] === 0 &&
183
				 is_uploaded_file($files['tmp_name'][0]) &&
184
				!\OC\Files\Filesystem::isFileBlacklisted($files['tmp_name'][0])
185
			) {
186
				if ($files['size'][0] > 20*1024*1024) {
187
					return new JSONResponse(
188
						['data' => ['message' => $this->l->t('File is too big')]],
189
						Http::STATUS_BAD_REQUEST
190
					);
191
				}
192
				$this->cache->set('avatar_upload', file_get_contents($files['tmp_name'][0]), 7200);
193
				$content = $this->cache->get('avatar_upload');
194
				unlink($files['tmp_name'][0]);
195
			} else {
196
				return new JSONResponse(
197
					['data' => ['message' => $this->l->t('Invalid file provided')]],
198
					Http::STATUS_BAD_REQUEST
199
				);
200
			}
201
		} else {
202
			//Add imgfile
203
			return new JSONResponse(
204
				['data' => ['message' => $this->l->t('No image or file provided')]],
205
				Http::STATUS_BAD_REQUEST
206
			);
207
		}
208
209
		try {
210
			$image = new \OC_Image();
211
			$image->loadFromData($content);
212
			$image->readExif($content);
213
			$image->fixOrientation();
214
215
			if ($image->valid()) {
216
				$mimeType = $image->mimeType();
217
				if ($mimeType !== 'image/jpeg' && $mimeType !== 'image/png') {
218
					return new JSONResponse(
219
						['data' => ['message' => $this->l->t('Unknown filetype')]],
220
						Http::STATUS_OK
221
					);
222
				}
223
224
				$this->cache->set('tmpAvatar', $image->data(), 7200);
225
				return new JSONResponse(
226
					['data' => 'notsquare'],
227
					Http::STATUS_OK
228
				);
229
			} else {
230
				return new JSONResponse(
231
					['data' => ['message' => $this->l->t('Invalid image')]],
232
					Http::STATUS_OK
233
				);
234
			}
235
		} catch (\Exception $e) {
236
			$this->logger->logException($e, ['app' => 'core']);
237
			return new JSONResponse(['data' => ['message' => $this->l->t('An error occurred. Please contact your admin.')]], Http::STATUS_OK);
238
		}
239
	}
240
241
	/**
242
	 * @NoAdminRequired
243
	 *
244
	 * @return JSONResponse
245
	 */
246
	public function deleteAvatar() {
247
		try {
248
			$avatar = $this->avatarManager->getAvatar($this->userId);
249
			$avatar->remove();
250
			return new JSONResponse();
251
		} catch (\Exception $e) {
252
			$this->logger->logException($e, ['app' => 'core']);
253
			return new JSONResponse(['data' => ['message' => $this->l->t('An error occurred. Please contact your admin.')]], Http::STATUS_BAD_REQUEST);
254
		}
255
	}
256
257
	/**
258
	 * @NoAdminRequired
259
	 *
260
	 * @return JSONResponse|DataDisplayResponse
261
	 */
262
	public function getTmpAvatar() {
263
		$tmpAvatar = $this->cache->get('tmpAvatar');
264
		if (is_null($tmpAvatar)) {
265
			return new JSONResponse(['data' => [
266
				'message' => $this->l->t("No temporary profile picture available, try again")
267
			]],
268
									Http::STATUS_NOT_FOUND);
269
		}
270
271
		$image = new \OC_Image();
272
		$image->loadFromData($tmpAvatar);
273
274
		$resp = new DataDisplayResponse($image->data(),
275
				Http::STATUS_OK,
276
				['Content-Type' => $image->mimeType()]);
277
278
		$resp->setETag((string)crc32($image->data()));
279
		$resp->cacheFor(0);
280
		$resp->setLastModified(new \DateTime('now', new \DateTimeZone('GMT')));
281
		return $resp;
282
	}
283
284
	/**
285
	 * @NoAdminRequired
286
	 *
287
	 * @param array $crop
288
	 * @return JSONResponse
289
	 */
290
	public function postCroppedAvatar($crop) {
291
		if (is_null($crop)) {
0 ignored issues
show
introduced by
The condition is_null($crop) is always false.
Loading history...
292
			return new JSONResponse(['data' => ['message' => $this->l->t("No crop data provided")]],
293
									Http::STATUS_BAD_REQUEST);
294
		}
295
296
		if (!isset($crop['x'], $crop['y'], $crop['w'], $crop['h'])) {
297
			return new JSONResponse(['data' => ['message' => $this->l->t("No valid crop data provided")]],
298
									Http::STATUS_BAD_REQUEST);
299
		}
300
301
		$tmpAvatar = $this->cache->get('tmpAvatar');
302
		if (is_null($tmpAvatar)) {
303
			return new JSONResponse(['data' => [
304
				'message' => $this->l->t("No temporary profile picture available, try again")
305
			]],
306
									Http::STATUS_BAD_REQUEST);
307
		}
308
309
		$image = new \OC_Image();
310
		$image->loadFromData($tmpAvatar);
311
		$image->crop($crop['x'], $crop['y'], (int)round($crop['w']), (int)round($crop['h']));
312
		try {
313
			$avatar = $this->avatarManager->getAvatar($this->userId);
314
			$avatar->set($image);
315
			// Clean up
316
			$this->cache->remove('tmpAvatar');
317
			return new JSONResponse(['status' => 'success']);
318
		} catch (\OC\NotSquareException $e) {
319
			return new JSONResponse(['data' => ['message' => $this->l->t('Crop is not square')]],
320
									Http::STATUS_BAD_REQUEST);
321
		} catch (\Exception $e) {
322
			$this->logger->logException($e, ['app' => 'core']);
323
			return new JSONResponse(['data' => ['message' => $this->l->t('An error occurred. Please contact your admin.')]], Http::STATUS_BAD_REQUEST);
324
		}
325
	}
326
}
327