Completed
Push — master ( 12736a...06fa48 )
by Lukas
207:09 queued 186:28
created

AvatarController::getTmpAvatar()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 20
Code Lines 14

Duplication

Lines 6
Ratio 30 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 14
c 1
b 0
f 0
nc 2
nop 0
dl 6
loc 20
rs 9.4285
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 OC\AppFramework\Utility\TimeFactory;
31
use OCP\AppFramework\Controller;
32
use OCP\AppFramework\Http;
33
use OCP\AppFramework\Http\DataDisplayResponse;
34
use OCP\AppFramework\Http\JSONResponse;
35
use OCP\Files\File;
36
use OCP\Files\IRootFolder;
37
use OCP\Files\NotFoundException;
38
use OCP\IAvatarManager;
39
use OCP\ICache;
40
use OCP\ILogger;
41
use OCP\IL10N;
42
use OCP\IRequest;
43
use OCP\IUserManager;
44
use OCP\IUserSession;
45
46
/**
47
 * Class AvatarController
48
 *
49
 * @package OC\Core\Controller
50
 */
51
class AvatarController extends Controller {
52
53
	/** @var IAvatarManager */
54
	protected $avatarManager;
55
56
	/** @var ICache */
57
	protected $cache;
58
59
	/** @var IL10N */
60
	protected $l;
61
62
	/** @var IUserManager */
63
	protected $userManager;
64
65
	/** @var IUserSession */
66
	protected $userSession;
67
68
	/** @var IRootFolder */
69
	protected $rootFolder;
70
71
	/** @var ILogger */
72
	protected $logger;
73
74
	/** @var string */
75
	protected $userId;
76
77
	/** @var TimeFactory */
78
	protected $timeFactory;
79
80
	/**
81
	 * @param string $appName
82
	 * @param IRequest $request
83
	 * @param IAvatarManager $avatarManager
84
	 * @param ICache $cache
85
	 * @param IL10N $l10n
86
	 * @param IUserManager $userManager
87
	 * @param IRootFolder $rootFolder
88
	 * @param ILogger $logger
89
	 * @param string $userId
90
	 * @param TimeFactory $timeFactory
91
	 */
92 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...
93
								IRequest $request,
94
								IAvatarManager $avatarManager,
95
								ICache $cache,
96
								IL10N $l10n,
97
								IUserManager $userManager,
98
								IRootFolder $rootFolder,
99
								ILogger $logger,
100
								$userId,
101
								TimeFactory $timeFactory) {
102
		parent::__construct($appName, $request);
103
104
		$this->avatarManager = $avatarManager;
105
		$this->cache = $cache;
106
		$this->l = $l10n;
107
		$this->userManager = $userManager;
108
		$this->rootFolder = $rootFolder;
109
		$this->logger = $logger;
110
		$this->userId = $userId;
111
		$this->timeFactory = $timeFactory;
112
	}
113
114
	/**
115
	 * @NoAdminRequired
116
	 * @NoCSRFRequired
117
	 * @PublicPage
118
	 *
119
	 * @param string $userId
120
	 * @param int $size
121
	 * @return JSONResponse|DataDisplayResponse
122
	 */
123
	public function getAvatar($userId, $size) {
124
		if ($size > 2048) {
125
			$size = 2048;
126
		} elseif ($size <= 0) {
127
			$size = 64;
128
		}
129
130
		try {
131
			$avatar = $this->avatarManager->getAvatar($userId)->getFile($size);
132
			$resp = new DataDisplayResponse($avatar->getContent(),
133
				Http::STATUS_OK,
134
				['Content-Type' => $avatar->getMimeType()]);
135
			$resp->setETag($avatar->getEtag());
136
137
			// Let cache this!
138
			$resp->addHeader('Pragma', 'public');
139
			// Cache for 15 minutes
140
			$resp->cacheFor(900);
141
			// Set last modified
142
			$lastModified = new \DateTime();
143
			$lastModified->setTimestamp($avatar->getMTime());
144
			$resp->setLastModified($lastModified);
145
146
			$expires = new \DateTime();
147
			$expires->setTimestamp($this->timeFactory->getTime());
148
			$expires->add(new \DateInterval('PT15M'));
149
			$resp->addHeader('Expires', $expires->format(\DateTime::RFC2822));
150
151
		} catch (NotFoundException $e) {
152
			$user = $this->userManager->get($userId);
153
			$resp = new JSONResponse([
154
				'data' => [
155
					'displayname' => $user->getDisplayName(),
156
				],
157
			]);
158
			// Don't cache this
159
			$resp->cacheFor(0);
160
			$resp->setLastModified(new \DateTime('now', new \DateTimeZone('GMT')));
161
		} catch (\Exception $e) {
162
			$resp = new JSONResponse([
163
				'data' => [
164
					'displayname' => '',
165
				],
166
			]);
167
			// Don't cache this
168
			$resp->cacheFor(0);
169
			$resp->setLastModified(new \DateTime('now', new \DateTimeZone('GMT')));
170
		}
171
172
		return $resp;
173
	}
174
175
	/**
176
	 * @NoAdminRequired
177
	 *
178
	 * @param string $path
179
	 * @return JSONResponse
180
	 */
181
	public function postAvatar($path) {
182
		$files = $this->request->getUploadedFile('files');
183
184
		if (isset($path)) {
185
			$path = stripslashes($path);
186
			$userFolder = $this->rootFolder->getUserFolder($this->userId);
187
			$node = $userFolder->get($path);
188
			if (!($node instanceof File)) {
189
				return new JSONResponse(['data' => ['message' => $this->l->t('Please select a file.')]]);
190
			}
191 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...
192
				return new JSONResponse(
193
					['data' => ['message' => $this->l->t('File is too big')]],
194
					Http::STATUS_BAD_REQUEST
195
				);
196
			}
197
			$content = $node->getContent();
198
		} elseif (!is_null($files)) {
199
			if (
200
				$files['error'][0] === 0 &&
201
				 is_uploaded_file($files['tmp_name'][0]) &&
202
				!\OC\Files\Filesystem::isFileBlacklisted($files['tmp_name'][0])
203
			) {
204 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...
205
					return new JSONResponse(
206
						['data' => ['message' => $this->l->t('File is too big')]],
207
						Http::STATUS_BAD_REQUEST
208
					);
209
				}
210
				$this->cache->set('avatar_upload', file_get_contents($files['tmp_name'][0]), 7200);
211
				$content = $this->cache->get('avatar_upload');
212
				unlink($files['tmp_name'][0]);
213 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...
214
				return new JSONResponse(
215
					['data' => ['message' => $this->l->t('Invalid file provided')]],
216
					Http::STATUS_BAD_REQUEST
217
				);
218
			}
219 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...
220
			//Add imgfile
221
			return new JSONResponse(
222
				['data' => ['message' => $this->l->t('No image or file provided')]],
223
				Http::STATUS_BAD_REQUEST
224
			);
225
		}
226
227
		try {
228
			$image = new \OC_Image();
229
			$image->loadFromData($content);
230
			$image->fixOrientation();
231
232
			if ($image->valid()) {
233
				$mimeType = $image->mimeType();
234
				if ($mimeType !== 'image/jpeg' && $mimeType !== 'image/png') {
235
					return new JSONResponse(
236
						['data' => ['message' => $this->l->t('Unknown filetype')]],
237
						Http::STATUS_OK
238
					);
239
				}
240
241
				$this->cache->set('tmpAvatar', $image->data(), 7200);
242
				return new JSONResponse(
243
					['data' => 'notsquare'],
244
					Http::STATUS_OK
245
				);
246 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...
247
				return new JSONResponse(
248
					['data' => ['message' => $this->l->t('Invalid image')]],
249
					Http::STATUS_OK
250
				);
251
			}
252
		} catch (\Exception $e) {
253
			$this->logger->logException($e, ['app' => 'core']);
254
			return new JSONResponse(['data' => ['message' => $this->l->t('An error occurred. Please contact your admin.')]], Http::STATUS_OK);
255
		}
256
	}
257
258
	/**
259
	 * @NoAdminRequired
260
     *
261
	 * @return JSONResponse
262
	 */
263
	public function deleteAvatar() {
264
		try {
265
			$avatar = $this->avatarManager->getAvatar($this->userId);
266
			$avatar->remove();
267
			return new JSONResponse();
268
		} catch (\Exception $e) {
269
			$this->logger->logException($e, ['app' => 'core']);
270
			return new JSONResponse(['data' => ['message' => $this->l->t('An error occurred. Please contact your admin.')]], Http::STATUS_BAD_REQUEST);
271
		}
272
	}
273
274
	/**
275
	 * @NoAdminRequired
276
	 *
277
	 * @return JSONResponse|DataDisplayResponse
278
	 */
279
	public function getTmpAvatar() {
280
		$tmpAvatar = $this->cache->get('tmpAvatar');
281 View Code Duplication
		if (is_null($tmpAvatar)) {
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...
282
			return new JSONResponse(['data' => [
283
										'message' => $this->l->t("No temporary profile picture available, try again")
284
									]],
285
									Http::STATUS_NOT_FOUND);
286
		}
287
288
		$image = new \OC_Image($tmpAvatar);
289
290
		$resp = new DataDisplayResponse($image->data(),
291
				Http::STATUS_OK,
292
				['Content-Type' => $image->mimeType()]);
293
294
		$resp->setETag(crc32($image->data()));
295
		$resp->cacheFor(0);
296
		$resp->setLastModified(new \DateTime('now', new \DateTimeZone('GMT')));
297
		return $resp;
298
	}
299
300
	/**
301
	 * @NoAdminRequired
302
	 *
303
	 * @param array $crop
304
	 * @return JSONResponse
305
	 */
306
	public function postCroppedAvatar($crop) {
307 View Code Duplication
		if (is_null($crop)) {
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...
308
			return new JSONResponse(['data' => ['message' => $this->l->t("No crop data provided")]],
309
									Http::STATUS_BAD_REQUEST);
310
		}
311
312
		if (!isset($crop['x'], $crop['y'], $crop['w'], $crop['h'])) {
313
			return new JSONResponse(['data' => ['message' => $this->l->t("No valid crop data provided")]],
314
									Http::STATUS_BAD_REQUEST);
315
		}
316
317
		$tmpAvatar = $this->cache->get('tmpAvatar');
318 View Code Duplication
		if (is_null($tmpAvatar)) {
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...
319
			return new JSONResponse(['data' => [
320
										'message' => $this->l->t("No temporary profile picture available, try again")
321
									]],
322
									Http::STATUS_BAD_REQUEST);
323
		}
324
325
		$image = new \OC_Image($tmpAvatar);
326
		$image->crop($crop['x'], $crop['y'], round($crop['w']), round($crop['h']));
327
		try {
328
			$avatar = $this->avatarManager->getAvatar($this->userId);
329
			$avatar->set($image);
330
			// Clean up
331
			$this->cache->remove('tmpAvatar');
332
			return new JSONResponse(['status' => 'success']);
333
		} catch (\OC\NotSquareException $e) {
334
			return new JSONResponse(['data' => ['message' => $this->l->t('Crop is not square')]],
335
									Http::STATUS_BAD_REQUEST);
336
		} catch (\Exception $e) {
337
			$this->logger->logException($e, ['app' => 'core']);
338
			return new JSONResponse(['data' => ['message' => $this->l->t('An error occurred. Please contact your admin.')]], Http::STATUS_BAD_REQUEST);
339
		}
340
	}
341
}
342