Completed
Push — master ( 3e14f2...b3a0de )
by Morris
15:06
created

ThemingController   C

Complexity

Total Complexity 29

Size/Duplication

Total Lines 391
Duplicated Lines 17.65 %

Coupling/Cohesion

Components 1
Dependencies 21

Importance

Changes 0
Metric Value
wmc 29
lcom 1
cbo 21
dl 69
loc 391
rs 6.1111
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A getJavascript() 0 18 1
B __construct() 29 29 1
C updateStylesheet() 40 61 9
D uploadImage() 0 95 10
A undo() 0 22 2
A getImage() 0 17 2
B getStylesheet() 0 26 3
B getManifest() 0 28 1

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 Bjoern Schiessle <[email protected]>
4
 * @copyright Copyright (c) 2016 Lukas Reschke <[email protected]>
5
 *
6
 * @author Arthur Schiwon <[email protected]>
7
 * @author Bjoern Schiessle <[email protected]>
8
 * @author Daniel Calviño Sánchez <[email protected]>
9
 * @author Jan-Christoph Borchardt <[email protected]>
10
 * @author Joas Schilling <[email protected]>
11
 * @author Julius Haertl <[email protected]>
12
 * @author Julius Härtl <[email protected]>
13
 * @author Lukas Reschke <[email protected]>
14
 * @author Robin Appelman <[email protected]>
15
 *
16
 * @license GNU AGPL version 3 or any later version
17
 *
18
 * This program is free software: you can redistribute it and/or modify
19
 * it under the terms of the GNU Affero General Public License as
20
 * published by the Free Software Foundation, either version 3 of the
21
 * License, or (at your option) any later version.
22
 *
23
 * This program is distributed in the hope that it will be useful,
24
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26
 * GNU Affero General Public License for more details.
27
 *
28
 * You should have received a copy of the GNU Affero General Public License
29
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
30
 *
31
 */
32
33
namespace OCA\Theming\Controller;
34
35
use OC\Template\SCSSCacher;
36
use OCA\Theming\ImageManager;
37
use OCA\Theming\ThemingDefaults;
38
use OCP\AppFramework\Controller;
39
use OCP\AppFramework\Http;
40
use OCP\AppFramework\Http\DataDownloadResponse;
41
use OCP\AppFramework\Http\FileDisplayResponse;
42
use OCP\AppFramework\Http\DataResponse;
43
use OCP\AppFramework\Http\NotFoundResponse;
44
use OCP\AppFramework\Utility\ITimeFactory;
45
use OCP\Files\File;
46
use OCP\Files\IAppData;
47
use OCP\Files\NotFoundException;
48
use OCP\Files\NotPermittedException;
49
use OCP\IConfig;
50
use OCP\IL10N;
51
use OCP\IRequest;
52
use OCA\Theming\Util;
53
use OCP\ITempManager;
54
use OCP\IURLGenerator;
55
use OCP\App\IAppManager;
56
57
/**
58
 * Class ThemingController
59
 *
60
 * handle ajax requests to update the theme
61
 *
62
 * @package OCA\Theming\Controller
63
 */
64
class ThemingController extends Controller {
65
	/** @var ThemingDefaults */
66
	private $themingDefaults;
67
	/** @var Util */
68
	private $util;
69
	/** @var ITimeFactory */
70
	private $timeFactory;
71
	/** @var IL10N */
72
	private $l10n;
73
	/** @var IConfig */
74
	private $config;
75
	/** @var ITempManager */
76
	private $tempManager;
77
	/** @var IAppData */
78
	private $appData;
79
	/** @var SCSSCacher */
80
	private $scssCacher;
81
	/** @var IURLGenerator */
82
	private $urlGenerator;
83
	/** @var IAppManager */
84
	private $appManager;
85
	/** @var ImageManager */
86
	private $imageManager;
87
88
	/**
89
	 * ThemingController constructor.
90
	 *
91
	 * @param string $appName
92
	 * @param IRequest $request
93
	 * @param IConfig $config
94
	 * @param ThemingDefaults $themingDefaults
95
	 * @param Util $util
96
	 * @param ITimeFactory $timeFactory
97
	 * @param IL10N $l
98
	 * @param ITempManager $tempManager
99
	 * @param IAppData $appData
100
	 * @param SCSSCacher $scssCacher
101
	 * @param IURLGenerator $urlGenerator
102
	 * @param IAppManager $appManager
103
	 * @param ImageManager $imageManager
104
	 */
105 View Code Duplication
	public function __construct(
106
		$appName,
107
		IRequest $request,
108
		IConfig $config,
109
		ThemingDefaults $themingDefaults,
110
		Util $util,
111
		ITimeFactory $timeFactory,
112
		IL10N $l,
113
		ITempManager $tempManager,
114
		IAppData $appData,
115
		SCSSCacher $scssCacher,
116
		IURLGenerator $urlGenerator,
117
		IAppManager $appManager,
118
		ImageManager $imageManager
119
	) {
120
		parent::__construct($appName, $request);
121
122
		$this->themingDefaults = $themingDefaults;
123
		$this->util = $util;
124
		$this->timeFactory = $timeFactory;
125
		$this->l10n = $l;
126
		$this->config = $config;
127
		$this->tempManager = $tempManager;
128
		$this->appData = $appData;
129
		$this->scssCacher = $scssCacher;
130
		$this->urlGenerator = $urlGenerator;
131
		$this->appManager = $appManager;
132
		$this->imageManager = $imageManager;
133
	}
134
135
	/**
136
	 * @param string $setting
137
	 * @param string $value
138
	 * @return DataResponse
139
	 * @throws NotPermittedException
140
	 */
141
	public function updateStylesheet($setting, $value) {
142
		$value = trim($value);
143
		switch ($setting) {
144 View Code Duplication
			case 'name':
145
				if (strlen($value) > 250) {
146
					return new DataResponse([
147
						'data' => [
148
							'message' => $this->l10n->t('The given name is too long'),
149
						],
150
						'status' => 'error'
151
					]);
152
				}
153
				break;
154 View Code Duplication
			case 'url':
155
				if (strlen($value) > 500) {
156
					return new DataResponse([
157
						'data' => [
158
							'message' => $this->l10n->t('The given web address is too long'),
159
						],
160
						'status' => 'error'
161
					]);
162
				}
163
				break;
164 View Code Duplication
			case 'slogan':
165
				if (strlen($value) > 500) {
166
					return new DataResponse([
167
						'data' => [
168
							'message' => $this->l10n->t('The given slogan is too long'),
169
						],
170
						'status' => 'error'
171
					]);
172
				}
173
				break;
174 View Code Duplication
			case 'color':
175
				if (!preg_match('/^\#([0-9a-f]{3}|[0-9a-f]{6})$/i', $value)) {
176
					return new DataResponse([
177
						'data' => [
178
							'message' => $this->l10n->t('The given color is invalid'),
179
						],
180
						'status' => 'error'
181
					]);
182
				}
183
				break;
184
		}
185
186
		$this->themingDefaults->set($setting, $value);
187
188
		// reprocess server scss for preview
189
		$cssCached = $this->scssCacher->process(\OC::$SERVERROOT, 'core/css/server.scss', 'core');
0 ignored issues
show
Unused Code introduced by
$cssCached 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...
190
191
		return new DataResponse(
192
			[
193
				'data' =>
194
					[
195
						'message' => $this->l10n->t('Saved'),
196
						'serverCssUrl' => $this->urlGenerator->linkTo('', $this->scssCacher->getCachedSCSS('core', '/core/css/server.scss'))
197
					],
198
				'status' => 'success'
199
			]
200
		);
201
	}
202
203
	/**
204
	 * @return DataResponse
205
	 * @throws NotPermittedException
206
	 */
207
	public function uploadImage(): DataResponse {
208
		// logo / background
209
		// new: favicon logo-header
210
		//
211
		$key = $this->request->getParam('key');
212
		$image = $this->request->getUploadedFile('image');
213
		$error = null;
214
		$phpFileUploadErrors = [
215
			UPLOAD_ERR_OK => $this->l10n->t('The file was uploaded'),
216
			UPLOAD_ERR_INI_SIZE => $this->l10n->t('The uploaded file exceeds the upload_max_filesize directive in php.ini'),
217
			UPLOAD_ERR_FORM_SIZE => $this->l10n->t('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form'),
218
			UPLOAD_ERR_PARTIAL => $this->l10n->t('The file was only partially uploaded'),
219
			UPLOAD_ERR_NO_FILE => $this->l10n->t('No file was uploaded'),
220
			UPLOAD_ERR_NO_TMP_DIR => $this->l10n->t('Missing a temporary folder'),
221
			UPLOAD_ERR_CANT_WRITE => $this->l10n->t('Could not write file to disk'),
222
			UPLOAD_ERR_EXTENSION => $this->l10n->t('A PHP extension stopped the file upload'),
223
		];
224
		if (empty($image)) {
225
			$error = $this->l10n->t('No file uploaded');
226
		}
227
		if (!empty($image) && array_key_exists('error', $image) && $image['error'] !== UPLOAD_ERR_OK) {
228
			$error = $phpFileUploadErrors[$image['error']];
229
		}
230
231
		if ($error !== null) {
232
			return new DataResponse(
233
				[
234
					'data' => [
235
						'message' => $error
236
					],
237
					'status' => 'failure',
238
				],
239
				Http::STATUS_UNPROCESSABLE_ENTITY
240
			);
241
		}
242
243
		$name = '';
0 ignored issues
show
Unused Code introduced by
$name 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...
244
		try {
245
			$folder = $this->appData->getFolder('images');
246
		} catch (NotFoundException $e) {
247
			$folder = $this->appData->newFolder('images');
248
		}
249
250
		$target = $folder->newFile($key);
251
		$supportedFormats = ['image/jpeg', 'image/png', 'image/gif', 'image/svg+xml', 'text/svg'];
252
		if (!in_array($image['type'], $supportedFormats)) {
253
			return new DataResponse(
254
				[
255
					'data' => [
256
						'message' => $this->l10n->t('Unsupported image type'),
257
					],
258
					'status' => 'failure',
259
				],
260
				Http::STATUS_UNPROCESSABLE_ENTITY
261
			);
262
		}
263
264
		$resizeKeys = ['background'];
265
		if (in_array($key, $resizeKeys, true)) {
266
			// Optimize the image since some people may upload images that will be
267
			// either to big or are not progressive rendering.
268
			$newImage = @imagecreatefromstring(file_get_contents($image['tmp_name'], 'r'));
269
270
			$tmpFile = $this->tempManager->getTemporaryFile();
271
			$newWidth = imagesx($newImage) < 4096 ? imagesx($newImage) : 4096;
272
			$newHeight = imagesy($newImage) / (imagesx($newImage) / $newWidth);
273
			$outputImage = imagescale($newImage, $newWidth, $newHeight);
274
275
			imageinterlace($outputImage, 1);
276
			imagejpeg($outputImage, $tmpFile, 75);
277
			imagedestroy($outputImage);
278
279
			$target->putContent(file_get_contents($tmpFile, 'r'));
280
		} else {
281
			$target->putContent(file_get_contents($image['tmp_name'], 'r'));
282
		}
283
		$name = $image['name'];
284
285
		$this->themingDefaults->set($key.'Mime', $image['type']);
286
287
		$cssCached = $this->scssCacher->process(\OC::$SERVERROOT, 'core/css/server.scss', 'core');
0 ignored issues
show
Unused Code introduced by
$cssCached 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...
288
289
		return new DataResponse(
290
			[
291
				'data' =>
292
					[
293
						'name' => $name,
294
						'url' => $this->imageManager->getImageUrl($key),
295
						'message' => $this->l10n->t('Saved'),
296
						'serverCssUrl' => $this->urlGenerator->linkTo('', $this->scssCacher->getCachedSCSS('core', '/core/css/server.scss'))
297
					],
298
				'status' => 'success'
299
			]
300
		);
301
	}
302
303
	/**
304
	 * Revert setting to default value
305
	 *
306
	 * @param string $setting setting which should be reverted
307
	 * @return DataResponse
308
	 * @throws NotPermittedException
309
	 */
310
	public function undo(string $setting): DataResponse {
311
		$value = $this->themingDefaults->undo($setting);
312
		// reprocess server scss for preview
313
		$cssCached = $this->scssCacher->process(\OC::$SERVERROOT, 'core/css/server.scss', 'core');
0 ignored issues
show
Unused Code introduced by
$cssCached 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...
314
315
		if (strpos($setting, 'Mime') !== -1) {
316
			$imageKey = str_replace('Mime', '', $setting);
317
			$this->imageManager->delete($imageKey);
318
		}
319
320
		return new DataResponse(
321
			[
322
				'data' =>
323
					[
324
						'value' => $value,
325
						'message' => $this->l10n->t('Saved'),
326
						'serverCssUrl' => $this->urlGenerator->linkTo('', $this->scssCacher->getCachedSCSS('core', '/core/css/server.scss'))
327
					],
328
				'status' => 'success'
329
			]
330
		);
331
	}
332
333
	/**
334
	 * @PublicPage
335
	 * @NoCSRFRequired
336
	 *
337
	 * @param string $key
338
	 * @return FileDisplayResponse|NotFoundResponse
339
	 * @throws \Exception
340
	 */
341
	public function getImage(string $key) {
342
		try {
343
			$file = $this->imageManager->getImage($key);
344
		} catch (NotFoundException $e) {
345
			return new NotFoundResponse();
346
		}
347
348
		$response = new FileDisplayResponse($file);
349
		$response->cacheFor(3600);
350
		$expires = new \DateTime();
351
		$expires->setTimestamp($this->timeFactory->getTime());
352
		$expires->add(new \DateInterval('PT24H'));
353
		$response->addHeader('Expires', $expires->format(\DateTime::RFC2822));
354
		$response->addHeader('Pragma', 'cache');
355
		$response->addHeader('Content-Type', $this->config->getAppValue($this->appName, $key . 'Mime', ''));
356
		return $response;
357
	}
358
359
	/**
360
	 * @NoCSRFRequired
361
	 * @PublicPage
362
	 *
363
	 * @return FileDisplayResponse|NotFoundResponse
364
	 * @throws NotPermittedException
365
	 * @throws \Exception
366
	 * @throws \OCP\App\AppPathNotFoundException
367
	 */
368
	public function getStylesheet() {
369
		$appPath = $this->appManager->getAppPath('theming');
370
371
		/* SCSSCacher is required here
372
		 * We cannot rely on automatic caching done by \OC_Util::addStyle,
373
		 * since we need to add the cacheBuster value to the url
374
		 */
375
		$cssCached = $this->scssCacher->process($appPath, 'css/theming.scss', 'theming');
376
		if(!$cssCached) {
377
			return new NotFoundResponse();
378
		}
379
380
		try {
381
			$cssFile = $this->scssCacher->getCachedCSS('theming', 'theming.css');
382
			$response = new FileDisplayResponse($cssFile, Http::STATUS_OK, ['Content-Type' => 'text/css']);
383
			$response->cacheFor(86400);
384
			$expires = new \DateTime();
385
			$expires->setTimestamp($this->timeFactory->getTime());
386
			$expires->add(new \DateInterval('PT24H'));
387
			$response->addHeader('Expires', $expires->format(\DateTime::RFC1123));
388
			$response->addHeader('Pragma', 'cache');
389
			return $response;
390
		} catch (NotFoundException $e) {
391
			return new NotFoundResponse();
392
		}
393
	}
394
395
	/**
396
	 * @NoCSRFRequired
397
	 * @PublicPage
398
	 *
399
	 * @return DataDownloadResponse
400
	 */
401
	public function getJavascript() {
402
		$cacheBusterValue = $this->config->getAppValue('theming', 'cachebuster', '0');
403
		$responseJS = '(function() {
404
	OCA.Theming = {
405
		name: ' . json_encode($this->themingDefaults->getName()) . ',
406
		url: ' . json_encode($this->themingDefaults->getBaseUrl()) . ',
407
		slogan: ' . json_encode($this->themingDefaults->getSlogan()) . ',
408
		color: ' . json_encode($this->themingDefaults->getColorPrimary()) . ',
409
		inverted: ' . json_encode($this->util->invertTextColor($this->themingDefaults->getColorPrimary())) . ',
410
		cacheBuster: ' . json_encode($cacheBusterValue) . '
411
	};
412
})();';
413
		$response = new DataDownloadResponse($responseJS, 'javascript', 'text/javascript');
414
		$response->addHeader('Expires', date(\DateTime::RFC2822, $this->timeFactory->getTime()));
415
		$response->addHeader('Pragma', 'cache');
416
		$response->cacheFor(3600);
417
		return $response;
418
	}
419
420
	/**
421
	 * @NoCSRFRequired
422
	 * @PublicPage
423
	 *
424
	 * @return Http\JSONResponse
425
	 */
426
	public function getManifest($app) {
427
		$cacheBusterValue = $this->config->getAppValue('theming', 'cachebuster', '0');
428
		$responseJS = [
429
			'name' => $this->themingDefaults->getName(),
430
			'start_url' => $this->urlGenerator->getBaseUrl(),
431
			'icons' =>
432
				[
433
					[
434
						'src' => $this->urlGenerator->linkToRoute('theming.Icon.getTouchIcon',
435
								['app' => $app]) . '?v=' . $cacheBusterValue,
436
						'type'=> 'image/png',
437
						'sizes'=> '128x128'
438
					],
439
					[
440
						'src' => $this->urlGenerator->linkToRoute('theming.Icon.getFavicon',
441
								['app' => $app]) . '?v=' . $cacheBusterValue,
442
						'type' => 'image/svg+xml',
443
						'sizes' => '16x16'
444
					]
445
				],
446
			'display' => 'standalone'
447
		];
448
		$response = new Http\JSONResponse($responseJS);
449
		$response->addHeader('Expires', date(\DateTime::RFC2822, $this->timeFactory->getTime()));
450
		$response->addHeader('Pragma', 'cache');
451
		$response->cacheFor(3600);
452
		return $response;
453
	}
454
}
455