Passed
Push — master ( 8555d5...a51f0d )
by John
14:05 queued 13s
created

ThemingController::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 24
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 10
c 0
b 0
f 0
nc 1
nop 11
dl 0
loc 24
rs 9.9332

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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 Christoph Wurst <[email protected]>
9
 * @author Daniel Calviño Sánchez <[email protected]>
10
 * @author Jan-Christoph Borchardt <[email protected]>
11
 * @author Joas Schilling <[email protected]>
12
 * @author Julius Haertl <[email protected]>
13
 * @author Julius Härtl <[email protected]>
14
 * @author Kyle Fazzari <[email protected]>
15
 * @author Lukas Reschke <[email protected]>
16
 * @author nhirokinet <[email protected]>
17
 * @author rakekniven <[email protected]>
18
 * @author Robin Appelman <[email protected]>
19
 * @author Roeland Jago Douma <[email protected]>
20
 * @author Thomas Citharel <[email protected]>
21
 *
22
 * @license GNU AGPL version 3 or any later version
23
 *
24
 * This program is free software: you can redistribute it and/or modify
25
 * it under the terms of the GNU Affero General Public License as
26
 * published by the Free Software Foundation, either version 3 of the
27
 * License, or (at your option) any later version.
28
 *
29
 * This program is distributed in the hope that it will be useful,
30
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32
 * GNU Affero General Public License for more details.
33
 *
34
 * You should have received a copy of the GNU Affero General Public License
35
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
36
 *
37
 */
38
namespace OCA\Theming\Controller;
39
40
use OCA\Theming\ImageManager;
41
use OCA\Theming\Service\ThemesService;
42
use OCA\Theming\ThemingDefaults;
43
use OCP\App\IAppManager;
44
use OCP\AppFramework\Controller;
45
use OCP\AppFramework\Http;
46
use OCP\AppFramework\Http\DataDisplayResponse;
47
use OCP\AppFramework\Http\DataResponse;
48
use OCP\AppFramework\Http\FileDisplayResponse;
49
use OCP\AppFramework\Http\NotFoundResponse;
50
use OCP\Files\IAppData;
51
use OCP\Files\NotFoundException;
52
use OCP\Files\NotPermittedException;
53
use OCP\IConfig;
54
use OCP\IL10N;
55
use OCP\IRequest;
56
use OCP\ITempManager;
57
use OCP\IURLGenerator;
58
use ScssPhp\ScssPhp\Compiler;
59
60
/**
61
 * Class ThemingController
62
 *
63
 * handle ajax requests to update the theme
64
 *
65
 * @package OCA\Theming\Controller
66
 */
67
class ThemingController extends Controller {
68
	private ThemingDefaults $themingDefaults;
69
	private IL10N $l10n;
70
	private IConfig $config;
71
	private ITempManager $tempManager;
72
	private IAppData $appData;
73
	private IURLGenerator $urlGenerator;
74
	private IAppManager $appManager;
75
	private ImageManager $imageManager;
76
	private ThemesService $themesService;
77
78
	public function __construct(
79
		$appName,
80
		IRequest $request,
81
		IConfig $config,
82
		ThemingDefaults $themingDefaults,
83
		IL10N $l,
84
		ITempManager $tempManager,
85
		IAppData $appData,
86
		IURLGenerator $urlGenerator,
87
		IAppManager $appManager,
88
		ImageManager $imageManager,
89
		ThemesService $themesService
90
	) {
91
		parent::__construct($appName, $request);
92
93
		$this->themingDefaults = $themingDefaults;
94
		$this->l10n = $l;
95
		$this->config = $config;
96
		$this->tempManager = $tempManager;
97
		$this->appData = $appData;
98
		$this->urlGenerator = $urlGenerator;
99
		$this->appManager = $appManager;
100
		$this->imageManager = $imageManager;
101
		$this->themesService = $themesService;
102
	}
103
104
	/**
105
	 * @AuthorizedAdminSetting(settings=OCA\Theming\Settings\Admin)
106
	 * @param string $setting
107
	 * @param string $value
108
	 * @return DataResponse
109
	 * @throws NotPermittedException
110
	 */
111
	public function updateStylesheet($setting, $value) {
112
		$value = trim($value);
113
		$error = null;
114
		switch ($setting) {
115
			case 'name':
116
				if (strlen($value) > 250) {
117
					$error = $this->l10n->t('The given name is too long');
118
				}
119
				break;
120
			case 'url':
121
				if (strlen($value) > 500) {
122
					$error = $this->l10n->t('The given web address is too long');
123
				}
124
				if (!$this->isValidUrl($value)) {
125
					$error = $this->l10n->t('The given web address is not a valid URL');
126
				}
127
				break;
128
			case 'imprintUrl':
129
				if (strlen($value) > 500) {
130
					$error = $this->l10n->t('The given legal notice address is too long');
131
				}
132
				if (!$this->isValidUrl($value)) {
133
					$error = $this->l10n->t('The given legal notice address is not a valid URL');
134
				}
135
				break;
136
			case 'privacyUrl':
137
				if (strlen($value) > 500) {
138
					$error = $this->l10n->t('The given privacy policy address is too long');
139
				}
140
				if (!$this->isValidUrl($value)) {
141
					$error = $this->l10n->t('The given privacy policy address is not a valid URL');
142
				}
143
				break;
144
			case 'slogan':
145
				if (strlen($value) > 500) {
146
					$error = $this->l10n->t('The given slogan is too long');
147
				}
148
				break;
149
			case 'color':
150
				if (!preg_match('/^\#([0-9a-f]{3}|[0-9a-f]{6})$/i', $value)) {
151
					$error = $this->l10n->t('The given color is invalid');
152
				}
153
				break;
154
			case 'disable-user-theming':
155
				if ($value !== "yes" && $value !== "no") {
156
					$error = $this->l10n->t('Disable-user-theming should be true or false');
157
				}
158
				break;
159
		}
160
		if ($error !== null) {
161
			return new DataResponse([
162
				'data' => [
163
					'message' => $error,
164
				],
165
				'status' => 'error'
166
			], Http::STATUS_BAD_REQUEST);
167
		}
168
169
		$this->themingDefaults->set($setting, $value);
170
171
		return new DataResponse([
172
			'data' => [
173
				'message' => $this->l10n->t('Saved'),
174
			],
175
			'status' => 'success'
176
		]);
177
	}
178
179
	/**
180
	 * Check that a string is a valid http/https url
181
	 */
182
	private function isValidUrl(string $url): bool {
183
		return ((strpos($url, 'http://') === 0 || strpos($url, 'https://') === 0) &&
184
			filter_var($url, FILTER_VALIDATE_URL) !== false);
185
	}
186
187
	/**
188
	 * @AuthorizedAdminSetting(settings=OCA\Theming\Settings\Admin)
189
	 * @return DataResponse
190
	 * @throws NotPermittedException
191
	 */
192
	public function uploadImage(): DataResponse {
193
		$key = $this->request->getParam('key');
194
		$image = $this->request->getUploadedFile('image');
195
		$error = null;
196
		$phpFileUploadErrors = [
197
			UPLOAD_ERR_OK => $this->l10n->t('The file was uploaded'),
198
			UPLOAD_ERR_INI_SIZE => $this->l10n->t('The uploaded file exceeds the upload_max_filesize directive in php.ini'),
199
			UPLOAD_ERR_FORM_SIZE => $this->l10n->t('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form'),
200
			UPLOAD_ERR_PARTIAL => $this->l10n->t('The file was only partially uploaded'),
201
			UPLOAD_ERR_NO_FILE => $this->l10n->t('No file was uploaded'),
202
			UPLOAD_ERR_NO_TMP_DIR => $this->l10n->t('Missing a temporary folder'),
203
			UPLOAD_ERR_CANT_WRITE => $this->l10n->t('Could not write file to disk'),
204
			UPLOAD_ERR_EXTENSION => $this->l10n->t('A PHP extension stopped the file upload'),
205
		];
206
		if (empty($image)) {
207
			$error = $this->l10n->t('No file uploaded');
208
		}
209
		if (!empty($image) && array_key_exists('error', $image) && $image['error'] !== UPLOAD_ERR_OK) {
210
			$error = $phpFileUploadErrors[$image['error']];
211
		}
212
213
		if ($error !== null) {
214
			return new DataResponse(
215
				[
216
					'data' => [
217
						'message' => $error
218
					],
219
					'status' => 'failure',
220
				],
221
				Http::STATUS_UNPROCESSABLE_ENTITY
222
			);
223
		}
224
225
		try {
226
			$mime = $this->imageManager->updateImage($key, $image['tmp_name']);
227
			$this->themingDefaults->set($key . 'Mime', $mime);
228
		} catch (\Exception $e) {
229
			return new DataResponse(
230
				[
231
					'data' => [
232
						'message' => $e->getMessage()
233
					],
234
					'status' => 'failure',
235
				],
236
				Http::STATUS_UNPROCESSABLE_ENTITY
237
			);
238
		}
239
240
		$name = $image['name'];
241
242
		return new DataResponse(
243
			[
244
				'data' =>
245
					[
246
						'name' => $name,
247
						'url' => $this->imageManager->getImageUrl($key),
248
						'message' => $this->l10n->t('Saved'),
249
					],
250
				'status' => 'success'
251
			]
252
		);
253
	}
254
255
	/**
256
	 * Revert setting to default value
257
	 * @AuthorizedAdminSetting(settings=OCA\Theming\Settings\Admin)
258
	 *
259
	 * @param string $setting setting which should be reverted
260
	 * @return DataResponse
261
	 * @throws NotPermittedException
262
	 */
263
	public function undo(string $setting): DataResponse {
264
		$value = $this->themingDefaults->undo($setting);
265
266
		return new DataResponse(
267
			[
268
				'data' =>
269
					[
270
						'value' => $value,
271
						'message' => $this->l10n->t('Saved'),
272
					],
273
				'status' => 'success'
274
			]
275
		);
276
	}
277
278
	/**
279
	 * Revert all theming settings to their default values
280
	 * @AuthorizedAdminSetting(settings=OCA\Theming\Settings\Admin)
281
	 *
282
	 * @return DataResponse
283
	 * @throws NotPermittedException
284
	 */
285
	public function undoAll(): DataResponse {
286
		$this->themingDefaults->undoAll();
287
288
		return new DataResponse(
289
			[
290
				'data' =>
291
					[
292
						'message' => $this->l10n->t('Saved'),
293
					],
294
				'status' => 'success'
295
			]
296
		);
297
	}
298
299
	/**
300
	 * @PublicPage
301
	 * @NoCSRFRequired
302
	 * @NoSameSiteCookieRequired
303
	 *
304
	 * @param string $key
305
	 * @param bool $useSvg
306
	 * @return FileDisplayResponse|NotFoundResponse
307
	 * @throws NotPermittedException
308
	 */
309
	public function getImage(string $key, bool $useSvg = true) {
310
		try {
311
			$file = $this->imageManager->getImage($key, $useSvg);
312
		} catch (NotFoundException $e) {
313
			return new NotFoundResponse();
314
		}
315
316
		$response = new FileDisplayResponse($file);
317
		$csp = new Http\ContentSecurityPolicy();
318
		$csp->allowInlineStyle();
319
		$response->setContentSecurityPolicy($csp);
320
		$response->cacheFor(3600);
321
		$response->addHeader('Content-Type', $this->config->getAppValue($this->appName, $key . 'Mime', ''));
322
		$response->addHeader('Content-Disposition', 'attachment; filename="' . $key . '"');
323
		if (!$useSvg) {
324
			$response->addHeader('Content-Type', 'image/png');
325
		} else {
326
			$response->addHeader('Content-Type', $this->config->getAppValue($this->appName, $key . 'Mime', ''));
327
		}
328
		return $response;
329
	}
330
331
	/**
332
	 * @NoCSRFRequired
333
	 * @PublicPage
334
	 * @NoSameSiteCookieRequired
335
	 * @NoTwoFactorRequired
336
	 *
337
	 * @return DataDisplayResponse|NotFoundResponse
338
	 */
339
	public function getThemeStylesheet(string $themeId, bool $plain = false, bool $withCustomCss = false) {
0 ignored issues
show
Unused Code introduced by
The parameter $withCustomCss is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

339
	public function getThemeStylesheet(string $themeId, bool $plain = false, /** @scrutinizer ignore-unused */ bool $withCustomCss = false) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
340
		$themes = $this->themesService->getThemes();
341
		if (!in_array($themeId, array_keys($themes))) {
342
			return new NotFoundResponse();
343
		}
344
345
		$theme = $themes[$themeId];
346
		$customCss  = $theme->getCustomCss();
347
348
		// Generate variables
349
		$variables = '';
350
		foreach ($theme->getCSSVariables() as $variable => $value) {
351
			$variables .= "$variable:$value; ";
352
		};
353
354
		// If plain is set, the browser decides of the css priority
355
		if ($plain) {
356
			$css = ":root { $variables } " . $customCss;
357
		} else { 
358
			// If not set, we'll rely on the body class
359
			$compiler = new Compiler();
360
			$compiledCss = $compiler->compileString("[data-theme-$themeId] { $variables $customCss }");
361
			$css = $compiledCss->getCss();;
362
		}
363
364
		try {
365
			$response = new DataDisplayResponse($css, Http::STATUS_OK, ['Content-Type' => 'text/css']);
366
			$response->cacheFor(86400);
367
			return $response;
368
		} catch (NotFoundException $e) {
369
			return new NotFoundResponse();
370
		}
371
	}
372
373
	/**
374
	 * @NoCSRFRequired
375
	 * @PublicPage
376
	 *
377
	 * @return Http\JSONResponse
378
	 */
379
	public function getManifest($app) {
380
		$cacheBusterValue = $this->config->getAppValue('theming', 'cachebuster', '0');
381
		if ($app === 'core' || $app === 'settings') {
382
			$name = $this->themingDefaults->getName();
383
			$shortName = $this->themingDefaults->getName();
384
			$startUrl = $this->urlGenerator->getBaseUrl();
385
			$description = $this->themingDefaults->getSlogan();
386
		} else {
387
			$info = $this->appManager->getAppInfo($app, false, $this->l10n->getLanguageCode());
388
			$name = $info['name'] . ' - ' . $this->themingDefaults->getName();
389
			$shortName = $info['name'];
390
			if (strpos($this->request->getRequestUri(), '/index.php/') !== false) {
391
				$startUrl = $this->urlGenerator->getBaseUrl() . '/index.php/apps/' . $app . '/';
392
			} else {
393
				$startUrl = $this->urlGenerator->getBaseUrl() . '/apps/' . $app . '/';
394
			}
395
			$description = $info['summary'] ?? '';
396
		}
397
		$responseJS = [
398
			'name' => $name,
399
			'short_name' => $shortName,
400
			'start_url' => $startUrl,
401
			'theme_color' => $this->themingDefaults->getColorPrimary(),
402
			'background_color' => $this->themingDefaults->getColorPrimary(),
403
			'description' => $description,
404
			'icons' =>
405
				[
406
					[
407
						'src' => $this->urlGenerator->linkToRoute('theming.Icon.getTouchIcon',
408
								['app' => $app]) . '?v=' . $cacheBusterValue,
409
						'type' => 'image/png',
410
						'sizes' => '512x512'
411
					],
412
					[
413
						'src' => $this->urlGenerator->linkToRoute('theming.Icon.getFavicon',
414
								['app' => $app]) . '?v=' . $cacheBusterValue,
415
						'type' => 'image/svg+xml',
416
						'sizes' => '16x16'
417
					]
418
				],
419
			'display' => 'standalone'
420
		];
421
		$response = new Http\JSONResponse($responseJS);
422
		$response->cacheFor(3600);
423
		return $response;
424
	}
425
}
426