Completed
Push — master ( 6c11c5...8b9ad4 )
by Robin
22:29 queued 14:09
created

ThemingController::getStylesheet()   B

Complexity

Conditions 6
Paths 32

Size

Total Lines 110
Code Lines 92

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 92
nc 32
nop 0
dl 0
loc 110
rs 8.1463
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\DataResponse;
35
use OCP\AppFramework\Http\NotFoundResponse;
36
use OCP\AppFramework\Http\StreamResponse;
37
use OCP\AppFramework\Utility\ITimeFactory;
38
use OCP\Files\File;
39
use OCP\Files\IRootFolder;
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 IRootFolder */
66
	private $rootFolder;
67
	/** @var ITempManager */
68
	private $tempManager;
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 IRootFolder $rootFolder
81
	 * @param ITempManager $tempManager
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
		IRootFolder $rootFolder,
92
		ITempManager $tempManager
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->rootFolder = $rootFolder;
102
		$this->tempManager = $tempManager;
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':
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...
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':
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...
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':
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...
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':
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...
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)) {
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...
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
		$name = '';
187
		if(!empty($newLogo)) {
188
			$target = $this->rootFolder->newFile('themedinstancelogo');
189
			stream_copy_to_stream(fopen($newLogo['tmp_name'], 'r'), $target->fopen('w'));
190
			$this->template->set('logoMime', $newLogo['type']);
191
			$name = $newLogo['name'];
192
		}
193
		if(!empty($newBackgroundLogo)) {
194
			$target = $this->rootFolder->newFile('themedbackgroundlogo');
195
196
			$image = @imagecreatefromstring(file_get_contents($newBackgroundLogo['tmp_name'], 'r'));
197
			if($image === false) {
198
				return new DataResponse(
199
					[
200
						'data' => [
201
							'message' => $this->l->t('Unsupported image type'),
202
						],
203
						'status' => 'failure',
204
					],
205
					Http::STATUS_UNPROCESSABLE_ENTITY
206
				);
207
			}
208
209
			// Optimize the image since some people may upload images that will be
210
			// either to big or are not progressive rendering.
211
			$tmpFile = $this->tempManager->getTemporaryFile();
212
			if(function_exists('imagescale')) {
213
				// FIXME: Once PHP 5.5.0 is a requirement the above check can be removed
214
				$image = imagescale($image, 1920);
215
			}
216
			imageinterlace($image, 1);
217
			imagejpeg($image, $tmpFile, 75);
218
			imagedestroy($image);
219
220
			stream_copy_to_stream(fopen($tmpFile, 'r'), $target->fopen('w'));
221
			$this->template->set('backgroundMime', $newBackgroundLogo['type']);
222
			$name = $newBackgroundLogo['name'];
223
		}
224
225
		return new DataResponse(
226
			[
227
				'data' =>
228
					[
229
						'name' => $name,
230
						'message' => $this->l->t('Saved')
231
					],
232
				'status' => 'success'
233
			]
234
		);
235
	}
236
237
	/**
238
	 * Revert setting to default value
239
	 *
240
	 * @param string $setting setting which should be reverted
241
	 * @return DataResponse
242
	 */
243
	public function undo($setting) {
244
		$value = $this->template->undo($setting);
245
		return new DataResponse(
246
			[
247
				'data' =>
248
					[
249
						'value' => $value,
250
						'message' => $this->l->t('Saved')
251
					],
252
				'status' => 'success'
253
			]
254
		);
255
	}
256
257
	/**
258
	 * @PublicPage
259
	 * @NoCSRFRequired
260
	 *
261
	 * @return StreamResponse|NotFoundResponse
262
	 */
263 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...
264
		try {
265
			/** @var File $file */
266
			$file = $this->rootFolder->get('themedinstancelogo');
267
		} catch (NotFoundException $e) {
268
			return new NotFoundResponse();
269
		}
270
271
		$response = new Http\StreamResponse($file->fopen('r'));
272
		$response->cacheFor(3600);
273
		$response->addHeader('Expires', date(\DateTime::RFC2822, $this->timeFactory->getTime()));
274
		$response->addHeader('Content-Disposition', 'attachment');
275
		$response->addHeader('Content-Type', $this->config->getAppValue($this->appName, 'logoMime', ''));
276
		$response->addHeader('Pragma', 'cache');
277
		return $response;
278
	}
279
280
	/**
281
	 * @PublicPage
282
	 * @NoCSRFRequired
283
	 *
284
	 * @return StreamResponse|NotFoundResponse
285
	 */
286 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...
287
		try {
288
			/** @var File $file */
289
			$file = $this->rootFolder->get('themedbackgroundlogo');
290
		} catch (NotFoundException $e) {
291
			return new NotFoundResponse();
292
		}
293
294
		$response = new StreamResponse($file->fopen('r'));
295
		$response->cacheFor(3600);
296
		$response->addHeader('Expires', date(\DateTime::RFC2822, $this->timeFactory->getTime()));
297
		$response->addHeader('Content-Disposition', 'attachment');
298
		$response->addHeader('Content-Type', $this->config->getAppValue($this->appName, 'backgroundMime', ''));
299
		$response->addHeader('Pragma', 'cache');
300
		return $response;
301
	}
302
303
	/**
304
	 * @NoCSRFRequired
305
	 * @PublicPage
306
	 *
307
	 * @return DataDownloadResponse
308
	 */
309
	public function getStylesheet() {
310
		$cacheBusterValue = $this->config->getAppValue('theming', 'cachebuster', '0');
311
		$responseCss = '';
312
		$color = $this->config->getAppValue($this->appName, 'color');
313
		$elementColor = $this->util->elementColor($color);
314
315
		if($this->util->invertTextColor($color)) {
316
			$textColor = '#000000';
317
		} else {
318
			$textColor = '#ffffff';
319
		}
320
321
		if($color !== '') {
322
			$responseCss .= sprintf(
323
				'#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",
324
				$color
325
			);
326
			$responseCss .= sprintf('input[type="checkbox"].checkbox:checked:enabled:not(.checkbox--white) + label:before {' .
327
				'background-image:url(\'%s/core/img/actions/checkmark-white.svg\');' .
328
				'background-color: %s; background-position: center center; background-size:contain;' .
329
				'width:12px; height:12px; padding:0; margin:2px 6px 6px 2px; border-radius:1px;' .
330
				"}\n",
331
				\OC::$WEBROOT,
332
				$elementColor
333
			);
334
			$responseCss .= 'input[type="radio"].radio:checked:not(.radio--white):not(:disabled) + label:before {' .
335
				'background-image: url(\'data:image/svg+xml;base64,'.$this->util->generateRadioButton($elementColor).'\');' .
336
				"}\n";
337
			$responseCss .= '.primary, input[type="submit"].primary, input[type="button"].primary, button.primary, .button.primary,' .
338
				'.primary:active, input[type="submit"].primary:active, input[type="button"].primary:active, button.primary:active, .button.primary:active {' .
339
				'border: 1px solid '.$elementColor.';'.
340
				'background-color: '.$elementColor.';'.
341
				'color: ' . $textColor . ';'.
342
				"}\n" .
343
				'.primary:hover, input[type="submit"].primary:hover, input[type="button"].primary:hover, button.primary:hover, .button.primary:hover,' .
344
				'.primary:focus, input[type="submit"].primary:focus, input[type="button"].primary:focus, button.primary:focus, .button.primary:focus {' .
345
				'border: 1px solid '.$elementColor.';'.
346
				'background-color: '.$elementColor.';'.
347
				'color: ' . $textColor . ';'.
348
				"}\n" .
349
				'.primary:disabled, input[type="submit"].primary:disabled, input[type="button"].primary:disabled, button.primary:disabled, .button.primary:disabled,' .
350
				'.primary:disabled:hover, input[type="submit"].primary:disabled:hover, input[type="button"].primary:disabled:hover, button.primary:disabled:hover, .button.primary:disabled:hover,' .
351
				'.primary:disabled:focus, input[type="submit"].primary:disabled:focus, input[type="button"].primary:disabled:focus, button.primary:disabled:focus, .button.primary:disabled:focus {' .
352
				'border: 1px solid '.$elementColor.';'.
353
				'background-color: '.$elementColor.';'.
354
				'opacity: 0.4;' .
355
				'color: '.$textColor.';'.
356
				"}\n";
357
			$responseCss .= '.ui-widget-header { border: 1px solid ' . $color . '; background: '. $color . '; color: #ffffff;' . "}\n";
358
			$responseCss .= '.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active {' .
359
				'border: 1px solid ' . $color . ';' .
360
				'color: ' . $elementColor . ';' .
361
				"}\n";
362
			$responseCss .= '.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited {' .
363
				'color: ' . $elementColor . ';' .
364
				"}\n";
365
			$responseCss .= '
366
				#firstrunwizard .firstrunwizard-header {
367
					background-color: ' . $color . ';
368
				}
369
				#firstrunwizard p a {
370
					color: ' . $color . ';
371
				}
372
				';
373
			$responseCss .= sprintf('.nc-theming-main-background {background-color: %s}' . "\n", $color);
374
			$responseCss .= sprintf('.nc-theming-main-text {color: %s}' . "\n", $color);
375
376
		}
377
		$logo = $this->config->getAppValue($this->appName, 'logoMime');
378
		if($logo !== '') {
379
			$responseCss .= sprintf(
380
				'#header .logo {' .
381
				'background-image: url(\'./logo?v='.$cacheBusterValue.'\');' .
382
				'background-size: contain;' .
383
				'}' . "\n" .
384
				'#header .logo-icon {' .
385
				'background-image: url(\'./logo?v='.$cacheBusterValue.'\');' .
386
				'background-size: contain;' .
387
				'}' . "\n" .
388
				'#firstrunwizard .firstrunwizard-header .logo {' .
389
				'background-image: url(\'./logo?v='.$cacheBusterValue.'\');' .
390
				'background-size: contain;' .
391
				'}' . "\n"
392
			);
393
		}
394
		$backgroundLogo = $this->config->getAppValue($this->appName, 'backgroundMime');
395
		if($backgroundLogo !== '') {
396
			$responseCss .= '#body-login {background-image: url(\'./loginbackground?v='.$cacheBusterValue.'\');}' . "\n";
397
			$responseCss .= '#firstrunwizard .firstrunwizard-header {' .
398
				'background-image: url(\'./loginbackground?v='.$cacheBusterValue.'\');' .
399
			'}' . "\n";
400
		}
401
		if($this->util->invertTextColor($color)) {
402
			$responseCss .= '#header .header-appname, #expandDisplayName { color: #000000; }' . "\n";
403
			$responseCss .= '#header .icon-caret { background-image: url(\'' . \OC::$WEBROOT . '/core/img/actions/caret-dark.svg\'); }' . "\n";
404
			$responseCss .= '.searchbox input[type="search"] { background: transparent url(\'' . \OC::$WEBROOT . '/core/img/actions/search.svg\') no-repeat 6px center; color: #000; }' . "\n";
405
			$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";
406
			$responseCss .= '#body-login input.login { background-image: url(\'' . \OC::$WEBROOT . '/core/img/actions/confirm.svg?v=2\'); }' . "\n";
407
			$responseCss .= '.nc-theming-contrast {color: #000000}' . "\n";
408
			$responseCss .= '.ui-widget-header { color: #000000; }' . "\n";
409
		} else {
410
			$responseCss .= '.nc-theming-contrast {color: #ffffff}' . "\n";
411
		}
412
413
		$response = new DataDownloadResponse($responseCss, 'style', 'text/css');
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
	 * @NoCSRFRequired
421
	 * @PublicPage
422
	 *
423
	 * @return DataDownloadResponse
424
	 */
425
	public function getJavascript() {
426
		$responseJS = '(function() {
427
	OCA.Theming = {
428
		name: ' . json_encode($this->template->getName()) . ',
429
		url: ' . json_encode($this->template->getBaseUrl()) . ',
430
		slogan: ' . json_encode($this->template->getSlogan()) . ',
431
		color: ' . json_encode($this->template->getMailHeaderColor()) . ',
432
		inverted: ' . json_encode($this->util->invertTextColor($this->template->getMailHeaderColor())) . ',
433
	};
434
})();';
435
		$response = new Http\DataDisplayResponse($responseJS);
436
		$response->addHeader('Content-type', 'text/javascript');
437
		$response->addHeader('Expires', date(\DateTime::RFC2822, $this->timeFactory->getTime()));
438
		$response->addHeader('Pragma', 'cache');
439
		$response->cacheFor(3600);
440
		return $response;
441
	}
442
}
443