Completed
Push — master ( 3eba37...dba55f )
by Morris
33:10 queued 21:33
created

ThemingController::undo()   C

Complexity

Conditions 7
Paths 36

Size

Total Lines 33
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

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