Passed
Push — master ( b3ea5c...a6a224 )
by John
15:47 queued 13s
created

ThemingDefaults   D

Complexity

Total Complexity 58

Size/Duplication

Total Lines 376
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 58
eloc 166
dl 0
loc 376
rs 4.5599
c 0
b 0
f 0

22 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 27 1
A getImprintUrl() 0 2 1
A getSlogan() 0 2 1
A getAndroidClientUrl() 0 2 1
A undo() 0 23 5
A getiTunesAppId() 0 2 1
A getHTMLName() 0 2 1
B getShortFooter() 0 46 7
B getScssVariables() 0 37 6
A getBackground() 0 2 1
A set() 0 3 1
A getColorPrimary() 0 2 1
A getBaseUrl() 0 2 1
A getLogo() 0 22 5
A getEntity() 0 2 1
A getTextColorPrimary() 0 2 2
A getTitle() 0 2 1
A increaseCacheBuster() 0 5 1
A getPrivacyUrl() 0 2 1
A getName() 0 2 1
A getiOSClientUrl() 0 2 1
F replaceImagePath() 0 37 17

How to fix   Complexity   

Complex Class

Complex classes like ThemingDefaults often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ThemingDefaults, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * @copyright Copyright (c) 2016 Bjoern Schiessle <[email protected]>
4
 * @copyright Copyright (c) 2017 Lukas Reschke <[email protected]>
5
 *
6
 * @author Arthur Schiwon <[email protected]>
7
 * @author Bjoern Schiessle <[email protected]>
8
 * @author Daniel Kesselberg <[email protected]>
9
 * @author Guillaume COMPAGNON <[email protected]>
10
 * @author Jan-Christoph Borchardt <[email protected]>
11
 * @author Joachim Bauch <[email protected]>
12
 * @author Joas Schilling <[email protected]>
13
 * @author John Molakvoæ (skjnldsv) <[email protected]>
14
 * @author Julius Haertl <[email protected]>
15
 * @author Julius Härtl <[email protected]>
16
 * @author Lukas Reschke <[email protected]>
17
 * @author Michael Weimann <[email protected]>
18
 * @author Morris Jobke <[email protected]>
19
 * @author Patrik Kernstock <[email protected]>
20
 * @author Robin Appelman <[email protected]>
21
 * @author Roeland Jago Douma <[email protected]>
22
 *
23
 * @license GNU AGPL version 3 or any later version
24
 *
25
 * This program is free software: you can redistribute it and/or modify
26
 * it under the terms of the GNU Affero General Public License as
27
 * published by the Free Software Foundation, either version 3 of the
28
 * License, or (at your option) any later version.
29
 *
30
 * This program is distributed in the hope that it will be useful,
31
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
33
 * GNU Affero General Public License for more details.
34
 *
35
 * You should have received a copy of the GNU Affero General Public License
36
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
37
 *
38
 */
39
40
namespace OCA\Theming;
41
42
use OCP\App\AppPathNotFoundException;
43
use OCP\App\IAppManager;
44
use OCP\Files\NotFoundException;
45
use OCP\ICacheFactory;
46
use OCP\IConfig;
47
use OCP\IL10N;
48
use OCP\INavigationManager;
49
use OCP\IURLGenerator;
50
51
class ThemingDefaults extends \OC_Defaults {
52
53
	/** @var IConfig */
54
	private $config;
55
	/** @var IL10N */
56
	private $l;
57
	/** @var ImageManager */
58
	private $imageManager;
59
	/** @var IURLGenerator */
60
	private $urlGenerator;
61
	/** @var ICacheFactory */
62
	private $cacheFactory;
63
	/** @var Util */
64
	private $util;
65
	/** @var IAppManager */
66
	private $appManager;
67
	/** @var INavigationManager */
68
	private $navigationManager;
69
70
	/** @var string */
71
	private $name;
72
	/** @var string */
73
	private $title;
74
	/** @var string */
75
	private $entity;
76
	/** @var string */
77
	private $url;
78
	/** @var string */
79
	private $color;
80
81
	/** @var string */
82
	private $iTunesAppId;
83
	/** @var string */
84
	private $iOSClientUrl;
85
	/** @var string */
86
	private $AndroidClientUrl;
87
88
	/**
89
	 * ThemingDefaults constructor.
90
	 *
91
	 * @param IConfig $config
92
	 * @param IL10N $l
93
	 * @param ImageManager $imageManager
94
	 * @param IURLGenerator $urlGenerator
95
	 * @param ICacheFactory $cacheFactory
96
	 * @param Util $util
97
	 * @param IAppManager $appManager
98
	 */
99
	public function __construct(IConfig $config,
100
								IL10N $l,
101
								IURLGenerator $urlGenerator,
102
								ICacheFactory $cacheFactory,
103
								Util $util,
104
								ImageManager $imageManager,
105
								IAppManager $appManager,
106
								INavigationManager $navigationManager
107
	) {
108
		parent::__construct();
109
		$this->config = $config;
110
		$this->l = $l;
111
		$this->imageManager = $imageManager;
112
		$this->urlGenerator = $urlGenerator;
113
		$this->cacheFactory = $cacheFactory;
114
		$this->util = $util;
115
		$this->appManager = $appManager;
116
		$this->navigationManager = $navigationManager;
117
118
		$this->name = parent::getName();
119
		$this->title = parent::getTitle();
120
		$this->entity = parent::getEntity();
121
		$this->url = parent::getBaseUrl();
122
		$this->color = parent::getColorPrimary();
123
		$this->iTunesAppId = parent::getiTunesAppId();
124
		$this->iOSClientUrl = parent::getiOSClientUrl();
125
		$this->AndroidClientUrl = parent::getAndroidClientUrl();
126
	}
127
128
	public function getName() {
129
		return strip_tags($this->config->getAppValue('theming', 'name', $this->name));
130
	}
131
132
	public function getHTMLName() {
133
		return $this->config->getAppValue('theming', 'name', $this->name);
134
	}
135
136
	public function getTitle() {
137
		return strip_tags($this->config->getAppValue('theming', 'name', $this->title));
138
	}
139
140
	public function getEntity() {
141
		return strip_tags($this->config->getAppValue('theming', 'name', $this->entity));
142
	}
143
144
	public function getBaseUrl() {
145
		return $this->config->getAppValue('theming', 'url', $this->url);
146
	}
147
148
	public function getSlogan() {
149
		return \OCP\Util::sanitizeHTML($this->config->getAppValue('theming', 'slogan', parent::getSlogan()));
150
	}
151
152
	public function getImprintUrl() {
153
		return (string)$this->config->getAppValue('theming', 'imprintUrl', '');
154
	}
155
156
	public function getPrivacyUrl() {
157
		return (string)$this->config->getAppValue('theming', 'privacyUrl', '');
158
	}
159
160
	public function getShortFooter() {
161
		$slogan = $this->getSlogan();
162
		$baseUrl = $this->getBaseUrl();
163
		if ($baseUrl !== '') {
164
			$footer = '<a href="' . $baseUrl . '" target="_blank"' .
165
				' rel="noreferrer noopener" class="entity-name">' . $this->getEntity() . '</a>';
166
		} else {
167
			$footer = '<span class="entity-name">' .$this->getEntity() . '</span>';
168
		}
169
		$footer .= ($slogan !== '' ? ' – ' . $slogan : '');
170
171
		$links = [
172
			[
173
				'text' => $this->l->t('Legal notice'),
174
				'url' => (string)$this->getImprintUrl()
175
			],
176
			[
177
				'text' => $this->l->t('Privacy policy'),
178
				'url' => (string)$this->getPrivacyUrl()
179
			],
180
		];
181
182
		$navigation = $this->navigationManager->getAll(INavigationManager::TYPE_GUEST);
183
		$guestNavigation = array_map(function($nav) {
184
			return [
185
				'text' => $nav['name'],
186
				'url' => $nav['href']
187
			];
188
		}, $navigation);
189
		$links = array_merge($links, $guestNavigation);
190
191
		$legalLinks = ''; $divider = '';
192
		foreach($links as $link) {
193
			if($link['url'] !== ''
194
				&& filter_var($link['url'], FILTER_VALIDATE_URL)
195
			) {
196
				$legalLinks .= $divider . '<a href="' . $link['url'] . '" class="legal" target="_blank"' .
197
					' rel="noreferrer noopener">' . $link['text'] . '</a>';
198
				$divider = ' · ';
199
			}
200
		}
201
		if($legalLinks !== '' ) {
202
			$footer .= '<br/>' . $legalLinks;
203
		}
204
205
		return $footer;
206
	}
207
208
	/**
209
	 * Color that is used for the header as well as for mail headers
210
	 *
211
	 * @return string
212
	 */
213
	public function getColorPrimary() {
214
		return $this->config->getAppValue('theming', 'color', $this->color);
215
	}
216
217
	/**
218
	 * Themed logo url
219
	 *
220
	 * @param bool $useSvg Whether to point to the SVG image or a fallback
221
	 * @return string
222
	 */
223
	public function getLogo($useSvg = true): string {
224
		$logo = $this->config->getAppValue('theming', 'logoMime', false);
0 ignored issues
show
Bug introduced by
false of type false is incompatible with the type string expected by parameter $default of OCP\IConfig::getAppValue(). ( Ignorable by Annotation )

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

224
		$logo = $this->config->getAppValue('theming', 'logoMime', /** @scrutinizer ignore-type */ false);
Loading history...
225
226
		$logoExists = true;
227
		try {
228
			$this->imageManager->getImage('logo', $useSvg);
229
		} catch (\Exception $e) {
230
			$logoExists = false;
231
		}
232
233
		$cacheBusterCounter = $this->config->getAppValue('theming', 'cachebuster', '0');
234
235
		if(!$logo || !$logoExists) {
236
			if($useSvg) {
237
				$logo = $this->urlGenerator->imagePath('core', 'logo/logo.svg');
238
			} else {
239
				$logo = $this->urlGenerator->imagePath('core', 'logo/logo.png');
240
			}
241
			return $logo . '?v=' . $cacheBusterCounter;
242
		}
243
244
		return $this->urlGenerator->linkToRoute('theming.Theming.getImage', [ 'key' => 'logo', 'useSvg' => $useSvg, 'v' => $cacheBusterCounter ]);
245
	}
246
247
	/**
248
	 * Themed background image url
249
	 *
250
	 * @return string
251
	 */
252
	public function getBackground(): string {
253
		return $this->imageManager->getImageUrl('background');
254
	}
255
256
	/**
257
	 * @return string
258
	 */
259
	public function getiTunesAppId() {
260
		return $this->config->getAppValue('theming', 'iTunesAppId', $this->iTunesAppId);
261
	}
262
263
	/**
264
	 * @return string
265
	 */
266
	public function getiOSClientUrl() {
267
		return $this->config->getAppValue('theming', 'iOSClientUrl', $this->iOSClientUrl);
268
	}
269
270
	/**
271
	 * @return string
272
	 */
273
	public function getAndroidClientUrl() {
274
		return $this->config->getAppValue('theming', 'AndroidClientUrl', $this->AndroidClientUrl);
275
	}
276
277
278
	/**
279
	 * @return array scss variables to overwrite
280
	 */
281
	public function getScssVariables() {
282
		$cache = $this->cacheFactory->createDistributed('theming-' . $this->urlGenerator->getBaseUrl());
283
		if ($value = $cache->get('getScssVariables')) {
284
			return $value;
285
		}
286
287
		$variables = [
288
			'theming-cachebuster' => "'" . $this->config->getAppValue('theming', 'cachebuster', '0') . "'",
289
			'theming-logo-mime' => "'" . $this->config->getAppValue('theming', 'logoMime') . "'",
290
			'theming-background-mime' => "'" . $this->config->getAppValue('theming', 'backgroundMime') . "'",
291
			'theming-logoheader-mime' => "'" . $this->config->getAppValue('theming', 'logoheaderMime') . "'",
292
			'theming-favicon-mime' => "'" . $this->config->getAppValue('theming', 'faviconMime') . "'"
293
		];
294
295
		$variables['image-logo'] = "url('".$this->imageManager->getImageUrl('logo')."')";
296
		$variables['image-logoheader'] = "url('".$this->imageManager->getImageUrl('logoheader')."')";
297
		$variables['image-favicon'] = "url('".$this->imageManager->getImageUrl('favicon')."')";
298
		$variables['image-login-background'] = "url('".$this->imageManager->getImageUrl('background')."')";
299
		$variables['image-login-plain'] = 'false';
300
301
		if ($this->config->getAppValue('theming', 'color', null) !== null) {
0 ignored issues
show
introduced by
The condition $this->config->getAppVal...'color', null) !== null is always true.
Loading history...
302
			$variables['color-primary'] = $this->getColorPrimary();
303
			$variables['color-primary-text'] = $this->getTextColorPrimary();
304
			$variables['color-primary-element'] = $this->util->elementColor($this->getColorPrimary());
305
		}
306
307
		if ($this->config->getAppValue('theming', 'backgroundMime', null) === 'backgroundColor') {
308
			$variables['image-login-plain'] = 'true';
309
		}
310
311
		$variables['has-legal-links'] = 'false';
312
		if($this->getImprintUrl() !== '' || $this->getPrivacyUrl() !== '') {
313
			$variables['has-legal-links'] = 'true';
314
		}
315
316
		$cache->set('getScssVariables', $variables);
317
		return $variables;
318
	}
319
320
	/**
321
	 * Check if the image should be replaced by the theming app
322
	 * and return the new image location then
323
	 *
324
	 * @param string $app name of the app
325
	 * @param string $image filename of the image
326
	 * @return bool|string false if image should not replaced, otherwise the location of the image
327
	 */
328
	public function replaceImagePath($app, $image) {
329
		if ($app === '' || $app === 'files_sharing') {
330
			$app = 'core';
331
		}
332
		$cacheBusterValue = $this->config->getAppValue('theming', 'cachebuster', '0');
333
334
		try {
335
			$customFavicon = $this->imageManager->getImage('favicon');
336
		} catch (NotFoundException $e) {
337
			$customFavicon = null;
338
		}
339
340
		$route = false;
341
		if ($image === 'favicon.ico' && ($customFavicon !== null || $this->imageManager->shouldReplaceIcons())) {
342
			$route = $this->urlGenerator->linkToRoute('theming.Icon.getFavicon', ['app' => $app]);
343
		}
344
		if (($image === 'favicon-touch.png' || $image === 'favicon-fb.png') && ($customFavicon !== null || $this->imageManager->shouldReplaceIcons())) {
345
			$route = $this->urlGenerator->linkToRoute('theming.Icon.getTouchIcon', ['app' => $app]);
346
		}
347
		if ($image === 'manifest.json') {
348
			try {
349
				$appPath = $this->appManager->getAppPath($app);
350
				if (file_exists($appPath . '/img/manifest.json')) {
351
					return false;
352
				}
353
			} catch (AppPathNotFoundException $e) {}
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
354
			$route = $this->urlGenerator->linkToRoute('theming.Theming.getManifest');
355
		}
356
		if (strpos($image, 'filetypes/') === 0 && file_exists(\OC::$SERVERROOT . '/core/img/' . $image )) {
357
			$route = $this->urlGenerator->linkToRoute('theming.Icon.getThemedIcon', ['app' => $app, 'image' => $image]);
358
		}
359
360
		if ($route) {
361
			return $route . '?v=' . $cacheBusterValue;
362
		}
363
364
		return false;
365
	}
366
367
	/**
368
	 * Increases the cache buster key
369
	 */
370
	private function increaseCacheBuster() {
371
		$cacheBusterKey = $this->config->getAppValue('theming', 'cachebuster', '0');
372
		$this->config->setAppValue('theming', 'cachebuster', (int)$cacheBusterKey+1);
373
		$this->cacheFactory->createDistributed('theming-')->clear();
374
		$this->cacheFactory->createDistributed('imagePath')->clear();
375
376
	}
377
378
	/**
379
	 * Update setting in the database
380
	 *
381
	 * @param string $setting
382
	 * @param string $value
383
	 */
384
	public function set($setting, $value) {
385
		$this->config->setAppValue('theming', $setting, $value);
386
		$this->increaseCacheBuster();
387
	}
388
389
	/**
390
	 * Revert settings to the default value
391
	 *
392
	 * @param string $setting setting which should be reverted
393
	 * @return string default value
394
	 */
395
	public function undo($setting) {
396
		$this->config->deleteAppValue('theming', $setting);
397
		$this->increaseCacheBuster();
398
399
		switch ($setting) {
400
			case 'name':
401
				$returnValue = $this->getEntity();
402
				break;
403
			case 'url':
404
				$returnValue = $this->getBaseUrl();
405
				break;
406
			case 'slogan':
407
				$returnValue = $this->getSlogan();
408
				break;
409
			case 'color':
410
				$returnValue = $this->getColorPrimary();
411
				break;
412
			default:
413
				$returnValue = '';
414
				break;
415
		}
416
417
		return $returnValue;
418
	}
419
420
	/**
421
	 * Color of text in the header and primary buttons
422
	 *
423
	 * @return string
424
	 */
425
	public function getTextColorPrimary() {
426
		return $this->util->invertTextColor($this->getColorPrimary()) ? '#000000' : '#ffffff';
427
	}
428
}
429