Completed
Push — master ( 9af26d...fabaf0 )
by Jan-Christoph
12:07
created

ThemingController   C

Complexity

Total Complexity 27

Size/Duplication

Total Lines 329
Duplicated Lines 26.14 %

Coupling/Cohesion

Components 1
Dependencies 19

Importance

Changes 0
Metric Value
dl 86
loc 329
rs 6.875
c 0
b 0
f 0
wmc 27
lcom 1
cbo 19

8 Methods

Rating   Name   Duplication   Size   Complexity  
A getJavascript() 0 18 1
C updateStylesheet() 40 60 9
C updateLogo() 10 71 8
A undo() 0 15 1
A getLogo() 18 18 2
A getLoginBackground() 18 18 2
B getStylesheet() 0 25 3
A __construct() 0 23 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 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 OC\Files\AppData\Factory;
31
use OC\Template\SCSSCacher;
32
use OCA\Theming\ThemingDefaults;
33
use OCP\AppFramework\Controller;
34
use OCP\AppFramework\Http;
35
use OCP\AppFramework\Http\DataDownloadResponse;
36
use OCP\AppFramework\Http\FileDisplayResponse;
37
use OCP\AppFramework\Http\DataResponse;
38
use OCP\AppFramework\Http\NotFoundResponse;
39
use OCP\AppFramework\Utility\ITimeFactory;
40
use OCP\Files\File;
41
use OCP\Files\IAppData;
42
use OCP\Files\NotFoundException;
43
use OCP\IConfig;
44
use OCP\IL10N;
45
use OCP\ILogger;
46
use OCP\IRequest;
47
use OCA\Theming\Util;
48
use OCP\ITempManager;
49
use OCP\IURLGenerator;
50
51
/**
52
 * Class ThemingController
53
 *
54
 * handle ajax requests to update the theme
55
 *
56
 * @package OCA\Theming\Controller
57
 */
58
class ThemingController extends Controller {
59
	/** @var ThemingDefaults */
60
	private $themingDefaults;
61
	/** @var Util */
62
	private $util;
63
	/** @var ITimeFactory */
64
	private $timeFactory;
65
	/** @var IL10N */
66
	private $l10n;
67
	/** @var IConfig */
68
	private $config;
69
	/** @var ITempManager */
70
	private $tempManager;
71
	/** @var IAppData */
72
	private $appData;
73
	/** @var SCSSCacher */
74
	private $scssCacher;
75
76
	/**
77
	 * ThemingController constructor.
78
	 *
79
	 * @param string $appName
80
	 * @param IRequest $request
81
	 * @param IConfig $config
82
	 * @param ThemingDefaults $themingDefaults
83
	 * @param Util $util
84
	 * @param ITimeFactory $timeFactory
85
	 * @param IL10N $l
86
	 * @param ITempManager $tempManager
87
	 * @param IAppData $appData
88
	 * @param SCSSCacher $scssCacher
89
	 */
90
	public function __construct(
91
		$appName,
92
		IRequest $request,
93
		IConfig $config,
94
		ThemingDefaults $themingDefaults,
95
		Util $util,
96
		ITimeFactory $timeFactory,
97
		IL10N $l,
98
		ITempManager $tempManager,
99
		IAppData $appData,
100
		SCSSCacher $scssCacher
101
	) {
102
		parent::__construct($appName, $request);
103
104
		$this->themingDefaults = $themingDefaults;
105
		$this->util = $util;
106
		$this->timeFactory = $timeFactory;
107
		$this->l10n = $l;
108
		$this->config = $config;
109
		$this->tempManager = $tempManager;
110
		$this->appData = $appData;
111
		$this->scssCacher = $scssCacher;
112
	}
113
114
	/**
115
	 * @param string $setting
116
	 * @param string $value
117
	 * @return DataResponse
118
	 * @internal param string $color
119
	 */
120
	public function updateStylesheet($setting, $value) {
121
		$value = trim($value);
122
		switch ($setting) {
123 View Code Duplication
			case 'name':
124
				if (strlen($value) > 250) {
125
					return new DataResponse([
126
						'data' => [
127
							'message' => $this->l10n->t('The given name is too long'),
128
						],
129
						'status' => 'error'
130
					]);
131
				}
132
				break;
133 View Code Duplication
			case 'url':
134
				if (strlen($value) > 500) {
135
					return new DataResponse([
136
						'data' => [
137
							'message' => $this->l10n->t('The given web address is too long'),
138
						],
139
						'status' => 'error'
140
					]);
141
				}
142
				break;
143 View Code Duplication
			case 'slogan':
144
				if (strlen($value) > 500) {
145
					return new DataResponse([
146
						'data' => [
147
							'message' => $this->l10n->t('The given slogan is too long'),
148
						],
149
						'status' => 'error'
150
					]);
151
				}
152
				break;
153 View Code Duplication
			case 'color':
154
				if (!preg_match('/^\#([0-9a-f]{3}|[0-9a-f]{6})$/i', $value)) {
155
					return new DataResponse([
156
						'data' => [
157
							'message' => $this->l10n->t('The given color is invalid'),
158
						],
159
						'status' => 'error'
160
					]);
161
				}
162
				break;
163
		}
164
165
		$this->themingDefaults->set($setting, $value);
166
167
		// reprocess server scss for preview
168
		$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...
169
170
		return new DataResponse(
171
			[
172
				'data' =>
173
					[
174
						'message' => $this->l10n->t('Saved')
175
					],
176
				'status' => 'success'
177
			]
178
		);
179
	}
180
181
	/**
182
	 * Update the logos and background image
183
	 *
184
	 * @return DataResponse
185
	 */
186
	public function updateLogo() {
187
		$newLogo = $this->request->getUploadedFile('uploadlogo');
188
		$newBackgroundLogo = $this->request->getUploadedFile('upload-login-background');
189 View Code Duplication
		if (empty($newLogo) && empty($newBackgroundLogo)) {
190
			return new DataResponse(
191
				[
192
					'data' => [
193
						'message' => $this->l10n->t('No file uploaded')
194
					]
195
				],
196
				Http::STATUS_UNPROCESSABLE_ENTITY
197
			);
198
		}
199
200
		$name = '';
201
		try {
202
			$folder = $this->appData->getFolder('images');
203
		} catch (NotFoundException $e) {
204
			$folder = $this->appData->newFolder('images');
205
		}
206
207
		if (!empty($newLogo)) {
208
			$target = $folder->newFile('logo');
209
			$target->putContent(file_get_contents($newLogo['tmp_name'], 'r'));
210
			$this->themingDefaults->set('logoMime', $newLogo['type']);
211
			$name = $newLogo['name'];
212
		}
213
		if (!empty($newBackgroundLogo)) {
214
			$target = $folder->newFile('background');
215
			$image = @imagecreatefromstring(file_get_contents($newBackgroundLogo['tmp_name'], 'r'));
216
			if ($image === false) {
217
				return new DataResponse(
218
					[
219
						'data' => [
220
							'message' => $this->l10n->t('Unsupported image type'),
221
						],
222
						'status' => 'failure',
223
					],
224
					Http::STATUS_UNPROCESSABLE_ENTITY
225
				);
226
			}
227
228
			// Optimize the image since some people may upload images that will be
229
			// either to big or are not progressive rendering.
230
			$tmpFile = $this->tempManager->getTemporaryFile();
231
			if (function_exists('imagescale')) {
232
				// FIXME: Once PHP 5.5.0 is a requirement the above check can be removed
233
				// Workaround for https://bugs.php.net/bug.php?id=65171
234
				$newHeight = imagesy($image) / (imagesx($image) / 1920);
235
				$image = imagescale($image, 1920, $newHeight);
236
			}
237
			imageinterlace($image, 1);
238
			imagejpeg($image, $tmpFile, 75);
239
			imagedestroy($image);
240
241
			$target->putContent(file_get_contents($tmpFile, 'r'));
242
			$this->themingDefaults->set('backgroundMime', $newBackgroundLogo['type']);
243
			$name = $newBackgroundLogo['name'];
244
		}
245
246
		return new DataResponse(
247
			[
248
				'data' =>
249
					[
250
						'name' => $name,
251
						'message' => $this->l10n->t('Saved')
252
					],
253
				'status' => 'success'
254
			]
255
		);
256
	}
257
258
	/**
259
	 * Revert setting to default value
260
	 *
261
	 * @param string $setting setting which should be reverted
262
	 * @return DataResponse
263
	 */
264
	public function undo($setting) {
265
		$value = $this->themingDefaults->undo($setting);
266
		// reprocess server scss for preview
267
		$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...
268
		return new DataResponse(
269
			[
270
				'data' =>
271
					[
272
						'value' => $value,
273
						'message' => $this->l10n->t('Saved')
274
					],
275
				'status' => 'success'
276
			]
277
		);
278
	}
279
280
	/**
281
	 * @PublicPage
282
	 * @NoCSRFRequired
283
	 *
284
	 * @return FileDisplayResponse|NotFoundResponse
285
	 */
286 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...
287
		try {
288
			/** @var File $file */
289
			$file = $this->appData->getFolder('images')->getFile('logo');
290
		} catch (NotFoundException $e) {
291
			return new NotFoundResponse();
292
		}
293
294
		$response = new FileDisplayResponse($file);
295
		$response->cacheFor(3600);
296
		$expires = new \DateTime();
297
		$expires->setTimestamp($this->timeFactory->getTime());
298
		$expires->add(new \DateInterval('PT24H'));
299
		$response->addHeader('Expires', $expires->format(\DateTime::RFC2822));
300
		$response->addHeader('Pragma', 'cache');
301
		$response->addHeader('Content-Type', $this->config->getAppValue($this->appName, 'logoMime', ''));
302
		return $response;
303
	}
304
305
	/**
306
	 * @PublicPage
307
	 * @NoCSRFRequired
308
	 *
309
	 * @return FileDisplayResponse|NotFoundResponse
310
	 */
311 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...
312
		try {
313
			/** @var File $file */
314
			$file = $this->appData->getFolder('images')->getFile('background');
315
		} catch (NotFoundException $e) {
316
			return new NotFoundResponse();
317
		}
318
319
		$response = new FileDisplayResponse($file);
320
		$response->cacheFor(3600);
321
		$expires = new \DateTime();
322
		$expires->setTimestamp($this->timeFactory->getTime());
323
		$expires->add(new \DateInterval('PT24H'));
324
		$response->addHeader('Expires', $expires->format(\DateTime::RFC2822));
325
		$response->addHeader('Pragma', 'cache');
326
		$response->addHeader('Content-Type', $this->config->getAppValue($this->appName, 'backgroundMime', ''));
327
		return $response;
328
	}
329
330
	/**
331
	 * @NoCSRFRequired
332
	 * @PublicPage
333
	 *
334
	 * @return FileDisplayResponse|NotFoundResponse
335
	 */
336
	public function getStylesheet() {
337
		$appPath = substr(\OC::$server->getAppManager()->getAppPath('theming'), strlen(\OC::$SERVERROOT) + 1);
338
		/* SCSSCacher is required here
339
		 * We cannot rely on automatic caching done by \OC_Util::addStyle,
340
		 * since we need to add the cacheBuster value to the url
341
		 */
342
		$cssCached = $this->scssCacher->process(\OC::$SERVERROOT, $appPath . '/css/theming.scss', 'theming');
343
		if(!$cssCached) {
344
			return new NotFoundResponse();
345
		}
346
347
		try {
348
			$cssFile = $this->scssCacher->getCachedCSS('theming', 'theming.css');
349
			$response = new FileDisplayResponse($cssFile, Http::STATUS_OK, ['Content-Type' => 'text/css']);
350
			$response->cacheFor(86400);
351
			$expires = new \DateTime();
352
			$expires->setTimestamp($this->timeFactory->getTime());
353
			$expires->add(new \DateInterval('PT24H'));
354
			$response->addHeader('Expires', $expires->format(\DateTime::RFC1123));
355
			$response->addHeader('Pragma', 'cache');
356
			return $response;
357
		} catch (NotFoundException $e) {
358
			return new NotFoundResponse();
359
		}
360
	}
361
362
	/**
363
	 * @NoCSRFRequired
364
	 * @PublicPage
365
	 *
366
	 * @return DataDownloadResponse
367
	 */
368
	public function getJavascript() {
369
		$cacheBusterValue = $this->config->getAppValue('theming', 'cachebuster', '0');
370
		$responseJS = '(function() {
371
	OCA.Theming = {
372
		name: ' . json_encode($this->themingDefaults->getName()) . ',
373
		url: ' . json_encode($this->themingDefaults->getBaseUrl()) . ',
374
		slogan: ' . json_encode($this->themingDefaults->getSlogan()) . ',
375
		color: ' . json_encode($this->themingDefaults->getColorPrimary()) . ',
376
		inverted: ' . json_encode($this->util->invertTextColor($this->themingDefaults->getColorPrimary())) . ',
377
		cacheBuster: ' . json_encode($cacheBusterValue) . '
378
	};
379
})();';
380
		$response = new DataDownloadResponse($responseJS, 'javascript', 'text/javascript');
381
		$response->addHeader('Expires', date(\DateTime::RFC2822, $this->timeFactory->getTime()));
382
		$response->addHeader('Pragma', 'cache');
383
		$response->cacheFor(3600);
384
		return $response;
385
	}
386
}
387