Completed
Push — master ( 54a5fe...db80fb )
by Lukas
77:50 queued 63:01
created

ThemingController::getStylesheet()   C

Complexity

Conditions 8
Paths 64

Size

Total Lines 120
Code Lines 100

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 100
nc 64
nop 0
dl 0
loc 120
rs 5.2676
c 0
b 0
f 0

How to fix   Long Method   

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 Bjoern Schiessle <[email protected]>
4
 * @copyright Copyright (c) 2016 Lukas Reschke <[email protected]>
5
 *
6
 * @author Bjoern Schiessle <[email protected]>
7
 * @author Julius Haertl <[email protected]>
8
 * @author Lukas Reschke <[email protected]>
9
 * @author oparoz <[email protected]>
10
 *
11
 * @license GNU AGPL version 3 or any later version
12
 *
13
 * This program is free software: you can redistribute it and/or modify
14
 * it under the terms of the GNU Affero General Public License as
15
 * published by the Free Software Foundation, either version 3 of the
16
 * License, or (at your option) any later version.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
 * GNU Affero General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU Affero General Public License
24
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
25
 *
26
 */
27
28
namespace OCA\Theming\Controller;
29
30
use OCA\Theming\ThemingDefaults;
31
use OCP\AppFramework\Controller;
32
use OCP\AppFramework\Http;
33
use OCP\AppFramework\Http\DataDownloadResponse;
34
use OCP\AppFramework\Http\FileDisplayResponse;
35
use OCP\AppFramework\Http\DataResponse;
36
use OCP\AppFramework\Http\NotFoundResponse;
37
use OCP\AppFramework\Utility\ITimeFactory;
38
use OCP\Files\File;
39
use OCP\Files\IAppData;
40
use OCP\Files\NotFoundException;
41
use OCP\IConfig;
42
use OCP\IL10N;
43
use OCP\IRequest;
44
use OCA\Theming\Util;
45
use OCP\ITempManager;
46
47
/**
48
 * Class ThemingController
49
 *
50
 * handle ajax requests to update the theme
51
 *
52
 * @package OCA\Theming\Controller
53
 */
54
class ThemingController extends Controller {
55
	/** @var ThemingDefaults */
56
	private $template;
57
	/** @var Util */
58
	private $util;
59
	/** @var ITimeFactory */
60
	private $timeFactory;
61
	/** @var IL10N */
62
	private $l;
63
	/** @var IConfig */
64
	private $config;
65
	/** @var ITempManager */
66
	private $tempManager;
67
	/** @var IAppData */
68
	private $appData;
69
70
	/**
71
	 * ThemingController constructor.
72
	 *
73
	 * @param string $appName
74
	 * @param IRequest $request
75
	 * @param IConfig $config
76
	 * @param ThemingDefaults $template
77
	 * @param Util $util
78
	 * @param ITimeFactory $timeFactory
79
	 * @param IL10N $l
80
	 * @param ITempManager $tempManager
81
	 * @param IAppData $appData
82
	 */
83 View Code Duplication
	public function __construct(
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
		$appName,
85
		IRequest $request,
86
		IConfig $config,
87
		ThemingDefaults $template,
88
		Util $util,
89
		ITimeFactory $timeFactory,
90
		IL10N $l,
91
		ITempManager $tempManager,
92
		IAppData $appData
93
	) {
94
		parent::__construct($appName, $request);
95
96
		$this->template = $template;
97
		$this->util = $util;
98
		$this->timeFactory = $timeFactory;
99
		$this->l = $l;
100
		$this->config = $config;
101
		$this->tempManager = $tempManager;
102
		$this->appData = $appData;
103
	}
104
105
	/**
106
	 * @param string $setting
107
	 * @param string $value
108
	 * @return DataResponse
109
	 * @internal param string $color
110
	 */
111
	public function updateStylesheet($setting, $value) {
112
		$value = trim($value);
113
		switch ($setting) {
114 View Code Duplication
			case 'name':
115
				if (strlen($value) > 250) {
116
					return new DataResponse([
117
						'data' => [
118
							'message' => $this->l->t('The given name is too long'),
119
						],
120
						'status' => 'error'
121
					]);
122
				}
123
				break;
124 View Code Duplication
			case 'url':
125
				if (strlen($value) > 500) {
126
					return new DataResponse([
127
						'data' => [
128
							'message' => $this->l->t('The given web address is too long'),
129
						],
130
						'status' => 'error'
131
					]);
132
				}
133
				break;
134 View Code Duplication
			case 'slogan':
135
				if (strlen($value) > 500) {
136
					return new DataResponse([
137
						'data' => [
138
							'message' => $this->l->t('The given slogan is too long'),
139
						],
140
						'status' => 'error'
141
					]);
142
				}
143
				break;
144 View Code Duplication
			case 'color':
145
				if (!preg_match('/^\#([0-9a-f]{3}|[0-9a-f]{6})$/i', $value)) {
146
					return new DataResponse([
147
						'data' => [
148
							'message' => $this->l->t('The given color is invalid'),
149
						],
150
						'status' => 'error'
151
					]);
152
				}
153
				break;
154
		}
155
156
		$this->template->set($setting, $value);
157
		return new DataResponse(
158
			[
159
				'data' =>
160
					[
161
						'message' => $this->l->t('Saved')
162
					],
163
				'status' => 'success'
164
			]
165
		);
166
	}
167
168
	/**
169
	 * Update the logos and background image
170
	 *
171
	 * @return DataResponse
172
	 */
173
	public function updateLogo() {
174
		$newLogo = $this->request->getUploadedFile('uploadlogo');
175
		$newBackgroundLogo = $this->request->getUploadedFile('upload-login-background');
176 View Code Duplication
		if (empty($newLogo) && empty($newBackgroundLogo)) {
177
			return new DataResponse(
178
				[
179
					'data' => [
180
						'message' => $this->l->t('No file uploaded')
181
					]
182
				],
183
				Http::STATUS_UNPROCESSABLE_ENTITY
184
			);
185
		}
186
187
		$name = '';
188
		try {
189
			$folder = $this->appData->getFolder('images');
190
		} catch (NotFoundException $e) {
191
			$folder = $this->appData->newFolder('images');
192
		}
193
194
		if(!empty($newLogo)) {
195
			$target = $folder->newFile('logo');
196
			$target->putContent(file_get_contents($newLogo['tmp_name'], 'r'));
197
			$this->template->set('logoMime', $newLogo['type']);
198
			$name = $newLogo['name'];
199
		}
200
		if(!empty($newBackgroundLogo)) {
201
			$target = $folder->newFile('background');
202
			$image = @imagecreatefromstring(file_get_contents($newBackgroundLogo['tmp_name'], 'r'));
203
			if($image === false) {
204
				return new DataResponse(
205
					[
206
						'data' => [
207
							'message' => $this->l->t('Unsupported image type'),
208
						],
209
						'status' => 'failure',
210
					],
211
					Http::STATUS_UNPROCESSABLE_ENTITY
212
				);
213
			}
214
215
			// Optimize the image since some people may upload images that will be
216
			// either to big or are not progressive rendering.
217
			$tmpFile = $this->tempManager->getTemporaryFile();
218
			if(function_exists('imagescale')) {
219
				// FIXME: Once PHP 5.5.0 is a requirement the above check can be removed
220
				// Workaround for https://bugs.php.net/bug.php?id=65171
221
				$newHeight = imagesy($image)/(imagesx($image)/1920);
222
				$image = imagescale($image, 1920, $newHeight);
223
			}
224
			imageinterlace($image, 1);
225
			imagejpeg($image, $tmpFile, 75);
226
			imagedestroy($image);
227
228
			$target->putContent(file_get_contents($tmpFile, 'r'));
229
			$this->template->set('backgroundMime', $newBackgroundLogo['type']);
230
			$name = $newBackgroundLogo['name'];
231
		}
232
233
		return new DataResponse(
234
			[
235
				'data' =>
236
					[
237
						'name' => $name,
238
						'message' => $this->l->t('Saved')
239
					],
240
				'status' => 'success'
241
			]
242
		);
243
	}
244
245
	/**
246
	 * Revert setting to default value
247
	 *
248
	 * @param string $setting setting which should be reverted
249
	 * @return DataResponse
250
	 */
251
	public function undo($setting) {
252
		$value = $this->template->undo($setting);
253
		return new DataResponse(
254
			[
255
				'data' =>
256
					[
257
						'value' => $value,
258
						'message' => $this->l->t('Saved')
259
					],
260
				'status' => 'success'
261
			]
262
		);
263
	}
264
265
	/**
266
	 * @PublicPage
267
	 * @NoCSRFRequired
268
	 *
269
	 * @return FileDisplayResponse|NotFoundResponse
270
	 */
271 View Code Duplication
	public function getLogo() {
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...
272
		try {
273
			/** @var File $file */
274
			$file = $this->appData->getFolder('images')->getFile('logo');
275
		} catch (NotFoundException $e) {
276
			return new NotFoundResponse();
277
		}
278
279
		$response = new FileDisplayResponse($file);
280
		$response->cacheFor(3600);
281
		$expires = new \DateTime();
282
		$expires->setTimestamp($this->timeFactory->getTime());
283
		$expires->add(new \DateInterval('PT24H'));
284
		$response->addHeader('Expires', $expires->format(\DateTime::RFC2822));
285
		$response->addHeader('Pragma', 'cache');
286
		$response->addHeader('Content-Type', $this->config->getAppValue($this->appName, 'logoMime', ''));
287
		return $response;
288
	}
289
290
	/**
291
	 * @PublicPage
292
	 * @NoCSRFRequired
293
	 *
294
	 * @return FileDisplayResponse|NotFoundResponse
295
	 */
296 View Code Duplication
	public function getLoginBackground() {
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...
297
		try {
298
			/** @var File $file */
299
			$file = $this->appData->getFolder('images')->getFile('background');
300
		} catch (NotFoundException $e) {
301
			return new NotFoundResponse();
302
		}
303
304
		$response = new FileDisplayResponse($file);
305
		$response->cacheFor(3600);
306
		$expires = new \DateTime();
307
		$expires->setTimestamp($this->timeFactory->getTime());
308
		$expires->add(new \DateInterval('PT24H'));
309
		$response->addHeader('Expires', $expires->format(\DateTime::RFC2822));
310
		$response->addHeader('Pragma', 'cache');
311
		$response->addHeader('Content-Type', $this->config->getAppValue($this->appName, 'backgroundMime', ''));
312
		return $response;
313
	}
314
315
	/**
316
	 * @NoCSRFRequired
317
	 * @PublicPage
318
	 *
319
	 * @return DataDownloadResponse
320
	 */
321
	public function getStylesheet() {
322
		$cacheBusterValue = $this->config->getAppValue('theming', 'cachebuster', '0');
323
		$responseCss = '';
324
		$color = $this->config->getAppValue($this->appName, 'color');
325
		$elementColor = $this->util->elementColor($color);
326
327
		if($this->util->invertTextColor($color)) {
328
			$textColor = '#000000';
329
		} else {
330
			$textColor = '#ffffff';
331
		}
332
333
		if($color !== '') {
334
			$responseCss .= sprintf(
335
				'#body-user #header,#body-settings #header,#body-public #header,#body-login,.searchbox input[type="search"]:focus,.searchbox input[type="search"]:active,.searchbox input[type="search"]:valid {background-color: %s}' . "\n",
336
				$color
337
			);
338
			$responseCss .= sprintf('input[type="checkbox"].checkbox:checked:enabled:not(.checkbox--white) + label:before {' .
339
				'background-image:url(\'%s/core/img/actions/checkmark-white.svg\');' .
340
				'background-color: %s; background-position: center center; background-size:contain;' .
341
				'width:12px; height:12px; padding:0; margin:2px 6px 6px 2px; border-radius:1px;' .
342
				"}\n",
343
				\OC::$WEBROOT,
344
				$elementColor
345
			);
346
			$responseCss .= 'input[type="radio"].radio:checked:not(.radio--white):not(:disabled) + label:before {' .
347
				'background-image: url(\'data:image/svg+xml;base64,'.$this->util->generateRadioButton($elementColor).'\');' .
348
				"}\n";
349
			$responseCss .= '.primary, input[type="submit"].primary, input[type="button"].primary, button.primary, .button.primary,' .
350
				'.primary:active, input[type="submit"].primary:active, input[type="button"].primary:active, button.primary:active, .button.primary:active {' .
351
				'border: 1px solid '.$elementColor.';'.
352
				'background-color: '.$elementColor.';'.
353
				'color: ' . $textColor . ';'.
354
				"}\n" .
355
				'.primary:hover, input[type="submit"].primary:hover, input[type="button"].primary:hover, button.primary:hover, .button.primary:hover,' .
356
				'.primary:focus, input[type="submit"].primary:focus, input[type="button"].primary:focus, button.primary:focus, .button.primary:focus {' .
357
				'border: 1px solid '.$elementColor.';'.
358
				'background-color: '.$elementColor.';'.
359
				'color: ' . $textColor . ';'.
360
				"}\n" .
361
				'.primary:disabled, input[type="submit"].primary:disabled, input[type="button"].primary:disabled, button.primary:disabled, .button.primary:disabled,' .
362
				'.primary:disabled:hover, input[type="submit"].primary:disabled:hover, input[type="button"].primary:disabled:hover, button.primary:disabled:hover, .button.primary:disabled:hover,' .
363
				'.primary:disabled:focus, input[type="submit"].primary:disabled:focus, input[type="button"].primary:disabled:focus, button.primary:disabled:focus, .button.primary:disabled:focus {' .
364
				'border: 1px solid '.$elementColor.';'.
365
				'background-color: '.$elementColor.';'.
366
				'opacity: 0.4;' .
367
				'color: '.$textColor.';'.
368
				"}\n";
369
			$responseCss .= '.ui-widget-header { border: 1px solid ' . $color . '; background: '. $color . '; color: #ffffff;' . "}\n";
370
			$responseCss .= '.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active {' .
371
				'border: 1px solid ' . $color . ';' .
372
				'color: ' . $elementColor . ';' .
373
				"}\n";
374
			$responseCss .= '.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited {' .
375
				'color: ' . $elementColor . ';' .
376
				"}\n";
377
			$responseCss .= '
378
				#firstrunwizard .firstrunwizard-header {
379
					background-color: ' . $color . ';
380
				}
381
				#firstrunwizard p a {
382
					color: ' . $color . ';
383
				}
384
				';
385
			$responseCss .= sprintf('.nc-theming-main-background {background-color: %s}' . "\n", $color);
386
			$responseCss .= sprintf('.nc-theming-main-text {color: %s}' . "\n", $color);
387
			$responseCss .= sprintf('#app-navigation li:hover > a, #app-navigation li:focus > a, #app-navigation a:focus, #app-navigation .selected, #app-navigation .selected a, #app-navigation .active, #app-navigation .active a {box-shadow: inset 2px 0 %s}' . "\n", $color);
388
389
		}
390
		$logo = $this->config->getAppValue($this->appName, 'logoMime');
391
		if($logo !== '') {
392
			$responseCss .= sprintf(
393
				'#header .logo {' .
394
				'background-image: url(\'./logo?v='.$cacheBusterValue.'\');' .
395
				'background-size: contain;' .
396
				'}' . "\n" .
397
				'#header .logo-icon {' .
398
				'background-image: url(\'./logo?v='.$cacheBusterValue.'\');' .
399
				'background-size: contain;' .
400
				'}' . "\n" .
401
				'#firstrunwizard .firstrunwizard-header .logo {' .
402
				'background-image: url(\'./logo?v='.$cacheBusterValue.'\');' .
403
				'background-size: contain;' .
404
				'}' . "\n"
405
			);
406
		}
407
		$backgroundLogo = $this->config->getAppValue($this->appName, 'backgroundMime');
408
		if($backgroundLogo !== '') {
409
			$responseCss .= '#body-login {background-image: url(\'./loginbackground?v='.$cacheBusterValue.'\');}' . "\n";
410
			$responseCss .= '#firstrunwizard .firstrunwizard-header {' .
411
				'background-image: url(\'./loginbackground?v='.$cacheBusterValue.'\');' .
412
			'}' . "\n";
413
		}
414
		if($this->util->invertTextColor($color)) {
415
			$responseCss .= '#header .header-appname, #expandDisplayName { color: #000000; }' . "\n";
416
			$responseCss .= '#header .icon-caret { background-image: url(\'' . \OC::$WEBROOT . '/core/img/actions/caret-dark.svg\'); }' . "\n";
417
			$responseCss .= '.searchbox input[type="search"] { background: transparent url(\'' . \OC::$WEBROOT . '/core/img/actions/search.svg\') no-repeat 6px center; color: #000; }' . "\n";
418
			$responseCss .= '.searchbox input[type="search"]:focus,.searchbox input[type="search"]:active,.searchbox input[type="search"]:valid { color: #000; border: 1px solid rgba(0, 0, 0, .5); }' . "\n";
419
			$responseCss .= '#body-login input.login { background-image: url(\'' . \OC::$WEBROOT . '/core/img/actions/confirm.svg?v=2\'); }' . "\n";
420
			$responseCss .= '.nc-theming-contrast {color: #000000}' . "\n";
421
			$responseCss .= '.ui-widget-header { color: #000000; }' . "\n";
422
		} else {
423
			$responseCss .= '.nc-theming-contrast {color: #ffffff}' . "\n";
424
		}
425
426
		if($logo !== '' or $color !== '') {
427
			$responseCss .= '.icon-file,.icon-filetype-text {' .
428
				'background-image: url(\'./img/core/filetypes/text.svg?v='.$cacheBusterValue.'\');' . "}\n" .
429
				'.icon-folder, .icon-filetype-folder {' .
430
				'background-image: url(\'./img/core/filetypes/folder.svg?v='.$cacheBusterValue.'\');' . "}\n" .
431
				'.icon-filetype-folder-drag-accept {' .
432
				'background-image: url(\'./img/core/filetypes/folder-drag-accept.svg?v='.$cacheBusterValue.'\')!important;' . "}\n";
433
		}
434
435
		$response = new DataDownloadResponse($responseCss, 'style', 'text/css');
436
		$response->addHeader('Expires', date(\DateTime::RFC2822, $this->timeFactory->getTime()));
437
		$response->addHeader('Pragma', 'cache');
438
		$response->cacheFor(3600);
439
		return $response;
440
	}
441
	/**
442
	 * @NoCSRFRequired
443
	 * @PublicPage
444
	 *
445
	 * @return DataDownloadResponse
446
	 */
447
	public function getJavascript() {
448
		$cacheBusterValue = $this->config->getAppValue('theming', 'cachebuster', '0');
449
		$responseJS = '(function() {
450
	OCA.Theming = {
451
		name: ' . json_encode($this->template->getName()) . ',
452
		url: ' . json_encode($this->template->getBaseUrl()) . ',
453
		slogan: ' . json_encode($this->template->getSlogan()) . ',
454
		color: ' . json_encode($this->template->getMailHeaderColor()) . ',
455
		inverted: ' . json_encode($this->util->invertTextColor($this->template->getMailHeaderColor())) . ',
456
		cacheBuster: ' . json_encode($cacheBusterValue). '
457
	};
458
})();';
459
		$response = new DataDownloadResponse($responseJS, 'javascript', 'text/javascript');
460
		$response->addHeader('Expires', date(\DateTime::RFC2822, $this->timeFactory->getTime()));
461
		$response->addHeader('Pragma', 'cache');
462
		$response->cacheFor(3600);
463
		return $response;
464
	}
465
}
466