Completed
Pull Request — master (#6451)
by Julius
73:56 queued 28:18
created

ThemingController::getManifest()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 28
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

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