Completed
Push — stable10 ( 08804b...4db595 )
by Roeland
23:12 queued 13:20
created

AvatarController   B

Complexity

Total Complexity 33

Size/Duplication

Total Lines 297
Duplicated Lines 22.9 %

Coupling/Cohesion

Components 1
Dependencies 16

Importance

Changes 0
Metric Value
dl 68
loc 297
rs 7.9538
c 0
b 0
f 0
wmc 33
lcom 1
cbo 16

6 Methods

Rating   Name   Duplication   Size   Complexity  
A getTmpAvatar() 0 20 2
A __construct() 19 19 1
B getAvatar() 0 34 5
D postAvatar() 49 104 17
A deleteAvatar() 0 12 2
B postCroppedAvatar() 0 37 6

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Joas Schilling <[email protected]>
6
 * @author Lukas Reschke <[email protected]>
7
 * @author Morris Jobke <[email protected]>
8
 * @author Robin Appelman <[email protected]>
9
 * @author Roeland Jago Douma <[email protected]>
10
 * @author Thomas Müller <[email protected]>
11
 * @author Vincent Petry <[email protected]>
12
 *
13
 * @license AGPL-3.0
14
 *
15
 * This code is free software: you can redistribute it and/or modify
16
 * it under the terms of the GNU Affero General Public License, version 3,
17
 * as published by the Free Software Foundation.
18
 *
19
 * This program is distributed in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
 * GNU Affero General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU Affero General Public License, version 3,
25
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
26
 *
27
 */
28
namespace OC\Core\Controller;
29
30
use OCP\AppFramework\Controller;
31
use OCP\AppFramework\Http;
32
use OCP\AppFramework\Http\DataResponse;
33
use OCP\AppFramework\Http\JSONResponse;
34
use OCP\AppFramework\Http\DataDisplayResponse;
35
use OCP\Files\NotFoundException;
36
use OCP\IAvatarManager;
37
use OCP\ILogger;
38
use OCP\IL10N;
39
use OCP\IRequest;
40
use OCP\IUserManager;
41
use OCP\IUserSession;
42
use OCP\Files\Folder;
43
44
/**
45
 * Class AvatarController
46
 *
47
 * @package OC\Core\Controller
48
 */
49
class AvatarController extends Controller {
50
51
	/** @var IAvatarManager */
52
	protected $avatarManager;
53
54
	/** @var \OC\Cache\File */
55
	protected $cache;
56
57
	/** @var IL10N */
58
	protected $l;
59
60
	/** @var IUserManager */
61
	protected $userManager;
62
63
	/** @var IUserSession */
64
	protected $userSession;
65
66
	/** @var Folder */
67
	protected $userFolder;
68
69
	/** @var ILogger */
70
	protected $logger;
71
72
	/**
73
	 * @param string $appName
74
	 * @param IRequest $request
75
	 * @param IAvatarManager $avatarManager
76
	 * @param \OC\Cache\File $cache
77
	 * @param IL10N $l10n
78
	 * @param IUserManager $userManager
79
	 * @param IUserSession $userSession
80
	 * @param Folder $userFolder
81
	 * @param ILogger $logger
82
	 */
83 View Code Duplication
	public function __construct($appName,
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
84
								IRequest $request,
85
								IAvatarManager $avatarManager,
86
								\OC\Cache\File $cache,
87
								IL10N $l10n,
88
								IUserManager $userManager,
89
								IUserSession $userSession,
90
								Folder $userFolder = null,
91
								ILogger $logger) {
92
		parent::__construct($appName, $request);
93
94
		$this->avatarManager = $avatarManager;
95
		$this->cache = $cache;
96
		$this->l = $l10n;
97
		$this->userManager = $userManager;
98
		$this->userSession = $userSession;
99
		$this->userFolder = $userFolder;
100
		$this->logger = $logger;
101
	}
102
103
	/**
104
	 * @NoAdminRequired
105
	 * @NoCSRFRequired
106
	 * @PublicPage
107
	 *
108
	 * @param string $userId
109
	 * @param int $size
110
	 * @return DataResponse|DataDisplayResponse
111
	 */
112
	public function getAvatar($userId, $size) {
113
		if ($size > 2048) {
114
			$size = 2048;
115
		} elseif ($size <= 0) {
116
			$size = 64;
117
		}
118
119
		try {
120
			$avatar = $this->avatarManager->getAvatar($userId)->getFile($size);
121
			$resp = new DataDisplayResponse($avatar->getContent(),
122
				Http::STATUS_OK,
123
				['Content-Type' => $avatar->getMimeType()]);
124
			$resp->setETag($avatar->getEtag());
125
		} catch (NotFoundException $e) {
126
			$user = $this->userManager->get($userId);
127
			$resp = new DataResponse([
128
				'data' => [
129
					'displayname' => $user->getDisplayName(),
130
				],
131
			]);
132
		} catch (\Exception $e) {
133
			$resp = new DataResponse([
134
				'data' => [
135
					'displayname' => '',
136
				],
137
			]);
138
		}
139
140
		$resp->addHeader('Pragma', 'public');
141
		$resp->cacheFor(0);
142
		$resp->setLastModified(new \DateTime('now', new \DateTimeZone('GMT')));
143
144
		return $resp;
145
	}
146
147
	/**
148
	 * @NoAdminRequired
149
	 *
150
	 * @param string $path
151
	 * @return DataResponse|JSONResponse
152
	 */
153
	public function postAvatar($path) {
154
		$userId = $this->userSession->getUser()->getUID();
0 ignored issues
show
Unused Code introduced by
$userId is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
155
		$files = $this->request->getUploadedFile('files');
156
157
		$headers = [];
158
		if ($this->request->isUserAgent([\OC\AppFramework\Http\Request::USER_AGENT_IE_8])) {
159
			// due to upload iframe workaround, need to set content-type to text/plain
160
			$headers['Content-Type'] = 'text/plain';
161
		}
162
163
		if (isset($path)) {
164
			$path = stripslashes($path);
165
			$node = $this->userFolder->get($path);
166
			if (!($node instanceof \OCP\Files\File)) {
167
				return new DataResponse(['data' => ['message' => $this->l->t('Please select a file.')]], Http::STATUS_OK, $headers);
168
			}
169 View Code Duplication
			if ($node->getSize() > 20*1024*1024) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
170
				return new DataResponse(
171
					['data' => ['message' => $this->l->t('File is too big')]],
172
					Http::STATUS_BAD_REQUEST,
173
					$headers
174
				);
175
			}
176
177 View Code Duplication
			if ($node->getMimeType() !== 'image/jpeg' && $node->getMimeType() !== 'image/png') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
178
				return new JSONResponse(
179
					['data' => ['message' => $this->l->t('The selected file is not an image.')]],
180
					Http::STATUS_BAD_REQUEST
181
				);
182
			}
183
184
			try {
185
				$content = $node->getContent();
186
			} catch (\OCP\Files\NotPermittedException $e) {
187
				return new JSONResponse(
188
					['data' => ['message' => $this->l->t('The selected file cannot be read.')]],
189
					Http::STATUS_BAD_REQUEST
190
				);
191
			}
192
		} elseif (!is_null($files)) {
193
			if (
194
				$files['error'][0] === 0 &&
195
				 is_uploaded_file($files['tmp_name'][0]) &&
196
				!\OC\Files\Filesystem::isFileBlacklisted($files['tmp_name'][0])
197
			) {
198 View Code Duplication
				if ($files['size'][0] > 20*1024*1024) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
199
					return new DataResponse(
200
						['data' => ['message' => $this->l->t('File is too big')]],
201
						Http::STATUS_BAD_REQUEST,
202
						$headers
203
					);
204
				}
205
				$this->cache->set('avatar_upload', file_get_contents($files['tmp_name'][0]), 7200);
206
				$content = $this->cache->get('avatar_upload');
207
				unlink($files['tmp_name'][0]);
208 View Code Duplication
			} else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
209
				return new DataResponse(
210
					['data' => ['message' => $this->l->t('Invalid file provided')]],
211
					Http::STATUS_BAD_REQUEST,
212
					$headers
213
				);
214
			}
215 View Code Duplication
		} else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
216
			//Add imgfile
217
			return new DataResponse(
218
				['data' => ['message' => $this->l->t('No image or file provided')]],
219
				Http::STATUS_BAD_REQUEST,
220
				$headers
221
			);
222
		}
223
224
		try {
225
			$image = new \OC_Image();
226
			$image->loadFromData($content);
227
			$image->fixOrientation();
228
229
			if ($image->valid()) {
230
				$mimeType = $image->mimeType();
231 View Code Duplication
				if ($mimeType !== 'image/jpeg' && $mimeType !== 'image/png') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
232
					return new DataResponse(
233
						['data' => ['message' => $this->l->t('Unknown filetype')]],
234
						Http::STATUS_OK,
235
						$headers
236
					);
237
				}
238
239
				$this->cache->set('tmpAvatar', $image->data(), 7200);
240
				return new DataResponse(
241
					['data' => 'notsquare'],
242
					Http::STATUS_OK,
243
					$headers
244
				);
245 View Code Duplication
			} else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
246
				return new DataResponse(
247
					['data' => ['message' => $this->l->t('Invalid image')]],
248
					Http::STATUS_OK,
249
					$headers
250
				);
251
			}
252
		} catch (\Exception $e) {
253
			$this->logger->logException($e, ['app' => 'core']);
254
			return new DataResponse(['data' => ['message' => $this->l->t('An error occurred. Please contact your admin.')]], Http::STATUS_OK, $headers);
255
		}
256
	}
257
258
	/**
259
	 * @NoAdminRequired
260
     *
261
	 * @return DataResponse
262
	 */
263
	public function deleteAvatar() {
264
		$userId = $this->userSession->getUser()->getUID();
265
266
		try {
267
			$avatar = $this->avatarManager->getAvatar($userId);
268
			$avatar->remove();
269
			return new DataResponse();
270
		} catch (\Exception $e) {
271
			$this->logger->logException($e, ['app' => 'core']);
272
			return new DataResponse(['data' => ['message' => $this->l->t('An error occurred. Please contact your admin.')]], Http::STATUS_BAD_REQUEST);
273
		}
274
	}
275
276
	/**
277
	 * @NoAdminRequired
278
	 *
279
	 * @return DataResponse|DataDisplayResponse
280
	 */
281
	public function getTmpAvatar() {
282
		$tmpAvatar = $this->cache->get('tmpAvatar');
283
		if (is_null($tmpAvatar)) {
284
			return new DataResponse(['data' => [
285
										'message' => $this->l->t("No temporary profile picture available, try again")
286
									]],
287
									Http::STATUS_NOT_FOUND);
288
		}
289
290
		$image = new \OC_Image($tmpAvatar);
291
292
		$resp = new DataDisplayResponse($image->data(),
293
				Http::STATUS_OK,
294
				['Content-Type' => $image->mimeType()]);
295
296
		$resp->setETag(crc32($image->data()));
297
		$resp->cacheFor(0);
298
		$resp->setLastModified(new \DateTime('now', new \DateTimeZone('GMT')));
299
		return $resp;
300
	}
301
302
	/**
303
	 * @NoAdminRequired
304
	 *
305
	 * @param array $crop
306
	 * @return DataResponse
307
	 */
308
	public function postCroppedAvatar($crop) {
309
		$userId = $this->userSession->getUser()->getUID();
310
311
		if (is_null($crop)) {
312
			return new DataResponse(['data' => ['message' => $this->l->t("No crop data provided")]],
313
									Http::STATUS_BAD_REQUEST);
314
		}
315
316
		if (!isset($crop['x'], $crop['y'], $crop['w'], $crop['h'])) {
317
			return new DataResponse(['data' => ['message' => $this->l->t("No valid crop data provided")]],
318
									Http::STATUS_BAD_REQUEST);
319
		}
320
321
		$tmpAvatar = $this->cache->get('tmpAvatar');
322
		if (is_null($tmpAvatar)) {
323
			return new DataResponse(['data' => [
324
										'message' => $this->l->t("No temporary profile picture available, try again")
325
									]],
326
									Http::STATUS_BAD_REQUEST);
327
		}
328
329
		$image = new \OC_Image($tmpAvatar);
330
		$image->crop($crop['x'], $crop['y'], round($crop['w']), round($crop['h']));
331
		try {
332
			$avatar = $this->avatarManager->getAvatar($userId);
333
			$avatar->set($image);
334
			// Clean up
335
			$this->cache->remove('tmpAvatar');
336
			return new DataResponse(['status' => 'success']);
337
		} catch (\OC\NotSquareException $e) {
338
			return new DataResponse(['data' => ['message' => $this->l->t('Crop is not square')]],
339
									Http::STATUS_BAD_REQUEST);
340
		} catch (\Exception $e) {
341
			$this->logger->logException($e, ['app' => 'core']);
342
			return new DataResponse(['data' => ['message' => $this->l->t('An error occurred. Please contact your admin.')]], Http::STATUS_BAD_REQUEST);
343
		}
344
	}
345
}
346