@@ -33,338 +33,338 @@ |
||
33 | 33 | |
34 | 34 | class ThemingDefaults extends \OC_Defaults { |
35 | 35 | |
36 | - /** @var IConfig */ |
|
37 | - private $config; |
|
38 | - /** @var IL10N */ |
|
39 | - private $l; |
|
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 $title; |
|
54 | - /** @var string */ |
|
55 | - private $entity; |
|
56 | - /** @var string */ |
|
57 | - private $url; |
|
58 | - /** @var string */ |
|
59 | - private $slogan; |
|
60 | - /** @var string */ |
|
61 | - private $color; |
|
62 | - |
|
63 | - /** @var string */ |
|
64 | - private $iTunesAppId; |
|
65 | - /** @var string */ |
|
66 | - private $iOSClientUrl; |
|
67 | - /** @var string */ |
|
68 | - private $AndroidClientUrl; |
|
69 | - |
|
70 | - /** |
|
71 | - * ThemingDefaults constructor. |
|
72 | - * |
|
73 | - * @param IConfig $config |
|
74 | - * @param IL10N $l |
|
75 | - * @param IURLGenerator $urlGenerator |
|
76 | - * @param \OC_Defaults $defaults |
|
77 | - * @param IAppData $appData |
|
78 | - * @param ICacheFactory $cacheFactory |
|
79 | - * @param Util $util |
|
80 | - * @param IAppManager $appManager |
|
81 | - */ |
|
82 | - public function __construct(IConfig $config, |
|
83 | - IL10N $l, |
|
84 | - IURLGenerator $urlGenerator, |
|
85 | - IAppData $appData, |
|
86 | - ICacheFactory $cacheFactory, |
|
87 | - Util $util, |
|
88 | - IAppManager $appManager |
|
89 | - ) { |
|
90 | - parent::__construct(); |
|
91 | - $this->config = $config; |
|
92 | - $this->l = $l; |
|
93 | - $this->urlGenerator = $urlGenerator; |
|
94 | - $this->appData = $appData; |
|
95 | - $this->cacheFactory = $cacheFactory; |
|
96 | - $this->util = $util; |
|
97 | - $this->appManager = $appManager; |
|
98 | - |
|
99 | - $this->name = parent::getName(); |
|
100 | - $this->title = parent::getTitle(); |
|
101 | - $this->entity = parent::getEntity(); |
|
102 | - $this->url = parent::getBaseUrl(); |
|
103 | - $this->slogan = parent::getSlogan(); |
|
104 | - $this->color = parent::getColorPrimary(); |
|
105 | - $this->iTunesAppId = parent::getiTunesAppId(); |
|
106 | - $this->iOSClientUrl = parent::getiOSClientUrl(); |
|
107 | - $this->AndroidClientUrl = parent::getAndroidClientUrl(); |
|
108 | - } |
|
109 | - |
|
110 | - public function getName() { |
|
111 | - return strip_tags($this->config->getAppValue('theming', 'name', $this->name)); |
|
112 | - } |
|
113 | - |
|
114 | - public function getHTMLName() { |
|
115 | - return $this->config->getAppValue('theming', 'name', $this->name); |
|
116 | - } |
|
117 | - |
|
118 | - public function getTitle() { |
|
119 | - return strip_tags($this->config->getAppValue('theming', 'name', $this->title)); |
|
120 | - } |
|
121 | - |
|
122 | - public function getEntity() { |
|
123 | - return strip_tags($this->config->getAppValue('theming', 'name', $this->entity)); |
|
124 | - } |
|
125 | - |
|
126 | - public function getBaseUrl() { |
|
127 | - return $this->config->getAppValue('theming', 'url', $this->url); |
|
128 | - } |
|
129 | - |
|
130 | - public function getSlogan() { |
|
131 | - return \OCP\Util::sanitizeHTML($this->config->getAppValue('theming', 'slogan', $this->slogan)); |
|
132 | - } |
|
133 | - |
|
134 | - public function getShortFooter() { |
|
135 | - $slogan = $this->getSlogan(); |
|
136 | - $footer = '<a href="'. $this->getBaseUrl() . '" target="_blank"' . |
|
137 | - ' rel="noreferrer noopener">' .$this->getEntity() . '</a>'. |
|
138 | - ($slogan !== '' ? ' – ' . $slogan : ''); |
|
139 | - |
|
140 | - return $footer; |
|
141 | - } |
|
142 | - |
|
143 | - /** |
|
144 | - * Color that is used for the header as well as for mail headers |
|
145 | - * |
|
146 | - * @return string |
|
147 | - */ |
|
148 | - public function getColorPrimary() { |
|
149 | - return $this->config->getAppValue('theming', 'color', $this->color); |
|
150 | - } |
|
151 | - |
|
152 | - /** |
|
153 | - * Themed logo url |
|
154 | - * |
|
155 | - * @param bool $useSvg Whether to point to the SVG image or a fallback |
|
156 | - * @return string |
|
157 | - */ |
|
158 | - public function getLogo($useSvg = true) { |
|
159 | - $logo = $this->config->getAppValue('theming', 'logoMime', false); |
|
160 | - |
|
161 | - $logoExists = true; |
|
162 | - try { |
|
163 | - $this->appData->getFolder('images')->getFile('logo'); |
|
164 | - } catch (\Exception $e) { |
|
165 | - $logoExists = false; |
|
166 | - } |
|
167 | - |
|
168 | - $cacheBusterCounter = $this->config->getAppValue('theming', 'cachebuster', '0'); |
|
169 | - |
|
170 | - if(!$logo || !$logoExists) { |
|
171 | - if($useSvg) { |
|
172 | - $logo = $this->urlGenerator->imagePath('core', 'logo.svg'); |
|
173 | - } else { |
|
174 | - $logo = $this->urlGenerator->imagePath('core', 'logo.png'); |
|
175 | - } |
|
176 | - return $logo . '?v=' . $cacheBusterCounter; |
|
177 | - } |
|
178 | - |
|
179 | - return $this->urlGenerator->linkToRoute('theming.Theming.getLogo') . '?v=' . $cacheBusterCounter; |
|
180 | - } |
|
181 | - |
|
182 | - /** |
|
183 | - * Themed background image url |
|
184 | - * |
|
185 | - * @return string |
|
186 | - */ |
|
187 | - public function getBackground() { |
|
188 | - $backgroundLogo = $this->config->getAppValue('theming', 'backgroundMime',false); |
|
189 | - |
|
190 | - $backgroundExists = true; |
|
191 | - try { |
|
192 | - $this->appData->getFolder('images')->getFile('background'); |
|
193 | - } catch (\Exception $e) { |
|
194 | - $backgroundExists = false; |
|
195 | - } |
|
196 | - |
|
197 | - $cacheBusterCounter = $this->config->getAppValue('theming', 'cachebuster', '0'); |
|
198 | - |
|
199 | - if(!$backgroundLogo || !$backgroundExists) { |
|
200 | - return $this->urlGenerator->imagePath('core','background.png') . '?v=' . $cacheBusterCounter; |
|
201 | - } |
|
202 | - |
|
203 | - return $this->urlGenerator->linkToRoute('theming.Theming.getLoginBackground') . '?v=' . $cacheBusterCounter; |
|
204 | - } |
|
205 | - |
|
206 | - /** |
|
207 | - * @return string |
|
208 | - */ |
|
209 | - public function getiTunesAppId() { |
|
210 | - return $this->config->getAppValue('theming', 'iTunesAppId', $this->iTunesAppId); |
|
211 | - } |
|
212 | - |
|
213 | - /** |
|
214 | - * @return string |
|
215 | - */ |
|
216 | - public function getiOSClientUrl() { |
|
217 | - return $this->config->getAppValue('theming', 'iOSClientUrl', $this->iOSClientUrl); |
|
218 | - } |
|
219 | - |
|
220 | - /** |
|
221 | - * @return string |
|
222 | - */ |
|
223 | - public function getAndroidClientUrl() { |
|
224 | - return $this->config->getAppValue('theming', 'AndroidClientUrl', $this->AndroidClientUrl); |
|
225 | - } |
|
226 | - |
|
227 | - |
|
228 | - /** |
|
229 | - * @return array scss variables to overwrite |
|
230 | - */ |
|
231 | - public function getScssVariables() { |
|
232 | - $cache = $this->cacheFactory->create('theming'); |
|
233 | - if ($value = $cache->get('getScssVariables')) { |
|
234 | - return $value; |
|
235 | - } |
|
236 | - |
|
237 | - $variables = [ |
|
238 | - 'theming-cachebuster' => "'" . $this->config->getAppValue('theming', 'cachebuster', '0') . "'", |
|
239 | - 'theming-logo-mime' => "'" . $this->config->getAppValue('theming', 'logoMime', '') . "'", |
|
240 | - 'theming-background-mime' => "'" . $this->config->getAppValue('theming', 'backgroundMime', '') . "'" |
|
241 | - ]; |
|
242 | - |
|
243 | - $variables['image-logo'] = "'".$this->urlGenerator->getAbsoluteURL($this->getLogo())."'"; |
|
244 | - $variables['image-login-background'] = "'".$this->urlGenerator->getAbsoluteURL($this->getBackground())."'"; |
|
245 | - $variables['image-login-plain'] = 'false'; |
|
246 | - |
|
247 | - if ($this->config->getAppValue('theming', 'color', null) !== null) { |
|
248 | - if ($this->util->invertTextColor($this->getColorPrimary())) { |
|
249 | - $colorPrimaryText = '#000000'; |
|
250 | - } else { |
|
251 | - $colorPrimaryText = '#ffffff'; |
|
252 | - } |
|
253 | - $variables['color-primary'] = $this->getColorPrimary(); |
|
254 | - $variables['color-primary-text'] = $colorPrimaryText; |
|
255 | - $variables['color-primary-element'] = $this->util->elementColor($this->getColorPrimary()); |
|
256 | - } |
|
257 | - |
|
258 | - if ($this->config->getAppValue('theming', 'backgroundMime', null) === 'backgroundColor') { |
|
259 | - $variables['image-login-plain'] = 'true'; |
|
260 | - } |
|
261 | - $cache->set('getScssVariables', $variables); |
|
262 | - return $variables; |
|
263 | - } |
|
264 | - |
|
265 | - /** |
|
266 | - * Check if the image should be replaced by the theming app |
|
267 | - * and return the new image location then |
|
268 | - * |
|
269 | - * @param string $app name of the app |
|
270 | - * @param string $image filename of the image |
|
271 | - * @return bool|string false if image should not replaced, otherwise the location of the image |
|
272 | - */ |
|
273 | - public function replaceImagePath($app, $image) { |
|
274 | - if($app==='') { |
|
275 | - $app = 'core'; |
|
276 | - } |
|
277 | - $cacheBusterValue = $this->config->getAppValue('theming', 'cachebuster', '0'); |
|
278 | - |
|
279 | - if ($image === 'favicon.ico' && $this->shouldReplaceIcons()) { |
|
280 | - return $this->urlGenerator->linkToRoute('theming.Icon.getFavicon', ['app' => $app]) . '?v=' . $cacheBusterValue; |
|
281 | - } |
|
282 | - if ($image === 'favicon-touch.png' && $this->shouldReplaceIcons()) { |
|
283 | - return $this->urlGenerator->linkToRoute('theming.Icon.getTouchIcon', ['app' => $app]) . '?v=' . $cacheBusterValue; |
|
284 | - } |
|
285 | - if ($image === 'manifest.json') { |
|
286 | - try { |
|
287 | - $appPath = $this->appManager->getAppPath($app); |
|
288 | - if (file_exists($appPath . '/img/manifest.json')) { |
|
289 | - return false; |
|
290 | - } |
|
291 | - } catch (AppPathNotFoundException $e) {} |
|
292 | - return $this->urlGenerator->linkToRoute('theming.Theming.getManifest') . '?v=' . $cacheBusterValue; |
|
293 | - } |
|
294 | - return false; |
|
295 | - } |
|
296 | - |
|
297 | - /** |
|
298 | - * Check if Imagemagick is enabled and if SVG is supported |
|
299 | - * otherwise we can't render custom icons |
|
300 | - * |
|
301 | - * @return bool |
|
302 | - */ |
|
303 | - public function shouldReplaceIcons() { |
|
304 | - $cache = $this->cacheFactory->create('theming'); |
|
305 | - if($value = $cache->get('shouldReplaceIcons')) { |
|
306 | - return (bool)$value; |
|
307 | - } |
|
308 | - $value = false; |
|
309 | - if(extension_loaded('imagick')) { |
|
310 | - $checkImagick = new \Imagick(); |
|
311 | - if (count($checkImagick->queryFormats('SVG')) >= 1) { |
|
312 | - $value = true; |
|
313 | - } |
|
314 | - $checkImagick->clear(); |
|
315 | - } |
|
316 | - $cache->set('shouldReplaceIcons', $value); |
|
317 | - return $value; |
|
318 | - } |
|
319 | - |
|
320 | - /** |
|
321 | - * Increases the cache buster key |
|
322 | - */ |
|
323 | - private function increaseCacheBuster() { |
|
324 | - $cacheBusterKey = $this->config->getAppValue('theming', 'cachebuster', '0'); |
|
325 | - $this->config->setAppValue('theming', 'cachebuster', (int)$cacheBusterKey+1); |
|
326 | - $this->cacheFactory->create('theming')->clear('getScssVariables'); |
|
327 | - } |
|
328 | - |
|
329 | - /** |
|
330 | - * Update setting in the database |
|
331 | - * |
|
332 | - * @param string $setting |
|
333 | - * @param string $value |
|
334 | - */ |
|
335 | - public function set($setting, $value) { |
|
336 | - $this->config->setAppValue('theming', $setting, $value); |
|
337 | - $this->increaseCacheBuster(); |
|
338 | - } |
|
339 | - |
|
340 | - /** |
|
341 | - * Revert settings to the default value |
|
342 | - * |
|
343 | - * @param string $setting setting which should be reverted |
|
344 | - * @return string default value |
|
345 | - */ |
|
346 | - public function undo($setting) { |
|
347 | - $this->config->deleteAppValue('theming', $setting); |
|
348 | - $this->increaseCacheBuster(); |
|
349 | - |
|
350 | - switch ($setting) { |
|
351 | - case 'name': |
|
352 | - $returnValue = $this->getEntity(); |
|
353 | - break; |
|
354 | - case 'url': |
|
355 | - $returnValue = $this->getBaseUrl(); |
|
356 | - break; |
|
357 | - case 'slogan': |
|
358 | - $returnValue = $this->getSlogan(); |
|
359 | - break; |
|
360 | - case 'color': |
|
361 | - $returnValue = $this->getColorPrimary(); |
|
362 | - break; |
|
363 | - default: |
|
364 | - $returnValue = ''; |
|
365 | - break; |
|
366 | - } |
|
367 | - |
|
368 | - return $returnValue; |
|
369 | - } |
|
36 | + /** @var IConfig */ |
|
37 | + private $config; |
|
38 | + /** @var IL10N */ |
|
39 | + private $l; |
|
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 $title; |
|
54 | + /** @var string */ |
|
55 | + private $entity; |
|
56 | + /** @var string */ |
|
57 | + private $url; |
|
58 | + /** @var string */ |
|
59 | + private $slogan; |
|
60 | + /** @var string */ |
|
61 | + private $color; |
|
62 | + |
|
63 | + /** @var string */ |
|
64 | + private $iTunesAppId; |
|
65 | + /** @var string */ |
|
66 | + private $iOSClientUrl; |
|
67 | + /** @var string */ |
|
68 | + private $AndroidClientUrl; |
|
69 | + |
|
70 | + /** |
|
71 | + * ThemingDefaults constructor. |
|
72 | + * |
|
73 | + * @param IConfig $config |
|
74 | + * @param IL10N $l |
|
75 | + * @param IURLGenerator $urlGenerator |
|
76 | + * @param \OC_Defaults $defaults |
|
77 | + * @param IAppData $appData |
|
78 | + * @param ICacheFactory $cacheFactory |
|
79 | + * @param Util $util |
|
80 | + * @param IAppManager $appManager |
|
81 | + */ |
|
82 | + public function __construct(IConfig $config, |
|
83 | + IL10N $l, |
|
84 | + IURLGenerator $urlGenerator, |
|
85 | + IAppData $appData, |
|
86 | + ICacheFactory $cacheFactory, |
|
87 | + Util $util, |
|
88 | + IAppManager $appManager |
|
89 | + ) { |
|
90 | + parent::__construct(); |
|
91 | + $this->config = $config; |
|
92 | + $this->l = $l; |
|
93 | + $this->urlGenerator = $urlGenerator; |
|
94 | + $this->appData = $appData; |
|
95 | + $this->cacheFactory = $cacheFactory; |
|
96 | + $this->util = $util; |
|
97 | + $this->appManager = $appManager; |
|
98 | + |
|
99 | + $this->name = parent::getName(); |
|
100 | + $this->title = parent::getTitle(); |
|
101 | + $this->entity = parent::getEntity(); |
|
102 | + $this->url = parent::getBaseUrl(); |
|
103 | + $this->slogan = parent::getSlogan(); |
|
104 | + $this->color = parent::getColorPrimary(); |
|
105 | + $this->iTunesAppId = parent::getiTunesAppId(); |
|
106 | + $this->iOSClientUrl = parent::getiOSClientUrl(); |
|
107 | + $this->AndroidClientUrl = parent::getAndroidClientUrl(); |
|
108 | + } |
|
109 | + |
|
110 | + public function getName() { |
|
111 | + return strip_tags($this->config->getAppValue('theming', 'name', $this->name)); |
|
112 | + } |
|
113 | + |
|
114 | + public function getHTMLName() { |
|
115 | + return $this->config->getAppValue('theming', 'name', $this->name); |
|
116 | + } |
|
117 | + |
|
118 | + public function getTitle() { |
|
119 | + return strip_tags($this->config->getAppValue('theming', 'name', $this->title)); |
|
120 | + } |
|
121 | + |
|
122 | + public function getEntity() { |
|
123 | + return strip_tags($this->config->getAppValue('theming', 'name', $this->entity)); |
|
124 | + } |
|
125 | + |
|
126 | + public function getBaseUrl() { |
|
127 | + return $this->config->getAppValue('theming', 'url', $this->url); |
|
128 | + } |
|
129 | + |
|
130 | + public function getSlogan() { |
|
131 | + return \OCP\Util::sanitizeHTML($this->config->getAppValue('theming', 'slogan', $this->slogan)); |
|
132 | + } |
|
133 | + |
|
134 | + public function getShortFooter() { |
|
135 | + $slogan = $this->getSlogan(); |
|
136 | + $footer = '<a href="'. $this->getBaseUrl() . '" target="_blank"' . |
|
137 | + ' rel="noreferrer noopener">' .$this->getEntity() . '</a>'. |
|
138 | + ($slogan !== '' ? ' – ' . $slogan : ''); |
|
139 | + |
|
140 | + return $footer; |
|
141 | + } |
|
142 | + |
|
143 | + /** |
|
144 | + * Color that is used for the header as well as for mail headers |
|
145 | + * |
|
146 | + * @return string |
|
147 | + */ |
|
148 | + public function getColorPrimary() { |
|
149 | + return $this->config->getAppValue('theming', 'color', $this->color); |
|
150 | + } |
|
151 | + |
|
152 | + /** |
|
153 | + * Themed logo url |
|
154 | + * |
|
155 | + * @param bool $useSvg Whether to point to the SVG image or a fallback |
|
156 | + * @return string |
|
157 | + */ |
|
158 | + public function getLogo($useSvg = true) { |
|
159 | + $logo = $this->config->getAppValue('theming', 'logoMime', false); |
|
160 | + |
|
161 | + $logoExists = true; |
|
162 | + try { |
|
163 | + $this->appData->getFolder('images')->getFile('logo'); |
|
164 | + } catch (\Exception $e) { |
|
165 | + $logoExists = false; |
|
166 | + } |
|
167 | + |
|
168 | + $cacheBusterCounter = $this->config->getAppValue('theming', 'cachebuster', '0'); |
|
169 | + |
|
170 | + if(!$logo || !$logoExists) { |
|
171 | + if($useSvg) { |
|
172 | + $logo = $this->urlGenerator->imagePath('core', 'logo.svg'); |
|
173 | + } else { |
|
174 | + $logo = $this->urlGenerator->imagePath('core', 'logo.png'); |
|
175 | + } |
|
176 | + return $logo . '?v=' . $cacheBusterCounter; |
|
177 | + } |
|
178 | + |
|
179 | + return $this->urlGenerator->linkToRoute('theming.Theming.getLogo') . '?v=' . $cacheBusterCounter; |
|
180 | + } |
|
181 | + |
|
182 | + /** |
|
183 | + * Themed background image url |
|
184 | + * |
|
185 | + * @return string |
|
186 | + */ |
|
187 | + public function getBackground() { |
|
188 | + $backgroundLogo = $this->config->getAppValue('theming', 'backgroundMime',false); |
|
189 | + |
|
190 | + $backgroundExists = true; |
|
191 | + try { |
|
192 | + $this->appData->getFolder('images')->getFile('background'); |
|
193 | + } catch (\Exception $e) { |
|
194 | + $backgroundExists = false; |
|
195 | + } |
|
196 | + |
|
197 | + $cacheBusterCounter = $this->config->getAppValue('theming', 'cachebuster', '0'); |
|
198 | + |
|
199 | + if(!$backgroundLogo || !$backgroundExists) { |
|
200 | + return $this->urlGenerator->imagePath('core','background.png') . '?v=' . $cacheBusterCounter; |
|
201 | + } |
|
202 | + |
|
203 | + return $this->urlGenerator->linkToRoute('theming.Theming.getLoginBackground') . '?v=' . $cacheBusterCounter; |
|
204 | + } |
|
205 | + |
|
206 | + /** |
|
207 | + * @return string |
|
208 | + */ |
|
209 | + public function getiTunesAppId() { |
|
210 | + return $this->config->getAppValue('theming', 'iTunesAppId', $this->iTunesAppId); |
|
211 | + } |
|
212 | + |
|
213 | + /** |
|
214 | + * @return string |
|
215 | + */ |
|
216 | + public function getiOSClientUrl() { |
|
217 | + return $this->config->getAppValue('theming', 'iOSClientUrl', $this->iOSClientUrl); |
|
218 | + } |
|
219 | + |
|
220 | + /** |
|
221 | + * @return string |
|
222 | + */ |
|
223 | + public function getAndroidClientUrl() { |
|
224 | + return $this->config->getAppValue('theming', 'AndroidClientUrl', $this->AndroidClientUrl); |
|
225 | + } |
|
226 | + |
|
227 | + |
|
228 | + /** |
|
229 | + * @return array scss variables to overwrite |
|
230 | + */ |
|
231 | + public function getScssVariables() { |
|
232 | + $cache = $this->cacheFactory->create('theming'); |
|
233 | + if ($value = $cache->get('getScssVariables')) { |
|
234 | + return $value; |
|
235 | + } |
|
236 | + |
|
237 | + $variables = [ |
|
238 | + 'theming-cachebuster' => "'" . $this->config->getAppValue('theming', 'cachebuster', '0') . "'", |
|
239 | + 'theming-logo-mime' => "'" . $this->config->getAppValue('theming', 'logoMime', '') . "'", |
|
240 | + 'theming-background-mime' => "'" . $this->config->getAppValue('theming', 'backgroundMime', '') . "'" |
|
241 | + ]; |
|
242 | + |
|
243 | + $variables['image-logo'] = "'".$this->urlGenerator->getAbsoluteURL($this->getLogo())."'"; |
|
244 | + $variables['image-login-background'] = "'".$this->urlGenerator->getAbsoluteURL($this->getBackground())."'"; |
|
245 | + $variables['image-login-plain'] = 'false'; |
|
246 | + |
|
247 | + if ($this->config->getAppValue('theming', 'color', null) !== null) { |
|
248 | + if ($this->util->invertTextColor($this->getColorPrimary())) { |
|
249 | + $colorPrimaryText = '#000000'; |
|
250 | + } else { |
|
251 | + $colorPrimaryText = '#ffffff'; |
|
252 | + } |
|
253 | + $variables['color-primary'] = $this->getColorPrimary(); |
|
254 | + $variables['color-primary-text'] = $colorPrimaryText; |
|
255 | + $variables['color-primary-element'] = $this->util->elementColor($this->getColorPrimary()); |
|
256 | + } |
|
257 | + |
|
258 | + if ($this->config->getAppValue('theming', 'backgroundMime', null) === 'backgroundColor') { |
|
259 | + $variables['image-login-plain'] = 'true'; |
|
260 | + } |
|
261 | + $cache->set('getScssVariables', $variables); |
|
262 | + return $variables; |
|
263 | + } |
|
264 | + |
|
265 | + /** |
|
266 | + * Check if the image should be replaced by the theming app |
|
267 | + * and return the new image location then |
|
268 | + * |
|
269 | + * @param string $app name of the app |
|
270 | + * @param string $image filename of the image |
|
271 | + * @return bool|string false if image should not replaced, otherwise the location of the image |
|
272 | + */ |
|
273 | + public function replaceImagePath($app, $image) { |
|
274 | + if($app==='') { |
|
275 | + $app = 'core'; |
|
276 | + } |
|
277 | + $cacheBusterValue = $this->config->getAppValue('theming', 'cachebuster', '0'); |
|
278 | + |
|
279 | + if ($image === 'favicon.ico' && $this->shouldReplaceIcons()) { |
|
280 | + return $this->urlGenerator->linkToRoute('theming.Icon.getFavicon', ['app' => $app]) . '?v=' . $cacheBusterValue; |
|
281 | + } |
|
282 | + if ($image === 'favicon-touch.png' && $this->shouldReplaceIcons()) { |
|
283 | + return $this->urlGenerator->linkToRoute('theming.Icon.getTouchIcon', ['app' => $app]) . '?v=' . $cacheBusterValue; |
|
284 | + } |
|
285 | + if ($image === 'manifest.json') { |
|
286 | + try { |
|
287 | + $appPath = $this->appManager->getAppPath($app); |
|
288 | + if (file_exists($appPath . '/img/manifest.json')) { |
|
289 | + return false; |
|
290 | + } |
|
291 | + } catch (AppPathNotFoundException $e) {} |
|
292 | + return $this->urlGenerator->linkToRoute('theming.Theming.getManifest') . '?v=' . $cacheBusterValue; |
|
293 | + } |
|
294 | + return false; |
|
295 | + } |
|
296 | + |
|
297 | + /** |
|
298 | + * Check if Imagemagick is enabled and if SVG is supported |
|
299 | + * otherwise we can't render custom icons |
|
300 | + * |
|
301 | + * @return bool |
|
302 | + */ |
|
303 | + public function shouldReplaceIcons() { |
|
304 | + $cache = $this->cacheFactory->create('theming'); |
|
305 | + if($value = $cache->get('shouldReplaceIcons')) { |
|
306 | + return (bool)$value; |
|
307 | + } |
|
308 | + $value = false; |
|
309 | + if(extension_loaded('imagick')) { |
|
310 | + $checkImagick = new \Imagick(); |
|
311 | + if (count($checkImagick->queryFormats('SVG')) >= 1) { |
|
312 | + $value = true; |
|
313 | + } |
|
314 | + $checkImagick->clear(); |
|
315 | + } |
|
316 | + $cache->set('shouldReplaceIcons', $value); |
|
317 | + return $value; |
|
318 | + } |
|
319 | + |
|
320 | + /** |
|
321 | + * Increases the cache buster key |
|
322 | + */ |
|
323 | + private function increaseCacheBuster() { |
|
324 | + $cacheBusterKey = $this->config->getAppValue('theming', 'cachebuster', '0'); |
|
325 | + $this->config->setAppValue('theming', 'cachebuster', (int)$cacheBusterKey+1); |
|
326 | + $this->cacheFactory->create('theming')->clear('getScssVariables'); |
|
327 | + } |
|
328 | + |
|
329 | + /** |
|
330 | + * Update setting in the database |
|
331 | + * |
|
332 | + * @param string $setting |
|
333 | + * @param string $value |
|
334 | + */ |
|
335 | + public function set($setting, $value) { |
|
336 | + $this->config->setAppValue('theming', $setting, $value); |
|
337 | + $this->increaseCacheBuster(); |
|
338 | + } |
|
339 | + |
|
340 | + /** |
|
341 | + * Revert settings to the default value |
|
342 | + * |
|
343 | + * @param string $setting setting which should be reverted |
|
344 | + * @return string default value |
|
345 | + */ |
|
346 | + public function undo($setting) { |
|
347 | + $this->config->deleteAppValue('theming', $setting); |
|
348 | + $this->increaseCacheBuster(); |
|
349 | + |
|
350 | + switch ($setting) { |
|
351 | + case 'name': |
|
352 | + $returnValue = $this->getEntity(); |
|
353 | + break; |
|
354 | + case 'url': |
|
355 | + $returnValue = $this->getBaseUrl(); |
|
356 | + break; |
|
357 | + case 'slogan': |
|
358 | + $returnValue = $this->getSlogan(); |
|
359 | + break; |
|
360 | + case 'color': |
|
361 | + $returnValue = $this->getColorPrimary(); |
|
362 | + break; |
|
363 | + default: |
|
364 | + $returnValue = ''; |
|
365 | + break; |
|
366 | + } |
|
367 | + |
|
368 | + return $returnValue; |
|
369 | + } |
|
370 | 370 | } |
@@ -3,12 +3,12 @@ |
||
3 | 3 | <h2 class="title"><?php p($l->t('Update needed')) ?></h2> |
4 | 4 | <div class="infogroup"> |
5 | 5 | <?php if ($_['tooBig']) { |
6 | - p($l->t('Please use the command line updater because you have a big instance with more than 50 users.')); |
|
7 | - } else { |
|
8 | - p($l->t('Please use the command line updater because automatic updating is disabled in the config.php.')); |
|
9 | - } ?><br><br> |
|
6 | + p($l->t('Please use the command line updater because you have a big instance with more than 50 users.')); |
|
7 | + } else { |
|
8 | + p($l->t('Please use the command line updater because automatic updating is disabled in the config.php.')); |
|
9 | + } ?><br><br> |
|
10 | 10 | <?php |
11 | - print_unescaped($l->t('For help, see the <a target="_blank" rel="noreferrer noopener" href="%s">documentation</a>.', [link_to_docs('admin-cli-upgrade')])); ?><br><br> |
|
11 | + print_unescaped($l->t('For help, see the <a target="_blank" rel="noreferrer noopener" href="%s">documentation</a>.', [link_to_docs('admin-cli-upgrade')])); ?><br><br> |
|
12 | 12 | </div> |
13 | 13 | </div> |
14 | 14 |
@@ -1,7 +1,7 @@ discard block |
||
1 | 1 | <?php |
2 | 2 | script('core', [ |
3 | - 'jquery-showpassword', |
|
4 | - 'installation' |
|
3 | + 'jquery-showpassword', |
|
4 | + 'installation' |
|
5 | 5 | ]); |
6 | 6 | ?> |
7 | 7 | <input type='hidden' id='hasMySQL' value='<?php p($_['hasMySQL']) ?>'> |
@@ -30,9 +30,9 @@ discard block |
||
30 | 30 | <legend><strong><?php p($l->t('Security warning'));?></strong></legend> |
31 | 31 | <p><?php p($l->t('Your data directory and files are probably accessible from the internet because the .htaccess file does not work.'));?><br> |
32 | 32 | <?php print_unescaped($l->t( |
33 | - 'For information how to properly configure your server, please see the <a href="%s" target="_blank" rel="noreferrer noopener">documentation</a>.', |
|
34 | - link_to_docs('admin-install') |
|
35 | - )); ?></p> |
|
33 | + 'For information how to properly configure your server, please see the <a href="%s" target="_blank" rel="noreferrer noopener">documentation</a>.', |
|
34 | + link_to_docs('admin-install') |
|
35 | + )); ?></p> |
|
36 | 36 | </fieldset> |
37 | 37 | <?php endif; ?> |
38 | 38 | <fieldset id="adminaccount"> |
@@ -76,7 +76,7 @@ discard block |
||
76 | 76 | <?php if(!$_['dbIsSet'] OR count($_['errors']) > 0): ?> |
77 | 77 | <fieldset id='databaseBackend'> |
78 | 78 | <?php if($_['hasMySQL'] or $_['hasPostgreSQL'] or $_['hasOracle']) |
79 | - $hasOtherDB = true; else $hasOtherDB =false; //other than SQLite ?> |
|
79 | + $hasOtherDB = true; else $hasOtherDB =false; //other than SQLite ?> |
|
80 | 80 | <legend><?php p($l->t( 'Configure the database' )); ?></legend> |
81 | 81 | <div id="selectDbType"> |
82 | 82 | <?php foreach($_['databases'] as $type => $label): ?> |
@@ -2,10 +2,10 @@ |
||
2 | 2 | <div id="nojavascript"> |
3 | 3 | <div> |
4 | 4 | <?php print_unescaped(str_replace( |
5 | - ['{linkstart}', '{linkend}'], |
|
6 | - ['<a href="https://www.enable-javascript.com/" target="_blank" rel="noreferrer noopener">', '</a>'], |
|
7 | - $l->t('This application requires JavaScript for correct operation. Please {linkstart}enable JavaScript{linkend} and reload the page.') |
|
8 | - )); ?> |
|
5 | + ['{linkstart}', '{linkend}'], |
|
6 | + ['<a href="https://www.enable-javascript.com/" target="_blank" rel="noreferrer noopener">', '</a>'], |
|
7 | + $l->t('This application requires JavaScript for correct operation. Please {linkstart}enable JavaScript{linkend} and reload the page.') |
|
8 | + )); ?> |
|
9 | 9 | </div> |
10 | 10 | </div> |
11 | 11 | </noscript> |
@@ -1,64 +1,64 @@ |
||
1 | 1 | <p> |
2 | 2 | <?php print_unescaped(str_replace( |
3 | - [ |
|
4 | - '{communityopen}', |
|
5 | - '{githubopen}', |
|
6 | - '{licenseopen}', |
|
7 | - '{linkclose}', |
|
8 | - ], |
|
9 | - [ |
|
10 | - '<a href="https://nextcloud.com/contribute" target="_blank" rel="noreferrer noopener">', |
|
11 | - '<a href="https://github.com/nextcloud" target="_blank" rel="noreferrer noopener">', |
|
12 | - '<a href="https://www.gnu.org/licenses/agpl-3.0.html" target="_blank" rel="noreferrer noopener">', |
|
13 | - '</a>', |
|
14 | - ], |
|
15 | - $l->t('Developed by the {communityopen}Nextcloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}AGPL{linkclose}.') |
|
16 | - )); ?> |
|
3 | + [ |
|
4 | + '{communityopen}', |
|
5 | + '{githubopen}', |
|
6 | + '{licenseopen}', |
|
7 | + '{linkclose}', |
|
8 | + ], |
|
9 | + [ |
|
10 | + '<a href="https://nextcloud.com/contribute" target="_blank" rel="noreferrer noopener">', |
|
11 | + '<a href="https://github.com/nextcloud" target="_blank" rel="noreferrer noopener">', |
|
12 | + '<a href="https://www.gnu.org/licenses/agpl-3.0.html" target="_blank" rel="noreferrer noopener">', |
|
13 | + '</a>', |
|
14 | + ], |
|
15 | + $l->t('Developed by the {communityopen}Nextcloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}AGPL{linkclose}.') |
|
16 | + )); ?> |
|
17 | 17 | </p> |
18 | 18 | |
19 | 19 | <p class="social-button"> |
20 | 20 | <?php print_unescaped(str_replace( |
21 | - [ |
|
22 | - '{googleimage}', |
|
23 | - '{facebookimage}', |
|
24 | - '{twitterimage}', |
|
25 | - '{rssimage}', |
|
26 | - '{mailimage}', |
|
27 | - '{googleopen}', |
|
28 | - '{facebookopen}', |
|
29 | - '{twitteropen}', |
|
30 | - '{rssopen}', |
|
31 | - '{newsletteropen}', |
|
32 | - '{linkclose}', |
|
33 | - '{googletext}', |
|
34 | - '{facebooktext}', |
|
35 | - '{twittertext}', |
|
36 | - '{rsstext}', |
|
37 | - '{mailtext}', |
|
38 | - ], |
|
39 | - [ |
|
40 | - image_path('core', 'googleplus.svg'), |
|
41 | - image_path('core', 'facebook.svg'), |
|
42 | - image_path('core', 'twitter.svg'), |
|
43 | - image_path('core', 'rss.svg'), |
|
44 | - image_path('core', 'mail.svg'), |
|
45 | - '<a target="_blank" rel="noreferrer noopener noopener" href="https://plus.google.com/+Nextcloud">', |
|
46 | - '<a target="_blank" rel="noreferrer noopener noopener" href="https://www.facebook.com/Nextclouders/">', |
|
47 | - '<a target="_blank" rel="noreferrer noopener noopener" href="https://twitter.com/nextclouders">', |
|
48 | - '<a target="_blank" rel="noreferrer noopener noopener" href="https://nextcloud.com/news/">', |
|
49 | - '<a target="_blank" rel="noreferrer noopener noopener" href="https://newsletter.nextcloud.com/?p=subscribe&id=1">', |
|
50 | - '</a>', |
|
51 | - $l->t('Follow us on Google+'), |
|
52 | - $l->t('Like our Facebook page'), |
|
53 | - $l->t('Follow us on Twitter'), |
|
54 | - $l->t('Check out our blog'), |
|
55 | - $l->t('Subscribe to our newsletter'), |
|
21 | + [ |
|
22 | + '{googleimage}', |
|
23 | + '{facebookimage}', |
|
24 | + '{twitterimage}', |
|
25 | + '{rssimage}', |
|
26 | + '{mailimage}', |
|
27 | + '{googleopen}', |
|
28 | + '{facebookopen}', |
|
29 | + '{twitteropen}', |
|
30 | + '{rssopen}', |
|
31 | + '{newsletteropen}', |
|
32 | + '{linkclose}', |
|
33 | + '{googletext}', |
|
34 | + '{facebooktext}', |
|
35 | + '{twittertext}', |
|
36 | + '{rsstext}', |
|
37 | + '{mailtext}', |
|
38 | + ], |
|
39 | + [ |
|
40 | + image_path('core', 'googleplus.svg'), |
|
41 | + image_path('core', 'facebook.svg'), |
|
42 | + image_path('core', 'twitter.svg'), |
|
43 | + image_path('core', 'rss.svg'), |
|
44 | + image_path('core', 'mail.svg'), |
|
45 | + '<a target="_blank" rel="noreferrer noopener noopener" href="https://plus.google.com/+Nextcloud">', |
|
46 | + '<a target="_blank" rel="noreferrer noopener noopener" href="https://www.facebook.com/Nextclouders/">', |
|
47 | + '<a target="_blank" rel="noreferrer noopener noopener" href="https://twitter.com/nextclouders">', |
|
48 | + '<a target="_blank" rel="noreferrer noopener noopener" href="https://nextcloud.com/news/">', |
|
49 | + '<a target="_blank" rel="noreferrer noopener noopener" href="https://newsletter.nextcloud.com/?p=subscribe&id=1">', |
|
50 | + '</a>', |
|
51 | + $l->t('Follow us on Google+'), |
|
52 | + $l->t('Like our Facebook page'), |
|
53 | + $l->t('Follow us on Twitter'), |
|
54 | + $l->t('Check out our blog'), |
|
55 | + $l->t('Subscribe to our newsletter'), |
|
56 | 56 | |
57 | - ], |
|
57 | + ], |
|
58 | 58 | '{googleopen}<img width="50" src="{googleimage}" title="{googletext}" alt="{googletext}">{linkclose} |
59 | 59 | {facebookopen}<img width="50" src="{facebookimage}" title="{facebooktext}" alt="{facebooktext}">{linkclose} |
60 | 60 | {twitteropen}<img width="50" src="{twitterimage}" title="{twittertext}" alt="{twittertext}">{linkclose} |
61 | 61 | {rssopen}<img class="img-circle" width="50" src="{rssimage}" title="{rsstext}" alt="{rsstext}">{linkclose} |
62 | 62 | {newsletteropen}<img width="50" src="{mailimage}" title="{mailtext}" alt="{mailtext}">{linkclose}' |
63 | - )); ?> |
|
63 | + )); ?> |
|
64 | 64 | </p> |
@@ -31,101 +31,101 @@ discard block |
||
31 | 31 | <p class="settings-hint"><?php p($l->t('It\'s important for the security and performance of your instance that everything is configured correctly. To help you with that we are doing some automatic checks. Please see the Tips & Tricks section and the documentation for more information.'));?></p> |
32 | 32 | <ul> |
33 | 33 | <?php |
34 | - // is php setup properly to query system environment variables like getenv('PATH') |
|
35 | - if ($_['getenvServerNotWorking']) { |
|
36 | - ?> |
|
34 | + // is php setup properly to query system environment variables like getenv('PATH') |
|
35 | + if ($_['getenvServerNotWorking']) { |
|
36 | + ?> |
|
37 | 37 | <li> |
38 | 38 | <?php p($l->t('PHP does not seem to be setup properly to query system environment variables. The test with getenv("PATH") only returns an empty response.')); ?><br> |
39 | 39 | <?php print_unescaped($l->t('Please check the <a target="_blank" rel="noreferrer noopener" href="%s">installation documentation ↗</a> for PHP configuration notes and the PHP configuration of your server, especially when using php-fpm.', link_to_docs('admin-php-fpm'))); ?> |
40 | 40 | </li> |
41 | 41 | <?php |
42 | - } |
|
42 | + } |
|
43 | 43 | |
44 | - // is read only config enabled |
|
45 | - if ($_['readOnlyConfigEnabled']) { |
|
46 | - ?> |
|
44 | + // is read only config enabled |
|
45 | + if ($_['readOnlyConfigEnabled']) { |
|
46 | + ?> |
|
47 | 47 | <li> |
48 | 48 | <?php p($l->t('The Read-Only config has been enabled. This prevents setting some configurations via the web-interface. Furthermore, the file needs to be made writable manually for every update.')); ?> |
49 | 49 | </li> |
50 | 50 | <?php |
51 | - } |
|
51 | + } |
|
52 | 52 | |
53 | - // Are doc blocks accessible? |
|
54 | - if (!$_['isAnnotationsWorking']) { |
|
55 | - ?> |
|
53 | + // Are doc blocks accessible? |
|
54 | + if (!$_['isAnnotationsWorking']) { |
|
55 | + ?> |
|
56 | 56 | <li> |
57 | 57 | <?php p($l->t('PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible.')); ?><br> |
58 | 58 | <?php p($l->t('This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator.')); ?> |
59 | 59 | </li> |
60 | 60 | <?php |
61 | - } |
|
61 | + } |
|
62 | 62 | |
63 | - // Is the Transaction isolation level READ_COMMITTED? |
|
64 | - if ($_['invalidTransactionIsolationLevel']) { |
|
65 | - ?> |
|
63 | + // Is the Transaction isolation level READ_COMMITTED? |
|
64 | + if ($_['invalidTransactionIsolationLevel']) { |
|
65 | + ?> |
|
66 | 66 | <li> |
67 | 67 | <?php p($l->t('Your database does not run with "READ COMMITTED" transaction isolation level. This can cause problems when multiple actions are executed in parallel.')); ?> |
68 | 68 | </li> |
69 | 69 | <?php |
70 | - } |
|
70 | + } |
|
71 | 71 | |
72 | - // Warning if memcache is outdated |
|
73 | - foreach ($_['OutdatedCacheWarning'] as $php_module => $data) { |
|
74 | - ?> |
|
72 | + // Warning if memcache is outdated |
|
73 | + foreach ($_['OutdatedCacheWarning'] as $php_module => $data) { |
|
74 | + ?> |
|
75 | 75 | <li> |
76 | 76 | <?php p($l->t('%1$s below version %2$s is installed, for stability and performance reasons it is recommended to update to a newer %1$s version.', $data)); ?> |
77 | 77 | </li> |
78 | 78 | <?php |
79 | - } |
|
79 | + } |
|
80 | 80 | |
81 | - // if module fileinfo available? |
|
82 | - if (!$_['has_fileinfo']) { |
|
83 | - ?> |
|
81 | + // if module fileinfo available? |
|
82 | + if (!$_['has_fileinfo']) { |
|
83 | + ?> |
|
84 | 84 | <li> |
85 | 85 | <?php p($l->t('The PHP module \'fileinfo\' is missing. It is strongly recommended to enable this module to get the best results with MIME type detection.')); ?> |
86 | 86 | </li> |
87 | 87 | <?php |
88 | - } |
|
88 | + } |
|
89 | 89 | |
90 | - // locking configured optimally? |
|
91 | - if ($_['fileLockingType'] === 'none') { |
|
92 | - ?> |
|
90 | + // locking configured optimally? |
|
91 | + if ($_['fileLockingType'] === 'none') { |
|
92 | + ?> |
|
93 | 93 | <li> |
94 | 94 | <?php print_unescaped($l->t('Transactional file locking is disabled, this might lead to issues with race conditions. Enable \'filelocking.enabled\' in config.php to avoid these problems. See the <a target="_blank" rel="noreferrer noopener" href="%s">documentation ↗</a> for more information.', link_to_docs('admin-transactional-locking'))); ?> |
95 | 95 | </li> |
96 | 96 | <?php |
97 | - } |
|
97 | + } |
|
98 | 98 | |
99 | - // is locale working ? |
|
100 | - if (!$_['isLocaleWorking']) { |
|
101 | - ?> |
|
99 | + // is locale working ? |
|
100 | + if (!$_['isLocaleWorking']) { |
|
101 | + ?> |
|
102 | 102 | <li> |
103 | 103 | <?php |
104 | - $locales = 'en_US.UTF-8/fr_FR.UTF-8/es_ES.UTF-8/de_DE.UTF-8/ru_RU.UTF-8/pt_BR.UTF-8/it_IT.UTF-8/ja_JP.UTF-8/zh_CN.UTF-8'; |
|
105 | - p($l->t('System locale can not be set to a one which supports UTF-8.')); |
|
106 | - ?> |
|
104 | + $locales = 'en_US.UTF-8/fr_FR.UTF-8/es_ES.UTF-8/de_DE.UTF-8/ru_RU.UTF-8/pt_BR.UTF-8/it_IT.UTF-8/ja_JP.UTF-8/zh_CN.UTF-8'; |
|
105 | + p($l->t('System locale can not be set to a one which supports UTF-8.')); |
|
106 | + ?> |
|
107 | 107 | <br> |
108 | 108 | <?php |
109 | - p($l->t('This means that there might be problems with certain characters in filenames.')); |
|
110 | - ?> |
|
109 | + p($l->t('This means that there might be problems with certain characters in filenames.')); |
|
110 | + ?> |
|
111 | 111 | <br> |
112 | 112 | <?php |
113 | - p($l->t('It is strongly proposed to install the required packages on your system to support one of the following locales: %s.', [$locales])); |
|
114 | - ?> |
|
113 | + p($l->t('It is strongly proposed to install the required packages on your system to support one of the following locales: %s.', [$locales])); |
|
114 | + ?> |
|
115 | 115 | </li> |
116 | 116 | <?php |
117 | - } |
|
117 | + } |
|
118 | 118 | |
119 | - if ($_['suggestedOverwriteCliUrl']) { |
|
120 | - ?> |
|
119 | + if ($_['suggestedOverwriteCliUrl']) { |
|
120 | + ?> |
|
121 | 121 | <li> |
122 | 122 | <?php p($l->t('If your installation is not installed at the root of the domain and uses system Cron, there can be issues with the URL generation. To avoid these problems, please set the "overwrite.cli.url" option in your config.php file to the webroot path of your installation (Suggested: "%s")', $_['suggestedOverwriteCliUrl'])); ?> |
123 | 123 | </li> |
124 | 124 | <?php |
125 | - } |
|
125 | + } |
|
126 | 126 | |
127 | - if ($_['cronErrors']) { |
|
128 | - ?> |
|
127 | + if ($_['cronErrors']) { |
|
128 | + ?> |
|
129 | 129 | <li> |
130 | 130 | <?php p($l->t('It was not possible to execute the cron job via CLI. The following technical errors have appeared:')); ?> |
131 | 131 | <br> |
@@ -136,8 +136,8 @@ discard block |
||
136 | 136 | </ol> |
137 | 137 | </li> |
138 | 138 | <?php |
139 | - } |
|
140 | - ?> |
|
139 | + } |
|
140 | + ?> |
|
141 | 141 | </ul> |
142 | 142 | |
143 | 143 | <div id="postsetupchecks" data-check-wellknown="<?php if($_['checkForWorkingWellKnownSetup']) { p('true'); } else { p('false'); } ?>"> |
@@ -158,9 +158,9 @@ discard block |
||
158 | 158 | <h2 class="inlineblock"><?php p($l->t('Background jobs'));?></h2> |
159 | 159 | <p class="cronlog inlineblock"> |
160 | 160 | <?php if ($_['lastcron'] !== false): |
161 | - $relative_time = relative_modified_date($_['lastcron']); |
|
162 | - $absolute_time = OC_Util::formatDate($_['lastcron']); |
|
163 | - if (time() - $_['lastcron'] <= 3600): ?> |
|
161 | + $relative_time = relative_modified_date($_['lastcron']); |
|
162 | + $absolute_time = OC_Util::formatDate($_['lastcron']); |
|
163 | + if (time() - $_['lastcron'] <= 3600): ?> |
|
164 | 164 | <span class="status success"></span> |
165 | 165 | <span class="crondate" title="<?php p($absolute_time);?>"> |
166 | 166 | <?php p($l->t("Last job ran %s.", [$relative_time]));?> |
@@ -171,10 +171,10 @@ discard block |
||
171 | 171 | <?php p($l->t("Last job execution ran %s. Something seems wrong.", [$relative_time]));?> |
172 | 172 | </span> |
173 | 173 | <?php endif; |
174 | - else: ?> |
|
174 | + else: ?> |
|
175 | 175 | <span class="status error"></span> |
176 | 176 | <?php p($l->t("Background job didn’t run yet!")); |
177 | - endif; ?> |
|
177 | + endif; ?> |
|
178 | 178 | </p> |
179 | 179 | <a target="_blank" rel="noreferrer noopener" class="icon-info" |
180 | 180 | title="<?php p($l->t('Open documentation'));?>" |
@@ -184,38 +184,38 @@ discard block |
||
184 | 184 | <p> |
185 | 185 | <input type="radio" name="mode" value="ajax" class="radio" |
186 | 186 | id="backgroundjobs_ajax" <?php if ($_['backgroundjobs_mode'] === "ajax") { |
187 | - print_unescaped('checked="checked"'); |
|
188 | - } ?>> |
|
187 | + print_unescaped('checked="checked"'); |
|
188 | + } ?>> |
|
189 | 189 | <label for="backgroundjobs_ajax">AJAX</label><br/> |
190 | 190 | <em><?php p($l->t("Execute one task with each page loaded")); ?></em> |
191 | 191 | </p> |
192 | 192 | <p> |
193 | 193 | <input type="radio" name="mode" value="webcron" class="radio" |
194 | 194 | id="backgroundjobs_webcron" <?php if ($_['backgroundjobs_mode'] === "webcron") { |
195 | - print_unescaped('checked="checked"'); |
|
196 | - } ?>> |
|
195 | + print_unescaped('checked="checked"'); |
|
196 | + } ?>> |
|
197 | 197 | <label for="backgroundjobs_webcron">Webcron</label><br/> |
198 | 198 | <em><?php p($l->t("cron.php is registered at a webcron service to call cron.php every 15 minutes over HTTP.")); ?></em> |
199 | 199 | </p> |
200 | 200 | <p> |
201 | 201 | <input type="radio" name="mode" value="cron" class="radio" |
202 | 202 | id="backgroundjobs_cron" <?php if ($_['backgroundjobs_mode'] === "cron") { |
203 | - print_unescaped('checked="checked"'); |
|
204 | - } |
|
205 | - if (!$_['cli_based_cron_possible']) { |
|
206 | - print_unescaped('disabled'); |
|
207 | - }?>> |
|
203 | + print_unescaped('checked="checked"'); |
|
204 | + } |
|
205 | + if (!$_['cli_based_cron_possible']) { |
|
206 | + print_unescaped('disabled'); |
|
207 | + }?>> |
|
208 | 208 | <label for="backgroundjobs_cron">Cron</label><br/> |
209 | 209 | <em><?php p($l->t("Use system cron service to call the cron.php file every 15 minutes.")); ?> |
210 | 210 | <?php if($_['cli_based_cron_possible']) { |
211 | - p($l->t('The cron.php needs to be executed by the system user "%s".', [$_['cli_based_cron_user']])); |
|
212 | - } else { |
|
213 | - print_unescaped(str_replace( |
|
214 | - ['{linkstart}', '{linkend}'], |
|
215 | - ['<a href="http://php.net/manual/en/book.posix.php">', ' ↗</a>'], |
|
216 | - $l->t('To run this you need the PHP POSIX extension. See {linkstart}PHP documentation{linkend} for more details.') |
|
217 | - )); |
|
218 | - } ?></em> |
|
211 | + p($l->t('The cron.php needs to be executed by the system user "%s".', [$_['cli_based_cron_user']])); |
|
212 | + } else { |
|
213 | + print_unescaped(str_replace( |
|
214 | + ['{linkstart}', '{linkend}'], |
|
215 | + ['<a href="http://php.net/manual/en/book.posix.php">', ' ↗</a>'], |
|
216 | + $l->t('To run this you need the PHP POSIX extension. See {linkstart}PHP documentation{linkend} for more details.') |
|
217 | + )); |
|
218 | + } ?></em> |
|
219 | 219 | |
220 | 220 | </p> |
221 | 221 | </div> |
@@ -31,287 +31,287 @@ |
||
31 | 31 | */ |
32 | 32 | class OC_Defaults { |
33 | 33 | |
34 | - private $theme; |
|
35 | - private $l; |
|
34 | + private $theme; |
|
35 | + private $l; |
|
36 | 36 | |
37 | - private $defaultEntity; |
|
38 | - private $defaultName; |
|
39 | - private $defaultTitle; |
|
40 | - private $defaultBaseUrl; |
|
41 | - private $defaultSyncClientUrl; |
|
42 | - private $defaultiOSClientUrl; |
|
43 | - private $defaultiTunesAppId; |
|
44 | - private $defaultAndroidClientUrl; |
|
45 | - private $defaultDocBaseUrl; |
|
46 | - private $defaultDocVersion; |
|
47 | - private $defaultSlogan; |
|
48 | - private $defaultColorPrimary; |
|
37 | + private $defaultEntity; |
|
38 | + private $defaultName; |
|
39 | + private $defaultTitle; |
|
40 | + private $defaultBaseUrl; |
|
41 | + private $defaultSyncClientUrl; |
|
42 | + private $defaultiOSClientUrl; |
|
43 | + private $defaultiTunesAppId; |
|
44 | + private $defaultAndroidClientUrl; |
|
45 | + private $defaultDocBaseUrl; |
|
46 | + private $defaultDocVersion; |
|
47 | + private $defaultSlogan; |
|
48 | + private $defaultColorPrimary; |
|
49 | 49 | |
50 | - public function __construct() { |
|
51 | - $this->l = \OC::$server->getL10N('lib'); |
|
50 | + public function __construct() { |
|
51 | + $this->l = \OC::$server->getL10N('lib'); |
|
52 | 52 | |
53 | - $this->defaultEntity = 'Nextcloud'; /* e.g. company name, used for footers and copyright notices */ |
|
54 | - $this->defaultName = 'Nextcloud'; /* short name, used when referring to the software */ |
|
55 | - $this->defaultTitle = 'Nextcloud'; /* can be a longer name, for titles */ |
|
56 | - $this->defaultBaseUrl = 'https://nextcloud.com'; |
|
57 | - $this->defaultSyncClientUrl = 'https://nextcloud.com/install/#install-clients'; |
|
58 | - $this->defaultiOSClientUrl = 'https://itunes.apple.com/us/app/nextcloud/id1125420102?mt=8'; |
|
59 | - $this->defaultiTunesAppId = '1125420102'; |
|
60 | - $this->defaultAndroidClientUrl = 'https://play.google.com/store/apps/details?id=com.nextcloud.client'; |
|
61 | - $this->defaultDocBaseUrl = 'https://docs.nextcloud.com'; |
|
62 | - $this->defaultDocVersion = '12'; // used to generate doc links |
|
63 | - $this->defaultSlogan = $this->l->t('a safe home for all your data'); |
|
64 | - $this->defaultColorPrimary = '#0082c9'; |
|
53 | + $this->defaultEntity = 'Nextcloud'; /* e.g. company name, used for footers and copyright notices */ |
|
54 | + $this->defaultName = 'Nextcloud'; /* short name, used when referring to the software */ |
|
55 | + $this->defaultTitle = 'Nextcloud'; /* can be a longer name, for titles */ |
|
56 | + $this->defaultBaseUrl = 'https://nextcloud.com'; |
|
57 | + $this->defaultSyncClientUrl = 'https://nextcloud.com/install/#install-clients'; |
|
58 | + $this->defaultiOSClientUrl = 'https://itunes.apple.com/us/app/nextcloud/id1125420102?mt=8'; |
|
59 | + $this->defaultiTunesAppId = '1125420102'; |
|
60 | + $this->defaultAndroidClientUrl = 'https://play.google.com/store/apps/details?id=com.nextcloud.client'; |
|
61 | + $this->defaultDocBaseUrl = 'https://docs.nextcloud.com'; |
|
62 | + $this->defaultDocVersion = '12'; // used to generate doc links |
|
63 | + $this->defaultSlogan = $this->l->t('a safe home for all your data'); |
|
64 | + $this->defaultColorPrimary = '#0082c9'; |
|
65 | 65 | |
66 | - $themePath = OC::$SERVERROOT . '/themes/' . OC_Util::getTheme() . '/defaults.php'; |
|
67 | - if (file_exists($themePath)) { |
|
68 | - // prevent defaults.php from printing output |
|
69 | - ob_start(); |
|
70 | - require_once $themePath; |
|
71 | - ob_end_clean(); |
|
72 | - if (class_exists('OC_Theme')) { |
|
73 | - $this->theme = new OC_Theme(); |
|
74 | - } |
|
75 | - } |
|
76 | - } |
|
66 | + $themePath = OC::$SERVERROOT . '/themes/' . OC_Util::getTheme() . '/defaults.php'; |
|
67 | + if (file_exists($themePath)) { |
|
68 | + // prevent defaults.php from printing output |
|
69 | + ob_start(); |
|
70 | + require_once $themePath; |
|
71 | + ob_end_clean(); |
|
72 | + if (class_exists('OC_Theme')) { |
|
73 | + $this->theme = new OC_Theme(); |
|
74 | + } |
|
75 | + } |
|
76 | + } |
|
77 | 77 | |
78 | - /** |
|
79 | - * @param string $method |
|
80 | - */ |
|
81 | - private function themeExist($method) { |
|
82 | - if (isset($this->theme) && method_exists($this->theme, $method)) { |
|
83 | - return true; |
|
84 | - } |
|
85 | - return false; |
|
86 | - } |
|
78 | + /** |
|
79 | + * @param string $method |
|
80 | + */ |
|
81 | + private function themeExist($method) { |
|
82 | + if (isset($this->theme) && method_exists($this->theme, $method)) { |
|
83 | + return true; |
|
84 | + } |
|
85 | + return false; |
|
86 | + } |
|
87 | 87 | |
88 | - /** |
|
89 | - * Returns the base URL |
|
90 | - * @return string URL |
|
91 | - */ |
|
92 | - public function getBaseUrl() { |
|
93 | - if ($this->themeExist('getBaseUrl')) { |
|
94 | - return $this->theme->getBaseUrl(); |
|
95 | - } else { |
|
96 | - return $this->defaultBaseUrl; |
|
97 | - } |
|
98 | - } |
|
88 | + /** |
|
89 | + * Returns the base URL |
|
90 | + * @return string URL |
|
91 | + */ |
|
92 | + public function getBaseUrl() { |
|
93 | + if ($this->themeExist('getBaseUrl')) { |
|
94 | + return $this->theme->getBaseUrl(); |
|
95 | + } else { |
|
96 | + return $this->defaultBaseUrl; |
|
97 | + } |
|
98 | + } |
|
99 | 99 | |
100 | - /** |
|
101 | - * Returns the URL where the sync clients are listed |
|
102 | - * @return string URL |
|
103 | - */ |
|
104 | - public function getSyncClientUrl() { |
|
105 | - if ($this->themeExist('getSyncClientUrl')) { |
|
106 | - return $this->theme->getSyncClientUrl(); |
|
107 | - } else { |
|
108 | - return $this->defaultSyncClientUrl; |
|
109 | - } |
|
110 | - } |
|
100 | + /** |
|
101 | + * Returns the URL where the sync clients are listed |
|
102 | + * @return string URL |
|
103 | + */ |
|
104 | + public function getSyncClientUrl() { |
|
105 | + if ($this->themeExist('getSyncClientUrl')) { |
|
106 | + return $this->theme->getSyncClientUrl(); |
|
107 | + } else { |
|
108 | + return $this->defaultSyncClientUrl; |
|
109 | + } |
|
110 | + } |
|
111 | 111 | |
112 | - /** |
|
113 | - * Returns the URL to the App Store for the iOS Client |
|
114 | - * @return string URL |
|
115 | - */ |
|
116 | - public function getiOSClientUrl() { |
|
117 | - if ($this->themeExist('getiOSClientUrl')) { |
|
118 | - return $this->theme->getiOSClientUrl(); |
|
119 | - } else { |
|
120 | - return $this->defaultiOSClientUrl; |
|
121 | - } |
|
122 | - } |
|
112 | + /** |
|
113 | + * Returns the URL to the App Store for the iOS Client |
|
114 | + * @return string URL |
|
115 | + */ |
|
116 | + public function getiOSClientUrl() { |
|
117 | + if ($this->themeExist('getiOSClientUrl')) { |
|
118 | + return $this->theme->getiOSClientUrl(); |
|
119 | + } else { |
|
120 | + return $this->defaultiOSClientUrl; |
|
121 | + } |
|
122 | + } |
|
123 | 123 | |
124 | - /** |
|
125 | - * Returns the AppId for the App Store for the iOS Client |
|
126 | - * @return string AppId |
|
127 | - */ |
|
128 | - public function getiTunesAppId() { |
|
129 | - if ($this->themeExist('getiTunesAppId')) { |
|
130 | - return $this->theme->getiTunesAppId(); |
|
131 | - } else { |
|
132 | - return $this->defaultiTunesAppId; |
|
133 | - } |
|
134 | - } |
|
124 | + /** |
|
125 | + * Returns the AppId for the App Store for the iOS Client |
|
126 | + * @return string AppId |
|
127 | + */ |
|
128 | + public function getiTunesAppId() { |
|
129 | + if ($this->themeExist('getiTunesAppId')) { |
|
130 | + return $this->theme->getiTunesAppId(); |
|
131 | + } else { |
|
132 | + return $this->defaultiTunesAppId; |
|
133 | + } |
|
134 | + } |
|
135 | 135 | |
136 | - /** |
|
137 | - * Returns the URL to Google Play for the Android Client |
|
138 | - * @return string URL |
|
139 | - */ |
|
140 | - public function getAndroidClientUrl() { |
|
141 | - if ($this->themeExist('getAndroidClientUrl')) { |
|
142 | - return $this->theme->getAndroidClientUrl(); |
|
143 | - } else { |
|
144 | - return $this->defaultAndroidClientUrl; |
|
145 | - } |
|
146 | - } |
|
136 | + /** |
|
137 | + * Returns the URL to Google Play for the Android Client |
|
138 | + * @return string URL |
|
139 | + */ |
|
140 | + public function getAndroidClientUrl() { |
|
141 | + if ($this->themeExist('getAndroidClientUrl')) { |
|
142 | + return $this->theme->getAndroidClientUrl(); |
|
143 | + } else { |
|
144 | + return $this->defaultAndroidClientUrl; |
|
145 | + } |
|
146 | + } |
|
147 | 147 | |
148 | - /** |
|
149 | - * Returns the documentation URL |
|
150 | - * @return string URL |
|
151 | - */ |
|
152 | - public function getDocBaseUrl() { |
|
153 | - if ($this->themeExist('getDocBaseUrl')) { |
|
154 | - return $this->theme->getDocBaseUrl(); |
|
155 | - } else { |
|
156 | - return $this->defaultDocBaseUrl; |
|
157 | - } |
|
158 | - } |
|
148 | + /** |
|
149 | + * Returns the documentation URL |
|
150 | + * @return string URL |
|
151 | + */ |
|
152 | + public function getDocBaseUrl() { |
|
153 | + if ($this->themeExist('getDocBaseUrl')) { |
|
154 | + return $this->theme->getDocBaseUrl(); |
|
155 | + } else { |
|
156 | + return $this->defaultDocBaseUrl; |
|
157 | + } |
|
158 | + } |
|
159 | 159 | |
160 | - /** |
|
161 | - * Returns the title |
|
162 | - * @return string title |
|
163 | - */ |
|
164 | - public function getTitle() { |
|
165 | - if ($this->themeExist('getTitle')) { |
|
166 | - return $this->theme->getTitle(); |
|
167 | - } else { |
|
168 | - return $this->defaultTitle; |
|
169 | - } |
|
170 | - } |
|
160 | + /** |
|
161 | + * Returns the title |
|
162 | + * @return string title |
|
163 | + */ |
|
164 | + public function getTitle() { |
|
165 | + if ($this->themeExist('getTitle')) { |
|
166 | + return $this->theme->getTitle(); |
|
167 | + } else { |
|
168 | + return $this->defaultTitle; |
|
169 | + } |
|
170 | + } |
|
171 | 171 | |
172 | - /** |
|
173 | - * Returns the short name of the software |
|
174 | - * @return string title |
|
175 | - */ |
|
176 | - public function getName() { |
|
177 | - if ($this->themeExist('getName')) { |
|
178 | - return $this->theme->getName(); |
|
179 | - } else { |
|
180 | - return $this->defaultName; |
|
181 | - } |
|
182 | - } |
|
172 | + /** |
|
173 | + * Returns the short name of the software |
|
174 | + * @return string title |
|
175 | + */ |
|
176 | + public function getName() { |
|
177 | + if ($this->themeExist('getName')) { |
|
178 | + return $this->theme->getName(); |
|
179 | + } else { |
|
180 | + return $this->defaultName; |
|
181 | + } |
|
182 | + } |
|
183 | 183 | |
184 | - /** |
|
185 | - * Returns the short name of the software containing HTML strings |
|
186 | - * @return string title |
|
187 | - */ |
|
188 | - public function getHTMLName() { |
|
189 | - if ($this->themeExist('getHTMLName')) { |
|
190 | - return $this->theme->getHTMLName(); |
|
191 | - } else { |
|
192 | - return $this->defaultName; |
|
193 | - } |
|
194 | - } |
|
184 | + /** |
|
185 | + * Returns the short name of the software containing HTML strings |
|
186 | + * @return string title |
|
187 | + */ |
|
188 | + public function getHTMLName() { |
|
189 | + if ($this->themeExist('getHTMLName')) { |
|
190 | + return $this->theme->getHTMLName(); |
|
191 | + } else { |
|
192 | + return $this->defaultName; |
|
193 | + } |
|
194 | + } |
|
195 | 195 | |
196 | - /** |
|
197 | - * Returns entity (e.g. company name) - used for footer, copyright |
|
198 | - * @return string entity name |
|
199 | - */ |
|
200 | - public function getEntity() { |
|
201 | - if ($this->themeExist('getEntity')) { |
|
202 | - return $this->theme->getEntity(); |
|
203 | - } else { |
|
204 | - return $this->defaultEntity; |
|
205 | - } |
|
206 | - } |
|
196 | + /** |
|
197 | + * Returns entity (e.g. company name) - used for footer, copyright |
|
198 | + * @return string entity name |
|
199 | + */ |
|
200 | + public function getEntity() { |
|
201 | + if ($this->themeExist('getEntity')) { |
|
202 | + return $this->theme->getEntity(); |
|
203 | + } else { |
|
204 | + return $this->defaultEntity; |
|
205 | + } |
|
206 | + } |
|
207 | 207 | |
208 | - /** |
|
209 | - * Returns slogan |
|
210 | - * @return string slogan |
|
211 | - */ |
|
212 | - public function getSlogan() { |
|
213 | - if ($this->themeExist('getSlogan')) { |
|
214 | - return $this->theme->getSlogan(); |
|
215 | - } else { |
|
216 | - return $this->defaultSlogan; |
|
217 | - } |
|
218 | - } |
|
208 | + /** |
|
209 | + * Returns slogan |
|
210 | + * @return string slogan |
|
211 | + */ |
|
212 | + public function getSlogan() { |
|
213 | + if ($this->themeExist('getSlogan')) { |
|
214 | + return $this->theme->getSlogan(); |
|
215 | + } else { |
|
216 | + return $this->defaultSlogan; |
|
217 | + } |
|
218 | + } |
|
219 | 219 | |
220 | - /** |
|
221 | - * Returns logo claim |
|
222 | - * @return string logo claim |
|
223 | - * @deprecated 13.0.0 |
|
224 | - */ |
|
225 | - public function getLogoClaim() { |
|
226 | - return ''; |
|
227 | - } |
|
220 | + /** |
|
221 | + * Returns logo claim |
|
222 | + * @return string logo claim |
|
223 | + * @deprecated 13.0.0 |
|
224 | + */ |
|
225 | + public function getLogoClaim() { |
|
226 | + return ''; |
|
227 | + } |
|
228 | 228 | |
229 | - /** |
|
230 | - * Returns short version of the footer |
|
231 | - * @return string short footer |
|
232 | - */ |
|
233 | - public function getShortFooter() { |
|
234 | - if ($this->themeExist('getShortFooter')) { |
|
235 | - $footer = $this->theme->getShortFooter(); |
|
236 | - } else { |
|
237 | - $footer = '<a href="'. $this->getBaseUrl() . '" target="_blank"' . |
|
238 | - ' rel="noreferrer noopener">' .$this->getEntity() . '</a>'. |
|
239 | - ' – ' . $this->getSlogan(); |
|
240 | - } |
|
229 | + /** |
|
230 | + * Returns short version of the footer |
|
231 | + * @return string short footer |
|
232 | + */ |
|
233 | + public function getShortFooter() { |
|
234 | + if ($this->themeExist('getShortFooter')) { |
|
235 | + $footer = $this->theme->getShortFooter(); |
|
236 | + } else { |
|
237 | + $footer = '<a href="'. $this->getBaseUrl() . '" target="_blank"' . |
|
238 | + ' rel="noreferrer noopener">' .$this->getEntity() . '</a>'. |
|
239 | + ' – ' . $this->getSlogan(); |
|
240 | + } |
|
241 | 241 | |
242 | - return $footer; |
|
243 | - } |
|
242 | + return $footer; |
|
243 | + } |
|
244 | 244 | |
245 | - /** |
|
246 | - * Returns long version of the footer |
|
247 | - * @return string long footer |
|
248 | - */ |
|
249 | - public function getLongFooter() { |
|
250 | - if ($this->themeExist('getLongFooter')) { |
|
251 | - $footer = $this->theme->getLongFooter(); |
|
252 | - } else { |
|
253 | - $footer = $this->getShortFooter(); |
|
254 | - } |
|
245 | + /** |
|
246 | + * Returns long version of the footer |
|
247 | + * @return string long footer |
|
248 | + */ |
|
249 | + public function getLongFooter() { |
|
250 | + if ($this->themeExist('getLongFooter')) { |
|
251 | + $footer = $this->theme->getLongFooter(); |
|
252 | + } else { |
|
253 | + $footer = $this->getShortFooter(); |
|
254 | + } |
|
255 | 255 | |
256 | - return $footer; |
|
257 | - } |
|
256 | + return $footer; |
|
257 | + } |
|
258 | 258 | |
259 | - /** |
|
260 | - * @param string $key |
|
261 | - * @return string URL to doc with key |
|
262 | - */ |
|
263 | - public function buildDocLinkToKey($key) { |
|
264 | - if ($this->themeExist('buildDocLinkToKey')) { |
|
265 | - return $this->theme->buildDocLinkToKey($key); |
|
266 | - } |
|
267 | - return $this->getDocBaseUrl() . '/server/' . $this->defaultDocVersion . '/go.php?to=' . $key; |
|
268 | - } |
|
259 | + /** |
|
260 | + * @param string $key |
|
261 | + * @return string URL to doc with key |
|
262 | + */ |
|
263 | + public function buildDocLinkToKey($key) { |
|
264 | + if ($this->themeExist('buildDocLinkToKey')) { |
|
265 | + return $this->theme->buildDocLinkToKey($key); |
|
266 | + } |
|
267 | + return $this->getDocBaseUrl() . '/server/' . $this->defaultDocVersion . '/go.php?to=' . $key; |
|
268 | + } |
|
269 | 269 | |
270 | - /** |
|
271 | - * Returns primary color |
|
272 | - * @return string |
|
273 | - */ |
|
274 | - public function getColorPrimary() { |
|
270 | + /** |
|
271 | + * Returns primary color |
|
272 | + * @return string |
|
273 | + */ |
|
274 | + public function getColorPrimary() { |
|
275 | 275 | |
276 | - if ($this->themeExist('getColorPrimary')) { |
|
277 | - return $this->theme->getColorPrimary(); |
|
278 | - } |
|
279 | - if ($this->themeExist('getMailHeaderColor')) { |
|
280 | - return $this->theme->getMailHeaderColor(); |
|
281 | - } |
|
282 | - return $this->defaultColorPrimary; |
|
283 | - } |
|
276 | + if ($this->themeExist('getColorPrimary')) { |
|
277 | + return $this->theme->getColorPrimary(); |
|
278 | + } |
|
279 | + if ($this->themeExist('getMailHeaderColor')) { |
|
280 | + return $this->theme->getMailHeaderColor(); |
|
281 | + } |
|
282 | + return $this->defaultColorPrimary; |
|
283 | + } |
|
284 | 284 | |
285 | - /** |
|
286 | - * @return array scss variables to overwrite |
|
287 | - */ |
|
288 | - public function getScssVariables() { |
|
289 | - if($this->themeExist('getScssVariables')) { |
|
290 | - return $this->theme->getScssVariables(); |
|
291 | - } |
|
292 | - return []; |
|
293 | - } |
|
285 | + /** |
|
286 | + * @return array scss variables to overwrite |
|
287 | + */ |
|
288 | + public function getScssVariables() { |
|
289 | + if($this->themeExist('getScssVariables')) { |
|
290 | + return $this->theme->getScssVariables(); |
|
291 | + } |
|
292 | + return []; |
|
293 | + } |
|
294 | 294 | |
295 | - public function shouldReplaceIcons() { |
|
296 | - return false; |
|
297 | - } |
|
295 | + public function shouldReplaceIcons() { |
|
296 | + return false; |
|
297 | + } |
|
298 | 298 | |
299 | - /** |
|
300 | - * Themed logo url |
|
301 | - * |
|
302 | - * @param bool $useSvg Whether to point to the SVG image or a fallback |
|
303 | - * @return string |
|
304 | - */ |
|
305 | - public function getLogo($useSvg = true) { |
|
306 | - if ($this->themeExist('getLogo')) { |
|
307 | - return $this->theme->getLogo($useSvg); |
|
308 | - } |
|
299 | + /** |
|
300 | + * Themed logo url |
|
301 | + * |
|
302 | + * @param bool $useSvg Whether to point to the SVG image or a fallback |
|
303 | + * @return string |
|
304 | + */ |
|
305 | + public function getLogo($useSvg = true) { |
|
306 | + if ($this->themeExist('getLogo')) { |
|
307 | + return $this->theme->getLogo($useSvg); |
|
308 | + } |
|
309 | 309 | |
310 | - if($useSvg) { |
|
311 | - $logo = \OC::$server->getURLGenerator()->imagePath('core', 'logo.svg'); |
|
312 | - } else { |
|
313 | - $logo = \OC::$server->getURLGenerator()->imagePath('core', 'logo.png'); |
|
314 | - } |
|
315 | - return $logo . '?v=' . hash('sha1', implode('.', \OCP\Util::getVersion())); |
|
316 | - } |
|
310 | + if($useSvg) { |
|
311 | + $logo = \OC::$server->getURLGenerator()->imagePath('core', 'logo.svg'); |
|
312 | + } else { |
|
313 | + $logo = \OC::$server->getURLGenerator()->imagePath('core', 'logo.png'); |
|
314 | + } |
|
315 | + return $logo . '?v=' . hash('sha1', implode('.', \OCP\Util::getVersion())); |
|
316 | + } |
|
317 | 317 | } |
@@ -63,560 +63,560 @@ |
||
63 | 63 | * This class provides the functionality needed to install, update and remove apps |
64 | 64 | */ |
65 | 65 | class Installer { |
66 | - /** @var AppFetcher */ |
|
67 | - private $appFetcher; |
|
68 | - /** @var IClientService */ |
|
69 | - private $clientService; |
|
70 | - /** @var ITempManager */ |
|
71 | - private $tempManager; |
|
72 | - /** @var ILogger */ |
|
73 | - private $logger; |
|
74 | - /** @var IConfig */ |
|
75 | - private $config; |
|
76 | - |
|
77 | - /** |
|
78 | - * @param AppFetcher $appFetcher |
|
79 | - * @param IClientService $clientService |
|
80 | - * @param ITempManager $tempManager |
|
81 | - * @param ILogger $logger |
|
82 | - * @param IConfig $config |
|
83 | - */ |
|
84 | - public function __construct(AppFetcher $appFetcher, |
|
85 | - IClientService $clientService, |
|
86 | - ITempManager $tempManager, |
|
87 | - ILogger $logger, |
|
88 | - IConfig $config) { |
|
89 | - $this->appFetcher = $appFetcher; |
|
90 | - $this->clientService = $clientService; |
|
91 | - $this->tempManager = $tempManager; |
|
92 | - $this->logger = $logger; |
|
93 | - $this->config = $config; |
|
94 | - } |
|
95 | - |
|
96 | - /** |
|
97 | - * Installs an app that is located in one of the app folders already |
|
98 | - * |
|
99 | - * @param string $appId App to install |
|
100 | - * @throws \Exception |
|
101 | - * @return string app ID |
|
102 | - */ |
|
103 | - public function installApp($appId) { |
|
104 | - $app = \OC_App::findAppInDirectories($appId); |
|
105 | - if($app === false) { |
|
106 | - throw new \Exception('App not found in any app directory'); |
|
107 | - } |
|
108 | - |
|
109 | - $basedir = $app['path'].'/'.$appId; |
|
110 | - $info = OC_App::getAppInfo($basedir.'/appinfo/info.xml', true); |
|
111 | - |
|
112 | - $l = \OC::$server->getL10N('core'); |
|
113 | - |
|
114 | - if(!is_array($info)) { |
|
115 | - throw new \Exception( |
|
116 | - $l->t('App "%s" cannot be installed because appinfo file cannot be read.', |
|
117 | - [$info['name']] |
|
118 | - ) |
|
119 | - ); |
|
120 | - } |
|
121 | - |
|
122 | - $version = \OCP\Util::getVersion(); |
|
123 | - if (!\OC_App::isAppCompatible($version, $info)) { |
|
124 | - throw new \Exception( |
|
125 | - // TODO $l |
|
126 | - $l->t('App "%s" cannot be installed because it is not compatible with this version of the server.', |
|
127 | - [$info['name']] |
|
128 | - ) |
|
129 | - ); |
|
130 | - } |
|
131 | - |
|
132 | - // check for required dependencies |
|
133 | - \OC_App::checkAppDependencies($this->config, $l, $info); |
|
134 | - \OC_App::registerAutoloading($appId, $basedir); |
|
135 | - |
|
136 | - //install the database |
|
137 | - if(is_file($basedir.'/appinfo/database.xml')) { |
|
138 | - if (\OC::$server->getAppConfig()->getValue($info['id'], 'installed_version') === null) { |
|
139 | - OC_DB::createDbFromStructure($basedir.'/appinfo/database.xml'); |
|
140 | - } else { |
|
141 | - OC_DB::updateDbFromStructure($basedir.'/appinfo/database.xml'); |
|
142 | - } |
|
143 | - } else { |
|
144 | - $ms = new \OC\DB\MigrationService($info['id'], \OC::$server->getDatabaseConnection()); |
|
145 | - $ms->migrate(); |
|
146 | - } |
|
147 | - |
|
148 | - \OC_App::setupBackgroundJobs($info['background-jobs']); |
|
149 | - if(isset($info['settings']) && is_array($info['settings'])) { |
|
150 | - \OC::$server->getSettingsManager()->setupSettings($info['settings']); |
|
151 | - } |
|
152 | - |
|
153 | - //run appinfo/install.php |
|
154 | - if((!isset($data['noinstall']) or $data['noinstall']==false)) { |
|
155 | - self::includeAppScript($basedir . '/appinfo/install.php'); |
|
156 | - } |
|
157 | - |
|
158 | - $appData = OC_App::getAppInfo($appId); |
|
159 | - OC_App::executeRepairSteps($appId, $appData['repair-steps']['install']); |
|
160 | - |
|
161 | - //set the installed version |
|
162 | - \OC::$server->getConfig()->setAppValue($info['id'], 'installed_version', OC_App::getAppVersion($info['id'], false)); |
|
163 | - \OC::$server->getConfig()->setAppValue($info['id'], 'enabled', 'no'); |
|
164 | - |
|
165 | - //set remote/public handlers |
|
166 | - foreach($info['remote'] as $name=>$path) { |
|
167 | - \OC::$server->getConfig()->setAppValue('core', 'remote_'.$name, $info['id'].'/'.$path); |
|
168 | - } |
|
169 | - foreach($info['public'] as $name=>$path) { |
|
170 | - \OC::$server->getConfig()->setAppValue('core', 'public_'.$name, $info['id'].'/'.$path); |
|
171 | - } |
|
172 | - |
|
173 | - OC_App::setAppTypes($info['id']); |
|
174 | - |
|
175 | - return $info['id']; |
|
176 | - } |
|
177 | - |
|
178 | - /** |
|
179 | - * @brief checks whether or not an app is installed |
|
180 | - * @param string $app app |
|
181 | - * @returns bool |
|
182 | - * |
|
183 | - * Checks whether or not an app is installed, i.e. registered in apps table. |
|
184 | - */ |
|
185 | - public static function isInstalled( $app ) { |
|
186 | - return (\OC::$server->getConfig()->getAppValue($app, "installed_version", null) !== null); |
|
187 | - } |
|
188 | - |
|
189 | - /** |
|
190 | - * Updates the specified app from the appstore |
|
191 | - * |
|
192 | - * @param string $appId |
|
193 | - * @return bool |
|
194 | - */ |
|
195 | - public function updateAppstoreApp($appId) { |
|
196 | - if(self::isUpdateAvailable($appId, $this->appFetcher)) { |
|
197 | - try { |
|
198 | - $this->downloadApp($appId); |
|
199 | - } catch (\Exception $e) { |
|
200 | - $this->logger->error($e->getMessage(), ['app' => 'core']); |
|
201 | - return false; |
|
202 | - } |
|
203 | - return OC_App::updateApp($appId); |
|
204 | - } |
|
205 | - |
|
206 | - return false; |
|
207 | - } |
|
208 | - |
|
209 | - /** |
|
210 | - * Downloads an app and puts it into the app directory |
|
211 | - * |
|
212 | - * @param string $appId |
|
213 | - * |
|
214 | - * @throws \Exception If the installation was not successful |
|
215 | - */ |
|
216 | - public function downloadApp($appId) { |
|
217 | - $appId = strtolower($appId); |
|
218 | - |
|
219 | - $apps = $this->appFetcher->get(); |
|
220 | - foreach($apps as $app) { |
|
221 | - if($app['id'] === $appId) { |
|
222 | - // Load the certificate |
|
223 | - $certificate = new X509(); |
|
224 | - $certificate->loadCA(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crt')); |
|
225 | - $loadedCertificate = $certificate->loadX509($app['certificate']); |
|
226 | - |
|
227 | - // Verify if the certificate has been revoked |
|
228 | - $crl = new X509(); |
|
229 | - $crl->loadCA(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crt')); |
|
230 | - $crl->loadCRL(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crl')); |
|
231 | - if($crl->validateSignature() !== true) { |
|
232 | - throw new \Exception('Could not validate CRL signature'); |
|
233 | - } |
|
234 | - $csn = $loadedCertificate['tbsCertificate']['serialNumber']->toString(); |
|
235 | - $revoked = $crl->getRevoked($csn); |
|
236 | - if ($revoked !== false) { |
|
237 | - throw new \Exception( |
|
238 | - sprintf( |
|
239 | - 'Certificate "%s" has been revoked', |
|
240 | - $csn |
|
241 | - ) |
|
242 | - ); |
|
243 | - } |
|
244 | - |
|
245 | - // Verify if the certificate has been issued by the Nextcloud Code Authority CA |
|
246 | - if($certificate->validateSignature() !== true) { |
|
247 | - throw new \Exception( |
|
248 | - sprintf( |
|
249 | - 'App with id %s has a certificate not issued by a trusted Code Signing Authority', |
|
250 | - $appId |
|
251 | - ) |
|
252 | - ); |
|
253 | - } |
|
254 | - |
|
255 | - // Verify if the certificate is issued for the requested app id |
|
256 | - $certInfo = openssl_x509_parse($app['certificate']); |
|
257 | - if(!isset($certInfo['subject']['CN'])) { |
|
258 | - throw new \Exception( |
|
259 | - sprintf( |
|
260 | - 'App with id %s has a cert with no CN', |
|
261 | - $appId |
|
262 | - ) |
|
263 | - ); |
|
264 | - } |
|
265 | - if($certInfo['subject']['CN'] !== $appId) { |
|
266 | - throw new \Exception( |
|
267 | - sprintf( |
|
268 | - 'App with id %s has a cert issued to %s', |
|
269 | - $appId, |
|
270 | - $certInfo['subject']['CN'] |
|
271 | - ) |
|
272 | - ); |
|
273 | - } |
|
274 | - |
|
275 | - // Download the release |
|
276 | - $tempFile = $this->tempManager->getTemporaryFile('.tar.gz'); |
|
277 | - $client = $this->clientService->newClient(); |
|
278 | - $client->get($app['releases'][0]['download'], ['save_to' => $tempFile]); |
|
279 | - |
|
280 | - // Check if the signature actually matches the downloaded content |
|
281 | - $certificate = openssl_get_publickey($app['certificate']); |
|
282 | - $verified = (bool)openssl_verify(file_get_contents($tempFile), base64_decode($app['releases'][0]['signature']), $certificate, OPENSSL_ALGO_SHA512); |
|
283 | - openssl_free_key($certificate); |
|
284 | - |
|
285 | - if($verified === true) { |
|
286 | - // Seems to match, let's proceed |
|
287 | - $extractDir = $this->tempManager->getTemporaryFolder(); |
|
288 | - $archive = new TAR($tempFile); |
|
289 | - |
|
290 | - if($archive) { |
|
291 | - if (!$archive->extract($extractDir)) { |
|
292 | - throw new \Exception( |
|
293 | - sprintf( |
|
294 | - 'Could not extract app %s', |
|
295 | - $appId |
|
296 | - ) |
|
297 | - ); |
|
298 | - } |
|
299 | - $allFiles = scandir($extractDir); |
|
300 | - $folders = array_diff($allFiles, ['.', '..']); |
|
301 | - $folders = array_values($folders); |
|
302 | - |
|
303 | - if(count($folders) > 1) { |
|
304 | - throw new \Exception( |
|
305 | - sprintf( |
|
306 | - 'Extracted app %s has more than 1 folder', |
|
307 | - $appId |
|
308 | - ) |
|
309 | - ); |
|
310 | - } |
|
311 | - |
|
312 | - // Check if appinfo/info.xml has the same app ID as well |
|
313 | - $loadEntities = libxml_disable_entity_loader(false); |
|
314 | - $xml = simplexml_load_file($extractDir . '/' . $folders[0] . '/appinfo/info.xml'); |
|
315 | - libxml_disable_entity_loader($loadEntities); |
|
316 | - if((string)$xml->id !== $appId) { |
|
317 | - throw new \Exception( |
|
318 | - sprintf( |
|
319 | - 'App for id %s has a wrong app ID in info.xml: %s', |
|
320 | - $appId, |
|
321 | - (string)$xml->id |
|
322 | - ) |
|
323 | - ); |
|
324 | - } |
|
325 | - |
|
326 | - // Check if the version is lower than before |
|
327 | - $currentVersion = OC_App::getAppVersion($appId); |
|
328 | - $newVersion = (string)$xml->version; |
|
329 | - if(version_compare($currentVersion, $newVersion) === 1) { |
|
330 | - throw new \Exception( |
|
331 | - sprintf( |
|
332 | - 'App for id %s has version %s and tried to update to lower version %s', |
|
333 | - $appId, |
|
334 | - $currentVersion, |
|
335 | - $newVersion |
|
336 | - ) |
|
337 | - ); |
|
338 | - } |
|
339 | - |
|
340 | - $baseDir = OC_App::getInstallPath() . '/' . $appId; |
|
341 | - // Remove old app with the ID if existent |
|
342 | - OC_Helper::rmdirr($baseDir); |
|
343 | - // Move to app folder |
|
344 | - if(@mkdir($baseDir)) { |
|
345 | - $extractDir .= '/' . $folders[0]; |
|
346 | - OC_Helper::copyr($extractDir, $baseDir); |
|
347 | - } |
|
348 | - OC_Helper::copyr($extractDir, $baseDir); |
|
349 | - OC_Helper::rmdirr($extractDir); |
|
350 | - return; |
|
351 | - } else { |
|
352 | - throw new \Exception( |
|
353 | - sprintf( |
|
354 | - 'Could not extract app with ID %s to %s', |
|
355 | - $appId, |
|
356 | - $extractDir |
|
357 | - ) |
|
358 | - ); |
|
359 | - } |
|
360 | - } else { |
|
361 | - // Signature does not match |
|
362 | - throw new \Exception( |
|
363 | - sprintf( |
|
364 | - 'App with id %s has invalid signature', |
|
365 | - $appId |
|
366 | - ) |
|
367 | - ); |
|
368 | - } |
|
369 | - } |
|
370 | - } |
|
371 | - |
|
372 | - throw new \Exception( |
|
373 | - sprintf( |
|
374 | - 'Could not download app %s', |
|
375 | - $appId |
|
376 | - ) |
|
377 | - ); |
|
378 | - } |
|
379 | - |
|
380 | - /** |
|
381 | - * Check if an update for the app is available |
|
382 | - * |
|
383 | - * @param string $appId |
|
384 | - * @param AppFetcher $appFetcher |
|
385 | - * @return string|false false or the version number of the update |
|
386 | - */ |
|
387 | - public static function isUpdateAvailable($appId, |
|
388 | - AppFetcher $appFetcher) { |
|
389 | - static $isInstanceReadyForUpdates = null; |
|
390 | - |
|
391 | - if ($isInstanceReadyForUpdates === null) { |
|
392 | - $installPath = OC_App::getInstallPath(); |
|
393 | - if ($installPath === false || $installPath === null) { |
|
394 | - $isInstanceReadyForUpdates = false; |
|
395 | - } else { |
|
396 | - $isInstanceReadyForUpdates = true; |
|
397 | - } |
|
398 | - } |
|
399 | - |
|
400 | - if ($isInstanceReadyForUpdates === false) { |
|
401 | - return false; |
|
402 | - } |
|
403 | - |
|
404 | - $apps = $appFetcher->get(); |
|
405 | - foreach($apps as $app) { |
|
406 | - if($app['id'] === $appId) { |
|
407 | - $currentVersion = OC_App::getAppVersion($appId); |
|
408 | - $newestVersion = $app['releases'][0]['version']; |
|
409 | - if (version_compare($newestVersion, $currentVersion, '>')) { |
|
410 | - return $newestVersion; |
|
411 | - } else { |
|
412 | - return false; |
|
413 | - } |
|
414 | - } |
|
415 | - } |
|
416 | - |
|
417 | - return false; |
|
418 | - } |
|
419 | - |
|
420 | - /** |
|
421 | - * Check if app is already downloaded |
|
422 | - * @param string $name name of the application to remove |
|
423 | - * @return boolean |
|
424 | - * |
|
425 | - * The function will check if the app is already downloaded in the apps repository |
|
426 | - */ |
|
427 | - public function isDownloaded($name) { |
|
428 | - foreach(\OC::$APPSROOTS as $dir) { |
|
429 | - $dirToTest = $dir['path']; |
|
430 | - $dirToTest .= '/'; |
|
431 | - $dirToTest .= $name; |
|
432 | - $dirToTest .= '/'; |
|
433 | - |
|
434 | - if (is_dir($dirToTest)) { |
|
435 | - return true; |
|
436 | - } |
|
437 | - } |
|
438 | - |
|
439 | - return false; |
|
440 | - } |
|
441 | - |
|
442 | - /** |
|
443 | - * Removes an app |
|
444 | - * @param string $appId ID of the application to remove |
|
445 | - * @return boolean |
|
446 | - * |
|
447 | - * |
|
448 | - * This function works as follows |
|
449 | - * -# call uninstall repair steps |
|
450 | - * -# removing the files |
|
451 | - * |
|
452 | - * The function will not delete preferences, tables and the configuration, |
|
453 | - * this has to be done by the function oc_app_uninstall(). |
|
454 | - */ |
|
455 | - public function removeApp($appId) { |
|
456 | - if($this->isDownloaded( $appId )) { |
|
457 | - $appDir = OC_App::getInstallPath() . '/' . $appId; |
|
458 | - OC_Helper::rmdirr($appDir); |
|
459 | - return true; |
|
460 | - }else{ |
|
461 | - \OCP\Util::writeLog('core', 'can\'t remove app '.$appId.'. It is not installed.', \OCP\Util::ERROR); |
|
462 | - |
|
463 | - return false; |
|
464 | - } |
|
465 | - |
|
466 | - } |
|
467 | - |
|
468 | - /** |
|
469 | - * Installs the app within the bundle and marks the bundle as installed |
|
470 | - * |
|
471 | - * @param Bundle $bundle |
|
472 | - * @throws \Exception If app could not get installed |
|
473 | - */ |
|
474 | - public function installAppBundle(Bundle $bundle) { |
|
475 | - $appIds = $bundle->getAppIdentifiers(); |
|
476 | - foreach($appIds as $appId) { |
|
477 | - if(!$this->isDownloaded($appId)) { |
|
478 | - $this->downloadApp($appId); |
|
479 | - } |
|
480 | - $this->installApp($appId); |
|
481 | - $app = new OC_App(); |
|
482 | - $app->enable($appId); |
|
483 | - } |
|
484 | - $bundles = json_decode($this->config->getAppValue('core', 'installed.bundles', json_encode([])), true); |
|
485 | - $bundles[] = $bundle->getIdentifier(); |
|
486 | - $this->config->setAppValue('core', 'installed.bundles', json_encode($bundles)); |
|
487 | - } |
|
488 | - |
|
489 | - /** |
|
490 | - * Installs shipped apps |
|
491 | - * |
|
492 | - * This function installs all apps found in the 'apps' directory that should be enabled by default; |
|
493 | - * @param bool $softErrors When updating we ignore errors and simply log them, better to have a |
|
494 | - * working ownCloud at the end instead of an aborted update. |
|
495 | - * @return array Array of error messages (appid => Exception) |
|
496 | - */ |
|
497 | - public static function installShippedApps($softErrors = false) { |
|
498 | - $errors = []; |
|
499 | - foreach(\OC::$APPSROOTS as $app_dir) { |
|
500 | - if($dir = opendir( $app_dir['path'] )) { |
|
501 | - while( false !== ( $filename = readdir( $dir ))) { |
|
502 | - if( substr( $filename, 0, 1 ) != '.' and is_dir($app_dir['path']."/$filename") ) { |
|
503 | - if( file_exists( $app_dir['path']."/$filename/appinfo/info.xml" )) { |
|
504 | - if(!Installer::isInstalled($filename)) { |
|
505 | - $info=OC_App::getAppInfo($filename); |
|
506 | - $enabled = isset($info['default_enable']); |
|
507 | - if (($enabled || in_array($filename, \OC::$server->getAppManager()->getAlwaysEnabledApps())) |
|
508 | - && \OC::$server->getConfig()->getAppValue($filename, 'enabled') !== 'no') { |
|
509 | - if ($softErrors) { |
|
510 | - try { |
|
511 | - Installer::installShippedApp($filename); |
|
512 | - } catch (HintException $e) { |
|
513 | - if ($e->getPrevious() instanceof TableExistsException) { |
|
514 | - $errors[$filename] = $e; |
|
515 | - continue; |
|
516 | - } |
|
517 | - throw $e; |
|
518 | - } |
|
519 | - } else { |
|
520 | - Installer::installShippedApp($filename); |
|
521 | - } |
|
522 | - \OC::$server->getConfig()->setAppValue($filename, 'enabled', 'yes'); |
|
523 | - } |
|
524 | - } |
|
525 | - } |
|
526 | - } |
|
527 | - } |
|
528 | - closedir( $dir ); |
|
529 | - } |
|
530 | - } |
|
531 | - |
|
532 | - return $errors; |
|
533 | - } |
|
534 | - |
|
535 | - /** |
|
536 | - * install an app already placed in the app folder |
|
537 | - * @param string $app id of the app to install |
|
538 | - * @return integer |
|
539 | - */ |
|
540 | - public static function installShippedApp($app) { |
|
541 | - //install the database |
|
542 | - $appPath = OC_App::getAppPath($app); |
|
543 | - \OC_App::registerAutoloading($app, $appPath); |
|
544 | - |
|
545 | - if(is_file("$appPath/appinfo/database.xml")) { |
|
546 | - try { |
|
547 | - OC_DB::createDbFromStructure("$appPath/appinfo/database.xml"); |
|
548 | - } catch (TableExistsException $e) { |
|
549 | - throw new HintException( |
|
550 | - 'Failed to enable app ' . $app, |
|
551 | - 'Please ask for help via one of our <a href="https://nextcloud.com/support/" target="_blank" rel="noreferrer noopener">support channels</a>.', |
|
552 | - 0, $e |
|
553 | - ); |
|
554 | - } |
|
555 | - } else { |
|
556 | - $ms = new \OC\DB\MigrationService($app, \OC::$server->getDatabaseConnection()); |
|
557 | - $ms->migrate(); |
|
558 | - } |
|
559 | - |
|
560 | - //run appinfo/install.php |
|
561 | - self::includeAppScript("$appPath/appinfo/install.php"); |
|
562 | - |
|
563 | - $info = OC_App::getAppInfo($app); |
|
564 | - if (is_null($info)) { |
|
565 | - return false; |
|
566 | - } |
|
567 | - \OC_App::setupBackgroundJobs($info['background-jobs']); |
|
568 | - |
|
569 | - OC_App::executeRepairSteps($app, $info['repair-steps']['install']); |
|
570 | - |
|
571 | - $config = \OC::$server->getConfig(); |
|
572 | - |
|
573 | - $config->setAppValue($app, 'installed_version', OC_App::getAppVersion($app)); |
|
574 | - if (array_key_exists('ocsid', $info)) { |
|
575 | - $config->setAppValue($app, 'ocsid', $info['ocsid']); |
|
576 | - } |
|
577 | - |
|
578 | - //set remote/public handlers |
|
579 | - foreach($info['remote'] as $name=>$path) { |
|
580 | - $config->setAppValue('core', 'remote_'.$name, $app.'/'.$path); |
|
581 | - } |
|
582 | - foreach($info['public'] as $name=>$path) { |
|
583 | - $config->setAppValue('core', 'public_'.$name, $app.'/'.$path); |
|
584 | - } |
|
585 | - |
|
586 | - OC_App::setAppTypes($info['id']); |
|
587 | - |
|
588 | - if(isset($info['settings']) && is_array($info['settings'])) { |
|
589 | - // requires that autoloading was registered for the app, |
|
590 | - // as happens before running the install.php some lines above |
|
591 | - \OC::$server->getSettingsManager()->setupSettings($info['settings']); |
|
592 | - } |
|
593 | - |
|
594 | - return $info['id']; |
|
595 | - } |
|
596 | - |
|
597 | - /** |
|
598 | - * check the code of an app with some static code checks |
|
599 | - * @param string $folder the folder of the app to check |
|
600 | - * @return boolean true for app is o.k. and false for app is not o.k. |
|
601 | - */ |
|
602 | - public static function checkCode($folder) { |
|
603 | - // is the code checker enabled? |
|
604 | - if(!\OC::$server->getConfig()->getSystemValue('appcodechecker', false)) { |
|
605 | - return true; |
|
606 | - } |
|
607 | - |
|
608 | - $codeChecker = new CodeChecker(new PrivateCheck(new EmptyCheck())); |
|
609 | - $errors = $codeChecker->analyseFolder(basename($folder), $folder); |
|
610 | - |
|
611 | - return empty($errors); |
|
612 | - } |
|
613 | - |
|
614 | - /** |
|
615 | - * @param string $script |
|
616 | - */ |
|
617 | - private static function includeAppScript($script) { |
|
618 | - if ( file_exists($script) ){ |
|
619 | - include $script; |
|
620 | - } |
|
621 | - } |
|
66 | + /** @var AppFetcher */ |
|
67 | + private $appFetcher; |
|
68 | + /** @var IClientService */ |
|
69 | + private $clientService; |
|
70 | + /** @var ITempManager */ |
|
71 | + private $tempManager; |
|
72 | + /** @var ILogger */ |
|
73 | + private $logger; |
|
74 | + /** @var IConfig */ |
|
75 | + private $config; |
|
76 | + |
|
77 | + /** |
|
78 | + * @param AppFetcher $appFetcher |
|
79 | + * @param IClientService $clientService |
|
80 | + * @param ITempManager $tempManager |
|
81 | + * @param ILogger $logger |
|
82 | + * @param IConfig $config |
|
83 | + */ |
|
84 | + public function __construct(AppFetcher $appFetcher, |
|
85 | + IClientService $clientService, |
|
86 | + ITempManager $tempManager, |
|
87 | + ILogger $logger, |
|
88 | + IConfig $config) { |
|
89 | + $this->appFetcher = $appFetcher; |
|
90 | + $this->clientService = $clientService; |
|
91 | + $this->tempManager = $tempManager; |
|
92 | + $this->logger = $logger; |
|
93 | + $this->config = $config; |
|
94 | + } |
|
95 | + |
|
96 | + /** |
|
97 | + * Installs an app that is located in one of the app folders already |
|
98 | + * |
|
99 | + * @param string $appId App to install |
|
100 | + * @throws \Exception |
|
101 | + * @return string app ID |
|
102 | + */ |
|
103 | + public function installApp($appId) { |
|
104 | + $app = \OC_App::findAppInDirectories($appId); |
|
105 | + if($app === false) { |
|
106 | + throw new \Exception('App not found in any app directory'); |
|
107 | + } |
|
108 | + |
|
109 | + $basedir = $app['path'].'/'.$appId; |
|
110 | + $info = OC_App::getAppInfo($basedir.'/appinfo/info.xml', true); |
|
111 | + |
|
112 | + $l = \OC::$server->getL10N('core'); |
|
113 | + |
|
114 | + if(!is_array($info)) { |
|
115 | + throw new \Exception( |
|
116 | + $l->t('App "%s" cannot be installed because appinfo file cannot be read.', |
|
117 | + [$info['name']] |
|
118 | + ) |
|
119 | + ); |
|
120 | + } |
|
121 | + |
|
122 | + $version = \OCP\Util::getVersion(); |
|
123 | + if (!\OC_App::isAppCompatible($version, $info)) { |
|
124 | + throw new \Exception( |
|
125 | + // TODO $l |
|
126 | + $l->t('App "%s" cannot be installed because it is not compatible with this version of the server.', |
|
127 | + [$info['name']] |
|
128 | + ) |
|
129 | + ); |
|
130 | + } |
|
131 | + |
|
132 | + // check for required dependencies |
|
133 | + \OC_App::checkAppDependencies($this->config, $l, $info); |
|
134 | + \OC_App::registerAutoloading($appId, $basedir); |
|
135 | + |
|
136 | + //install the database |
|
137 | + if(is_file($basedir.'/appinfo/database.xml')) { |
|
138 | + if (\OC::$server->getAppConfig()->getValue($info['id'], 'installed_version') === null) { |
|
139 | + OC_DB::createDbFromStructure($basedir.'/appinfo/database.xml'); |
|
140 | + } else { |
|
141 | + OC_DB::updateDbFromStructure($basedir.'/appinfo/database.xml'); |
|
142 | + } |
|
143 | + } else { |
|
144 | + $ms = new \OC\DB\MigrationService($info['id'], \OC::$server->getDatabaseConnection()); |
|
145 | + $ms->migrate(); |
|
146 | + } |
|
147 | + |
|
148 | + \OC_App::setupBackgroundJobs($info['background-jobs']); |
|
149 | + if(isset($info['settings']) && is_array($info['settings'])) { |
|
150 | + \OC::$server->getSettingsManager()->setupSettings($info['settings']); |
|
151 | + } |
|
152 | + |
|
153 | + //run appinfo/install.php |
|
154 | + if((!isset($data['noinstall']) or $data['noinstall']==false)) { |
|
155 | + self::includeAppScript($basedir . '/appinfo/install.php'); |
|
156 | + } |
|
157 | + |
|
158 | + $appData = OC_App::getAppInfo($appId); |
|
159 | + OC_App::executeRepairSteps($appId, $appData['repair-steps']['install']); |
|
160 | + |
|
161 | + //set the installed version |
|
162 | + \OC::$server->getConfig()->setAppValue($info['id'], 'installed_version', OC_App::getAppVersion($info['id'], false)); |
|
163 | + \OC::$server->getConfig()->setAppValue($info['id'], 'enabled', 'no'); |
|
164 | + |
|
165 | + //set remote/public handlers |
|
166 | + foreach($info['remote'] as $name=>$path) { |
|
167 | + \OC::$server->getConfig()->setAppValue('core', 'remote_'.$name, $info['id'].'/'.$path); |
|
168 | + } |
|
169 | + foreach($info['public'] as $name=>$path) { |
|
170 | + \OC::$server->getConfig()->setAppValue('core', 'public_'.$name, $info['id'].'/'.$path); |
|
171 | + } |
|
172 | + |
|
173 | + OC_App::setAppTypes($info['id']); |
|
174 | + |
|
175 | + return $info['id']; |
|
176 | + } |
|
177 | + |
|
178 | + /** |
|
179 | + * @brief checks whether or not an app is installed |
|
180 | + * @param string $app app |
|
181 | + * @returns bool |
|
182 | + * |
|
183 | + * Checks whether or not an app is installed, i.e. registered in apps table. |
|
184 | + */ |
|
185 | + public static function isInstalled( $app ) { |
|
186 | + return (\OC::$server->getConfig()->getAppValue($app, "installed_version", null) !== null); |
|
187 | + } |
|
188 | + |
|
189 | + /** |
|
190 | + * Updates the specified app from the appstore |
|
191 | + * |
|
192 | + * @param string $appId |
|
193 | + * @return bool |
|
194 | + */ |
|
195 | + public function updateAppstoreApp($appId) { |
|
196 | + if(self::isUpdateAvailable($appId, $this->appFetcher)) { |
|
197 | + try { |
|
198 | + $this->downloadApp($appId); |
|
199 | + } catch (\Exception $e) { |
|
200 | + $this->logger->error($e->getMessage(), ['app' => 'core']); |
|
201 | + return false; |
|
202 | + } |
|
203 | + return OC_App::updateApp($appId); |
|
204 | + } |
|
205 | + |
|
206 | + return false; |
|
207 | + } |
|
208 | + |
|
209 | + /** |
|
210 | + * Downloads an app and puts it into the app directory |
|
211 | + * |
|
212 | + * @param string $appId |
|
213 | + * |
|
214 | + * @throws \Exception If the installation was not successful |
|
215 | + */ |
|
216 | + public function downloadApp($appId) { |
|
217 | + $appId = strtolower($appId); |
|
218 | + |
|
219 | + $apps = $this->appFetcher->get(); |
|
220 | + foreach($apps as $app) { |
|
221 | + if($app['id'] === $appId) { |
|
222 | + // Load the certificate |
|
223 | + $certificate = new X509(); |
|
224 | + $certificate->loadCA(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crt')); |
|
225 | + $loadedCertificate = $certificate->loadX509($app['certificate']); |
|
226 | + |
|
227 | + // Verify if the certificate has been revoked |
|
228 | + $crl = new X509(); |
|
229 | + $crl->loadCA(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crt')); |
|
230 | + $crl->loadCRL(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crl')); |
|
231 | + if($crl->validateSignature() !== true) { |
|
232 | + throw new \Exception('Could not validate CRL signature'); |
|
233 | + } |
|
234 | + $csn = $loadedCertificate['tbsCertificate']['serialNumber']->toString(); |
|
235 | + $revoked = $crl->getRevoked($csn); |
|
236 | + if ($revoked !== false) { |
|
237 | + throw new \Exception( |
|
238 | + sprintf( |
|
239 | + 'Certificate "%s" has been revoked', |
|
240 | + $csn |
|
241 | + ) |
|
242 | + ); |
|
243 | + } |
|
244 | + |
|
245 | + // Verify if the certificate has been issued by the Nextcloud Code Authority CA |
|
246 | + if($certificate->validateSignature() !== true) { |
|
247 | + throw new \Exception( |
|
248 | + sprintf( |
|
249 | + 'App with id %s has a certificate not issued by a trusted Code Signing Authority', |
|
250 | + $appId |
|
251 | + ) |
|
252 | + ); |
|
253 | + } |
|
254 | + |
|
255 | + // Verify if the certificate is issued for the requested app id |
|
256 | + $certInfo = openssl_x509_parse($app['certificate']); |
|
257 | + if(!isset($certInfo['subject']['CN'])) { |
|
258 | + throw new \Exception( |
|
259 | + sprintf( |
|
260 | + 'App with id %s has a cert with no CN', |
|
261 | + $appId |
|
262 | + ) |
|
263 | + ); |
|
264 | + } |
|
265 | + if($certInfo['subject']['CN'] !== $appId) { |
|
266 | + throw new \Exception( |
|
267 | + sprintf( |
|
268 | + 'App with id %s has a cert issued to %s', |
|
269 | + $appId, |
|
270 | + $certInfo['subject']['CN'] |
|
271 | + ) |
|
272 | + ); |
|
273 | + } |
|
274 | + |
|
275 | + // Download the release |
|
276 | + $tempFile = $this->tempManager->getTemporaryFile('.tar.gz'); |
|
277 | + $client = $this->clientService->newClient(); |
|
278 | + $client->get($app['releases'][0]['download'], ['save_to' => $tempFile]); |
|
279 | + |
|
280 | + // Check if the signature actually matches the downloaded content |
|
281 | + $certificate = openssl_get_publickey($app['certificate']); |
|
282 | + $verified = (bool)openssl_verify(file_get_contents($tempFile), base64_decode($app['releases'][0]['signature']), $certificate, OPENSSL_ALGO_SHA512); |
|
283 | + openssl_free_key($certificate); |
|
284 | + |
|
285 | + if($verified === true) { |
|
286 | + // Seems to match, let's proceed |
|
287 | + $extractDir = $this->tempManager->getTemporaryFolder(); |
|
288 | + $archive = new TAR($tempFile); |
|
289 | + |
|
290 | + if($archive) { |
|
291 | + if (!$archive->extract($extractDir)) { |
|
292 | + throw new \Exception( |
|
293 | + sprintf( |
|
294 | + 'Could not extract app %s', |
|
295 | + $appId |
|
296 | + ) |
|
297 | + ); |
|
298 | + } |
|
299 | + $allFiles = scandir($extractDir); |
|
300 | + $folders = array_diff($allFiles, ['.', '..']); |
|
301 | + $folders = array_values($folders); |
|
302 | + |
|
303 | + if(count($folders) > 1) { |
|
304 | + throw new \Exception( |
|
305 | + sprintf( |
|
306 | + 'Extracted app %s has more than 1 folder', |
|
307 | + $appId |
|
308 | + ) |
|
309 | + ); |
|
310 | + } |
|
311 | + |
|
312 | + // Check if appinfo/info.xml has the same app ID as well |
|
313 | + $loadEntities = libxml_disable_entity_loader(false); |
|
314 | + $xml = simplexml_load_file($extractDir . '/' . $folders[0] . '/appinfo/info.xml'); |
|
315 | + libxml_disable_entity_loader($loadEntities); |
|
316 | + if((string)$xml->id !== $appId) { |
|
317 | + throw new \Exception( |
|
318 | + sprintf( |
|
319 | + 'App for id %s has a wrong app ID in info.xml: %s', |
|
320 | + $appId, |
|
321 | + (string)$xml->id |
|
322 | + ) |
|
323 | + ); |
|
324 | + } |
|
325 | + |
|
326 | + // Check if the version is lower than before |
|
327 | + $currentVersion = OC_App::getAppVersion($appId); |
|
328 | + $newVersion = (string)$xml->version; |
|
329 | + if(version_compare($currentVersion, $newVersion) === 1) { |
|
330 | + throw new \Exception( |
|
331 | + sprintf( |
|
332 | + 'App for id %s has version %s and tried to update to lower version %s', |
|
333 | + $appId, |
|
334 | + $currentVersion, |
|
335 | + $newVersion |
|
336 | + ) |
|
337 | + ); |
|
338 | + } |
|
339 | + |
|
340 | + $baseDir = OC_App::getInstallPath() . '/' . $appId; |
|
341 | + // Remove old app with the ID if existent |
|
342 | + OC_Helper::rmdirr($baseDir); |
|
343 | + // Move to app folder |
|
344 | + if(@mkdir($baseDir)) { |
|
345 | + $extractDir .= '/' . $folders[0]; |
|
346 | + OC_Helper::copyr($extractDir, $baseDir); |
|
347 | + } |
|
348 | + OC_Helper::copyr($extractDir, $baseDir); |
|
349 | + OC_Helper::rmdirr($extractDir); |
|
350 | + return; |
|
351 | + } else { |
|
352 | + throw new \Exception( |
|
353 | + sprintf( |
|
354 | + 'Could not extract app with ID %s to %s', |
|
355 | + $appId, |
|
356 | + $extractDir |
|
357 | + ) |
|
358 | + ); |
|
359 | + } |
|
360 | + } else { |
|
361 | + // Signature does not match |
|
362 | + throw new \Exception( |
|
363 | + sprintf( |
|
364 | + 'App with id %s has invalid signature', |
|
365 | + $appId |
|
366 | + ) |
|
367 | + ); |
|
368 | + } |
|
369 | + } |
|
370 | + } |
|
371 | + |
|
372 | + throw new \Exception( |
|
373 | + sprintf( |
|
374 | + 'Could not download app %s', |
|
375 | + $appId |
|
376 | + ) |
|
377 | + ); |
|
378 | + } |
|
379 | + |
|
380 | + /** |
|
381 | + * Check if an update for the app is available |
|
382 | + * |
|
383 | + * @param string $appId |
|
384 | + * @param AppFetcher $appFetcher |
|
385 | + * @return string|false false or the version number of the update |
|
386 | + */ |
|
387 | + public static function isUpdateAvailable($appId, |
|
388 | + AppFetcher $appFetcher) { |
|
389 | + static $isInstanceReadyForUpdates = null; |
|
390 | + |
|
391 | + if ($isInstanceReadyForUpdates === null) { |
|
392 | + $installPath = OC_App::getInstallPath(); |
|
393 | + if ($installPath === false || $installPath === null) { |
|
394 | + $isInstanceReadyForUpdates = false; |
|
395 | + } else { |
|
396 | + $isInstanceReadyForUpdates = true; |
|
397 | + } |
|
398 | + } |
|
399 | + |
|
400 | + if ($isInstanceReadyForUpdates === false) { |
|
401 | + return false; |
|
402 | + } |
|
403 | + |
|
404 | + $apps = $appFetcher->get(); |
|
405 | + foreach($apps as $app) { |
|
406 | + if($app['id'] === $appId) { |
|
407 | + $currentVersion = OC_App::getAppVersion($appId); |
|
408 | + $newestVersion = $app['releases'][0]['version']; |
|
409 | + if (version_compare($newestVersion, $currentVersion, '>')) { |
|
410 | + return $newestVersion; |
|
411 | + } else { |
|
412 | + return false; |
|
413 | + } |
|
414 | + } |
|
415 | + } |
|
416 | + |
|
417 | + return false; |
|
418 | + } |
|
419 | + |
|
420 | + /** |
|
421 | + * Check if app is already downloaded |
|
422 | + * @param string $name name of the application to remove |
|
423 | + * @return boolean |
|
424 | + * |
|
425 | + * The function will check if the app is already downloaded in the apps repository |
|
426 | + */ |
|
427 | + public function isDownloaded($name) { |
|
428 | + foreach(\OC::$APPSROOTS as $dir) { |
|
429 | + $dirToTest = $dir['path']; |
|
430 | + $dirToTest .= '/'; |
|
431 | + $dirToTest .= $name; |
|
432 | + $dirToTest .= '/'; |
|
433 | + |
|
434 | + if (is_dir($dirToTest)) { |
|
435 | + return true; |
|
436 | + } |
|
437 | + } |
|
438 | + |
|
439 | + return false; |
|
440 | + } |
|
441 | + |
|
442 | + /** |
|
443 | + * Removes an app |
|
444 | + * @param string $appId ID of the application to remove |
|
445 | + * @return boolean |
|
446 | + * |
|
447 | + * |
|
448 | + * This function works as follows |
|
449 | + * -# call uninstall repair steps |
|
450 | + * -# removing the files |
|
451 | + * |
|
452 | + * The function will not delete preferences, tables and the configuration, |
|
453 | + * this has to be done by the function oc_app_uninstall(). |
|
454 | + */ |
|
455 | + public function removeApp($appId) { |
|
456 | + if($this->isDownloaded( $appId )) { |
|
457 | + $appDir = OC_App::getInstallPath() . '/' . $appId; |
|
458 | + OC_Helper::rmdirr($appDir); |
|
459 | + return true; |
|
460 | + }else{ |
|
461 | + \OCP\Util::writeLog('core', 'can\'t remove app '.$appId.'. It is not installed.', \OCP\Util::ERROR); |
|
462 | + |
|
463 | + return false; |
|
464 | + } |
|
465 | + |
|
466 | + } |
|
467 | + |
|
468 | + /** |
|
469 | + * Installs the app within the bundle and marks the bundle as installed |
|
470 | + * |
|
471 | + * @param Bundle $bundle |
|
472 | + * @throws \Exception If app could not get installed |
|
473 | + */ |
|
474 | + public function installAppBundle(Bundle $bundle) { |
|
475 | + $appIds = $bundle->getAppIdentifiers(); |
|
476 | + foreach($appIds as $appId) { |
|
477 | + if(!$this->isDownloaded($appId)) { |
|
478 | + $this->downloadApp($appId); |
|
479 | + } |
|
480 | + $this->installApp($appId); |
|
481 | + $app = new OC_App(); |
|
482 | + $app->enable($appId); |
|
483 | + } |
|
484 | + $bundles = json_decode($this->config->getAppValue('core', 'installed.bundles', json_encode([])), true); |
|
485 | + $bundles[] = $bundle->getIdentifier(); |
|
486 | + $this->config->setAppValue('core', 'installed.bundles', json_encode($bundles)); |
|
487 | + } |
|
488 | + |
|
489 | + /** |
|
490 | + * Installs shipped apps |
|
491 | + * |
|
492 | + * This function installs all apps found in the 'apps' directory that should be enabled by default; |
|
493 | + * @param bool $softErrors When updating we ignore errors and simply log them, better to have a |
|
494 | + * working ownCloud at the end instead of an aborted update. |
|
495 | + * @return array Array of error messages (appid => Exception) |
|
496 | + */ |
|
497 | + public static function installShippedApps($softErrors = false) { |
|
498 | + $errors = []; |
|
499 | + foreach(\OC::$APPSROOTS as $app_dir) { |
|
500 | + if($dir = opendir( $app_dir['path'] )) { |
|
501 | + while( false !== ( $filename = readdir( $dir ))) { |
|
502 | + if( substr( $filename, 0, 1 ) != '.' and is_dir($app_dir['path']."/$filename") ) { |
|
503 | + if( file_exists( $app_dir['path']."/$filename/appinfo/info.xml" )) { |
|
504 | + if(!Installer::isInstalled($filename)) { |
|
505 | + $info=OC_App::getAppInfo($filename); |
|
506 | + $enabled = isset($info['default_enable']); |
|
507 | + if (($enabled || in_array($filename, \OC::$server->getAppManager()->getAlwaysEnabledApps())) |
|
508 | + && \OC::$server->getConfig()->getAppValue($filename, 'enabled') !== 'no') { |
|
509 | + if ($softErrors) { |
|
510 | + try { |
|
511 | + Installer::installShippedApp($filename); |
|
512 | + } catch (HintException $e) { |
|
513 | + if ($e->getPrevious() instanceof TableExistsException) { |
|
514 | + $errors[$filename] = $e; |
|
515 | + continue; |
|
516 | + } |
|
517 | + throw $e; |
|
518 | + } |
|
519 | + } else { |
|
520 | + Installer::installShippedApp($filename); |
|
521 | + } |
|
522 | + \OC::$server->getConfig()->setAppValue($filename, 'enabled', 'yes'); |
|
523 | + } |
|
524 | + } |
|
525 | + } |
|
526 | + } |
|
527 | + } |
|
528 | + closedir( $dir ); |
|
529 | + } |
|
530 | + } |
|
531 | + |
|
532 | + return $errors; |
|
533 | + } |
|
534 | + |
|
535 | + /** |
|
536 | + * install an app already placed in the app folder |
|
537 | + * @param string $app id of the app to install |
|
538 | + * @return integer |
|
539 | + */ |
|
540 | + public static function installShippedApp($app) { |
|
541 | + //install the database |
|
542 | + $appPath = OC_App::getAppPath($app); |
|
543 | + \OC_App::registerAutoloading($app, $appPath); |
|
544 | + |
|
545 | + if(is_file("$appPath/appinfo/database.xml")) { |
|
546 | + try { |
|
547 | + OC_DB::createDbFromStructure("$appPath/appinfo/database.xml"); |
|
548 | + } catch (TableExistsException $e) { |
|
549 | + throw new HintException( |
|
550 | + 'Failed to enable app ' . $app, |
|
551 | + 'Please ask for help via one of our <a href="https://nextcloud.com/support/" target="_blank" rel="noreferrer noopener">support channels</a>.', |
|
552 | + 0, $e |
|
553 | + ); |
|
554 | + } |
|
555 | + } else { |
|
556 | + $ms = new \OC\DB\MigrationService($app, \OC::$server->getDatabaseConnection()); |
|
557 | + $ms->migrate(); |
|
558 | + } |
|
559 | + |
|
560 | + //run appinfo/install.php |
|
561 | + self::includeAppScript("$appPath/appinfo/install.php"); |
|
562 | + |
|
563 | + $info = OC_App::getAppInfo($app); |
|
564 | + if (is_null($info)) { |
|
565 | + return false; |
|
566 | + } |
|
567 | + \OC_App::setupBackgroundJobs($info['background-jobs']); |
|
568 | + |
|
569 | + OC_App::executeRepairSteps($app, $info['repair-steps']['install']); |
|
570 | + |
|
571 | + $config = \OC::$server->getConfig(); |
|
572 | + |
|
573 | + $config->setAppValue($app, 'installed_version', OC_App::getAppVersion($app)); |
|
574 | + if (array_key_exists('ocsid', $info)) { |
|
575 | + $config->setAppValue($app, 'ocsid', $info['ocsid']); |
|
576 | + } |
|
577 | + |
|
578 | + //set remote/public handlers |
|
579 | + foreach($info['remote'] as $name=>$path) { |
|
580 | + $config->setAppValue('core', 'remote_'.$name, $app.'/'.$path); |
|
581 | + } |
|
582 | + foreach($info['public'] as $name=>$path) { |
|
583 | + $config->setAppValue('core', 'public_'.$name, $app.'/'.$path); |
|
584 | + } |
|
585 | + |
|
586 | + OC_App::setAppTypes($info['id']); |
|
587 | + |
|
588 | + if(isset($info['settings']) && is_array($info['settings'])) { |
|
589 | + // requires that autoloading was registered for the app, |
|
590 | + // as happens before running the install.php some lines above |
|
591 | + \OC::$server->getSettingsManager()->setupSettings($info['settings']); |
|
592 | + } |
|
593 | + |
|
594 | + return $info['id']; |
|
595 | + } |
|
596 | + |
|
597 | + /** |
|
598 | + * check the code of an app with some static code checks |
|
599 | + * @param string $folder the folder of the app to check |
|
600 | + * @return boolean true for app is o.k. and false for app is not o.k. |
|
601 | + */ |
|
602 | + public static function checkCode($folder) { |
|
603 | + // is the code checker enabled? |
|
604 | + if(!\OC::$server->getConfig()->getSystemValue('appcodechecker', false)) { |
|
605 | + return true; |
|
606 | + } |
|
607 | + |
|
608 | + $codeChecker = new CodeChecker(new PrivateCheck(new EmptyCheck())); |
|
609 | + $errors = $codeChecker->analyseFolder(basename($folder), $folder); |
|
610 | + |
|
611 | + return empty($errors); |
|
612 | + } |
|
613 | + |
|
614 | + /** |
|
615 | + * @param string $script |
|
616 | + */ |
|
617 | + private static function includeAppScript($script) { |
|
618 | + if ( file_exists($script) ){ |
|
619 | + include $script; |
|
620 | + } |
|
621 | + } |
|
622 | 622 | } |