Passed
Push — master ( e1f644...b1099f )
by Julius
12:15 queued 12s
created

ThemingDefaults::getEntity()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 2
rs 10
c 0
b 0
f 0
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 Christoph Wurst <[email protected]>
9
 * @author Daniel Kesselberg <[email protected]>
10
 * @author Guillaume COMPAGNON <[email protected]>
11
 * @author Jan-Christoph Borchardt <[email protected]>
12
 * @author Joachim Bauch <[email protected]>
13
 * @author Joas Schilling <[email protected]>
14
 * @author John Molakvoæ <[email protected]>
15
 * @author Julien Veyssier <[email protected]>
16
 * @author Julius Haertl <[email protected]>
17
 * @author Julius Härtl <[email protected]>
18
 * @author Lukas Reschke <[email protected]>
19
 * @author Michael Weimann <[email protected]>
20
 * @author Morris Jobke <[email protected]>
21
 * @author Patrik Kernstock <[email protected]>
22
 * @author Robin Appelman <[email protected]>
23
 * @author Roeland Jago Douma <[email protected]>
24
 *
25
 * @license GNU AGPL version 3 or any later version
26
 *
27
 * This program is free software: you can redistribute it and/or modify
28
 * it under the terms of the GNU Affero General Public License as
29
 * published by the Free Software Foundation, either version 3 of the
30
 * License, or (at your option) any later version.
31
 *
32
 * This program is distributed in the hope that it will be useful,
33
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
34
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35
 * GNU Affero General Public License for more details.
36
 *
37
 * You should have received a copy of the GNU Affero General Public License
38
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
39
 *
40
 */
41
namespace OCA\Theming;
42
43
use OCP\App\AppPathNotFoundException;
44
use OCP\App\IAppManager;
45
use OCP\Files\NotFoundException;
46
use OCP\ICacheFactory;
47
use OCP\IConfig;
48
use OCP\IL10N;
49
use OCP\INavigationManager;
50
use OCP\IURLGenerator;
51
52
class ThemingDefaults extends \OC_Defaults {
53
54
	/** @var IConfig */
55
	private $config;
56
	/** @var IL10N */
57
	private $l;
58
	/** @var ImageManager */
59
	private $imageManager;
60
	/** @var IURLGenerator */
61
	private $urlGenerator;
62
	/** @var ICacheFactory */
63
	private $cacheFactory;
64
	/** @var Util */
65
	private $util;
66
	/** @var IAppManager */
67
	private $appManager;
68
	/** @var INavigationManager */
69
	private $navigationManager;
70
71
	/** @var string */
72
	private $name;
73
	/** @var string */
74
	private $title;
75
	/** @var string */
76
	private $entity;
77
	/** @var string */
78
	private $productName;
79
	/** @var string */
80
	private $url;
81
	/** @var string */
82
	private $color;
83
84
	/** @var string */
85
	private $iTunesAppId;
86
	/** @var string */
87
	private $iOSClientUrl;
88
	/** @var string */
89
	private $AndroidClientUrl;
90
	/** @var string */
91
	private $FDroidClientUrl;
92
93
	/**
94
	 * ThemingDefaults constructor.
95
	 *
96
	 * @param IConfig $config
97
	 * @param IL10N $l
98
	 * @param ImageManager $imageManager
99
	 * @param IURLGenerator $urlGenerator
100
	 * @param ICacheFactory $cacheFactory
101
	 * @param Util $util
102
	 * @param IAppManager $appManager
103
	 */
104
	public function __construct(IConfig $config,
105
								IL10N $l,
106
								IURLGenerator $urlGenerator,
107
								ICacheFactory $cacheFactory,
108
								Util $util,
109
								ImageManager $imageManager,
110
								IAppManager $appManager,
111
								INavigationManager $navigationManager
112
	) {
113
		parent::__construct();
114
		$this->config = $config;
115
		$this->l = $l;
116
		$this->imageManager = $imageManager;
117
		$this->urlGenerator = $urlGenerator;
118
		$this->cacheFactory = $cacheFactory;
119
		$this->util = $util;
120
		$this->appManager = $appManager;
121
		$this->navigationManager = $navigationManager;
122
123
		$this->name = parent::getName();
124
		$this->title = parent::getTitle();
125
		$this->entity = parent::getEntity();
126
		$this->productName = parent::getProductName();
127
		$this->url = parent::getBaseUrl();
128
		$this->color = parent::getColorPrimary();
129
		$this->iTunesAppId = parent::getiTunesAppId();
130
		$this->iOSClientUrl = parent::getiOSClientUrl();
131
		$this->AndroidClientUrl = parent::getAndroidClientUrl();
132
		$this->FDroidClientUrl = parent::getFDroidClientUrl();
133
	}
134
135
	public function getName() {
136
		return strip_tags($this->config->getAppValue('theming', 'name', $this->name));
137
	}
138
139
	public function getHTMLName() {
140
		return $this->config->getAppValue('theming', 'name', $this->name);
141
	}
142
143
	public function getTitle() {
144
		return strip_tags($this->config->getAppValue('theming', 'name', $this->title));
145
	}
146
147
	public function getEntity() {
148
		return strip_tags($this->config->getAppValue('theming', 'name', $this->entity));
149
	}
150
151
	public function getProductName() {
152
		return strip_tags($this->config->getAppValue('theming', 'productName', $this->productName));
153
	}
154
155
	public function getBaseUrl() {
156
		return $this->config->getAppValue('theming', 'url', $this->url);
157
	}
158
159
	public function getSlogan(?string $lang = null) {
160
		return \OCP\Util::sanitizeHTML($this->config->getAppValue('theming', 'slogan', parent::getSlogan($lang)));
161
	}
162
163
	public function getImprintUrl() {
164
		return (string)$this->config->getAppValue('theming', 'imprintUrl', '');
165
	}
166
167
	public function getPrivacyUrl() {
168
		return (string)$this->config->getAppValue('theming', 'privacyUrl', '');
169
	}
170
171
	public function getShortFooter() {
172
		$slogan = $this->getSlogan();
173
		$baseUrl = $this->getBaseUrl();
174
		if ($baseUrl !== '') {
175
			$footer = '<a href="' . $baseUrl . '" target="_blank"' .
176
				' rel="noreferrer noopener" class="entity-name">' . $this->getEntity() . '</a>';
177
		} else {
178
			$footer = '<span class="entity-name">' .$this->getEntity() . '</span>';
179
		}
180
		$footer .= ($slogan !== '' ? ' – ' . $slogan : '');
181
182
		$links = [
183
			[
184
				'text' => $this->l->t('Legal notice'),
185
				'url' => (string)$this->getImprintUrl()
186
			],
187
			[
188
				'text' => $this->l->t('Privacy policy'),
189
				'url' => (string)$this->getPrivacyUrl()
190
			],
191
		];
192
193
		$navigation = $this->navigationManager->getAll(INavigationManager::TYPE_GUEST);
194
		$guestNavigation = array_map(function ($nav) {
195
			return [
196
				'text' => $nav['name'],
197
				'url' => $nav['href']
198
			];
199
		}, $navigation);
200
		$links = array_merge($links, $guestNavigation);
201
202
		$legalLinks = '';
203
		$divider = '';
204
		foreach ($links as $link) {
205
			if ($link['url'] !== ''
206
				&& filter_var($link['url'], FILTER_VALIDATE_URL)
207
			) {
208
				$legalLinks .= $divider . '<a href="' . $link['url'] . '" class="legal" target="_blank"' .
209
					' rel="noreferrer noopener">' . $link['text'] . '</a>';
210
				$divider = ' · ';
211
			}
212
		}
213
		if ($legalLinks !== '') {
214
			$footer .= '<br/>' . $legalLinks;
215
		}
216
217
		return $footer;
218
	}
219
220
	/**
221
	 * Color that is used for the header as well as for mail headers
222
	 *
223
	 * @return string
224
	 */
225
	public function getColorPrimary() {
226
		$color = $this->config->getAppValue('theming', 'color', $this->color);
227
		if (!preg_match('/^\#([0-9a-f]{3}|[0-9a-f]{6})$/i', $color)) {
228
			$color = '#0082c9';
229
		}
230
		return $color;
231
	}
232
233
	/**
234
	 * Themed logo url
235
	 *
236
	 * @param bool $useSvg Whether to point to the SVG image or a fallback
237
	 * @return string
238
	 */
239
	public function getLogo($useSvg = true): string {
240
		$logo = $this->config->getAppValue('theming', 'logoMime', '');
241
242
		// short cut to avoid setting up the filesystem just to check if the logo is there
243
		//
244
		// explanation: if an SVG is requested and the app config value for logoMime is set then the logo is there.
245
		// otherwise we need to check it and maybe also generate a PNG from the SVG (that's done in getImage() which
246
		// needs to be called then)
247
		if ($useSvg === true && $logo !== false) {
248
			$logoExists = true;
249
		} else {
250
			try {
251
				$this->imageManager->getImage('logo', $useSvg);
252
				$logoExists = true;
253
			} catch (\Exception $e) {
254
				$logoExists = false;
255
			}
256
		}
257
258
		$cacheBusterCounter = $this->config->getAppValue('theming', 'cachebuster', '0');
259
260
		if (!$logo || !$logoExists) {
261
			if ($useSvg) {
262
				$logo = $this->urlGenerator->imagePath('core', 'logo/logo.svg');
263
			} else {
264
				$logo = $this->urlGenerator->imagePath('core', 'logo/logo.png');
265
			}
266
			return $logo . '?v=' . $cacheBusterCounter;
267
		}
268
269
		return $this->urlGenerator->linkToRoute('theming.Theming.getImage', [ 'key' => 'logo', 'useSvg' => $useSvg, 'v' => $cacheBusterCounter ]);
270
	}
271
272
	/**
273
	 * Themed background image url
274
	 *
275
	 * @return string
276
	 */
277
	public function getBackground(): string {
278
		return $this->imageManager->getImageUrl('background');
279
	}
280
281
	/**
282
	 * @return string
283
	 */
284
	public function getiTunesAppId() {
285
		return $this->config->getAppValue('theming', 'iTunesAppId', $this->iTunesAppId);
286
	}
287
288
	/**
289
	 * @return string
290
	 */
291
	public function getiOSClientUrl() {
292
		return $this->config->getAppValue('theming', 'iOSClientUrl', $this->iOSClientUrl);
293
	}
294
295
	/**
296
	 * @return string
297
	 */
298
	public function getAndroidClientUrl() {
299
		return $this->config->getAppValue('theming', 'AndroidClientUrl', $this->AndroidClientUrl);
300
	}
301
302
	/**
303
	 * @return string
304
	 */
305
	public function getFDroidClientUrl() {
306
		return $this->config->getAppValue('theming', 'FDroidClientUrl', $this->FDroidClientUrl);
307
	}
308
309
	/**
310
	 * @return array scss variables to overwrite
311
	 */
312
	public function getScssVariables() {
313
		$cacheBuster = $this->config->getAppValue('theming', 'cachebuster', '0');
314
		$cache = $this->cacheFactory->createDistributed('theming-' . $cacheBuster . '-' . $this->urlGenerator->getBaseUrl());
315
		if ($value = $cache->get('getScssVariables')) {
316
			return $value;
317
		}
318
319
		$variables = [
320
			'theming-cachebuster' => "'" . $cacheBuster . "'",
321
			'theming-logo-mime' => "'" . $this->config->getAppValue('theming', 'logoMime') . "'",
322
			'theming-background-mime' => "'" . $this->config->getAppValue('theming', 'backgroundMime') . "'",
323
			'theming-logoheader-mime' => "'" . $this->config->getAppValue('theming', 'logoheaderMime') . "'",
324
			'theming-favicon-mime' => "'" . $this->config->getAppValue('theming', 'faviconMime') . "'"
325
		];
326
327
		$variables['image-logo'] = "url('".$this->imageManager->getImageUrl('logo')."')";
328
		$variables['image-logoheader'] = "url('".$this->imageManager->getImageUrl('logoheader')."')";
329
		$variables['image-favicon'] = "url('".$this->imageManager->getImageUrl('favicon')."')";
330
		$variables['image-login-background'] = "url('".$this->imageManager->getImageUrl('background')."')";
331
		$variables['image-login-plain'] = 'false';
332
333
		if ($this->config->getAppValue('theming', 'color', '') !== '') {
334
			$variables['color-primary'] = $this->getColorPrimary();
335
			$variables['color-primary-text'] = $this->getTextColorPrimary();
336
			$variables['color-primary-element'] = $this->util->elementColor($this->getColorPrimary());
337
		}
338
339
		if ($this->config->getAppValue('theming', 'backgroundMime', '') === 'backgroundColor') {
340
			$variables['image-login-plain'] = 'true';
341
		}
342
343
		$variables['has-legal-links'] = 'false';
344
		if ($this->getImprintUrl() !== '' || $this->getPrivacyUrl() !== '') {
345
			$variables['has-legal-links'] = 'true';
346
		}
347
348
		$cache->set('getScssVariables', $variables);
349
		return $variables;
350
	}
351
352
	/**
353
	 * Check if the image should be replaced by the theming app
354
	 * and return the new image location then
355
	 *
356
	 * @param string $app name of the app
357
	 * @param string $image filename of the image
358
	 * @return bool|string false if image should not replaced, otherwise the location of the image
359
	 */
360
	public function replaceImagePath($app, $image) {
361
		if ($app === '' || $app === 'files_sharing') {
362
			$app = 'core';
363
		}
364
		$cacheBusterValue = $this->config->getAppValue('theming', 'cachebuster', '0');
365
366
		try {
367
			$customFavicon = $this->imageManager->getImage('favicon');
368
		} catch (NotFoundException $e) {
369
			$customFavicon = null;
370
		}
371
372
		$route = false;
373
		if ($image === 'favicon.ico' && ($customFavicon !== null || $this->imageManager->shouldReplaceIcons())) {
374
			$route = $this->urlGenerator->linkToRoute('theming.Icon.getFavicon', ['app' => $app]);
375
		}
376
		if (($image === 'favicon-touch.png' || $image === 'favicon-fb.png') && ($customFavicon !== null || $this->imageManager->shouldReplaceIcons())) {
377
			$route = $this->urlGenerator->linkToRoute('theming.Icon.getTouchIcon', ['app' => $app]);
378
		}
379
		if ($image === 'manifest.json') {
380
			try {
381
				$appPath = $this->appManager->getAppPath($app);
382
				if (file_exists($appPath . '/img/manifest.json')) {
383
					return false;
384
				}
385
			} catch (AppPathNotFoundException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
386
			}
387
			$route = $this->urlGenerator->linkToRoute('theming.Theming.getManifest');
388
		}
389
		if (strpos($image, 'filetypes/') === 0 && file_exists(\OC::$SERVERROOT . '/core/img/' . $image)) {
390
			$route = $this->urlGenerator->linkToRoute('theming.Icon.getThemedIcon', ['app' => $app, 'image' => $image]);
391
		}
392
393
		if ($route) {
394
			return $route . '?v=' . $cacheBusterValue;
395
		}
396
397
		return false;
398
	}
399
400
	/**
401
	 * Increases the cache buster key
402
	 */
403
	private function increaseCacheBuster() {
404
		$cacheBusterKey = $this->config->getAppValue('theming', 'cachebuster', '0');
405
		$this->config->setAppValue('theming', 'cachebuster', (int)$cacheBusterKey + 1);
406
		$this->cacheFactory->createDistributed('theming-')->clear();
407
		$this->cacheFactory->createDistributed('imagePath')->clear();
408
	}
409
410
	/**
411
	 * Update setting in the database
412
	 *
413
	 * @param string $setting
414
	 * @param string $value
415
	 */
416
	public function set($setting, $value) {
417
		$this->config->setAppValue('theming', $setting, $value);
418
		$this->increaseCacheBuster();
419
	}
420
421
	/**
422
	 * Revert settings to the default value
423
	 *
424
	 * @param string $setting setting which should be reverted
425
	 * @return string default value
426
	 */
427
	public function undo($setting) {
428
		$this->config->deleteAppValue('theming', $setting);
429
		$this->increaseCacheBuster();
430
431
		$returnValue = '';
432
		switch ($setting) {
433
			case 'name':
434
				$returnValue = $this->getEntity();
435
				break;
436
			case 'url':
437
				$returnValue = $this->getBaseUrl();
438
				break;
439
			case 'slogan':
440
				$returnValue = $this->getSlogan();
441
				break;
442
			case 'color':
443
				$returnValue = $this->getColorPrimary();
444
				break;
445
			case 'logo':
446
			case 'logoheader':
447
			case 'background':
448
			case 'favicon':
449
				$this->imageManager->delete($setting);
450
				break;
451
		}
452
453
		return $returnValue;
454
	}
455
456
	/**
457
	 * Color of text in the header and primary buttons
458
	 *
459
	 * @return string
460
	 */
461
	public function getTextColorPrimary() {
462
		return $this->util->invertTextColor($this->getColorPrimary()) ? '#000000' : '#ffffff';
463
	}
464
}
465