Completed
Pull Request — master (#6451)
by Julius
73:56 queued 28:18
created

ThemingDefaults::replaceImagePath()   C

Complexity

Conditions 9
Paths 14

Size

Total Lines 23
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 16
nc 14
nop 2
dl 0
loc 23
rs 5.8541
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
 * @license GNU AGPL version 3 or any later version
7
 *
8
 * This program is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Affero General Public License as
10
 * published by the Free Software Foundation, either version 3 of the
11
 * License, or (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU Affero General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Affero General Public License
19
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
 *
21
 */
22
23
namespace OCA\Theming;
24
25
26
use OCP\App\AppPathNotFoundException;
27
use OCP\App\IAppManager;
28
use OCP\Files\IAppData;
29
use OCP\ICacheFactory;
30
use OCP\IConfig;
31
use OCP\IL10N;
32
use OCP\IURLGenerator;
33
34
class ThemingDefaults extends \OC_Defaults {
35
36
	/** @var IConfig */
37
	private $config;
38
	/** @var IL10N */
39
	private $l;
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
40
	/** @var IURLGenerator */
41
	private $urlGenerator;
42
	/** @var IAppData */
43
	private $appData;
44
	/** @var ICacheFactory */
45
	private $cacheFactory;
46
	/** @var Util */
47
	private $util;
48
	/** @var IAppManager */
49
	private $appManager;
50
	/** @var string */
51
	private $name;
52
	/** @var string */
53
	private $url;
54
	/** @var string */
55
	private $slogan;
56
	/** @var string */
57
	private $color;
58
59
	/** @var string */
60
	private $iTunesAppId;
61
	/** @var string */
62
	private $iOSClientUrl;
63
	/** @var string */
64
	private $AndroidClientUrl;
65
66
	/**
67
	 * ThemingDefaults constructor.
68
	 *
69
	 * @param IConfig $config
70
	 * @param IL10N $l
71
	 * @param IURLGenerator $urlGenerator
72
	 * @param \OC_Defaults $defaults
0 ignored issues
show
Bug introduced by
There is no parameter named $defaults. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
73
	 * @param IAppData $appData
74
	 * @param ICacheFactory $cacheFactory
75
	 * @param Util $util
76
	 * @param IAppManager $appManager
77
	 */
78
	public function __construct(IConfig $config,
79
								IL10N $l,
80
								IURLGenerator $urlGenerator,
81
								IAppData $appData,
82
								ICacheFactory $cacheFactory,
83
								Util $util,
84
								IAppManager $appManager
85
	) {
86
		parent::__construct();
87
		$this->config = $config;
88
		$this->l = $l;
89
		$this->urlGenerator = $urlGenerator;
90
		$this->appData = $appData;
91
		$this->cacheFactory = $cacheFactory;
92
		$this->util = $util;
93
		$this->appManager = $appManager;
94
95
		$this->name = parent::getName();
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (getName() instead of __construct()). Are you sure this is correct? If so, you might want to change this to $this->getName().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
96
		$this->url = parent::getBaseUrl();
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (getBaseUrl() instead of __construct()). Are you sure this is correct? If so, you might want to change this to $this->getBaseUrl().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
97
		$this->slogan = parent::getSlogan();
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (getSlogan() instead of __construct()). Are you sure this is correct? If so, you might want to change this to $this->getSlogan().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
98
		$this->color = parent::getColorPrimary();
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (getColorPrimary() instead of __construct()). Are you sure this is correct? If so, you might want to change this to $this->getColorPrimary().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
99
		$this->iTunesAppId = parent::getiTunesAppId();
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (getiTunesAppId() instead of __construct()). Are you sure this is correct? If so, you might want to change this to $this->getiTunesAppId().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
100
		$this->iOSClientUrl = parent::getiOSClientUrl();
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (getiOSClientUrl() instead of __construct()). Are you sure this is correct? If so, you might want to change this to $this->getiOSClientUrl().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
101
		$this->AndroidClientUrl = parent::getAndroidClientUrl();
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (getAndroidClientUrl() instead of __construct()). Are you sure this is correct? If so, you might want to change this to $this->getAndroidClientUrl().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
102
	}
103
104
	public function getName() {
105
		return strip_tags($this->config->getAppValue('theming', 'name', $this->name));
106
	}
107
108
	public function getHTMLName() {
109
		return $this->config->getAppValue('theming', 'name', $this->name);
110
	}
111
112
	public function getTitle() {
113
		return $this->getName();
114
	}
115
116
	public function getEntity() {
117
		return $this->getName();
118
	}
119
120
	public function getBaseUrl() {
121
		return $this->config->getAppValue('theming', 'url', $this->url);
122
	}
123
124
	public function getSlogan() {
125
		return \OCP\Util::sanitizeHTML($this->config->getAppValue('theming', 'slogan', $this->slogan));
0 ignored issues
show
Bug Compatibility introduced by
The expression \OCP\Util::sanitizeHTML(...ogan', $this->slogan)); of type array|string adds the type array to the return on line 125 which is incompatible with the return type of the parent method OC_Defaults::getSlogan of type string.
Loading history...
126
	}
127
128
	public function getShortFooter() {
129
		$slogan = $this->getSlogan();
130
		$footer = '<a href="'. $this->getBaseUrl() . '" target="_blank"' .
131
			' rel="noreferrer">' .$this->getEntity() . '</a>'.
132
			($slogan !== '' ? ' – ' . $slogan : '');
133
134
		return $footer;
135
	}
136
137
	/**
138
	 * Color that is used for the header as well as for mail headers
139
	 *
140
	 * @return string
141
	 */
142
	public function getColorPrimary() {
143
		return $this->config->getAppValue('theming', 'color', $this->color);
144
	}
145
146
	/**
147
	 * Themed logo url
148
	 *
149
	 * @param bool $useSvg Whether to point to the SVG image or a fallback
150
	 * @return string
151
	 */
152
	public function getLogo($useSvg = true) {
153
		$logo = $this->config->getAppValue('theming', 'logoMime', false);
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
154
155
		$logoExists = true;
156
		try {
157
			$this->appData->getFolder('images')->getFile('logo');
158
		} catch (\Exception $e) {
159
			$logoExists = false;
160
		}
161
162
		$cacheBusterCounter = $this->config->getAppValue('theming', 'cachebuster', '0');
163
164
		if(!$logo || !$logoExists) {
165
			if($useSvg) {
166
				$logo = $this->urlGenerator->imagePath('core', 'logo.svg');
167
			} else {
168
				$logo = $this->urlGenerator->imagePath('core', 'logo.png');
169
			}
170
			return $logo . '?v=' . $cacheBusterCounter;
171
		}
172
173
		return $this->urlGenerator->linkToRoute('theming.Theming.getLogo') . '?v=' . $cacheBusterCounter;
174
	}
175
176
	/**
177
	 * Themed background image url
178
	 *
179
	 * @return string
180
	 */
181
	public function getBackground() {
182
		$backgroundLogo = $this->config->getAppValue('theming', 'backgroundMime',false);
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
183
184
		$backgroundExists = true;
185
		try {
186
			$this->appData->getFolder('images')->getFile('background');
187
		} catch (\Exception $e) {
188
			$backgroundExists = false;
189
		}
190
191
		$cacheBusterCounter = $this->config->getAppValue('theming', 'cachebuster', '0');
192
193
		if(!$backgroundLogo || !$backgroundExists) {
194
			return $this->urlGenerator->imagePath('core','background.png') . '?v=' . $cacheBusterCounter;
195
		}
196
197
		return $this->urlGenerator->linkToRoute('theming.Theming.getLoginBackground') . '?v=' . $cacheBusterCounter;
198
	}
199
200
	/**
201
	 * @return string
202
	 */
203
	public function getiTunesAppId() {
204
		return $this->config->getAppValue('theming', 'iTunesAppId', $this->iTunesAppId);
205
	}
206
207
	/**
208
	 * @return string
209
	 */
210
	public function getiOSClientUrl() {
211
		return $this->config->getAppValue('theming', 'iOSClientUrl', $this->iOSClientUrl);
212
	}
213
214
	/**
215
	 * @return string
216
	 */
217
	public function getAndroidClientUrl() {
218
		return $this->config->getAppValue('theming', 'AndroidClientUrl', $this->AndroidClientUrl);
219
	}
220
221
222
	/**
223
	 * @return array scss variables to overwrite
224
	 */
225
	public function getScssVariables() {
226
		$cache = $this->cacheFactory->create('theming');
227
		if ($value = $cache->get('getScssVariables')) {
228
			return $value;
229
		}
230
231
		$variables = [
232
			'theming-cachebuster' => "'" . $this->config->getAppValue('theming', 'cachebuster', '0') . "'",
233
			'theming-logo-mime' => "'" . $this->config->getAppValue('theming', 'logoMime', '') . "'",
234
			'theming-background-mime' => "'" . $this->config->getAppValue('theming', 'backgroundMime', '') . "'"
235
		];
236
237
		$variables['image-logo'] = "'".$this->urlGenerator->getAbsoluteURL($this->getLogo())."'";
238
		$variables['image-login-background'] = "'".$this->urlGenerator->getAbsoluteURL($this->getBackground())."'";
239
		$variables['image-login-plain'] = 'false';
240
241
		if ($this->config->getAppValue('theming', 'color', null) !== null) {
242
			if ($this->util->invertTextColor($this->getColorPrimary())) {
243
				$colorPrimaryText = '#000000';
244
			} else {
245
				$colorPrimaryText = '#ffffff';
246
			}
247
			$variables['color-primary'] = $this->getColorPrimary();
248
			$variables['color-primary-text'] = $colorPrimaryText;
249
			$variables['color-primary-element'] = $this->util->elementColor($this->getColorPrimary());
250
		}
251
252
		if ($this->config->getAppValue('theming', 'backgroundMime', null) === 'backgroundColor') {
253
			$variables['image-login-plain'] = 'true';
254
		}
255
		$cache->set('getScssVariables', $variables);
256
		return $variables;
257
	}
258
259
	/**
260
	 * Check if the image should be replaced by the theming app
261
	 * and return the new image location then
262
	 *
263
	 * @param string $app name of the app
264
	 * @param string $image filename of the image
265
	 * @return bool|string false if image should not replaced, otherwise the location of the image
266
	 */
267
	public function replaceImagePath($app, $image) {
268
		if($app==='') {
269
			$app = 'core';
270
		}
271
		$cacheBusterValue = $this->config->getAppValue('theming', 'cachebuster', '0');
272
273
		if ($image === 'favicon.ico' && $this->shouldReplaceIcons()) {
274
			return $this->urlGenerator->linkToRoute('theming.Icon.getFavicon', ['app' => $app]) . '?v=' . $cacheBusterValue;
275
		}
276
		if ($image === 'favicon-touch.png' && $this->shouldReplaceIcons()) {
277
			return $this->urlGenerator->linkToRoute('theming.Icon.getTouchIcon', ['app' => $app]) . '?v=' . $cacheBusterValue;
278
		}
279
		if ($image === 'manifest.json') {
280
			try {
281
				$appPath = $this->appManager->getAppPath($app);
282
				if (file_exists($appPath . '/img/manifest.json')) {
283
					return false;
284
				}
285
			} catch (AppPathNotFoundException $e) {}
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
286
			return $this->urlGenerator->linkToRoute('theming.Theming.getManifest') . '?v=' . $cacheBusterValue;
287
		}
288
		return false;
289
	}
290
291
	/**
292
	 * Check if Imagemagick is enabled and if SVG is supported
293
	 * otherwise we can't render custom icons
294
	 *
295
	 * @return bool
296
	 */
297
	public function shouldReplaceIcons() {
298
		$cache = $this->cacheFactory->create('theming');
299
		if($value = $cache->get('shouldReplaceIcons')) {
300
			return (bool)$value;
301
		}
302
		$value = false;
303
		if(extension_loaded('imagick')) {
304
			$checkImagick = new \Imagick();
305
			if (count($checkImagick->queryFormats('SVG')) >= 1) {
306
				$value = true;
307
			}
308
			$checkImagick->clear();
309
		}
310
		$cache->set('shouldReplaceIcons', $value);
311
		return $value;
312
	}
313
314
	/**
315
	 * Increases the cache buster key
316
	 */
317
	private function increaseCacheBuster() {
318
		$cacheBusterKey = $this->config->getAppValue('theming', 'cachebuster', '0');
319
		$this->config->setAppValue('theming', 'cachebuster', (int)$cacheBusterKey+1);
320
		$this->cacheFactory->create('theming')->clear('getScssVariables');
321
	}
322
323
	/**
324
	 * Update setting in the database
325
	 *
326
	 * @param string $setting
327
	 * @param string $value
328
	 */
329
	public function set($setting, $value) {
330
		$this->config->setAppValue('theming', $setting, $value);
331
		$this->increaseCacheBuster();
332
	}
333
334
	/**
335
	 * Revert settings to the default value
336
	 *
337
	 * @param string $setting setting which should be reverted
338
	 * @return string default value
339
	 */
340
	public function undo($setting) {
341
		$this->config->deleteAppValue('theming', $setting);
342
		$this->increaseCacheBuster();
343
344
		switch ($setting) {
345
			case 'name':
346
				$returnValue = $this->getEntity();
347
				break;
348
			case 'url':
349
				$returnValue = $this->getBaseUrl();
350
				break;
351
			case 'slogan':
352
				$returnValue = $this->getSlogan();
353
				break;
354
			case 'color':
355
				$returnValue = $this->getColorPrimary();
356
				break;
357
			default:
358
				$returnValue = '';
359
				break;
360
		}
361
362
		return $returnValue;
363
	}
364
}
365