Completed
Push — master ( 1a07c5...9a8e74 )
by
unknown
18:49 queued 15s
created
apps/theming/lib/Controller/ThemingController.php 2 patches
Indentation   +427 added lines, -427 removed lines patch added patch discarded remove patch
@@ -42,457 +42,457 @@
 block discarded – undo
42 42
  * @package OCA\Theming\Controller
43 43
  */
44 44
 class ThemingController extends Controller {
45
-	public const VALID_UPLOAD_KEYS = ['header', 'logo', 'logoheader', 'background', 'favicon'];
45
+    public const VALID_UPLOAD_KEYS = ['header', 'logo', 'logoheader', 'background', 'favicon'];
46 46
 
47
-	public function __construct(
48
-		string $appName,
49
-		IRequest $request,
50
-		private IConfig $config,
51
-		private IAppConfig $appConfig,
52
-		private ThemingDefaults $themingDefaults,
53
-		private IL10N $l10n,
54
-		private IURLGenerator $urlGenerator,
55
-		private IAppManager $appManager,
56
-		private ImageManager $imageManager,
57
-		private ThemesService $themesService,
58
-		private INavigationManager $navigationManager,
59
-	) {
60
-		parent::__construct($appName, $request);
61
-	}
47
+    public function __construct(
48
+        string $appName,
49
+        IRequest $request,
50
+        private IConfig $config,
51
+        private IAppConfig $appConfig,
52
+        private ThemingDefaults $themingDefaults,
53
+        private IL10N $l10n,
54
+        private IURLGenerator $urlGenerator,
55
+        private IAppManager $appManager,
56
+        private ImageManager $imageManager,
57
+        private ThemesService $themesService,
58
+        private INavigationManager $navigationManager,
59
+    ) {
60
+        parent::__construct($appName, $request);
61
+    }
62 62
 
63
-	/**
64
-	 * @param string $setting
65
-	 * @param string $value
66
-	 * @return DataResponse
67
-	 * @throws NotPermittedException
68
-	 */
69
-	#[AuthorizedAdminSetting(settings: Admin::class)]
70
-	public function updateStylesheet($setting, $value) {
71
-		$value = trim($value);
72
-		$error = null;
73
-		$saved = false;
74
-		switch ($setting) {
75
-			case 'name':
76
-				if (strlen($value) > 250) {
77
-					$error = $this->l10n->t('The given name is too long');
78
-				}
79
-				break;
80
-			case 'url':
81
-				if (strlen($value) > 500) {
82
-					$error = $this->l10n->t('The given web address is too long');
83
-				}
84
-				if (!$this->isValidUrl($value)) {
85
-					$error = $this->l10n->t('The given web address is not a valid URL');
86
-				}
87
-				break;
88
-			case 'imprintUrl':
89
-				if (strlen($value) > 500) {
90
-					$error = $this->l10n->t('The given legal notice address is too long');
91
-				}
92
-				if (!$this->isValidUrl($value)) {
93
-					$error = $this->l10n->t('The given legal notice address is not a valid URL');
94
-				}
95
-				break;
96
-			case 'privacyUrl':
97
-				if (strlen($value) > 500) {
98
-					$error = $this->l10n->t('The given privacy policy address is too long');
99
-				}
100
-				if (!$this->isValidUrl($value)) {
101
-					$error = $this->l10n->t('The given privacy policy address is not a valid URL');
102
-				}
103
-				break;
104
-			case 'slogan':
105
-				if (strlen($value) > 500) {
106
-					$error = $this->l10n->t('The given slogan is too long');
107
-				}
108
-				break;
109
-			case 'primary_color':
110
-				if (!preg_match('/^\#([0-9a-f]{3}|[0-9a-f]{6})$/i', $value)) {
111
-					$error = $this->l10n->t('The given color is invalid');
112
-				} else {
113
-					$this->appConfig->setAppValueString('primary_color', $value);
114
-					$saved = true;
115
-				}
116
-				break;
117
-			case 'background_color':
118
-				if (!preg_match('/^\#([0-9a-f]{3}|[0-9a-f]{6})$/i', $value)) {
119
-					$error = $this->l10n->t('The given color is invalid');
120
-				} else {
121
-					$this->appConfig->setAppValueString('background_color', $value);
122
-					$saved = true;
123
-				}
124
-				break;
125
-			case 'disable-user-theming':
126
-				if (!in_array($value, ['yes', 'true', 'no', 'false'])) {
127
-					$error = $this->l10n->t('Disable-user-theming should be true or false');
128
-				} else {
129
-					$this->appConfig->setAppValueBool('disable-user-theming', $value === 'yes' || $value === 'true');
130
-					$saved = true;
131
-				}
132
-				break;
133
-		}
134
-		if ($error !== null) {
135
-			return new DataResponse([
136
-				'data' => [
137
-					'message' => $error,
138
-				],
139
-				'status' => 'error'
140
-			], Http::STATUS_BAD_REQUEST);
141
-		}
63
+    /**
64
+     * @param string $setting
65
+     * @param string $value
66
+     * @return DataResponse
67
+     * @throws NotPermittedException
68
+     */
69
+    #[AuthorizedAdminSetting(settings: Admin::class)]
70
+    public function updateStylesheet($setting, $value) {
71
+        $value = trim($value);
72
+        $error = null;
73
+        $saved = false;
74
+        switch ($setting) {
75
+            case 'name':
76
+                if (strlen($value) > 250) {
77
+                    $error = $this->l10n->t('The given name is too long');
78
+                }
79
+                break;
80
+            case 'url':
81
+                if (strlen($value) > 500) {
82
+                    $error = $this->l10n->t('The given web address is too long');
83
+                }
84
+                if (!$this->isValidUrl($value)) {
85
+                    $error = $this->l10n->t('The given web address is not a valid URL');
86
+                }
87
+                break;
88
+            case 'imprintUrl':
89
+                if (strlen($value) > 500) {
90
+                    $error = $this->l10n->t('The given legal notice address is too long');
91
+                }
92
+                if (!$this->isValidUrl($value)) {
93
+                    $error = $this->l10n->t('The given legal notice address is not a valid URL');
94
+                }
95
+                break;
96
+            case 'privacyUrl':
97
+                if (strlen($value) > 500) {
98
+                    $error = $this->l10n->t('The given privacy policy address is too long');
99
+                }
100
+                if (!$this->isValidUrl($value)) {
101
+                    $error = $this->l10n->t('The given privacy policy address is not a valid URL');
102
+                }
103
+                break;
104
+            case 'slogan':
105
+                if (strlen($value) > 500) {
106
+                    $error = $this->l10n->t('The given slogan is too long');
107
+                }
108
+                break;
109
+            case 'primary_color':
110
+                if (!preg_match('/^\#([0-9a-f]{3}|[0-9a-f]{6})$/i', $value)) {
111
+                    $error = $this->l10n->t('The given color is invalid');
112
+                } else {
113
+                    $this->appConfig->setAppValueString('primary_color', $value);
114
+                    $saved = true;
115
+                }
116
+                break;
117
+            case 'background_color':
118
+                if (!preg_match('/^\#([0-9a-f]{3}|[0-9a-f]{6})$/i', $value)) {
119
+                    $error = $this->l10n->t('The given color is invalid');
120
+                } else {
121
+                    $this->appConfig->setAppValueString('background_color', $value);
122
+                    $saved = true;
123
+                }
124
+                break;
125
+            case 'disable-user-theming':
126
+                if (!in_array($value, ['yes', 'true', 'no', 'false'])) {
127
+                    $error = $this->l10n->t('Disable-user-theming should be true or false');
128
+                } else {
129
+                    $this->appConfig->setAppValueBool('disable-user-theming', $value === 'yes' || $value === 'true');
130
+                    $saved = true;
131
+                }
132
+                break;
133
+        }
134
+        if ($error !== null) {
135
+            return new DataResponse([
136
+                'data' => [
137
+                    'message' => $error,
138
+                ],
139
+                'status' => 'error'
140
+            ], Http::STATUS_BAD_REQUEST);
141
+        }
142 142
 
143
-		if (!$saved) {
144
-			$this->themingDefaults->set($setting, $value);
145
-		}
143
+        if (!$saved) {
144
+            $this->themingDefaults->set($setting, $value);
145
+        }
146 146
 
147
-		return new DataResponse([
148
-			'data' => [
149
-				'message' => $this->l10n->t('Saved'),
150
-			],
151
-			'status' => 'success'
152
-		]);
153
-	}
147
+        return new DataResponse([
148
+            'data' => [
149
+                'message' => $this->l10n->t('Saved'),
150
+            ],
151
+            'status' => 'success'
152
+        ]);
153
+    }
154 154
 
155
-	/**
156
-	 * @param string $setting
157
-	 * @param mixed $value
158
-	 * @return DataResponse
159
-	 * @throws NotPermittedException
160
-	 */
161
-	#[AuthorizedAdminSetting(settings: Admin::class)]
162
-	public function updateAppMenu($setting, $value) {
163
-		$error = null;
164
-		switch ($setting) {
165
-			case 'defaultApps':
166
-				if (is_array($value)) {
167
-					try {
168
-						$this->navigationManager->setDefaultEntryIds($value);
169
-					} catch (InvalidArgumentException $e) {
170
-						$error = $this->l10n->t('Invalid app given');
171
-					}
172
-				} else {
173
-					$error = $this->l10n->t('Invalid type for setting "defaultApp" given');
174
-				}
175
-				break;
176
-			default:
177
-				$error = $this->l10n->t('Invalid setting key');
178
-		}
179
-		if ($error !== null) {
180
-			return new DataResponse([
181
-				'data' => [
182
-					'message' => $error,
183
-				],
184
-				'status' => 'error'
185
-			], Http::STATUS_BAD_REQUEST);
186
-		}
155
+    /**
156
+     * @param string $setting
157
+     * @param mixed $value
158
+     * @return DataResponse
159
+     * @throws NotPermittedException
160
+     */
161
+    #[AuthorizedAdminSetting(settings: Admin::class)]
162
+    public function updateAppMenu($setting, $value) {
163
+        $error = null;
164
+        switch ($setting) {
165
+            case 'defaultApps':
166
+                if (is_array($value)) {
167
+                    try {
168
+                        $this->navigationManager->setDefaultEntryIds($value);
169
+                    } catch (InvalidArgumentException $e) {
170
+                        $error = $this->l10n->t('Invalid app given');
171
+                    }
172
+                } else {
173
+                    $error = $this->l10n->t('Invalid type for setting "defaultApp" given');
174
+                }
175
+                break;
176
+            default:
177
+                $error = $this->l10n->t('Invalid setting key');
178
+        }
179
+        if ($error !== null) {
180
+            return new DataResponse([
181
+                'data' => [
182
+                    'message' => $error,
183
+                ],
184
+                'status' => 'error'
185
+            ], Http::STATUS_BAD_REQUEST);
186
+        }
187 187
 
188
-		return new DataResponse([
189
-			'data' => [
190
-				'message' => $this->l10n->t('Saved'),
191
-			],
192
-			'status' => 'success'
193
-		]);
194
-	}
188
+        return new DataResponse([
189
+            'data' => [
190
+                'message' => $this->l10n->t('Saved'),
191
+            ],
192
+            'status' => 'success'
193
+        ]);
194
+    }
195 195
 
196
-	/**
197
-	 * Check that a string is a valid http/https url.
198
-	 * Also validates that there is no way for XSS through HTML
199
-	 */
200
-	private function isValidUrl(string $url): bool {
201
-		return ((str_starts_with($url, 'http://') || str_starts_with($url, 'https://'))
202
-			&& filter_var($url, FILTER_VALIDATE_URL) !== false)
203
-			&& !str_contains($url, '"');
204
-	}
196
+    /**
197
+     * Check that a string is a valid http/https url.
198
+     * Also validates that there is no way for XSS through HTML
199
+     */
200
+    private function isValidUrl(string $url): bool {
201
+        return ((str_starts_with($url, 'http://') || str_starts_with($url, 'https://'))
202
+            && filter_var($url, FILTER_VALIDATE_URL) !== false)
203
+            && !str_contains($url, '"');
204
+    }
205 205
 
206
-	/**
207
-	 * @return DataResponse
208
-	 * @throws NotPermittedException
209
-	 */
210
-	#[AuthorizedAdminSetting(settings: Admin::class)]
211
-	public function uploadImage(): DataResponse {
212
-		$key = $this->request->getParam('key');
213
-		if (!in_array($key, self::VALID_UPLOAD_KEYS, true)) {
214
-			return new DataResponse(
215
-				[
216
-					'data' => [
217
-						'message' => 'Invalid key'
218
-					],
219
-					'status' => 'failure',
220
-				],
221
-				Http::STATUS_BAD_REQUEST
222
-			);
223
-		}
224
-		$image = $this->request->getUploadedFile('image');
225
-		$error = null;
226
-		$phpFileUploadErrors = [
227
-			UPLOAD_ERR_OK => $this->l10n->t('The file was uploaded'),
228
-			UPLOAD_ERR_INI_SIZE => $this->l10n->t('The uploaded file exceeds the upload_max_filesize directive in php.ini'),
229
-			UPLOAD_ERR_FORM_SIZE => $this->l10n->t('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form'),
230
-			UPLOAD_ERR_PARTIAL => $this->l10n->t('The file was only partially uploaded'),
231
-			UPLOAD_ERR_NO_FILE => $this->l10n->t('No file was uploaded'),
232
-			UPLOAD_ERR_NO_TMP_DIR => $this->l10n->t('Missing a temporary folder'),
233
-			UPLOAD_ERR_CANT_WRITE => $this->l10n->t('Could not write file to disk'),
234
-			UPLOAD_ERR_EXTENSION => $this->l10n->t('A PHP extension stopped the file upload'),
235
-		];
236
-		if (empty($image)) {
237
-			$error = $this->l10n->t('No file uploaded');
238
-		}
239
-		if (!empty($image) && array_key_exists('error', $image) && $image['error'] !== UPLOAD_ERR_OK) {
240
-			$error = $phpFileUploadErrors[$image['error']];
241
-		}
206
+    /**
207
+     * @return DataResponse
208
+     * @throws NotPermittedException
209
+     */
210
+    #[AuthorizedAdminSetting(settings: Admin::class)]
211
+    public function uploadImage(): DataResponse {
212
+        $key = $this->request->getParam('key');
213
+        if (!in_array($key, self::VALID_UPLOAD_KEYS, true)) {
214
+            return new DataResponse(
215
+                [
216
+                    'data' => [
217
+                        'message' => 'Invalid key'
218
+                    ],
219
+                    'status' => 'failure',
220
+                ],
221
+                Http::STATUS_BAD_REQUEST
222
+            );
223
+        }
224
+        $image = $this->request->getUploadedFile('image');
225
+        $error = null;
226
+        $phpFileUploadErrors = [
227
+            UPLOAD_ERR_OK => $this->l10n->t('The file was uploaded'),
228
+            UPLOAD_ERR_INI_SIZE => $this->l10n->t('The uploaded file exceeds the upload_max_filesize directive in php.ini'),
229
+            UPLOAD_ERR_FORM_SIZE => $this->l10n->t('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form'),
230
+            UPLOAD_ERR_PARTIAL => $this->l10n->t('The file was only partially uploaded'),
231
+            UPLOAD_ERR_NO_FILE => $this->l10n->t('No file was uploaded'),
232
+            UPLOAD_ERR_NO_TMP_DIR => $this->l10n->t('Missing a temporary folder'),
233
+            UPLOAD_ERR_CANT_WRITE => $this->l10n->t('Could not write file to disk'),
234
+            UPLOAD_ERR_EXTENSION => $this->l10n->t('A PHP extension stopped the file upload'),
235
+        ];
236
+        if (empty($image)) {
237
+            $error = $this->l10n->t('No file uploaded');
238
+        }
239
+        if (!empty($image) && array_key_exists('error', $image) && $image['error'] !== UPLOAD_ERR_OK) {
240
+            $error = $phpFileUploadErrors[$image['error']];
241
+        }
242 242
 
243
-		if ($error !== null) {
244
-			return new DataResponse(
245
-				[
246
-					'data' => [
247
-						'message' => $error
248
-					],
249
-					'status' => 'failure',
250
-				],
251
-				Http::STATUS_UNPROCESSABLE_ENTITY
252
-			);
253
-		}
243
+        if ($error !== null) {
244
+            return new DataResponse(
245
+                [
246
+                    'data' => [
247
+                        'message' => $error
248
+                    ],
249
+                    'status' => 'failure',
250
+                ],
251
+                Http::STATUS_UNPROCESSABLE_ENTITY
252
+            );
253
+        }
254 254
 
255
-		try {
256
-			$mime = $this->imageManager->updateImage($key, $image['tmp_name']);
257
-			$this->themingDefaults->set($key . 'Mime', $mime);
258
-		} catch (\Exception $e) {
259
-			return new DataResponse(
260
-				[
261
-					'data' => [
262
-						'message' => $e->getMessage()
263
-					],
264
-					'status' => 'failure',
265
-				],
266
-				Http::STATUS_UNPROCESSABLE_ENTITY
267
-			);
268
-		}
255
+        try {
256
+            $mime = $this->imageManager->updateImage($key, $image['tmp_name']);
257
+            $this->themingDefaults->set($key . 'Mime', $mime);
258
+        } catch (\Exception $e) {
259
+            return new DataResponse(
260
+                [
261
+                    'data' => [
262
+                        'message' => $e->getMessage()
263
+                    ],
264
+                    'status' => 'failure',
265
+                ],
266
+                Http::STATUS_UNPROCESSABLE_ENTITY
267
+            );
268
+        }
269 269
 
270
-		$name = $image['name'];
270
+        $name = $image['name'];
271 271
 
272
-		return new DataResponse(
273
-			[
274
-				'data'
275
-					=> [
276
-						'name' => $name,
277
-						'url' => $this->imageManager->getImageUrl($key),
278
-						'message' => $this->l10n->t('Saved'),
279
-					],
280
-				'status' => 'success'
281
-			]
282
-		);
283
-	}
272
+        return new DataResponse(
273
+            [
274
+                'data'
275
+                    => [
276
+                        'name' => $name,
277
+                        'url' => $this->imageManager->getImageUrl($key),
278
+                        'message' => $this->l10n->t('Saved'),
279
+                    ],
280
+                'status' => 'success'
281
+            ]
282
+        );
283
+    }
284 284
 
285
-	/**
286
-	 * Revert setting to default value
287
-	 *
288
-	 * @param string $setting setting which should be reverted
289
-	 * @return DataResponse
290
-	 * @throws NotPermittedException
291
-	 */
292
-	#[AuthorizedAdminSetting(settings: Admin::class)]
293
-	public function undo(string $setting): DataResponse {
294
-		$value = $this->themingDefaults->undo($setting);
285
+    /**
286
+     * Revert setting to default value
287
+     *
288
+     * @param string $setting setting which should be reverted
289
+     * @return DataResponse
290
+     * @throws NotPermittedException
291
+     */
292
+    #[AuthorizedAdminSetting(settings: Admin::class)]
293
+    public function undo(string $setting): DataResponse {
294
+        $value = $this->themingDefaults->undo($setting);
295 295
 
296
-		return new DataResponse(
297
-			[
298
-				'data'
299
-					=> [
300
-						'value' => $value,
301
-						'message' => $this->l10n->t('Saved'),
302
-					],
303
-				'status' => 'success'
304
-			]
305
-		);
306
-	}
296
+        return new DataResponse(
297
+            [
298
+                'data'
299
+                    => [
300
+                        'value' => $value,
301
+                        'message' => $this->l10n->t('Saved'),
302
+                    ],
303
+                'status' => 'success'
304
+            ]
305
+        );
306
+    }
307 307
 
308
-	/**
309
-	 * Revert all theming settings to their default values
310
-	 *
311
-	 * @return DataResponse
312
-	 * @throws NotPermittedException
313
-	 */
314
-	#[AuthorizedAdminSetting(settings: Admin::class)]
315
-	public function undoAll(): DataResponse {
316
-		$this->themingDefaults->undoAll();
317
-		$this->navigationManager->setDefaultEntryIds([]);
308
+    /**
309
+     * Revert all theming settings to their default values
310
+     *
311
+     * @return DataResponse
312
+     * @throws NotPermittedException
313
+     */
314
+    #[AuthorizedAdminSetting(settings: Admin::class)]
315
+    public function undoAll(): DataResponse {
316
+        $this->themingDefaults->undoAll();
317
+        $this->navigationManager->setDefaultEntryIds([]);
318 318
 
319
-		return new DataResponse(
320
-			[
321
-				'data'
322
-					=> [
323
-						'message' => $this->l10n->t('Saved'),
324
-					],
325
-				'status' => 'success'
326
-			]
327
-		);
328
-	}
319
+        return new DataResponse(
320
+            [
321
+                'data'
322
+                    => [
323
+                        'message' => $this->l10n->t('Saved'),
324
+                    ],
325
+                'status' => 'success'
326
+            ]
327
+        );
328
+    }
329 329
 
330
-	/**
331
-	 * @NoSameSiteCookieRequired
332
-	 *
333
-	 * Get an image
334
-	 *
335
-	 * @param string $key Key of the image
336
-	 * @param bool $useSvg Return image as SVG
337
-	 * @return FileDisplayResponse<Http::STATUS_OK, array{}>|NotFoundResponse<Http::STATUS_NOT_FOUND, array{}>
338
-	 * @throws NotPermittedException
339
-	 *
340
-	 * 200: Image returned
341
-	 * 404: Image not found
342
-	 */
343
-	#[PublicPage]
344
-	#[NoCSRFRequired]
345
-	#[OpenAPI(scope: OpenAPI::SCOPE_DEFAULT)]
346
-	public function getImage(string $key, bool $useSvg = true) {
347
-		try {
348
-			$file = $this->imageManager->getImage($key, $useSvg);
349
-		} catch (NotFoundException $e) {
350
-			return new NotFoundResponse();
351
-		}
330
+    /**
331
+     * @NoSameSiteCookieRequired
332
+     *
333
+     * Get an image
334
+     *
335
+     * @param string $key Key of the image
336
+     * @param bool $useSvg Return image as SVG
337
+     * @return FileDisplayResponse<Http::STATUS_OK, array{}>|NotFoundResponse<Http::STATUS_NOT_FOUND, array{}>
338
+     * @throws NotPermittedException
339
+     *
340
+     * 200: Image returned
341
+     * 404: Image not found
342
+     */
343
+    #[PublicPage]
344
+    #[NoCSRFRequired]
345
+    #[OpenAPI(scope: OpenAPI::SCOPE_DEFAULT)]
346
+    public function getImage(string $key, bool $useSvg = true) {
347
+        try {
348
+            $file = $this->imageManager->getImage($key, $useSvg);
349
+        } catch (NotFoundException $e) {
350
+            return new NotFoundResponse();
351
+        }
352 352
 
353
-		$response = new FileDisplayResponse($file);
354
-		$csp = new ContentSecurityPolicy();
355
-		$csp->allowInlineStyle();
356
-		$response->setContentSecurityPolicy($csp);
357
-		$response->cacheFor(3600);
358
-		$response->addHeader('Content-Type', $this->config->getAppValue($this->appName, $key . 'Mime', ''));
359
-		$response->addHeader('Content-Disposition', 'attachment; filename="' . $key . '"');
360
-		if (!$useSvg) {
361
-			$response->addHeader('Content-Type', 'image/png');
362
-		} else {
363
-			$response->addHeader('Content-Type', $this->config->getAppValue($this->appName, $key . 'Mime', ''));
364
-		}
365
-		return $response;
366
-	}
353
+        $response = new FileDisplayResponse($file);
354
+        $csp = new ContentSecurityPolicy();
355
+        $csp->allowInlineStyle();
356
+        $response->setContentSecurityPolicy($csp);
357
+        $response->cacheFor(3600);
358
+        $response->addHeader('Content-Type', $this->config->getAppValue($this->appName, $key . 'Mime', ''));
359
+        $response->addHeader('Content-Disposition', 'attachment; filename="' . $key . '"');
360
+        if (!$useSvg) {
361
+            $response->addHeader('Content-Type', 'image/png');
362
+        } else {
363
+            $response->addHeader('Content-Type', $this->config->getAppValue($this->appName, $key . 'Mime', ''));
364
+        }
365
+        return $response;
366
+    }
367 367
 
368
-	/**
369
-	 * @NoSameSiteCookieRequired
370
-	 * @NoTwoFactorRequired
371
-	 *
372
-	 * Get the CSS stylesheet for a theme
373
-	 *
374
-	 * @param string $themeId ID of the theme
375
-	 * @param bool $plain Let the browser decide the CSS priority
376
-	 * @param bool $withCustomCss Include custom CSS
377
-	 * @return DataDisplayResponse<Http::STATUS_OK, array{Content-Type: 'text/css'}>|NotFoundResponse<Http::STATUS_NOT_FOUND, array{}>
378
-	 *
379
-	 * 200: Stylesheet returned
380
-	 * 404: Theme not found
381
-	 */
382
-	#[PublicPage]
383
-	#[NoCSRFRequired]
384
-	#[OpenAPI(scope: OpenAPI::SCOPE_DEFAULT)]
385
-	public function getThemeStylesheet(string $themeId, bool $plain = false, bool $withCustomCss = false) {
386
-		$themes = $this->themesService->getThemes();
387
-		if (!in_array($themeId, array_keys($themes))) {
388
-			return new NotFoundResponse();
389
-		}
368
+    /**
369
+     * @NoSameSiteCookieRequired
370
+     * @NoTwoFactorRequired
371
+     *
372
+     * Get the CSS stylesheet for a theme
373
+     *
374
+     * @param string $themeId ID of the theme
375
+     * @param bool $plain Let the browser decide the CSS priority
376
+     * @param bool $withCustomCss Include custom CSS
377
+     * @return DataDisplayResponse<Http::STATUS_OK, array{Content-Type: 'text/css'}>|NotFoundResponse<Http::STATUS_NOT_FOUND, array{}>
378
+     *
379
+     * 200: Stylesheet returned
380
+     * 404: Theme not found
381
+     */
382
+    #[PublicPage]
383
+    #[NoCSRFRequired]
384
+    #[OpenAPI(scope: OpenAPI::SCOPE_DEFAULT)]
385
+    public function getThemeStylesheet(string $themeId, bool $plain = false, bool $withCustomCss = false) {
386
+        $themes = $this->themesService->getThemes();
387
+        if (!in_array($themeId, array_keys($themes))) {
388
+            return new NotFoundResponse();
389
+        }
390 390
 
391
-		$theme = $themes[$themeId];
392
-		$customCss = $theme->getCustomCss();
391
+        $theme = $themes[$themeId];
392
+        $customCss = $theme->getCustomCss();
393 393
 
394
-		// Generate variables
395
-		$variables = '';
396
-		foreach ($theme->getCSSVariables() as $variable => $value) {
397
-			$variables .= "$variable:$value; ";
398
-		};
394
+        // Generate variables
395
+        $variables = '';
396
+        foreach ($theme->getCSSVariables() as $variable => $value) {
397
+            $variables .= "$variable:$value; ";
398
+        };
399 399
 
400
-		// If plain is set, the browser decides of the css priority
401
-		if ($plain) {
402
-			$css = ":root { $variables } " . $customCss;
403
-		} else {
404
-			// If not set, we'll rely on the body class
405
-			// We need to separate @-rules from normal selectors, as they can't be nested
406
-			// This is a replacement for the SCSS compiler that did this automatically before f1448fcf0777db7d4254cb0a3ef94d63be9f7a24
407
-			// We need a better way to handle this, but for now we just remove comments and split the at-rules
408
-			// from the rest of the CSS.
409
-			$customCssWithoutComments = preg_replace('!/\*.*?\*/!s', '', $customCss);
410
-			$customCssWithoutComments = preg_replace('!//.*!', '', $customCssWithoutComments);
411
-			preg_match_all('/(@[^{]+{(?:[^{}]*|(?R))*})/', $customCssWithoutComments, $atRules);
412
-			$atRulesCss = implode('', $atRules[0]);
413
-			$scopedCss = preg_replace('/(@[^{]+{(?:[^{}]*|(?R))*})/', '', $customCssWithoutComments);
400
+        // If plain is set, the browser decides of the css priority
401
+        if ($plain) {
402
+            $css = ":root { $variables } " . $customCss;
403
+        } else {
404
+            // If not set, we'll rely on the body class
405
+            // We need to separate @-rules from normal selectors, as they can't be nested
406
+            // This is a replacement for the SCSS compiler that did this automatically before f1448fcf0777db7d4254cb0a3ef94d63be9f7a24
407
+            // We need a better way to handle this, but for now we just remove comments and split the at-rules
408
+            // from the rest of the CSS.
409
+            $customCssWithoutComments = preg_replace('!/\*.*?\*/!s', '', $customCss);
410
+            $customCssWithoutComments = preg_replace('!//.*!', '', $customCssWithoutComments);
411
+            preg_match_all('/(@[^{]+{(?:[^{}]*|(?R))*})/', $customCssWithoutComments, $atRules);
412
+            $atRulesCss = implode('', $atRules[0]);
413
+            $scopedCss = preg_replace('/(@[^{]+{(?:[^{}]*|(?R))*})/', '', $customCssWithoutComments);
414 414
 
415
-			$css = "$atRulesCss [data-theme-$themeId] { $variables $scopedCss }";
416
-		}
415
+            $css = "$atRulesCss [data-theme-$themeId] { $variables $scopedCss }";
416
+        }
417 417
 
418
-		try {
419
-			$response = new DataDisplayResponse($css, Http::STATUS_OK, ['Content-Type' => 'text/css']);
420
-			$response->cacheFor(86400);
421
-			return $response;
422
-		} catch (NotFoundException $e) {
423
-			return new NotFoundResponse();
424
-		}
425
-	}
418
+        try {
419
+            $response = new DataDisplayResponse($css, Http::STATUS_OK, ['Content-Type' => 'text/css']);
420
+            $response->cacheFor(86400);
421
+            return $response;
422
+        } catch (NotFoundException $e) {
423
+            return new NotFoundResponse();
424
+        }
425
+    }
426 426
 
427
-	/**
428
-	 * Get the manifest for an app
429
-	 *
430
-	 * @param string $app ID of the app
431
-	 * @psalm-suppress LessSpecificReturnStatement The content of the Manifest doesn't need to be described in the return type
432
-	 * @return JSONResponse<Http::STATUS_OK, array{name: string, short_name: string, start_url: string, theme_color: string, background_color: string, description: string, icons: list<array{src: non-empty-string, type: string, sizes: string}>, display_override: list<string>, display: string}, array{}>|JSONResponse<Http::STATUS_NOT_FOUND, array{}, array{}>
433
-	 *
434
-	 * 200: Manifest returned
435
-	 * 404: App not found
436
-	 */
437
-	#[PublicPage]
438
-	#[NoCSRFRequired]
439
-	#[BruteForceProtection(action: 'manifest')]
440
-	#[OpenAPI(scope: OpenAPI::SCOPE_DEFAULT)]
441
-	public function getManifest(string $app): JSONResponse {
442
-		$cacheBusterValue = $this->config->getAppValue('theming', 'cachebuster', '0');
443
-		if ($app === 'core' || $app === 'settings') {
444
-			$name = $this->themingDefaults->getName();
445
-			$shortName = $this->themingDefaults->getName();
446
-			$startUrl = $this->urlGenerator->getBaseUrl();
447
-			$description = $this->themingDefaults->getSlogan();
448
-		} else {
449
-			if (!$this->appManager->isEnabledForUser($app)) {
450
-				$response = new JSONResponse([], Http::STATUS_NOT_FOUND);
451
-				$response->throttle(['action' => 'manifest', 'app' => $app]);
452
-				return $response;
453
-			}
427
+    /**
428
+     * Get the manifest for an app
429
+     *
430
+     * @param string $app ID of the app
431
+     * @psalm-suppress LessSpecificReturnStatement The content of the Manifest doesn't need to be described in the return type
432
+     * @return JSONResponse<Http::STATUS_OK, array{name: string, short_name: string, start_url: string, theme_color: string, background_color: string, description: string, icons: list<array{src: non-empty-string, type: string, sizes: string}>, display_override: list<string>, display: string}, array{}>|JSONResponse<Http::STATUS_NOT_FOUND, array{}, array{}>
433
+     *
434
+     * 200: Manifest returned
435
+     * 404: App not found
436
+     */
437
+    #[PublicPage]
438
+    #[NoCSRFRequired]
439
+    #[BruteForceProtection(action: 'manifest')]
440
+    #[OpenAPI(scope: OpenAPI::SCOPE_DEFAULT)]
441
+    public function getManifest(string $app): JSONResponse {
442
+        $cacheBusterValue = $this->config->getAppValue('theming', 'cachebuster', '0');
443
+        if ($app === 'core' || $app === 'settings') {
444
+            $name = $this->themingDefaults->getName();
445
+            $shortName = $this->themingDefaults->getName();
446
+            $startUrl = $this->urlGenerator->getBaseUrl();
447
+            $description = $this->themingDefaults->getSlogan();
448
+        } else {
449
+            if (!$this->appManager->isEnabledForUser($app)) {
450
+                $response = new JSONResponse([], Http::STATUS_NOT_FOUND);
451
+                $response->throttle(['action' => 'manifest', 'app' => $app]);
452
+                return $response;
453
+            }
454 454
 
455
-			$info = $this->appManager->getAppInfo($app, false, $this->l10n->getLanguageCode());
456
-			$name = $info['name'] . ' - ' . $this->themingDefaults->getName();
457
-			$shortName = $info['name'];
458
-			if (str_contains($this->request->getRequestUri(), '/index.php/')) {
459
-				$startUrl = $this->urlGenerator->getBaseUrl() . '/index.php/apps/' . $app . '/';
460
-			} else {
461
-				$startUrl = $this->urlGenerator->getBaseUrl() . '/apps/' . $app . '/';
462
-			}
463
-			$description = $info['summary'] ?? '';
464
-		}
465
-		/**
466
-		 * @var string $description
467
-		 * @var string $shortName
468
-		 */
469
-		$responseJS = [
470
-			'name' => $name,
471
-			'short_name' => $shortName,
472
-			'start_url' => $startUrl,
473
-			'theme_color' => $this->themingDefaults->getColorPrimary(),
474
-			'background_color' => $this->themingDefaults->getColorPrimary(),
475
-			'description' => $description,
476
-			'icons'
477
-				=> [
478
-					[
479
-						'src' => $this->urlGenerator->linkToRoute('theming.Icon.getTouchIcon',
480
-							['app' => $app]) . '?v=' . $cacheBusterValue,
481
-						'type' => 'image/png',
482
-						'sizes' => '512x512'
483
-					],
484
-					[
485
-						'src' => $this->urlGenerator->linkToRoute('theming.Icon.getFavicon',
486
-							['app' => $app]) . '?v=' . $cacheBusterValue,
487
-						'type' => 'image/svg+xml',
488
-						'sizes' => '16x16'
489
-					]
490
-				],
491
-			'display_override' => [$this->config->getSystemValueBool('theming.standalone_window.enabled', true) ? 'minimal-ui' : ''],
492
-			'display' => $this->config->getSystemValueBool('theming.standalone_window.enabled', true) ? 'standalone' : 'browser'
493
-		];
494
-		$response = new JSONResponse($responseJS);
495
-		$response->cacheFor(3600);
496
-		return $response;
497
-	}
455
+            $info = $this->appManager->getAppInfo($app, false, $this->l10n->getLanguageCode());
456
+            $name = $info['name'] . ' - ' . $this->themingDefaults->getName();
457
+            $shortName = $info['name'];
458
+            if (str_contains($this->request->getRequestUri(), '/index.php/')) {
459
+                $startUrl = $this->urlGenerator->getBaseUrl() . '/index.php/apps/' . $app . '/';
460
+            } else {
461
+                $startUrl = $this->urlGenerator->getBaseUrl() . '/apps/' . $app . '/';
462
+            }
463
+            $description = $info['summary'] ?? '';
464
+        }
465
+        /**
466
+         * @var string $description
467
+         * @var string $shortName
468
+         */
469
+        $responseJS = [
470
+            'name' => $name,
471
+            'short_name' => $shortName,
472
+            'start_url' => $startUrl,
473
+            'theme_color' => $this->themingDefaults->getColorPrimary(),
474
+            'background_color' => $this->themingDefaults->getColorPrimary(),
475
+            'description' => $description,
476
+            'icons'
477
+                => [
478
+                    [
479
+                        'src' => $this->urlGenerator->linkToRoute('theming.Icon.getTouchIcon',
480
+                            ['app' => $app]) . '?v=' . $cacheBusterValue,
481
+                        'type' => 'image/png',
482
+                        'sizes' => '512x512'
483
+                    ],
484
+                    [
485
+                        'src' => $this->urlGenerator->linkToRoute('theming.Icon.getFavicon',
486
+                            ['app' => $app]) . '?v=' . $cacheBusterValue,
487
+                        'type' => 'image/svg+xml',
488
+                        'sizes' => '16x16'
489
+                    ]
490
+                ],
491
+            'display_override' => [$this->config->getSystemValueBool('theming.standalone_window.enabled', true) ? 'minimal-ui' : ''],
492
+            'display' => $this->config->getSystemValueBool('theming.standalone_window.enabled', true) ? 'standalone' : 'browser'
493
+        ];
494
+        $response = new JSONResponse($responseJS);
495
+        $response->cacheFor(3600);
496
+        return $response;
497
+    }
498 498
 }
Please login to merge, or discard this patch.
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -254,7 +254,7 @@  discard block
 block discarded – undo
254 254
 
255 255
 		try {
256 256
 			$mime = $this->imageManager->updateImage($key, $image['tmp_name']);
257
-			$this->themingDefaults->set($key . 'Mime', $mime);
257
+			$this->themingDefaults->set($key.'Mime', $mime);
258 258
 		} catch (\Exception $e) {
259 259
 			return new DataResponse(
260 260
 				[
@@ -355,12 +355,12 @@  discard block
 block discarded – undo
355 355
 		$csp->allowInlineStyle();
356 356
 		$response->setContentSecurityPolicy($csp);
357 357
 		$response->cacheFor(3600);
358
-		$response->addHeader('Content-Type', $this->config->getAppValue($this->appName, $key . 'Mime', ''));
359
-		$response->addHeader('Content-Disposition', 'attachment; filename="' . $key . '"');
358
+		$response->addHeader('Content-Type', $this->config->getAppValue($this->appName, $key.'Mime', ''));
359
+		$response->addHeader('Content-Disposition', 'attachment; filename="'.$key.'"');
360 360
 		if (!$useSvg) {
361 361
 			$response->addHeader('Content-Type', 'image/png');
362 362
 		} else {
363
-			$response->addHeader('Content-Type', $this->config->getAppValue($this->appName, $key . 'Mime', ''));
363
+			$response->addHeader('Content-Type', $this->config->getAppValue($this->appName, $key.'Mime', ''));
364 364
 		}
365 365
 		return $response;
366 366
 	}
@@ -399,7 +399,7 @@  discard block
 block discarded – undo
399 399
 
400 400
 		// If plain is set, the browser decides of the css priority
401 401
 		if ($plain) {
402
-			$css = ":root { $variables } " . $customCss;
402
+			$css = ":root { $variables } ".$customCss;
403 403
 		} else {
404 404
 			// If not set, we'll rely on the body class
405 405
 			// We need to separate @-rules from normal selectors, as they can't be nested
@@ -453,12 +453,12 @@  discard block
 block discarded – undo
453 453
 			}
454 454
 
455 455
 			$info = $this->appManager->getAppInfo($app, false, $this->l10n->getLanguageCode());
456
-			$name = $info['name'] . ' - ' . $this->themingDefaults->getName();
456
+			$name = $info['name'].' - '.$this->themingDefaults->getName();
457 457
 			$shortName = $info['name'];
458 458
 			if (str_contains($this->request->getRequestUri(), '/index.php/')) {
459
-				$startUrl = $this->urlGenerator->getBaseUrl() . '/index.php/apps/' . $app . '/';
459
+				$startUrl = $this->urlGenerator->getBaseUrl().'/index.php/apps/'.$app.'/';
460 460
 			} else {
461
-				$startUrl = $this->urlGenerator->getBaseUrl() . '/apps/' . $app . '/';
461
+				$startUrl = $this->urlGenerator->getBaseUrl().'/apps/'.$app.'/';
462 462
 			}
463 463
 			$description = $info['summary'] ?? '';
464 464
 		}
@@ -477,13 +477,13 @@  discard block
 block discarded – undo
477 477
 				=> [
478 478
 					[
479 479
 						'src' => $this->urlGenerator->linkToRoute('theming.Icon.getTouchIcon',
480
-							['app' => $app]) . '?v=' . $cacheBusterValue,
480
+							['app' => $app]).'?v='.$cacheBusterValue,
481 481
 						'type' => 'image/png',
482 482
 						'sizes' => '512x512'
483 483
 					],
484 484
 					[
485 485
 						'src' => $this->urlGenerator->linkToRoute('theming.Icon.getFavicon',
486
-							['app' => $app]) . '?v=' . $cacheBusterValue,
486
+							['app' => $app]).'?v='.$cacheBusterValue,
487 487
 						'type' => 'image/svg+xml',
488 488
 						'sizes' => '16x16'
489 489
 					]
Please login to merge, or discard this patch.