Completed
Push — master ( a60d7a...4076c0 )
by Morris
108:46 queued 89:41
created

ThemingController::getLogo()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 18
Code Lines 14

Duplication

Lines 18
Ratio 100 %

Importance

Changes 0
Metric Value
cc 2
eloc 14
nc 2
nop 0
dl 18
loc 18
rs 9.4285
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 Arthur Schiwon <[email protected]>
7
 * @author Bjoern Schiessle <[email protected]>
8
 * @author Daniel Calviño Sánchez <[email protected]>
9
 * @author Jan-Christoph Borchardt <[email protected]>
10
 * @author Joas Schilling <[email protected]>
11
 * @author Julius Haertl <[email protected]>
12
 * @author Julius Härtl <[email protected]>
13
 * @author Lukas Reschke <[email protected]>
14
 * @author Robin Appelman <[email protected]>
15
 *
16
 * @license GNU AGPL version 3 or any later version
17
 *
18
 * This program is free software: you can redistribute it and/or modify
19
 * it under the terms of the GNU Affero General Public License as
20
 * published by the Free Software Foundation, either version 3 of the
21
 * License, or (at your option) any later version.
22
 *
23
 * This program is distributed in the hope that it will be useful,
24
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26
 * GNU Affero General Public License for more details.
27
 *
28
 * You should have received a copy of the GNU Affero General Public License
29
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
30
 *
31
 */
32
33
namespace OCA\Theming\Controller;
34
35
use OC\Template\SCSSCacher;
36
use OCA\Theming\ThemingDefaults;
37
use OCP\AppFramework\Controller;
38
use OCP\AppFramework\Http;
39
use OCP\AppFramework\Http\DataDownloadResponse;
40
use OCP\AppFramework\Http\FileDisplayResponse;
41
use OCP\AppFramework\Http\DataResponse;
42
use OCP\AppFramework\Http\NotFoundResponse;
43
use OCP\AppFramework\Utility\ITimeFactory;
44
use OCP\Files\File;
45
use OCP\Files\IAppData;
46
use OCP\Files\NotFoundException;
47
use OCP\Files\NotPermittedException;
48
use OCP\IConfig;
49
use OCP\IL10N;
50
use OCP\IRequest;
51
use OCA\Theming\Util;
52
use OCP\ITempManager;
53
use OCP\IURLGenerator;
54
use OCP\App\IAppManager;
55
56
/**
57
 * Class ThemingController
58
 *
59
 * handle ajax requests to update the theme
60
 *
61
 * @package OCA\Theming\Controller
62
 */
63
class ThemingController extends Controller {
64
	/** @var ThemingDefaults */
65
	private $themingDefaults;
66
	/** @var Util */
67
	private $util;
68
	/** @var ITimeFactory */
69
	private $timeFactory;
70
	/** @var IL10N */
71
	private $l10n;
72
	/** @var IConfig */
73
	private $config;
74
	/** @var ITempManager */
75
	private $tempManager;
76
	/** @var IAppData */
77
	private $appData;
78
	/** @var SCSSCacher */
79
	private $scssCacher;
80
	/** @var IURLGenerator */
81
	private $urlGenerator;
82
	/** @var IAppManager */
83
	private $appManager;
84
85
	/**
86
	 * ThemingController constructor.
87
	 *
88
	 * @param string $appName
89
	 * @param IRequest $request
90
	 * @param IConfig $config
91
	 * @param ThemingDefaults $themingDefaults
92
	 * @param Util $util
93
	 * @param ITimeFactory $timeFactory
94
	 * @param IL10N $l
95
	 * @param ITempManager $tempManager
96
	 * @param IAppData $appData
97
	 * @param SCSSCacher $scssCacher
98
	 * @param IURLGenerator $urlGenerator
99
	 * @param IAppManager $appManager
100
	 */
101 View Code Duplication
	public function __construct(
102
		$appName,
103
		IRequest $request,
104
		IConfig $config,
105
		ThemingDefaults $themingDefaults,
106
		Util $util,
107
		ITimeFactory $timeFactory,
108
		IL10N $l,
109
		ITempManager $tempManager,
110
		IAppData $appData,
111
		SCSSCacher $scssCacher,
112
		IURLGenerator $urlGenerator,
113
		IAppManager $appManager
114
	) {
115
		parent::__construct($appName, $request);
116
117
		$this->themingDefaults = $themingDefaults;
118
		$this->util = $util;
119
		$this->timeFactory = $timeFactory;
120
		$this->l10n = $l;
121
		$this->config = $config;
122
		$this->tempManager = $tempManager;
123
		$this->appData = $appData;
124
		$this->scssCacher = $scssCacher;
125
		$this->urlGenerator = $urlGenerator;
126
		$this->appManager = $appManager;
127
	}
128
129
	/**
130
	 * @param string $setting
131
	 * @param string $value
132
	 * @return DataResponse
133
	 * @internal param string $color
134
	 */
135
	public function updateStylesheet($setting, $value) {
136
		$value = trim($value);
137
		switch ($setting) {
138 View Code Duplication
			case 'name':
139
				if (strlen($value) > 250) {
140
					return new DataResponse([
141
						'data' => [
142
							'message' => $this->l10n->t('The given name is too long'),
143
						],
144
						'status' => 'error'
145
					]);
146
				}
147
				break;
148 View Code Duplication
			case 'url':
149
				if (strlen($value) > 500) {
150
					return new DataResponse([
151
						'data' => [
152
							'message' => $this->l10n->t('The given web address is too long'),
153
						],
154
						'status' => 'error'
155
					]);
156
				}
157
				break;
158 View Code Duplication
			case 'slogan':
159
				if (strlen($value) > 500) {
160
					return new DataResponse([
161
						'data' => [
162
							'message' => $this->l10n->t('The given slogan is too long'),
163
						],
164
						'status' => 'error'
165
					]);
166
				}
167
				break;
168 View Code Duplication
			case 'color':
169
				if (!preg_match('/^\#([0-9a-f]{3}|[0-9a-f]{6})$/i', $value)) {
170
					return new DataResponse([
171
						'data' => [
172
							'message' => $this->l10n->t('The given color is invalid'),
173
						],
174
						'status' => 'error'
175
					]);
176
				}
177
				break;
178
		}
179
180
		$this->themingDefaults->set($setting, $value);
181
182
		// reprocess server scss for preview
183
		$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...
184
185
		return new DataResponse(
186
			[
187
				'data' =>
188
					[
189
						'message' => $this->l10n->t('Saved'),
190
						'serverCssUrl' => $this->urlGenerator->linkTo('', $this->scssCacher->getCachedSCSS('core', '/core/css/server.scss'))
191
					],
192
				'status' => 'success'
193
			]
194
		);
195
	}
196
197
	/**
198
	 * Update the logos and background image
199
	 *
200
	 * @return DataResponse
201
	 */
202
	public function updateLogo() {
203
		$backgroundColor = $this->request->getParam('backgroundColor', false);
204
		if($backgroundColor) {
205
			$this->themingDefaults->set('backgroundMime', 'backgroundColor');
206
			return new DataResponse(
207
				[
208
					'data' =>
209
						[
210
							'name' => 'backgroundColor',
211
							'message' => $this->l10n->t('Saved')
212
						],
213
					'status' => 'success'
214
				]
215
			);
216
		}
217
		$newLogo = $this->request->getUploadedFile('uploadlogo');
218
		$newBackgroundLogo = $this->request->getUploadedFile('upload-login-background');
219
		$error = null;
220
		$phpFileUploadErrors = [
221
			UPLOAD_ERR_OK => $this->l10n->t('There is no error, the file uploaded with success'),
222
			UPLOAD_ERR_INI_SIZE => $this->l10n->t('The uploaded file exceeds the upload_max_filesize directive in php.ini'),
223
			UPLOAD_ERR_FORM_SIZE => $this->l10n->t('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form'),
224
			UPLOAD_ERR_PARTIAL => $this->l10n->t('The uploaded file was only partially uploaded'),
225
			UPLOAD_ERR_NO_FILE => $this->l10n->t('No file was uploaded'),
226
			UPLOAD_ERR_NO_TMP_DIR => $this->l10n->t('Missing a temporary folder'),
227
			UPLOAD_ERR_CANT_WRITE => $this->l10n->t('Failed to write file to disk.'),
228
			UPLOAD_ERR_EXTENSION => $this->l10n->t('A PHP extension stopped the file upload.'),
229
		];
230
		if (empty($newLogo) && empty($newBackgroundLogo)) {
231
			$error = $this->l10n->t('No file uploaded');
232
		}
233 View Code Duplication
		if (!empty($newLogo) && array_key_exists('error', $newLogo) && $newLogo['error'] !== UPLOAD_ERR_OK) {
234
			$error = $phpFileUploadErrors[$newLogo['error']];
235
		}
236 View Code Duplication
		if (!empty($newBackgroundLogo) && array_key_exists('error', $newBackgroundLogo) && $newBackgroundLogo['error'] !== UPLOAD_ERR_OK) {
237
			$error = $phpFileUploadErrors[$newBackgroundLogo['error']];
238
		}
239
240
		if ($error !== null) {
241
			return new DataResponse(
242
				[
243
					'data' => [
244
						'message' => $error
245
					],
246
					'status' => 'failure',
247
				],
248
				Http::STATUS_UNPROCESSABLE_ENTITY
249
			);
250
		}
251
252
		$name = '';
253
		try {
254
			$folder = $this->appData->getFolder('images');
255
		} catch (NotFoundException $e) {
256
			$folder = $this->appData->newFolder('images');
257
		}
258
259
		if (!empty($newLogo)) {
260
			$target = $folder->newFile('logo');
261
			$supportedFormats = ['image/jpeg', 'image/png', 'image/gif', 'image/svg+xml', 'text/svg'];
262
			if (!in_array($newLogo['type'], $supportedFormats)) {
263
				return new DataResponse(
264
					[
265
						'data' => [
266
							'message' => $this->l10n->t('Unsupported image type'),
267
						],
268
						'status' => 'failure',
269
					],
270
					Http::STATUS_UNPROCESSABLE_ENTITY
271
				);
272
			}
273
			$target->putContent(file_get_contents($newLogo['tmp_name'], 'r'));
274
			$this->themingDefaults->set('logoMime', $newLogo['type']);
275
			$name = $newLogo['name'];
276
		}
277
		if (!empty($newBackgroundLogo)) {
278
			$target = $folder->newFile('background');
279
			$image = @imagecreatefromstring(file_get_contents($newBackgroundLogo['tmp_name'], 'r'));
280
			if ($image === false) {
281
				return new DataResponse(
282
					[
283
						'data' => [
284
							'message' => $this->l10n->t('Unsupported image type'),
285
						],
286
						'status' => 'failure',
287
					],
288
					Http::STATUS_UNPROCESSABLE_ENTITY
289
				);
290
			}
291
292
			// Optimize the image since some people may upload images that will be
293
			// either to big or are not progressive rendering.
294
			$tmpFile = $this->tempManager->getTemporaryFile();
295
			$newWidth = imagesx($image) < 4096 ? imagesx($image) : 4096;
296
			$newHeight = imagesy($image) / (imagesx($image) / $newWidth);
297
			$image = imagescale($image, $newWidth, $newHeight);
298
299
			imageinterlace($image, 1);
300
			imagejpeg($image, $tmpFile, 75);
301
			imagedestroy($image);
302
303
			$target->putContent(file_get_contents($tmpFile, 'r'));
304
			$this->themingDefaults->set('backgroundMime', $newBackgroundLogo['type']);
305
			$name = $newBackgroundLogo['name'];
306
		}
307
308
		return new DataResponse(
309
			[
310
				'data' =>
311
					[
312
						'name' => $name,
313
						'message' => $this->l10n->t('Saved')
314
					],
315
				'status' => 'success'
316
			]
317
		);
318
	}
319
320
	/**
321
	 * Revert setting to default value
322
	 *
323
	 * @param string $setting setting which should be reverted
324
	 * @return DataResponse
325
	 */
326
	public function undo($setting) {
327
		$value = $this->themingDefaults->undo($setting);
328
		// reprocess server scss for preview
329
		$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...
330
331
		if($setting === 'logoMime') {
332
			try {
333
				$file = $this->appData->getFolder('images')->getFile('logo');
334
				$file->delete();
335
			} catch (NotFoundException $e) {
336
			} catch (NotPermittedException $e) {
337
			}
338
		}
339
		if($setting === 'backgroundMime') {
340
			try {
341
				$file = $this->appData->getFolder('images')->getFile('background');
342
				$file->delete();
343
			} catch (NotFoundException $e) {
344
			} catch (NotPermittedException $e) {
345
			}
346
		}
347
348
		return new DataResponse(
349
			[
350
				'data' =>
351
					[
352
						'value' => $value,
353
						'message' => $this->l10n->t('Saved'),
354
						'serverCssUrl' => $this->urlGenerator->linkTo('', $this->scssCacher->getCachedSCSS('core', '/core/css/server.scss'))
355
					],
356
				'status' => 'success'
357
			]
358
		);
359
	}
360
361
	/**
362
	 * @PublicPage
363
	 * @NoCSRFRequired
364
	 *
365
	 * @return FileDisplayResponse|NotFoundResponse
366
	 */
367 View Code Duplication
	public function getLogo() {
368
		try {
369
			/** @var File $file */
370
			$file = $this->appData->getFolder('images')->getFile('logo');
371
		} catch (NotFoundException $e) {
372
			return new NotFoundResponse();
373
		}
374
375
		$response = new FileDisplayResponse($file);
376
		$response->cacheFor(3600);
377
		$expires = new \DateTime();
378
		$expires->setTimestamp($this->timeFactory->getTime());
379
		$expires->add(new \DateInterval('PT24H'));
380
		$response->addHeader('Expires', $expires->format(\DateTime::RFC2822));
381
		$response->addHeader('Pragma', 'cache');
382
		$response->addHeader('Content-Type', $this->config->getAppValue($this->appName, 'logoMime', ''));
383
		return $response;
384
	}
385
386
	/**
387
	 * @PublicPage
388
	 * @NoCSRFRequired
389
	 *
390
	 * @return FileDisplayResponse|NotFoundResponse
391
	 */
392 View Code Duplication
	public function getLoginBackground() {
393
		try {
394
			/** @var File $file */
395
			$file = $this->appData->getFolder('images')->getFile('background');
396
		} catch (NotFoundException $e) {
397
			return new NotFoundResponse();
398
		}
399
400
		$response = new FileDisplayResponse($file);
401
		$response->cacheFor(3600);
402
		$expires = new \DateTime();
403
		$expires->setTimestamp($this->timeFactory->getTime());
404
		$expires->add(new \DateInterval('PT24H'));
405
		$response->addHeader('Expires', $expires->format(\DateTime::RFC2822));
406
		$response->addHeader('Pragma', 'cache');
407
		$response->addHeader('Content-Type', $this->config->getAppValue($this->appName, 'backgroundMime', ''));
408
		return $response;
409
	}
410
411
	/**
412
	 * @NoCSRFRequired
413
	 * @PublicPage
414
	 *
415
	 * @return FileDisplayResponse|NotFoundResponse
416
	 */
417
	public function getStylesheet() {
418
		$appPath = $this->appManager->getAppPath('theming');
419
420
		/* SCSSCacher is required here
421
		 * We cannot rely on automatic caching done by \OC_Util::addStyle,
422
		 * since we need to add the cacheBuster value to the url
423
		 */
424
		$cssCached = $this->scssCacher->process($appPath, 'css/theming.scss', 'theming');
425
		if(!$cssCached) {
426
			return new NotFoundResponse();
427
		}
428
429
		try {
430
			$cssFile = $this->scssCacher->getCachedCSS('theming', 'theming.css');
431
			$response = new FileDisplayResponse($cssFile, Http::STATUS_OK, ['Content-Type' => 'text/css']);
432
			$response->cacheFor(86400);
433
			$expires = new \DateTime();
434
			$expires->setTimestamp($this->timeFactory->getTime());
435
			$expires->add(new \DateInterval('PT24H'));
436
			$response->addHeader('Expires', $expires->format(\DateTime::RFC1123));
437
			$response->addHeader('Pragma', 'cache');
438
			return $response;
439
		} catch (NotFoundException $e) {
440
			return new NotFoundResponse();
441
		}
442
	}
443
444
	/**
445
	 * @NoCSRFRequired
446
	 * @PublicPage
447
	 *
448
	 * @return DataDownloadResponse
449
	 */
450
	public function getJavascript() {
451
		$cacheBusterValue = $this->config->getAppValue('theming', 'cachebuster', '0');
452
		$responseJS = '(function() {
453
	OCA.Theming = {
454
		name: ' . json_encode($this->themingDefaults->getName()) . ',
455
		url: ' . json_encode($this->themingDefaults->getBaseUrl()) . ',
456
		slogan: ' . json_encode($this->themingDefaults->getSlogan()) . ',
457
		color: ' . json_encode($this->themingDefaults->getColorPrimary()) . ',
458
		inverted: ' . json_encode($this->util->invertTextColor($this->themingDefaults->getColorPrimary())) . ',
459
		cacheBuster: ' . json_encode($cacheBusterValue) . '
460
	};
461
})();';
462
		$response = new DataDownloadResponse($responseJS, 'javascript', 'text/javascript');
463
		$response->addHeader('Expires', date(\DateTime::RFC2822, $this->timeFactory->getTime()));
464
		$response->addHeader('Pragma', 'cache');
465
		$response->cacheFor(3600);
466
		return $response;
467
	}
468
469
	/**
470
	 * @NoCSRFRequired
471
	 * @PublicPage
472
	 *
473
	 * @return Http\JSONResponse
474
	 */
475
	public function getManifest($app) {
476
		$cacheBusterValue = $this->config->getAppValue('theming', 'cachebuster', '0');
477
		$responseJS = [
478
			'name' => $this->themingDefaults->getName(),
479
			'start_url' => $this->urlGenerator->getBaseUrl(),
480
			'icons' =>
481
				[
482
					[
483
						'src' => $this->urlGenerator->linkToRoute('theming.Icon.getTouchIcon',
484
								['app' => $app]) . '?v=' . $cacheBusterValue,
485
						'type'=> 'image/png',
486
						'sizes'=> '128x128'
487
					],
488
					[
489
						'src' => $this->urlGenerator->linkToRoute('theming.Icon.getFavicon',
490
								['app' => $app]) . '?v=' . $cacheBusterValue,
491
						'type' => 'image/svg+xml',
492
						'sizes' => '16x16'
493
					]
494
				],
495
			'display' => 'standalone'
496
		];
497
		$response = new Http\JSONResponse($responseJS);
498
		$response->addHeader('Expires', date(\DateTime::RFC2822, $this->timeFactory->getTime()));
499
		$response->addHeader('Pragma', 'cache');
500
		$response->cacheFor(3600);
501
		return $response;
502
	}
503
}
504