Completed
Pull Request — master (#8097)
by Julius
15:23
created
lib/private/legacy/app.php 3 patches
Doc Comments   +5 added lines patch added patch discarded remove patch
@@ -1047,6 +1047,11 @@
 block discarded – undo
1047 1047
 		}
1048 1048
 	}
1049 1049
 
1050
+	/**
1051
+	 * @param string $lang
1052
+	 *
1053
+	 * @return string
1054
+	 */
1050 1055
 	protected static function findBestL10NOption($options, $lang) {
1051 1056
 		$fallback = $similarLangFallback = $englishFallback = false;
1052 1057
 
Please login to merge, or discard this patch.
Indentation   +1074 added lines, -1074 removed lines patch added patch discarded remove patch
@@ -62,1078 +62,1078 @@
 block discarded – undo
62 62
  * upgrading and removing apps.
63 63
  */
64 64
 class OC_App {
65
-	static private $adminForms = array();
66
-	static private $personalForms = array();
67
-	static private $appTypes = array();
68
-	static private $loadedApps = array();
69
-	static private $altLogin = array();
70
-	static private $alreadyRegistered = [];
71
-	const officialApp = 200;
72
-
73
-	/**
74
-	 * clean the appId
75
-	 *
76
-	 * @param string|boolean $app AppId that needs to be cleaned
77
-	 * @return string
78
-	 */
79
-	public static function cleanAppId($app) {
80
-		return str_replace(array('\0', '/', '\\', '..'), '', $app);
81
-	}
82
-
83
-	/**
84
-	 * Check if an app is loaded
85
-	 *
86
-	 * @param string $app
87
-	 * @return bool
88
-	 */
89
-	public static function isAppLoaded($app) {
90
-		return in_array($app, self::$loadedApps, true);
91
-	}
92
-
93
-	/**
94
-	 * loads all apps
95
-	 *
96
-	 * @param string[] | string | null $types
97
-	 * @return bool
98
-	 *
99
-	 * This function walks through the ownCloud directory and loads all apps
100
-	 * it can find. A directory contains an app if the file /appinfo/info.xml
101
-	 * exists.
102
-	 *
103
-	 * if $types is set, only apps of those types will be loaded
104
-	 */
105
-	public static function loadApps($types = null) {
106
-		if (\OC::$server->getSystemConfig()->getValue('maintenance', false)) {
107
-			return false;
108
-		}
109
-		// Load the enabled apps here
110
-		$apps = self::getEnabledApps();
111
-
112
-		// Add each apps' folder as allowed class path
113
-		foreach($apps as $app) {
114
-			$path = self::getAppPath($app);
115
-			if($path !== false) {
116
-				self::registerAutoloading($app, $path);
117
-			}
118
-		}
119
-
120
-		// prevent app.php from printing output
121
-		ob_start();
122
-		foreach ($apps as $app) {
123
-			if ((is_null($types) or self::isType($app, $types)) && !in_array($app, self::$loadedApps)) {
124
-				self::loadApp($app);
125
-			}
126
-		}
127
-		ob_end_clean();
128
-
129
-		return true;
130
-	}
131
-
132
-	/**
133
-	 * load a single app
134
-	 *
135
-	 * @param string $app
136
-	 */
137
-	public static function loadApp($app) {
138
-		self::$loadedApps[] = $app;
139
-		$appPath = self::getAppPath($app);
140
-		if($appPath === false) {
141
-			return;
142
-		}
143
-
144
-		// in case someone calls loadApp() directly
145
-		self::registerAutoloading($app, $appPath);
146
-
147
-		if (is_file($appPath . '/appinfo/app.php')) {
148
-			\OC::$server->getEventLogger()->start('load_app_' . $app, 'Load app: ' . $app);
149
-			self::requireAppFile($app);
150
-			if (self::isType($app, array('authentication'))) {
151
-				// since authentication apps affect the "is app enabled for group" check,
152
-				// the enabled apps cache needs to be cleared to make sure that the
153
-				// next time getEnableApps() is called it will also include apps that were
154
-				// enabled for groups
155
-				self::$enabledAppsCache = array();
156
-			}
157
-			\OC::$server->getEventLogger()->end('load_app_' . $app);
158
-		}
159
-
160
-		$info = self::getAppInfo($app);
161
-		if (!empty($info['activity']['filters'])) {
162
-			foreach ($info['activity']['filters'] as $filter) {
163
-				\OC::$server->getActivityManager()->registerFilter($filter);
164
-			}
165
-		}
166
-		if (!empty($info['activity']['settings'])) {
167
-			foreach ($info['activity']['settings'] as $setting) {
168
-				\OC::$server->getActivityManager()->registerSetting($setting);
169
-			}
170
-		}
171
-		if (!empty($info['activity']['providers'])) {
172
-			foreach ($info['activity']['providers'] as $provider) {
173
-				\OC::$server->getActivityManager()->registerProvider($provider);
174
-			}
175
-		}
176
-		if (!empty($info['collaboration']['plugins'])) {
177
-			// deal with one or many plugin entries
178
-			$plugins = isset($info['collaboration']['plugins']['plugin']['@value']) ?
179
-				[$info['collaboration']['plugins']['plugin']] : $info['collaboration']['plugins']['plugin'];
180
-			foreach ($plugins as $plugin) {
181
-				if($plugin['@attributes']['type'] === 'collaborator-search') {
182
-					$pluginInfo = [
183
-						'shareType' => $plugin['@attributes']['share-type'],
184
-						'class' => $plugin['@value'],
185
-					];
186
-					\OC::$server->getCollaboratorSearch()->registerPlugin($pluginInfo);
187
-				} else if ($plugin['@attributes']['type'] === 'autocomplete-sort') {
188
-					\OC::$server->getAutoCompleteManager()->registerSorter($plugin['@value']);
189
-				}
190
-			}
191
-		}
192
-	}
193
-
194
-	/**
195
-	 * @internal
196
-	 * @param string $app
197
-	 * @param string $path
198
-	 */
199
-	public static function registerAutoloading($app, $path) {
200
-		$key = $app . '-' . $path;
201
-		if(isset(self::$alreadyRegistered[$key])) {
202
-			return;
203
-		}
204
-
205
-		self::$alreadyRegistered[$key] = true;
206
-
207
-		// Register on PSR-4 composer autoloader
208
-		$appNamespace = \OC\AppFramework\App::buildAppNamespace($app);
209
-		\OC::$server->registerNamespace($app, $appNamespace);
210
-
211
-		if (file_exists($path . '/composer/autoload.php')) {
212
-			require_once $path . '/composer/autoload.php';
213
-		} else {
214
-			\OC::$composerAutoloader->addPsr4($appNamespace . '\\', $path . '/lib/', true);
215
-			// Register on legacy autoloader
216
-			\OC::$loader->addValidRoot($path);
217
-		}
218
-
219
-		// Register Test namespace only when testing
220
-		if (defined('PHPUNIT_RUN') || defined('CLI_TEST_RUN')) {
221
-			\OC::$composerAutoloader->addPsr4($appNamespace . '\\Tests\\', $path . '/tests/', true);
222
-		}
223
-	}
224
-
225
-	/**
226
-	 * Load app.php from the given app
227
-	 *
228
-	 * @param string $app app name
229
-	 */
230
-	private static function requireAppFile($app) {
231
-		try {
232
-			// encapsulated here to avoid variable scope conflicts
233
-			require_once $app . '/appinfo/app.php';
234
-		} catch (Error $ex) {
235
-			\OC::$server->getLogger()->logException($ex);
236
-			if (!\OC::$server->getAppManager()->isShipped($app)) {
237
-				// Only disable apps which are not shipped
238
-				self::disable($app);
239
-			}
240
-		}
241
-	}
242
-
243
-	/**
244
-	 * check if an app is of a specific type
245
-	 *
246
-	 * @param string $app
247
-	 * @param string|array $types
248
-	 * @return bool
249
-	 */
250
-	public static function isType($app, $types) {
251
-		if (is_string($types)) {
252
-			$types = array($types);
253
-		}
254
-		$appTypes = self::getAppTypes($app);
255
-		foreach ($types as $type) {
256
-			if (array_search($type, $appTypes) !== false) {
257
-				return true;
258
-			}
259
-		}
260
-		return false;
261
-	}
262
-
263
-	/**
264
-	 * get the types of an app
265
-	 *
266
-	 * @param string $app
267
-	 * @return array
268
-	 */
269
-	private static function getAppTypes($app) {
270
-		//load the cache
271
-		if (count(self::$appTypes) == 0) {
272
-			self::$appTypes = \OC::$server->getAppConfig()->getValues(false, 'types');
273
-		}
274
-
275
-		if (isset(self::$appTypes[$app])) {
276
-			return explode(',', self::$appTypes[$app]);
277
-		} else {
278
-			return array();
279
-		}
280
-	}
281
-
282
-	/**
283
-	 * read app types from info.xml and cache them in the database
284
-	 */
285
-	public static function setAppTypes($app) {
286
-		$appData = self::getAppInfo($app);
287
-		if(!is_array($appData)) {
288
-			return;
289
-		}
290
-
291
-		if (isset($appData['types'])) {
292
-			$appTypes = implode(',', $appData['types']);
293
-		} else {
294
-			$appTypes = '';
295
-			$appData['types'] = [];
296
-		}
297
-
298
-		\OC::$server->getConfig()->setAppValue($app, 'types', $appTypes);
299
-
300
-		if (\OC::$server->getAppManager()->hasProtectedAppType($appData['types'])) {
301
-			$enabled = \OC::$server->getConfig()->getAppValue($app, 'enabled', 'yes');
302
-			if ($enabled !== 'yes' && $enabled !== 'no') {
303
-				\OC::$server->getConfig()->setAppValue($app, 'enabled', 'yes');
304
-			}
305
-		}
306
-	}
307
-
308
-	/**
309
-	 * get all enabled apps
310
-	 */
311
-	protected static $enabledAppsCache = array();
312
-
313
-	/**
314
-	 * Returns apps enabled for the current user.
315
-	 *
316
-	 * @param bool $forceRefresh whether to refresh the cache
317
-	 * @param bool $all whether to return apps for all users, not only the
318
-	 * currently logged in one
319
-	 * @return string[]
320
-	 */
321
-	public static function getEnabledApps($forceRefresh = false, $all = false) {
322
-		if (!\OC::$server->getSystemConfig()->getValue('installed', false)) {
323
-			return array();
324
-		}
325
-		// in incognito mode or when logged out, $user will be false,
326
-		// which is also the case during an upgrade
327
-		$appManager = \OC::$server->getAppManager();
328
-		if ($all) {
329
-			$user = null;
330
-		} else {
331
-			$user = \OC::$server->getUserSession()->getUser();
332
-		}
333
-
334
-		if (is_null($user)) {
335
-			$apps = $appManager->getInstalledApps();
336
-		} else {
337
-			$apps = $appManager->getEnabledAppsForUser($user);
338
-		}
339
-		$apps = array_filter($apps, function ($app) {
340
-			return $app !== 'files';//we add this manually
341
-		});
342
-		sort($apps);
343
-		array_unshift($apps, 'files');
344
-		return $apps;
345
-	}
346
-
347
-	/**
348
-	 * checks whether or not an app is enabled
349
-	 *
350
-	 * @param string $app app
351
-	 * @return bool
352
-	 * @deprecated 13.0.0 use \OC::$server->getAppManager()->isEnabledForUser($appId)
353
-	 *
354
-	 * This function checks whether or not an app is enabled.
355
-	 */
356
-	public static function isEnabled($app) {
357
-		return \OC::$server->getAppManager()->isEnabledForUser($app);
358
-	}
359
-
360
-	/**
361
-	 * enables an app
362
-	 *
363
-	 * @param string $appId
364
-	 * @param array $groups (optional) when set, only these groups will have access to the app
365
-	 * @throws \Exception
366
-	 * @return void
367
-	 *
368
-	 * This function set an app as enabled in appconfig.
369
-	 */
370
-	public function enable($appId,
371
-						   $groups = null) {
372
-		self::$enabledAppsCache = []; // flush
373
-
374
-		// Check if app is already downloaded
375
-		$installer = \OC::$server->query(Installer::class);
376
-		$isDownloaded = $installer->isDownloaded($appId);
377
-
378
-		if(!$isDownloaded) {
379
-			$installer->downloadApp($appId);
380
-		}
381
-
382
-		$installer->installApp($appId);
383
-
384
-		$appManager = \OC::$server->getAppManager();
385
-		if (!is_null($groups)) {
386
-			$groupManager = \OC::$server->getGroupManager();
387
-			$groupsList = [];
388
-			foreach ($groups as $group) {
389
-				$groupItem = $groupManager->get($group);
390
-				if ($groupItem instanceof \OCP\IGroup) {
391
-					$groupsList[] = $groupManager->get($group);
392
-				}
393
-			}
394
-			$appManager->enableAppForGroups($appId, $groupsList);
395
-		} else {
396
-			$appManager->enableApp($appId);
397
-		}
398
-	}
399
-
400
-	/**
401
-	 * This function set an app as disabled in appconfig.
402
-	 *
403
-	 * @param string $app app
404
-	 * @throws Exception
405
-	 */
406
-	public static function disable($app) {
407
-		// flush
408
-		self::$enabledAppsCache = array();
409
-
410
-		// run uninstall steps
411
-		$appData = OC_App::getAppInfo($app);
412
-		if (!is_null($appData)) {
413
-			OC_App::executeRepairSteps($app, $appData['repair-steps']['uninstall']);
414
-		}
415
-
416
-		// emit disable hook - needed anymore ?
417
-		\OC_Hook::emit('OC_App', 'pre_disable', array('app' => $app));
418
-
419
-		// finally disable it
420
-		$appManager = \OC::$server->getAppManager();
421
-		$appManager->disableApp($app);
422
-	}
423
-
424
-	// This is private as well. It simply works, so don't ask for more details
425
-	private static function proceedNavigation($list) {
426
-		usort($list, function($a, $b) {
427
-			if (isset($a['order']) && isset($b['order'])) {
428
-				return ($a['order'] < $b['order']) ? -1 : 1;
429
-			} else if (isset($a['order']) || isset($b['order'])) {
430
-				return isset($a['order']) ? -1 : 1;
431
-			} else {
432
-				return ($a['name'] < $b['name']) ? -1 : 1;
433
-			}
434
-		});
435
-
436
-		$activeApp = OC::$server->getNavigationManager()->getActiveEntry();
437
-		foreach ($list as $index => &$navEntry) {
438
-			if ($navEntry['id'] == $activeApp) {
439
-				$navEntry['active'] = true;
440
-			} else {
441
-				$navEntry['active'] = false;
442
-			}
443
-		}
444
-		unset($navEntry);
445
-
446
-		return $list;
447
-	}
448
-
449
-	/**
450
-	 * Get the path where to install apps
451
-	 *
452
-	 * @return string|false
453
-	 */
454
-	public static function getInstallPath() {
455
-		if (\OC::$server->getSystemConfig()->getValue('appstoreenabled', true) == false) {
456
-			return false;
457
-		}
458
-
459
-		foreach (OC::$APPSROOTS as $dir) {
460
-			if (isset($dir['writable']) && $dir['writable'] === true) {
461
-				return $dir['path'];
462
-			}
463
-		}
464
-
465
-		\OCP\Util::writeLog('core', 'No application directories are marked as writable.', \OCP\Util::ERROR);
466
-		return null;
467
-	}
468
-
469
-
470
-	/**
471
-	 * search for an app in all app-directories
472
-	 *
473
-	 * @param string $appId
474
-	 * @return false|string
475
-	 */
476
-	public static function findAppInDirectories($appId) {
477
-		$sanitizedAppId = self::cleanAppId($appId);
478
-		if($sanitizedAppId !== $appId) {
479
-			return false;
480
-		}
481
-		static $app_dir = array();
482
-
483
-		if (isset($app_dir[$appId])) {
484
-			return $app_dir[$appId];
485
-		}
486
-
487
-		$possibleApps = array();
488
-		foreach (OC::$APPSROOTS as $dir) {
489
-			if (file_exists($dir['path'] . '/' . $appId)) {
490
-				$possibleApps[] = $dir;
491
-			}
492
-		}
493
-
494
-		if (empty($possibleApps)) {
495
-			return false;
496
-		} elseif (count($possibleApps) === 1) {
497
-			$dir = array_shift($possibleApps);
498
-			$app_dir[$appId] = $dir;
499
-			return $dir;
500
-		} else {
501
-			$versionToLoad = array();
502
-			foreach ($possibleApps as $possibleApp) {
503
-				$version = self::getAppVersionByPath($possibleApp['path']);
504
-				if (empty($versionToLoad) || version_compare($version, $versionToLoad['version'], '>')) {
505
-					$versionToLoad = array(
506
-						'dir' => $possibleApp,
507
-						'version' => $version,
508
-					);
509
-				}
510
-			}
511
-			$app_dir[$appId] = $versionToLoad['dir'];
512
-			return $versionToLoad['dir'];
513
-			//TODO - write test
514
-		}
515
-	}
516
-
517
-	/**
518
-	 * Get the directory for the given app.
519
-	 * If the app is defined in multiple directories, the first one is taken. (false if not found)
520
-	 *
521
-	 * @param string $appId
522
-	 * @return string|false
523
-	 */
524
-	public static function getAppPath($appId) {
525
-		if ($appId === null || trim($appId) === '') {
526
-			return false;
527
-		}
528
-
529
-		if (($dir = self::findAppInDirectories($appId)) != false) {
530
-			return $dir['path'] . '/' . $appId;
531
-		}
532
-		return false;
533
-	}
534
-
535
-	/**
536
-	 * Get the path for the given app on the access
537
-	 * If the app is defined in multiple directories, the first one is taken. (false if not found)
538
-	 *
539
-	 * @param string $appId
540
-	 * @return string|false
541
-	 */
542
-	public static function getAppWebPath($appId) {
543
-		if (($dir = self::findAppInDirectories($appId)) != false) {
544
-			return OC::$WEBROOT . $dir['url'] . '/' . $appId;
545
-		}
546
-		return false;
547
-	}
548
-
549
-	/**
550
-	 * get the last version of the app from appinfo/info.xml
551
-	 *
552
-	 * @param string $appId
553
-	 * @param bool $useCache
554
-	 * @return string
555
-	 * @deprecated 14.0.0 use \OC::$server->getAppManager()->getAppVersion()
556
-	 */
557
-	public static function getAppVersion($appId, $useCache = true) {
558
-		return \OC::$server->getAppManager()->getAppVersion($appId, $useCache);
559
-	}
560
-
561
-	/**
562
-	 * get app's version based on it's path
563
-	 *
564
-	 * @param string $path
565
-	 * @return string
566
-	 */
567
-	public static function getAppVersionByPath($path) {
568
-		$infoFile = $path . '/appinfo/info.xml';
569
-		$appData = \OC::$server->getAppManager()->getAppInfo($infoFile, true);
570
-		return isset($appData['version']) ? $appData['version'] : '';
571
-	}
572
-
573
-
574
-	/**
575
-	 * Read all app metadata from the info.xml file
576
-	 *
577
-	 * @param string $appId id of the app or the path of the info.xml file
578
-	 * @param bool $path
579
-	 * @param string $lang
580
-	 * @return array|null
581
-	 * @note all data is read from info.xml, not just pre-defined fields
582
-	 * @deprecated 14.0.0 use \OC::$server->getAppManager()->getAppInfo()
583
-	 */
584
-	public static function getAppInfo($appId, $path = false, $lang = null) {
585
-		return \OC::$server->getAppManager()->getAppInfo($appId, $path, $lang);
586
-	}
587
-
588
-	/**
589
-	 * Returns the navigation
590
-	 *
591
-	 * @return array
592
-	 *
593
-	 * This function returns an array containing all entries added. The
594
-	 * entries are sorted by the key 'order' ascending. Additional to the keys
595
-	 * given for each app the following keys exist:
596
-	 *   - active: boolean, signals if the user is on this navigation entry
597
-	 */
598
-	public static function getNavigation() {
599
-		$entries = OC::$server->getNavigationManager()->getAll();
600
-		return self::proceedNavigation($entries);
601
-	}
602
-
603
-	/**
604
-	 * Returns the Settings Navigation
605
-	 *
606
-	 * @return string[]
607
-	 *
608
-	 * This function returns an array containing all settings pages added. The
609
-	 * entries are sorted by the key 'order' ascending.
610
-	 */
611
-	public static function getSettingsNavigation() {
612
-		$entries = OC::$server->getNavigationManager()->getAll('settings');
613
-		return self::proceedNavigation($entries);
614
-	}
615
-
616
-	/**
617
-	 * get the id of loaded app
618
-	 *
619
-	 * @return string
620
-	 */
621
-	public static function getCurrentApp() {
622
-		$request = \OC::$server->getRequest();
623
-		$script = substr($request->getScriptName(), strlen(OC::$WEBROOT) + 1);
624
-		$topFolder = substr($script, 0, strpos($script, '/') ?: 0);
625
-		if (empty($topFolder)) {
626
-			$path_info = $request->getPathInfo();
627
-			if ($path_info) {
628
-				$topFolder = substr($path_info, 1, strpos($path_info, '/', 1) - 1);
629
-			}
630
-		}
631
-		if ($topFolder == 'apps') {
632
-			$length = strlen($topFolder);
633
-			return substr($script, $length + 1, strpos($script, '/', $length + 1) - $length - 1);
634
-		} else {
635
-			return $topFolder;
636
-		}
637
-	}
638
-
639
-	/**
640
-	 * @param string $type
641
-	 * @return array
642
-	 */
643
-	public static function getForms($type) {
644
-		$forms = array();
645
-		switch ($type) {
646
-			case 'admin':
647
-				$source = self::$adminForms;
648
-				break;
649
-			case 'personal':
650
-				$source = self::$personalForms;
651
-				break;
652
-			default:
653
-				return array();
654
-		}
655
-		foreach ($source as $form) {
656
-			$forms[] = include $form;
657
-		}
658
-		return $forms;
659
-	}
660
-
661
-	/**
662
-	 * register an admin form to be shown
663
-	 *
664
-	 * @param string $app
665
-	 * @param string $page
666
-	 */
667
-	public static function registerAdmin($app, $page) {
668
-		self::$adminForms[] = $app . '/' . $page . '.php';
669
-	}
670
-
671
-	/**
672
-	 * register a personal form to be shown
673
-	 * @param string $app
674
-	 * @param string $page
675
-	 */
676
-	public static function registerPersonal($app, $page) {
677
-		self::$personalForms[] = $app . '/' . $page . '.php';
678
-	}
679
-
680
-	/**
681
-	 * @param array $entry
682
-	 */
683
-	public static function registerLogIn(array $entry) {
684
-		self::$altLogin[] = $entry;
685
-	}
686
-
687
-	/**
688
-	 * @return array
689
-	 */
690
-	public static function getAlternativeLogIns() {
691
-		return self::$altLogin;
692
-	}
693
-
694
-	/**
695
-	 * get a list of all apps in the apps folder
696
-	 *
697
-	 * @return array an array of app names (string IDs)
698
-	 * @todo: change the name of this method to getInstalledApps, which is more accurate
699
-	 */
700
-	public static function getAllApps() {
701
-
702
-		$apps = array();
703
-
704
-		foreach (OC::$APPSROOTS as $apps_dir) {
705
-			if (!is_readable($apps_dir['path'])) {
706
-				\OCP\Util::writeLog('core', 'unable to read app folder : ' . $apps_dir['path'], \OCP\Util::WARN);
707
-				continue;
708
-			}
709
-			$dh = opendir($apps_dir['path']);
710
-
711
-			if (is_resource($dh)) {
712
-				while (($file = readdir($dh)) !== false) {
713
-
714
-					if ($file[0] != '.' and is_dir($apps_dir['path'] . '/' . $file) and is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml')) {
715
-
716
-						$apps[] = $file;
717
-					}
718
-				}
719
-			}
720
-		}
721
-
722
-		$apps = array_unique($apps);
723
-
724
-		return $apps;
725
-	}
726
-
727
-	/**
728
-	 * List all apps, this is used in apps.php
729
-	 *
730
-	 * @return array
731
-	 */
732
-	public function listAllApps() {
733
-		$installedApps = OC_App::getAllApps();
734
-
735
-		$appManager = \OC::$server->getAppManager();
736
-		//we don't want to show configuration for these
737
-		$blacklist = $appManager->getAlwaysEnabledApps();
738
-		$appList = array();
739
-		$langCode = \OC::$server->getL10N('core')->getLanguageCode();
740
-		$urlGenerator = \OC::$server->getURLGenerator();
741
-
742
-		foreach ($installedApps as $app) {
743
-			if (array_search($app, $blacklist) === false) {
744
-
745
-				$info = OC_App::getAppInfo($app, false, $langCode);
746
-				if (!is_array($info)) {
747
-					\OCP\Util::writeLog('core', 'Could not read app info file for app "' . $app . '"', \OCP\Util::ERROR);
748
-					continue;
749
-				}
750
-
751
-				if (!isset($info['name'])) {
752
-					\OCP\Util::writeLog('core', 'App id "' . $app . '" has no name in appinfo', \OCP\Util::ERROR);
753
-					continue;
754
-				}
755
-
756
-				$enabled = \OC::$server->getConfig()->getAppValue($app, 'enabled', 'no');
757
-				$info['groups'] = null;
758
-				if ($enabled === 'yes') {
759
-					$active = true;
760
-				} else if ($enabled === 'no') {
761
-					$active = false;
762
-				} else {
763
-					$active = true;
764
-					$info['groups'] = $enabled;
765
-				}
766
-
767
-				$info['active'] = $active;
768
-
769
-				if ($appManager->isShipped($app)) {
770
-					$info['internal'] = true;
771
-					$info['level'] = self::officialApp;
772
-					$info['removable'] = false;
773
-				} else {
774
-					$info['internal'] = false;
775
-					$info['removable'] = true;
776
-				}
777
-
778
-				$appPath = self::getAppPath($app);
779
-				if($appPath !== false) {
780
-					$appIcon = $appPath . '/img/' . $app . '.svg';
781
-					if (file_exists($appIcon)) {
782
-						$info['preview'] = $urlGenerator->imagePath($app, $app . '.svg');
783
-						$info['previewAsIcon'] = true;
784
-					} else {
785
-						$appIcon = $appPath . '/img/app.svg';
786
-						if (file_exists($appIcon)) {
787
-							$info['preview'] = $urlGenerator->imagePath($app, 'app.svg');
788
-							$info['previewAsIcon'] = true;
789
-						}
790
-					}
791
-				}
792
-				// fix documentation
793
-				if (isset($info['documentation']) && is_array($info['documentation'])) {
794
-					foreach ($info['documentation'] as $key => $url) {
795
-						// If it is not an absolute URL we assume it is a key
796
-						// i.e. admin-ldap will get converted to go.php?to=admin-ldap
797
-						if (stripos($url, 'https://') !== 0 && stripos($url, 'http://') !== 0) {
798
-							$url = $urlGenerator->linkToDocs($url);
799
-						}
800
-
801
-						$info['documentation'][$key] = $url;
802
-					}
803
-				}
804
-
805
-				$info['version'] = OC_App::getAppVersion($app);
806
-				$appList[] = $info;
807
-			}
808
-		}
809
-
810
-		return $appList;
811
-	}
812
-
813
-	public static function shouldUpgrade($app) {
814
-		$versions = self::getAppVersions();
815
-		$currentVersion = OC_App::getAppVersion($app);
816
-		if ($currentVersion && isset($versions[$app])) {
817
-			$installedVersion = $versions[$app];
818
-			if (!version_compare($currentVersion, $installedVersion, '=')) {
819
-				return true;
820
-			}
821
-		}
822
-		return false;
823
-	}
824
-
825
-	/**
826
-	 * Adjust the number of version parts of $version1 to match
827
-	 * the number of version parts of $version2.
828
-	 *
829
-	 * @param string $version1 version to adjust
830
-	 * @param string $version2 version to take the number of parts from
831
-	 * @return string shortened $version1
832
-	 */
833
-	private static function adjustVersionParts($version1, $version2) {
834
-		$version1 = explode('.', $version1);
835
-		$version2 = explode('.', $version2);
836
-		// reduce $version1 to match the number of parts in $version2
837
-		while (count($version1) > count($version2)) {
838
-			array_pop($version1);
839
-		}
840
-		// if $version1 does not have enough parts, add some
841
-		while (count($version1) < count($version2)) {
842
-			$version1[] = '0';
843
-		}
844
-		return implode('.', $version1);
845
-	}
846
-
847
-	/**
848
-	 * Check whether the current ownCloud version matches the given
849
-	 * application's version requirements.
850
-	 *
851
-	 * The comparison is made based on the number of parts that the
852
-	 * app info version has. For example for ownCloud 6.0.3 if the
853
-	 * app info version is expecting version 6.0, the comparison is
854
-	 * made on the first two parts of the ownCloud version.
855
-	 * This means that it's possible to specify "requiremin" => 6
856
-	 * and "requiremax" => 6 and it will still match ownCloud 6.0.3.
857
-	 *
858
-	 * @param string $ocVersion ownCloud version to check against
859
-	 * @param array $appInfo app info (from xml)
860
-	 *
861
-	 * @return boolean true if compatible, otherwise false
862
-	 */
863
-	public static function isAppCompatible($ocVersion, $appInfo) {
864
-		$requireMin = '';
865
-		$requireMax = '';
866
-		if (isset($appInfo['dependencies']['nextcloud']['@attributes']['min-version'])) {
867
-			$requireMin = $appInfo['dependencies']['nextcloud']['@attributes']['min-version'];
868
-		} elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['min-version'])) {
869
-			$requireMin = $appInfo['dependencies']['owncloud']['@attributes']['min-version'];
870
-		} else if (isset($appInfo['requiremin'])) {
871
-			$requireMin = $appInfo['requiremin'];
872
-		} else if (isset($appInfo['require'])) {
873
-			$requireMin = $appInfo['require'];
874
-		}
875
-
876
-		if (isset($appInfo['dependencies']['nextcloud']['@attributes']['max-version'])) {
877
-			$requireMax = $appInfo['dependencies']['nextcloud']['@attributes']['max-version'];
878
-		} elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['max-version'])) {
879
-			$requireMax = $appInfo['dependencies']['owncloud']['@attributes']['max-version'];
880
-		} else if (isset($appInfo['requiremax'])) {
881
-			$requireMax = $appInfo['requiremax'];
882
-		}
883
-
884
-		if (is_array($ocVersion)) {
885
-			$ocVersion = implode('.', $ocVersion);
886
-		}
887
-
888
-		if (!empty($requireMin)
889
-			&& version_compare(self::adjustVersionParts($ocVersion, $requireMin), $requireMin, '<')
890
-		) {
891
-
892
-			return false;
893
-		}
894
-
895
-		if (!empty($requireMax)
896
-			&& version_compare(self::adjustVersionParts($ocVersion, $requireMax), $requireMax, '>')
897
-		) {
898
-			return false;
899
-		}
900
-
901
-		return true;
902
-	}
903
-
904
-	/**
905
-	 * get the installed version of all apps
906
-	 */
907
-	public static function getAppVersions() {
908
-		static $versions;
909
-
910
-		if(!$versions) {
911
-			$appConfig = \OC::$server->getAppConfig();
912
-			$versions = $appConfig->getValues(false, 'installed_version');
913
-		}
914
-		return $versions;
915
-	}
916
-
917
-	/**
918
-	 * update the database for the app and call the update script
919
-	 *
920
-	 * @param string $appId
921
-	 * @return bool
922
-	 */
923
-	public static function updateApp($appId) {
924
-		$appPath = self::getAppPath($appId);
925
-		if($appPath === false) {
926
-			return false;
927
-		}
928
-		self::registerAutoloading($appId, $appPath);
929
-
930
-		$appData = self::getAppInfo($appId);
931
-		self::executeRepairSteps($appId, $appData['repair-steps']['pre-migration']);
932
-
933
-		if (file_exists($appPath . '/appinfo/database.xml')) {
934
-			OC_DB::updateDbFromStructure($appPath . '/appinfo/database.xml');
935
-		} else {
936
-			$ms = new MigrationService($appId, \OC::$server->getDatabaseConnection());
937
-			$ms->migrate();
938
-		}
939
-
940
-		self::executeRepairSteps($appId, $appData['repair-steps']['post-migration']);
941
-		self::setupLiveMigrations($appId, $appData['repair-steps']['live-migration']);
942
-		// update appversion in app manager
943
-		\OC::$server->getAppManager()->getAppVersion($appId, false);
944
-
945
-		// run upgrade code
946
-		if (file_exists($appPath . '/appinfo/update.php')) {
947
-			self::loadApp($appId);
948
-			include $appPath . '/appinfo/update.php';
949
-		}
950
-		self::setupBackgroundJobs($appData['background-jobs']);
951
-		if(isset($appData['settings']) && is_array($appData['settings'])) {
952
-			\OC::$server->getSettingsManager()->setupSettings($appData['settings']);
953
-		}
954
-
955
-		//set remote/public handlers
956
-		if (array_key_exists('ocsid', $appData)) {
957
-			\OC::$server->getConfig()->setAppValue($appId, 'ocsid', $appData['ocsid']);
958
-		} elseif(\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
959
-			\OC::$server->getConfig()->deleteAppValue($appId, 'ocsid');
960
-		}
961
-		foreach ($appData['remote'] as $name => $path) {
962
-			\OC::$server->getConfig()->setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
963
-		}
964
-		foreach ($appData['public'] as $name => $path) {
965
-			\OC::$server->getConfig()->setAppValue('core', 'public_' . $name, $appId . '/' . $path);
966
-		}
967
-
968
-		self::setAppTypes($appId);
969
-
970
-		$version = \OC_App::getAppVersion($appId);
971
-		\OC::$server->getConfig()->setAppValue($appId, 'installed_version', $version);
972
-
973
-		\OC::$server->getEventDispatcher()->dispatch(ManagerEvent::EVENT_APP_UPDATE, new ManagerEvent(
974
-			ManagerEvent::EVENT_APP_UPDATE, $appId
975
-		));
976
-
977
-		return true;
978
-	}
979
-
980
-	/**
981
-	 * @param string $appId
982
-	 * @param string[] $steps
983
-	 * @throws \OC\NeedsUpdateException
984
-	 */
985
-	public static function executeRepairSteps($appId, array $steps) {
986
-		if (empty($steps)) {
987
-			return;
988
-		}
989
-		// load the app
990
-		self::loadApp($appId);
991
-
992
-		$dispatcher = OC::$server->getEventDispatcher();
993
-
994
-		// load the steps
995
-		$r = new Repair([], $dispatcher);
996
-		foreach ($steps as $step) {
997
-			try {
998
-				$r->addStep($step);
999
-			} catch (Exception $ex) {
1000
-				$r->emit('\OC\Repair', 'error', [$ex->getMessage()]);
1001
-				\OC::$server->getLogger()->logException($ex);
1002
-			}
1003
-		}
1004
-		// run the steps
1005
-		$r->run();
1006
-	}
1007
-
1008
-	public static function setupBackgroundJobs(array $jobs) {
1009
-		$queue = \OC::$server->getJobList();
1010
-		foreach ($jobs as $job) {
1011
-			$queue->add($job);
1012
-		}
1013
-	}
1014
-
1015
-	/**
1016
-	 * @param string $appId
1017
-	 * @param string[] $steps
1018
-	 */
1019
-	private static function setupLiveMigrations($appId, array $steps) {
1020
-		$queue = \OC::$server->getJobList();
1021
-		foreach ($steps as $step) {
1022
-			$queue->add('OC\Migration\BackgroundRepair', [
1023
-				'app' => $appId,
1024
-				'step' => $step]);
1025
-		}
1026
-	}
1027
-
1028
-	/**
1029
-	 * @param string $appId
1030
-	 * @return \OC\Files\View|false
1031
-	 */
1032
-	public static function getStorage($appId) {
1033
-		if (\OC::$server->getAppManager()->isEnabledForUser($appId)) { //sanity check
1034
-			if (\OC::$server->getUserSession()->isLoggedIn()) {
1035
-				$view = new \OC\Files\View('/' . OC_User::getUser());
1036
-				if (!$view->file_exists($appId)) {
1037
-					$view->mkdir($appId);
1038
-				}
1039
-				return new \OC\Files\View('/' . OC_User::getUser() . '/' . $appId);
1040
-			} else {
1041
-				\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ', user not logged in', \OCP\Util::ERROR);
1042
-				return false;
1043
-			}
1044
-		} else {
1045
-			\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ' not enabled', \OCP\Util::ERROR);
1046
-			return false;
1047
-		}
1048
-	}
1049
-
1050
-	protected static function findBestL10NOption($options, $lang) {
1051
-		$fallback = $similarLangFallback = $englishFallback = false;
1052
-
1053
-		$lang = strtolower($lang);
1054
-		$similarLang = $lang;
1055
-		if (strpos($similarLang, '_')) {
1056
-			// For "de_DE" we want to find "de" and the other way around
1057
-			$similarLang = substr($lang, 0, strpos($lang, '_'));
1058
-		}
1059
-
1060
-		foreach ($options as $option) {
1061
-			if (is_array($option)) {
1062
-				if ($fallback === false) {
1063
-					$fallback = $option['@value'];
1064
-				}
1065
-
1066
-				if (!isset($option['@attributes']['lang'])) {
1067
-					continue;
1068
-				}
1069
-
1070
-				$attributeLang = strtolower($option['@attributes']['lang']);
1071
-				if ($attributeLang === $lang) {
1072
-					return $option['@value'];
1073
-				}
1074
-
1075
-				if ($attributeLang === $similarLang) {
1076
-					$similarLangFallback = $option['@value'];
1077
-				} else if (strpos($attributeLang, $similarLang . '_') === 0) {
1078
-					if ($similarLangFallback === false) {
1079
-						$similarLangFallback =  $option['@value'];
1080
-					}
1081
-				}
1082
-			} else {
1083
-				$englishFallback = $option;
1084
-			}
1085
-		}
1086
-
1087
-		if ($similarLangFallback !== false) {
1088
-			return $similarLangFallback;
1089
-		} else if ($englishFallback !== false) {
1090
-			return $englishFallback;
1091
-		}
1092
-		return (string) $fallback;
1093
-	}
1094
-
1095
-	/**
1096
-	 * parses the app data array and enhanced the 'description' value
1097
-	 *
1098
-	 * @param array $data the app data
1099
-	 * @param string $lang
1100
-	 * @return array improved app data
1101
-	 */
1102
-	public static function parseAppInfo(array $data, $lang = null) {
1103
-
1104
-		if ($lang && isset($data['name']) && is_array($data['name'])) {
1105
-			$data['name'] = self::findBestL10NOption($data['name'], $lang);
1106
-		}
1107
-		if ($lang && isset($data['summary']) && is_array($data['summary'])) {
1108
-			$data['summary'] = self::findBestL10NOption($data['summary'], $lang);
1109
-		}
1110
-		if ($lang && isset($data['description']) && is_array($data['description'])) {
1111
-			$data['description'] = trim(self::findBestL10NOption($data['description'], $lang));
1112
-		} else if (isset($data['description']) && is_string($data['description'])) {
1113
-			$data['description'] = trim($data['description']);
1114
-		} else  {
1115
-			$data['description'] = '';
1116
-		}
1117
-
1118
-		return $data;
1119
-	}
1120
-
1121
-	/**
1122
-	 * @param \OCP\IConfig $config
1123
-	 * @param \OCP\IL10N $l
1124
-	 * @param array $info
1125
-	 * @throws \Exception
1126
-	 */
1127
-	public static function checkAppDependencies($config, $l, $info) {
1128
-		$dependencyAnalyzer = new DependencyAnalyzer(new Platform($config), $l);
1129
-		$missing = $dependencyAnalyzer->analyze($info);
1130
-		if (!empty($missing)) {
1131
-			$missingMsg = implode(PHP_EOL, $missing);
1132
-			throw new \Exception(
1133
-				$l->t('App "%s" cannot be installed because the following dependencies are not fulfilled: %s',
1134
-					[$info['name'], $missingMsg]
1135
-				)
1136
-			);
1137
-		}
1138
-	}
65
+    static private $adminForms = array();
66
+    static private $personalForms = array();
67
+    static private $appTypes = array();
68
+    static private $loadedApps = array();
69
+    static private $altLogin = array();
70
+    static private $alreadyRegistered = [];
71
+    const officialApp = 200;
72
+
73
+    /**
74
+     * clean the appId
75
+     *
76
+     * @param string|boolean $app AppId that needs to be cleaned
77
+     * @return string
78
+     */
79
+    public static function cleanAppId($app) {
80
+        return str_replace(array('\0', '/', '\\', '..'), '', $app);
81
+    }
82
+
83
+    /**
84
+     * Check if an app is loaded
85
+     *
86
+     * @param string $app
87
+     * @return bool
88
+     */
89
+    public static function isAppLoaded($app) {
90
+        return in_array($app, self::$loadedApps, true);
91
+    }
92
+
93
+    /**
94
+     * loads all apps
95
+     *
96
+     * @param string[] | string | null $types
97
+     * @return bool
98
+     *
99
+     * This function walks through the ownCloud directory and loads all apps
100
+     * it can find. A directory contains an app if the file /appinfo/info.xml
101
+     * exists.
102
+     *
103
+     * if $types is set, only apps of those types will be loaded
104
+     */
105
+    public static function loadApps($types = null) {
106
+        if (\OC::$server->getSystemConfig()->getValue('maintenance', false)) {
107
+            return false;
108
+        }
109
+        // Load the enabled apps here
110
+        $apps = self::getEnabledApps();
111
+
112
+        // Add each apps' folder as allowed class path
113
+        foreach($apps as $app) {
114
+            $path = self::getAppPath($app);
115
+            if($path !== false) {
116
+                self::registerAutoloading($app, $path);
117
+            }
118
+        }
119
+
120
+        // prevent app.php from printing output
121
+        ob_start();
122
+        foreach ($apps as $app) {
123
+            if ((is_null($types) or self::isType($app, $types)) && !in_array($app, self::$loadedApps)) {
124
+                self::loadApp($app);
125
+            }
126
+        }
127
+        ob_end_clean();
128
+
129
+        return true;
130
+    }
131
+
132
+    /**
133
+     * load a single app
134
+     *
135
+     * @param string $app
136
+     */
137
+    public static function loadApp($app) {
138
+        self::$loadedApps[] = $app;
139
+        $appPath = self::getAppPath($app);
140
+        if($appPath === false) {
141
+            return;
142
+        }
143
+
144
+        // in case someone calls loadApp() directly
145
+        self::registerAutoloading($app, $appPath);
146
+
147
+        if (is_file($appPath . '/appinfo/app.php')) {
148
+            \OC::$server->getEventLogger()->start('load_app_' . $app, 'Load app: ' . $app);
149
+            self::requireAppFile($app);
150
+            if (self::isType($app, array('authentication'))) {
151
+                // since authentication apps affect the "is app enabled for group" check,
152
+                // the enabled apps cache needs to be cleared to make sure that the
153
+                // next time getEnableApps() is called it will also include apps that were
154
+                // enabled for groups
155
+                self::$enabledAppsCache = array();
156
+            }
157
+            \OC::$server->getEventLogger()->end('load_app_' . $app);
158
+        }
159
+
160
+        $info = self::getAppInfo($app);
161
+        if (!empty($info['activity']['filters'])) {
162
+            foreach ($info['activity']['filters'] as $filter) {
163
+                \OC::$server->getActivityManager()->registerFilter($filter);
164
+            }
165
+        }
166
+        if (!empty($info['activity']['settings'])) {
167
+            foreach ($info['activity']['settings'] as $setting) {
168
+                \OC::$server->getActivityManager()->registerSetting($setting);
169
+            }
170
+        }
171
+        if (!empty($info['activity']['providers'])) {
172
+            foreach ($info['activity']['providers'] as $provider) {
173
+                \OC::$server->getActivityManager()->registerProvider($provider);
174
+            }
175
+        }
176
+        if (!empty($info['collaboration']['plugins'])) {
177
+            // deal with one or many plugin entries
178
+            $plugins = isset($info['collaboration']['plugins']['plugin']['@value']) ?
179
+                [$info['collaboration']['plugins']['plugin']] : $info['collaboration']['plugins']['plugin'];
180
+            foreach ($plugins as $plugin) {
181
+                if($plugin['@attributes']['type'] === 'collaborator-search') {
182
+                    $pluginInfo = [
183
+                        'shareType' => $plugin['@attributes']['share-type'],
184
+                        'class' => $plugin['@value'],
185
+                    ];
186
+                    \OC::$server->getCollaboratorSearch()->registerPlugin($pluginInfo);
187
+                } else if ($plugin['@attributes']['type'] === 'autocomplete-sort') {
188
+                    \OC::$server->getAutoCompleteManager()->registerSorter($plugin['@value']);
189
+                }
190
+            }
191
+        }
192
+    }
193
+
194
+    /**
195
+     * @internal
196
+     * @param string $app
197
+     * @param string $path
198
+     */
199
+    public static function registerAutoloading($app, $path) {
200
+        $key = $app . '-' . $path;
201
+        if(isset(self::$alreadyRegistered[$key])) {
202
+            return;
203
+        }
204
+
205
+        self::$alreadyRegistered[$key] = true;
206
+
207
+        // Register on PSR-4 composer autoloader
208
+        $appNamespace = \OC\AppFramework\App::buildAppNamespace($app);
209
+        \OC::$server->registerNamespace($app, $appNamespace);
210
+
211
+        if (file_exists($path . '/composer/autoload.php')) {
212
+            require_once $path . '/composer/autoload.php';
213
+        } else {
214
+            \OC::$composerAutoloader->addPsr4($appNamespace . '\\', $path . '/lib/', true);
215
+            // Register on legacy autoloader
216
+            \OC::$loader->addValidRoot($path);
217
+        }
218
+
219
+        // Register Test namespace only when testing
220
+        if (defined('PHPUNIT_RUN') || defined('CLI_TEST_RUN')) {
221
+            \OC::$composerAutoloader->addPsr4($appNamespace . '\\Tests\\', $path . '/tests/', true);
222
+        }
223
+    }
224
+
225
+    /**
226
+     * Load app.php from the given app
227
+     *
228
+     * @param string $app app name
229
+     */
230
+    private static function requireAppFile($app) {
231
+        try {
232
+            // encapsulated here to avoid variable scope conflicts
233
+            require_once $app . '/appinfo/app.php';
234
+        } catch (Error $ex) {
235
+            \OC::$server->getLogger()->logException($ex);
236
+            if (!\OC::$server->getAppManager()->isShipped($app)) {
237
+                // Only disable apps which are not shipped
238
+                self::disable($app);
239
+            }
240
+        }
241
+    }
242
+
243
+    /**
244
+     * check if an app is of a specific type
245
+     *
246
+     * @param string $app
247
+     * @param string|array $types
248
+     * @return bool
249
+     */
250
+    public static function isType($app, $types) {
251
+        if (is_string($types)) {
252
+            $types = array($types);
253
+        }
254
+        $appTypes = self::getAppTypes($app);
255
+        foreach ($types as $type) {
256
+            if (array_search($type, $appTypes) !== false) {
257
+                return true;
258
+            }
259
+        }
260
+        return false;
261
+    }
262
+
263
+    /**
264
+     * get the types of an app
265
+     *
266
+     * @param string $app
267
+     * @return array
268
+     */
269
+    private static function getAppTypes($app) {
270
+        //load the cache
271
+        if (count(self::$appTypes) == 0) {
272
+            self::$appTypes = \OC::$server->getAppConfig()->getValues(false, 'types');
273
+        }
274
+
275
+        if (isset(self::$appTypes[$app])) {
276
+            return explode(',', self::$appTypes[$app]);
277
+        } else {
278
+            return array();
279
+        }
280
+    }
281
+
282
+    /**
283
+     * read app types from info.xml and cache them in the database
284
+     */
285
+    public static function setAppTypes($app) {
286
+        $appData = self::getAppInfo($app);
287
+        if(!is_array($appData)) {
288
+            return;
289
+        }
290
+
291
+        if (isset($appData['types'])) {
292
+            $appTypes = implode(',', $appData['types']);
293
+        } else {
294
+            $appTypes = '';
295
+            $appData['types'] = [];
296
+        }
297
+
298
+        \OC::$server->getConfig()->setAppValue($app, 'types', $appTypes);
299
+
300
+        if (\OC::$server->getAppManager()->hasProtectedAppType($appData['types'])) {
301
+            $enabled = \OC::$server->getConfig()->getAppValue($app, 'enabled', 'yes');
302
+            if ($enabled !== 'yes' && $enabled !== 'no') {
303
+                \OC::$server->getConfig()->setAppValue($app, 'enabled', 'yes');
304
+            }
305
+        }
306
+    }
307
+
308
+    /**
309
+     * get all enabled apps
310
+     */
311
+    protected static $enabledAppsCache = array();
312
+
313
+    /**
314
+     * Returns apps enabled for the current user.
315
+     *
316
+     * @param bool $forceRefresh whether to refresh the cache
317
+     * @param bool $all whether to return apps for all users, not only the
318
+     * currently logged in one
319
+     * @return string[]
320
+     */
321
+    public static function getEnabledApps($forceRefresh = false, $all = false) {
322
+        if (!\OC::$server->getSystemConfig()->getValue('installed', false)) {
323
+            return array();
324
+        }
325
+        // in incognito mode or when logged out, $user will be false,
326
+        // which is also the case during an upgrade
327
+        $appManager = \OC::$server->getAppManager();
328
+        if ($all) {
329
+            $user = null;
330
+        } else {
331
+            $user = \OC::$server->getUserSession()->getUser();
332
+        }
333
+
334
+        if (is_null($user)) {
335
+            $apps = $appManager->getInstalledApps();
336
+        } else {
337
+            $apps = $appManager->getEnabledAppsForUser($user);
338
+        }
339
+        $apps = array_filter($apps, function ($app) {
340
+            return $app !== 'files';//we add this manually
341
+        });
342
+        sort($apps);
343
+        array_unshift($apps, 'files');
344
+        return $apps;
345
+    }
346
+
347
+    /**
348
+     * checks whether or not an app is enabled
349
+     *
350
+     * @param string $app app
351
+     * @return bool
352
+     * @deprecated 13.0.0 use \OC::$server->getAppManager()->isEnabledForUser($appId)
353
+     *
354
+     * This function checks whether or not an app is enabled.
355
+     */
356
+    public static function isEnabled($app) {
357
+        return \OC::$server->getAppManager()->isEnabledForUser($app);
358
+    }
359
+
360
+    /**
361
+     * enables an app
362
+     *
363
+     * @param string $appId
364
+     * @param array $groups (optional) when set, only these groups will have access to the app
365
+     * @throws \Exception
366
+     * @return void
367
+     *
368
+     * This function set an app as enabled in appconfig.
369
+     */
370
+    public function enable($appId,
371
+                            $groups = null) {
372
+        self::$enabledAppsCache = []; // flush
373
+
374
+        // Check if app is already downloaded
375
+        $installer = \OC::$server->query(Installer::class);
376
+        $isDownloaded = $installer->isDownloaded($appId);
377
+
378
+        if(!$isDownloaded) {
379
+            $installer->downloadApp($appId);
380
+        }
381
+
382
+        $installer->installApp($appId);
383
+
384
+        $appManager = \OC::$server->getAppManager();
385
+        if (!is_null($groups)) {
386
+            $groupManager = \OC::$server->getGroupManager();
387
+            $groupsList = [];
388
+            foreach ($groups as $group) {
389
+                $groupItem = $groupManager->get($group);
390
+                if ($groupItem instanceof \OCP\IGroup) {
391
+                    $groupsList[] = $groupManager->get($group);
392
+                }
393
+            }
394
+            $appManager->enableAppForGroups($appId, $groupsList);
395
+        } else {
396
+            $appManager->enableApp($appId);
397
+        }
398
+    }
399
+
400
+    /**
401
+     * This function set an app as disabled in appconfig.
402
+     *
403
+     * @param string $app app
404
+     * @throws Exception
405
+     */
406
+    public static function disable($app) {
407
+        // flush
408
+        self::$enabledAppsCache = array();
409
+
410
+        // run uninstall steps
411
+        $appData = OC_App::getAppInfo($app);
412
+        if (!is_null($appData)) {
413
+            OC_App::executeRepairSteps($app, $appData['repair-steps']['uninstall']);
414
+        }
415
+
416
+        // emit disable hook - needed anymore ?
417
+        \OC_Hook::emit('OC_App', 'pre_disable', array('app' => $app));
418
+
419
+        // finally disable it
420
+        $appManager = \OC::$server->getAppManager();
421
+        $appManager->disableApp($app);
422
+    }
423
+
424
+    // This is private as well. It simply works, so don't ask for more details
425
+    private static function proceedNavigation($list) {
426
+        usort($list, function($a, $b) {
427
+            if (isset($a['order']) && isset($b['order'])) {
428
+                return ($a['order'] < $b['order']) ? -1 : 1;
429
+            } else if (isset($a['order']) || isset($b['order'])) {
430
+                return isset($a['order']) ? -1 : 1;
431
+            } else {
432
+                return ($a['name'] < $b['name']) ? -1 : 1;
433
+            }
434
+        });
435
+
436
+        $activeApp = OC::$server->getNavigationManager()->getActiveEntry();
437
+        foreach ($list as $index => &$navEntry) {
438
+            if ($navEntry['id'] == $activeApp) {
439
+                $navEntry['active'] = true;
440
+            } else {
441
+                $navEntry['active'] = false;
442
+            }
443
+        }
444
+        unset($navEntry);
445
+
446
+        return $list;
447
+    }
448
+
449
+    /**
450
+     * Get the path where to install apps
451
+     *
452
+     * @return string|false
453
+     */
454
+    public static function getInstallPath() {
455
+        if (\OC::$server->getSystemConfig()->getValue('appstoreenabled', true) == false) {
456
+            return false;
457
+        }
458
+
459
+        foreach (OC::$APPSROOTS as $dir) {
460
+            if (isset($dir['writable']) && $dir['writable'] === true) {
461
+                return $dir['path'];
462
+            }
463
+        }
464
+
465
+        \OCP\Util::writeLog('core', 'No application directories are marked as writable.', \OCP\Util::ERROR);
466
+        return null;
467
+    }
468
+
469
+
470
+    /**
471
+     * search for an app in all app-directories
472
+     *
473
+     * @param string $appId
474
+     * @return false|string
475
+     */
476
+    public static function findAppInDirectories($appId) {
477
+        $sanitizedAppId = self::cleanAppId($appId);
478
+        if($sanitizedAppId !== $appId) {
479
+            return false;
480
+        }
481
+        static $app_dir = array();
482
+
483
+        if (isset($app_dir[$appId])) {
484
+            return $app_dir[$appId];
485
+        }
486
+
487
+        $possibleApps = array();
488
+        foreach (OC::$APPSROOTS as $dir) {
489
+            if (file_exists($dir['path'] . '/' . $appId)) {
490
+                $possibleApps[] = $dir;
491
+            }
492
+        }
493
+
494
+        if (empty($possibleApps)) {
495
+            return false;
496
+        } elseif (count($possibleApps) === 1) {
497
+            $dir = array_shift($possibleApps);
498
+            $app_dir[$appId] = $dir;
499
+            return $dir;
500
+        } else {
501
+            $versionToLoad = array();
502
+            foreach ($possibleApps as $possibleApp) {
503
+                $version = self::getAppVersionByPath($possibleApp['path']);
504
+                if (empty($versionToLoad) || version_compare($version, $versionToLoad['version'], '>')) {
505
+                    $versionToLoad = array(
506
+                        'dir' => $possibleApp,
507
+                        'version' => $version,
508
+                    );
509
+                }
510
+            }
511
+            $app_dir[$appId] = $versionToLoad['dir'];
512
+            return $versionToLoad['dir'];
513
+            //TODO - write test
514
+        }
515
+    }
516
+
517
+    /**
518
+     * Get the directory for the given app.
519
+     * If the app is defined in multiple directories, the first one is taken. (false if not found)
520
+     *
521
+     * @param string $appId
522
+     * @return string|false
523
+     */
524
+    public static function getAppPath($appId) {
525
+        if ($appId === null || trim($appId) === '') {
526
+            return false;
527
+        }
528
+
529
+        if (($dir = self::findAppInDirectories($appId)) != false) {
530
+            return $dir['path'] . '/' . $appId;
531
+        }
532
+        return false;
533
+    }
534
+
535
+    /**
536
+     * Get the path for the given app on the access
537
+     * If the app is defined in multiple directories, the first one is taken. (false if not found)
538
+     *
539
+     * @param string $appId
540
+     * @return string|false
541
+     */
542
+    public static function getAppWebPath($appId) {
543
+        if (($dir = self::findAppInDirectories($appId)) != false) {
544
+            return OC::$WEBROOT . $dir['url'] . '/' . $appId;
545
+        }
546
+        return false;
547
+    }
548
+
549
+    /**
550
+     * get the last version of the app from appinfo/info.xml
551
+     *
552
+     * @param string $appId
553
+     * @param bool $useCache
554
+     * @return string
555
+     * @deprecated 14.0.0 use \OC::$server->getAppManager()->getAppVersion()
556
+     */
557
+    public static function getAppVersion($appId, $useCache = true) {
558
+        return \OC::$server->getAppManager()->getAppVersion($appId, $useCache);
559
+    }
560
+
561
+    /**
562
+     * get app's version based on it's path
563
+     *
564
+     * @param string $path
565
+     * @return string
566
+     */
567
+    public static function getAppVersionByPath($path) {
568
+        $infoFile = $path . '/appinfo/info.xml';
569
+        $appData = \OC::$server->getAppManager()->getAppInfo($infoFile, true);
570
+        return isset($appData['version']) ? $appData['version'] : '';
571
+    }
572
+
573
+
574
+    /**
575
+     * Read all app metadata from the info.xml file
576
+     *
577
+     * @param string $appId id of the app or the path of the info.xml file
578
+     * @param bool $path
579
+     * @param string $lang
580
+     * @return array|null
581
+     * @note all data is read from info.xml, not just pre-defined fields
582
+     * @deprecated 14.0.0 use \OC::$server->getAppManager()->getAppInfo()
583
+     */
584
+    public static function getAppInfo($appId, $path = false, $lang = null) {
585
+        return \OC::$server->getAppManager()->getAppInfo($appId, $path, $lang);
586
+    }
587
+
588
+    /**
589
+     * Returns the navigation
590
+     *
591
+     * @return array
592
+     *
593
+     * This function returns an array containing all entries added. The
594
+     * entries are sorted by the key 'order' ascending. Additional to the keys
595
+     * given for each app the following keys exist:
596
+     *   - active: boolean, signals if the user is on this navigation entry
597
+     */
598
+    public static function getNavigation() {
599
+        $entries = OC::$server->getNavigationManager()->getAll();
600
+        return self::proceedNavigation($entries);
601
+    }
602
+
603
+    /**
604
+     * Returns the Settings Navigation
605
+     *
606
+     * @return string[]
607
+     *
608
+     * This function returns an array containing all settings pages added. The
609
+     * entries are sorted by the key 'order' ascending.
610
+     */
611
+    public static function getSettingsNavigation() {
612
+        $entries = OC::$server->getNavigationManager()->getAll('settings');
613
+        return self::proceedNavigation($entries);
614
+    }
615
+
616
+    /**
617
+     * get the id of loaded app
618
+     *
619
+     * @return string
620
+     */
621
+    public static function getCurrentApp() {
622
+        $request = \OC::$server->getRequest();
623
+        $script = substr($request->getScriptName(), strlen(OC::$WEBROOT) + 1);
624
+        $topFolder = substr($script, 0, strpos($script, '/') ?: 0);
625
+        if (empty($topFolder)) {
626
+            $path_info = $request->getPathInfo();
627
+            if ($path_info) {
628
+                $topFolder = substr($path_info, 1, strpos($path_info, '/', 1) - 1);
629
+            }
630
+        }
631
+        if ($topFolder == 'apps') {
632
+            $length = strlen($topFolder);
633
+            return substr($script, $length + 1, strpos($script, '/', $length + 1) - $length - 1);
634
+        } else {
635
+            return $topFolder;
636
+        }
637
+    }
638
+
639
+    /**
640
+     * @param string $type
641
+     * @return array
642
+     */
643
+    public static function getForms($type) {
644
+        $forms = array();
645
+        switch ($type) {
646
+            case 'admin':
647
+                $source = self::$adminForms;
648
+                break;
649
+            case 'personal':
650
+                $source = self::$personalForms;
651
+                break;
652
+            default:
653
+                return array();
654
+        }
655
+        foreach ($source as $form) {
656
+            $forms[] = include $form;
657
+        }
658
+        return $forms;
659
+    }
660
+
661
+    /**
662
+     * register an admin form to be shown
663
+     *
664
+     * @param string $app
665
+     * @param string $page
666
+     */
667
+    public static function registerAdmin($app, $page) {
668
+        self::$adminForms[] = $app . '/' . $page . '.php';
669
+    }
670
+
671
+    /**
672
+     * register a personal form to be shown
673
+     * @param string $app
674
+     * @param string $page
675
+     */
676
+    public static function registerPersonal($app, $page) {
677
+        self::$personalForms[] = $app . '/' . $page . '.php';
678
+    }
679
+
680
+    /**
681
+     * @param array $entry
682
+     */
683
+    public static function registerLogIn(array $entry) {
684
+        self::$altLogin[] = $entry;
685
+    }
686
+
687
+    /**
688
+     * @return array
689
+     */
690
+    public static function getAlternativeLogIns() {
691
+        return self::$altLogin;
692
+    }
693
+
694
+    /**
695
+     * get a list of all apps in the apps folder
696
+     *
697
+     * @return array an array of app names (string IDs)
698
+     * @todo: change the name of this method to getInstalledApps, which is more accurate
699
+     */
700
+    public static function getAllApps() {
701
+
702
+        $apps = array();
703
+
704
+        foreach (OC::$APPSROOTS as $apps_dir) {
705
+            if (!is_readable($apps_dir['path'])) {
706
+                \OCP\Util::writeLog('core', 'unable to read app folder : ' . $apps_dir['path'], \OCP\Util::WARN);
707
+                continue;
708
+            }
709
+            $dh = opendir($apps_dir['path']);
710
+
711
+            if (is_resource($dh)) {
712
+                while (($file = readdir($dh)) !== false) {
713
+
714
+                    if ($file[0] != '.' and is_dir($apps_dir['path'] . '/' . $file) and is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml')) {
715
+
716
+                        $apps[] = $file;
717
+                    }
718
+                }
719
+            }
720
+        }
721
+
722
+        $apps = array_unique($apps);
723
+
724
+        return $apps;
725
+    }
726
+
727
+    /**
728
+     * List all apps, this is used in apps.php
729
+     *
730
+     * @return array
731
+     */
732
+    public function listAllApps() {
733
+        $installedApps = OC_App::getAllApps();
734
+
735
+        $appManager = \OC::$server->getAppManager();
736
+        //we don't want to show configuration for these
737
+        $blacklist = $appManager->getAlwaysEnabledApps();
738
+        $appList = array();
739
+        $langCode = \OC::$server->getL10N('core')->getLanguageCode();
740
+        $urlGenerator = \OC::$server->getURLGenerator();
741
+
742
+        foreach ($installedApps as $app) {
743
+            if (array_search($app, $blacklist) === false) {
744
+
745
+                $info = OC_App::getAppInfo($app, false, $langCode);
746
+                if (!is_array($info)) {
747
+                    \OCP\Util::writeLog('core', 'Could not read app info file for app "' . $app . '"', \OCP\Util::ERROR);
748
+                    continue;
749
+                }
750
+
751
+                if (!isset($info['name'])) {
752
+                    \OCP\Util::writeLog('core', 'App id "' . $app . '" has no name in appinfo', \OCP\Util::ERROR);
753
+                    continue;
754
+                }
755
+
756
+                $enabled = \OC::$server->getConfig()->getAppValue($app, 'enabled', 'no');
757
+                $info['groups'] = null;
758
+                if ($enabled === 'yes') {
759
+                    $active = true;
760
+                } else if ($enabled === 'no') {
761
+                    $active = false;
762
+                } else {
763
+                    $active = true;
764
+                    $info['groups'] = $enabled;
765
+                }
766
+
767
+                $info['active'] = $active;
768
+
769
+                if ($appManager->isShipped($app)) {
770
+                    $info['internal'] = true;
771
+                    $info['level'] = self::officialApp;
772
+                    $info['removable'] = false;
773
+                } else {
774
+                    $info['internal'] = false;
775
+                    $info['removable'] = true;
776
+                }
777
+
778
+                $appPath = self::getAppPath($app);
779
+                if($appPath !== false) {
780
+                    $appIcon = $appPath . '/img/' . $app . '.svg';
781
+                    if (file_exists($appIcon)) {
782
+                        $info['preview'] = $urlGenerator->imagePath($app, $app . '.svg');
783
+                        $info['previewAsIcon'] = true;
784
+                    } else {
785
+                        $appIcon = $appPath . '/img/app.svg';
786
+                        if (file_exists($appIcon)) {
787
+                            $info['preview'] = $urlGenerator->imagePath($app, 'app.svg');
788
+                            $info['previewAsIcon'] = true;
789
+                        }
790
+                    }
791
+                }
792
+                // fix documentation
793
+                if (isset($info['documentation']) && is_array($info['documentation'])) {
794
+                    foreach ($info['documentation'] as $key => $url) {
795
+                        // If it is not an absolute URL we assume it is a key
796
+                        // i.e. admin-ldap will get converted to go.php?to=admin-ldap
797
+                        if (stripos($url, 'https://') !== 0 && stripos($url, 'http://') !== 0) {
798
+                            $url = $urlGenerator->linkToDocs($url);
799
+                        }
800
+
801
+                        $info['documentation'][$key] = $url;
802
+                    }
803
+                }
804
+
805
+                $info['version'] = OC_App::getAppVersion($app);
806
+                $appList[] = $info;
807
+            }
808
+        }
809
+
810
+        return $appList;
811
+    }
812
+
813
+    public static function shouldUpgrade($app) {
814
+        $versions = self::getAppVersions();
815
+        $currentVersion = OC_App::getAppVersion($app);
816
+        if ($currentVersion && isset($versions[$app])) {
817
+            $installedVersion = $versions[$app];
818
+            if (!version_compare($currentVersion, $installedVersion, '=')) {
819
+                return true;
820
+            }
821
+        }
822
+        return false;
823
+    }
824
+
825
+    /**
826
+     * Adjust the number of version parts of $version1 to match
827
+     * the number of version parts of $version2.
828
+     *
829
+     * @param string $version1 version to adjust
830
+     * @param string $version2 version to take the number of parts from
831
+     * @return string shortened $version1
832
+     */
833
+    private static function adjustVersionParts($version1, $version2) {
834
+        $version1 = explode('.', $version1);
835
+        $version2 = explode('.', $version2);
836
+        // reduce $version1 to match the number of parts in $version2
837
+        while (count($version1) > count($version2)) {
838
+            array_pop($version1);
839
+        }
840
+        // if $version1 does not have enough parts, add some
841
+        while (count($version1) < count($version2)) {
842
+            $version1[] = '0';
843
+        }
844
+        return implode('.', $version1);
845
+    }
846
+
847
+    /**
848
+     * Check whether the current ownCloud version matches the given
849
+     * application's version requirements.
850
+     *
851
+     * The comparison is made based on the number of parts that the
852
+     * app info version has. For example for ownCloud 6.0.3 if the
853
+     * app info version is expecting version 6.0, the comparison is
854
+     * made on the first two parts of the ownCloud version.
855
+     * This means that it's possible to specify "requiremin" => 6
856
+     * and "requiremax" => 6 and it will still match ownCloud 6.0.3.
857
+     *
858
+     * @param string $ocVersion ownCloud version to check against
859
+     * @param array $appInfo app info (from xml)
860
+     *
861
+     * @return boolean true if compatible, otherwise false
862
+     */
863
+    public static function isAppCompatible($ocVersion, $appInfo) {
864
+        $requireMin = '';
865
+        $requireMax = '';
866
+        if (isset($appInfo['dependencies']['nextcloud']['@attributes']['min-version'])) {
867
+            $requireMin = $appInfo['dependencies']['nextcloud']['@attributes']['min-version'];
868
+        } elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['min-version'])) {
869
+            $requireMin = $appInfo['dependencies']['owncloud']['@attributes']['min-version'];
870
+        } else if (isset($appInfo['requiremin'])) {
871
+            $requireMin = $appInfo['requiremin'];
872
+        } else if (isset($appInfo['require'])) {
873
+            $requireMin = $appInfo['require'];
874
+        }
875
+
876
+        if (isset($appInfo['dependencies']['nextcloud']['@attributes']['max-version'])) {
877
+            $requireMax = $appInfo['dependencies']['nextcloud']['@attributes']['max-version'];
878
+        } elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['max-version'])) {
879
+            $requireMax = $appInfo['dependencies']['owncloud']['@attributes']['max-version'];
880
+        } else if (isset($appInfo['requiremax'])) {
881
+            $requireMax = $appInfo['requiremax'];
882
+        }
883
+
884
+        if (is_array($ocVersion)) {
885
+            $ocVersion = implode('.', $ocVersion);
886
+        }
887
+
888
+        if (!empty($requireMin)
889
+            && version_compare(self::adjustVersionParts($ocVersion, $requireMin), $requireMin, '<')
890
+        ) {
891
+
892
+            return false;
893
+        }
894
+
895
+        if (!empty($requireMax)
896
+            && version_compare(self::adjustVersionParts($ocVersion, $requireMax), $requireMax, '>')
897
+        ) {
898
+            return false;
899
+        }
900
+
901
+        return true;
902
+    }
903
+
904
+    /**
905
+     * get the installed version of all apps
906
+     */
907
+    public static function getAppVersions() {
908
+        static $versions;
909
+
910
+        if(!$versions) {
911
+            $appConfig = \OC::$server->getAppConfig();
912
+            $versions = $appConfig->getValues(false, 'installed_version');
913
+        }
914
+        return $versions;
915
+    }
916
+
917
+    /**
918
+     * update the database for the app and call the update script
919
+     *
920
+     * @param string $appId
921
+     * @return bool
922
+     */
923
+    public static function updateApp($appId) {
924
+        $appPath = self::getAppPath($appId);
925
+        if($appPath === false) {
926
+            return false;
927
+        }
928
+        self::registerAutoloading($appId, $appPath);
929
+
930
+        $appData = self::getAppInfo($appId);
931
+        self::executeRepairSteps($appId, $appData['repair-steps']['pre-migration']);
932
+
933
+        if (file_exists($appPath . '/appinfo/database.xml')) {
934
+            OC_DB::updateDbFromStructure($appPath . '/appinfo/database.xml');
935
+        } else {
936
+            $ms = new MigrationService($appId, \OC::$server->getDatabaseConnection());
937
+            $ms->migrate();
938
+        }
939
+
940
+        self::executeRepairSteps($appId, $appData['repair-steps']['post-migration']);
941
+        self::setupLiveMigrations($appId, $appData['repair-steps']['live-migration']);
942
+        // update appversion in app manager
943
+        \OC::$server->getAppManager()->getAppVersion($appId, false);
944
+
945
+        // run upgrade code
946
+        if (file_exists($appPath . '/appinfo/update.php')) {
947
+            self::loadApp($appId);
948
+            include $appPath . '/appinfo/update.php';
949
+        }
950
+        self::setupBackgroundJobs($appData['background-jobs']);
951
+        if(isset($appData['settings']) && is_array($appData['settings'])) {
952
+            \OC::$server->getSettingsManager()->setupSettings($appData['settings']);
953
+        }
954
+
955
+        //set remote/public handlers
956
+        if (array_key_exists('ocsid', $appData)) {
957
+            \OC::$server->getConfig()->setAppValue($appId, 'ocsid', $appData['ocsid']);
958
+        } elseif(\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
959
+            \OC::$server->getConfig()->deleteAppValue($appId, 'ocsid');
960
+        }
961
+        foreach ($appData['remote'] as $name => $path) {
962
+            \OC::$server->getConfig()->setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
963
+        }
964
+        foreach ($appData['public'] as $name => $path) {
965
+            \OC::$server->getConfig()->setAppValue('core', 'public_' . $name, $appId . '/' . $path);
966
+        }
967
+
968
+        self::setAppTypes($appId);
969
+
970
+        $version = \OC_App::getAppVersion($appId);
971
+        \OC::$server->getConfig()->setAppValue($appId, 'installed_version', $version);
972
+
973
+        \OC::$server->getEventDispatcher()->dispatch(ManagerEvent::EVENT_APP_UPDATE, new ManagerEvent(
974
+            ManagerEvent::EVENT_APP_UPDATE, $appId
975
+        ));
976
+
977
+        return true;
978
+    }
979
+
980
+    /**
981
+     * @param string $appId
982
+     * @param string[] $steps
983
+     * @throws \OC\NeedsUpdateException
984
+     */
985
+    public static function executeRepairSteps($appId, array $steps) {
986
+        if (empty($steps)) {
987
+            return;
988
+        }
989
+        // load the app
990
+        self::loadApp($appId);
991
+
992
+        $dispatcher = OC::$server->getEventDispatcher();
993
+
994
+        // load the steps
995
+        $r = new Repair([], $dispatcher);
996
+        foreach ($steps as $step) {
997
+            try {
998
+                $r->addStep($step);
999
+            } catch (Exception $ex) {
1000
+                $r->emit('\OC\Repair', 'error', [$ex->getMessage()]);
1001
+                \OC::$server->getLogger()->logException($ex);
1002
+            }
1003
+        }
1004
+        // run the steps
1005
+        $r->run();
1006
+    }
1007
+
1008
+    public static function setupBackgroundJobs(array $jobs) {
1009
+        $queue = \OC::$server->getJobList();
1010
+        foreach ($jobs as $job) {
1011
+            $queue->add($job);
1012
+        }
1013
+    }
1014
+
1015
+    /**
1016
+     * @param string $appId
1017
+     * @param string[] $steps
1018
+     */
1019
+    private static function setupLiveMigrations($appId, array $steps) {
1020
+        $queue = \OC::$server->getJobList();
1021
+        foreach ($steps as $step) {
1022
+            $queue->add('OC\Migration\BackgroundRepair', [
1023
+                'app' => $appId,
1024
+                'step' => $step]);
1025
+        }
1026
+    }
1027
+
1028
+    /**
1029
+     * @param string $appId
1030
+     * @return \OC\Files\View|false
1031
+     */
1032
+    public static function getStorage($appId) {
1033
+        if (\OC::$server->getAppManager()->isEnabledForUser($appId)) { //sanity check
1034
+            if (\OC::$server->getUserSession()->isLoggedIn()) {
1035
+                $view = new \OC\Files\View('/' . OC_User::getUser());
1036
+                if (!$view->file_exists($appId)) {
1037
+                    $view->mkdir($appId);
1038
+                }
1039
+                return new \OC\Files\View('/' . OC_User::getUser() . '/' . $appId);
1040
+            } else {
1041
+                \OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ', user not logged in', \OCP\Util::ERROR);
1042
+                return false;
1043
+            }
1044
+        } else {
1045
+            \OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ' not enabled', \OCP\Util::ERROR);
1046
+            return false;
1047
+        }
1048
+    }
1049
+
1050
+    protected static function findBestL10NOption($options, $lang) {
1051
+        $fallback = $similarLangFallback = $englishFallback = false;
1052
+
1053
+        $lang = strtolower($lang);
1054
+        $similarLang = $lang;
1055
+        if (strpos($similarLang, '_')) {
1056
+            // For "de_DE" we want to find "de" and the other way around
1057
+            $similarLang = substr($lang, 0, strpos($lang, '_'));
1058
+        }
1059
+
1060
+        foreach ($options as $option) {
1061
+            if (is_array($option)) {
1062
+                if ($fallback === false) {
1063
+                    $fallback = $option['@value'];
1064
+                }
1065
+
1066
+                if (!isset($option['@attributes']['lang'])) {
1067
+                    continue;
1068
+                }
1069
+
1070
+                $attributeLang = strtolower($option['@attributes']['lang']);
1071
+                if ($attributeLang === $lang) {
1072
+                    return $option['@value'];
1073
+                }
1074
+
1075
+                if ($attributeLang === $similarLang) {
1076
+                    $similarLangFallback = $option['@value'];
1077
+                } else if (strpos($attributeLang, $similarLang . '_') === 0) {
1078
+                    if ($similarLangFallback === false) {
1079
+                        $similarLangFallback =  $option['@value'];
1080
+                    }
1081
+                }
1082
+            } else {
1083
+                $englishFallback = $option;
1084
+            }
1085
+        }
1086
+
1087
+        if ($similarLangFallback !== false) {
1088
+            return $similarLangFallback;
1089
+        } else if ($englishFallback !== false) {
1090
+            return $englishFallback;
1091
+        }
1092
+        return (string) $fallback;
1093
+    }
1094
+
1095
+    /**
1096
+     * parses the app data array and enhanced the 'description' value
1097
+     *
1098
+     * @param array $data the app data
1099
+     * @param string $lang
1100
+     * @return array improved app data
1101
+     */
1102
+    public static function parseAppInfo(array $data, $lang = null) {
1103
+
1104
+        if ($lang && isset($data['name']) && is_array($data['name'])) {
1105
+            $data['name'] = self::findBestL10NOption($data['name'], $lang);
1106
+        }
1107
+        if ($lang && isset($data['summary']) && is_array($data['summary'])) {
1108
+            $data['summary'] = self::findBestL10NOption($data['summary'], $lang);
1109
+        }
1110
+        if ($lang && isset($data['description']) && is_array($data['description'])) {
1111
+            $data['description'] = trim(self::findBestL10NOption($data['description'], $lang));
1112
+        } else if (isset($data['description']) && is_string($data['description'])) {
1113
+            $data['description'] = trim($data['description']);
1114
+        } else  {
1115
+            $data['description'] = '';
1116
+        }
1117
+
1118
+        return $data;
1119
+    }
1120
+
1121
+    /**
1122
+     * @param \OCP\IConfig $config
1123
+     * @param \OCP\IL10N $l
1124
+     * @param array $info
1125
+     * @throws \Exception
1126
+     */
1127
+    public static function checkAppDependencies($config, $l, $info) {
1128
+        $dependencyAnalyzer = new DependencyAnalyzer(new Platform($config), $l);
1129
+        $missing = $dependencyAnalyzer->analyze($info);
1130
+        if (!empty($missing)) {
1131
+            $missingMsg = implode(PHP_EOL, $missing);
1132
+            throw new \Exception(
1133
+                $l->t('App "%s" cannot be installed because the following dependencies are not fulfilled: %s',
1134
+                    [$info['name'], $missingMsg]
1135
+                )
1136
+            );
1137
+        }
1138
+    }
1139 1139
 }
Please login to merge, or discard this patch.
Spacing   +50 added lines, -50 removed lines patch added patch discarded remove patch
@@ -110,9 +110,9 @@  discard block
 block discarded – undo
110 110
 		$apps = self::getEnabledApps();
111 111
 
112 112
 		// Add each apps' folder as allowed class path
113
-		foreach($apps as $app) {
113
+		foreach ($apps as $app) {
114 114
 			$path = self::getAppPath($app);
115
-			if($path !== false) {
115
+			if ($path !== false) {
116 116
 				self::registerAutoloading($app, $path);
117 117
 			}
118 118
 		}
@@ -137,15 +137,15 @@  discard block
 block discarded – undo
137 137
 	public static function loadApp($app) {
138 138
 		self::$loadedApps[] = $app;
139 139
 		$appPath = self::getAppPath($app);
140
-		if($appPath === false) {
140
+		if ($appPath === false) {
141 141
 			return;
142 142
 		}
143 143
 
144 144
 		// in case someone calls loadApp() directly
145 145
 		self::registerAutoloading($app, $appPath);
146 146
 
147
-		if (is_file($appPath . '/appinfo/app.php')) {
148
-			\OC::$server->getEventLogger()->start('load_app_' . $app, 'Load app: ' . $app);
147
+		if (is_file($appPath.'/appinfo/app.php')) {
148
+			\OC::$server->getEventLogger()->start('load_app_'.$app, 'Load app: '.$app);
149 149
 			self::requireAppFile($app);
150 150
 			if (self::isType($app, array('authentication'))) {
151 151
 				// since authentication apps affect the "is app enabled for group" check,
@@ -154,7 +154,7 @@  discard block
 block discarded – undo
154 154
 				// enabled for groups
155 155
 				self::$enabledAppsCache = array();
156 156
 			}
157
-			\OC::$server->getEventLogger()->end('load_app_' . $app);
157
+			\OC::$server->getEventLogger()->end('load_app_'.$app);
158 158
 		}
159 159
 
160 160
 		$info = self::getAppInfo($app);
@@ -178,7 +178,7 @@  discard block
 block discarded – undo
178 178
 			$plugins = isset($info['collaboration']['plugins']['plugin']['@value']) ?
179 179
 				[$info['collaboration']['plugins']['plugin']] : $info['collaboration']['plugins']['plugin'];
180 180
 			foreach ($plugins as $plugin) {
181
-				if($plugin['@attributes']['type'] === 'collaborator-search') {
181
+				if ($plugin['@attributes']['type'] === 'collaborator-search') {
182 182
 					$pluginInfo = [
183 183
 						'shareType' => $plugin['@attributes']['share-type'],
184 184
 						'class' => $plugin['@value'],
@@ -197,8 +197,8 @@  discard block
 block discarded – undo
197 197
 	 * @param string $path
198 198
 	 */
199 199
 	public static function registerAutoloading($app, $path) {
200
-		$key = $app . '-' . $path;
201
-		if(isset(self::$alreadyRegistered[$key])) {
200
+		$key = $app.'-'.$path;
201
+		if (isset(self::$alreadyRegistered[$key])) {
202 202
 			return;
203 203
 		}
204 204
 
@@ -208,17 +208,17 @@  discard block
 block discarded – undo
208 208
 		$appNamespace = \OC\AppFramework\App::buildAppNamespace($app);
209 209
 		\OC::$server->registerNamespace($app, $appNamespace);
210 210
 
211
-		if (file_exists($path . '/composer/autoload.php')) {
212
-			require_once $path . '/composer/autoload.php';
211
+		if (file_exists($path.'/composer/autoload.php')) {
212
+			require_once $path.'/composer/autoload.php';
213 213
 		} else {
214
-			\OC::$composerAutoloader->addPsr4($appNamespace . '\\', $path . '/lib/', true);
214
+			\OC::$composerAutoloader->addPsr4($appNamespace.'\\', $path.'/lib/', true);
215 215
 			// Register on legacy autoloader
216 216
 			\OC::$loader->addValidRoot($path);
217 217
 		}
218 218
 
219 219
 		// Register Test namespace only when testing
220 220
 		if (defined('PHPUNIT_RUN') || defined('CLI_TEST_RUN')) {
221
-			\OC::$composerAutoloader->addPsr4($appNamespace . '\\Tests\\', $path . '/tests/', true);
221
+			\OC::$composerAutoloader->addPsr4($appNamespace.'\\Tests\\', $path.'/tests/', true);
222 222
 		}
223 223
 	}
224 224
 
@@ -230,7 +230,7 @@  discard block
 block discarded – undo
230 230
 	private static function requireAppFile($app) {
231 231
 		try {
232 232
 			// encapsulated here to avoid variable scope conflicts
233
-			require_once $app . '/appinfo/app.php';
233
+			require_once $app.'/appinfo/app.php';
234 234
 		} catch (Error $ex) {
235 235
 			\OC::$server->getLogger()->logException($ex);
236 236
 			if (!\OC::$server->getAppManager()->isShipped($app)) {
@@ -284,7 +284,7 @@  discard block
 block discarded – undo
284 284
 	 */
285 285
 	public static function setAppTypes($app) {
286 286
 		$appData = self::getAppInfo($app);
287
-		if(!is_array($appData)) {
287
+		if (!is_array($appData)) {
288 288
 			return;
289 289
 		}
290 290
 
@@ -336,8 +336,8 @@  discard block
 block discarded – undo
336 336
 		} else {
337 337
 			$apps = $appManager->getEnabledAppsForUser($user);
338 338
 		}
339
-		$apps = array_filter($apps, function ($app) {
340
-			return $app !== 'files';//we add this manually
339
+		$apps = array_filter($apps, function($app) {
340
+			return $app !== 'files'; //we add this manually
341 341
 		});
342 342
 		sort($apps);
343 343
 		array_unshift($apps, 'files');
@@ -375,7 +375,7 @@  discard block
 block discarded – undo
375 375
 		$installer = \OC::$server->query(Installer::class);
376 376
 		$isDownloaded = $installer->isDownloaded($appId);
377 377
 
378
-		if(!$isDownloaded) {
378
+		if (!$isDownloaded) {
379 379
 			$installer->downloadApp($appId);
380 380
 		}
381 381
 
@@ -475,7 +475,7 @@  discard block
 block discarded – undo
475 475
 	 */
476 476
 	public static function findAppInDirectories($appId) {
477 477
 		$sanitizedAppId = self::cleanAppId($appId);
478
-		if($sanitizedAppId !== $appId) {
478
+		if ($sanitizedAppId !== $appId) {
479 479
 			return false;
480 480
 		}
481 481
 		static $app_dir = array();
@@ -486,7 +486,7 @@  discard block
 block discarded – undo
486 486
 
487 487
 		$possibleApps = array();
488 488
 		foreach (OC::$APPSROOTS as $dir) {
489
-			if (file_exists($dir['path'] . '/' . $appId)) {
489
+			if (file_exists($dir['path'].'/'.$appId)) {
490 490
 				$possibleApps[] = $dir;
491 491
 			}
492 492
 		}
@@ -527,7 +527,7 @@  discard block
 block discarded – undo
527 527
 		}
528 528
 
529 529
 		if (($dir = self::findAppInDirectories($appId)) != false) {
530
-			return $dir['path'] . '/' . $appId;
530
+			return $dir['path'].'/'.$appId;
531 531
 		}
532 532
 		return false;
533 533
 	}
@@ -541,7 +541,7 @@  discard block
 block discarded – undo
541 541
 	 */
542 542
 	public static function getAppWebPath($appId) {
543 543
 		if (($dir = self::findAppInDirectories($appId)) != false) {
544
-			return OC::$WEBROOT . $dir['url'] . '/' . $appId;
544
+			return OC::$WEBROOT.$dir['url'].'/'.$appId;
545 545
 		}
546 546
 		return false;
547 547
 	}
@@ -565,7 +565,7 @@  discard block
 block discarded – undo
565 565
 	 * @return string
566 566
 	 */
567 567
 	public static function getAppVersionByPath($path) {
568
-		$infoFile = $path . '/appinfo/info.xml';
568
+		$infoFile = $path.'/appinfo/info.xml';
569 569
 		$appData = \OC::$server->getAppManager()->getAppInfo($infoFile, true);
570 570
 		return isset($appData['version']) ? $appData['version'] : '';
571 571
 	}
@@ -665,7 +665,7 @@  discard block
 block discarded – undo
665 665
 	 * @param string $page
666 666
 	 */
667 667
 	public static function registerAdmin($app, $page) {
668
-		self::$adminForms[] = $app . '/' . $page . '.php';
668
+		self::$adminForms[] = $app.'/'.$page.'.php';
669 669
 	}
670 670
 
671 671
 	/**
@@ -674,7 +674,7 @@  discard block
 block discarded – undo
674 674
 	 * @param string $page
675 675
 	 */
676 676
 	public static function registerPersonal($app, $page) {
677
-		self::$personalForms[] = $app . '/' . $page . '.php';
677
+		self::$personalForms[] = $app.'/'.$page.'.php';
678 678
 	}
679 679
 
680 680
 	/**
@@ -703,7 +703,7 @@  discard block
 block discarded – undo
703 703
 
704 704
 		foreach (OC::$APPSROOTS as $apps_dir) {
705 705
 			if (!is_readable($apps_dir['path'])) {
706
-				\OCP\Util::writeLog('core', 'unable to read app folder : ' . $apps_dir['path'], \OCP\Util::WARN);
706
+				\OCP\Util::writeLog('core', 'unable to read app folder : '.$apps_dir['path'], \OCP\Util::WARN);
707 707
 				continue;
708 708
 			}
709 709
 			$dh = opendir($apps_dir['path']);
@@ -711,7 +711,7 @@  discard block
 block discarded – undo
711 711
 			if (is_resource($dh)) {
712 712
 				while (($file = readdir($dh)) !== false) {
713 713
 
714
-					if ($file[0] != '.' and is_dir($apps_dir['path'] . '/' . $file) and is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml')) {
714
+					if ($file[0] != '.' and is_dir($apps_dir['path'].'/'.$file) and is_file($apps_dir['path'].'/'.$file.'/appinfo/info.xml')) {
715 715
 
716 716
 						$apps[] = $file;
717 717
 					}
@@ -744,12 +744,12 @@  discard block
 block discarded – undo
744 744
 
745 745
 				$info = OC_App::getAppInfo($app, false, $langCode);
746 746
 				if (!is_array($info)) {
747
-					\OCP\Util::writeLog('core', 'Could not read app info file for app "' . $app . '"', \OCP\Util::ERROR);
747
+					\OCP\Util::writeLog('core', 'Could not read app info file for app "'.$app.'"', \OCP\Util::ERROR);
748 748
 					continue;
749 749
 				}
750 750
 
751 751
 				if (!isset($info['name'])) {
752
-					\OCP\Util::writeLog('core', 'App id "' . $app . '" has no name in appinfo', \OCP\Util::ERROR);
752
+					\OCP\Util::writeLog('core', 'App id "'.$app.'" has no name in appinfo', \OCP\Util::ERROR);
753 753
 					continue;
754 754
 				}
755 755
 
@@ -776,13 +776,13 @@  discard block
 block discarded – undo
776 776
 				}
777 777
 
778 778
 				$appPath = self::getAppPath($app);
779
-				if($appPath !== false) {
780
-					$appIcon = $appPath . '/img/' . $app . '.svg';
779
+				if ($appPath !== false) {
780
+					$appIcon = $appPath.'/img/'.$app.'.svg';
781 781
 					if (file_exists($appIcon)) {
782
-						$info['preview'] = $urlGenerator->imagePath($app, $app . '.svg');
782
+						$info['preview'] = $urlGenerator->imagePath($app, $app.'.svg');
783 783
 						$info['previewAsIcon'] = true;
784 784
 					} else {
785
-						$appIcon = $appPath . '/img/app.svg';
785
+						$appIcon = $appPath.'/img/app.svg';
786 786
 						if (file_exists($appIcon)) {
787 787
 							$info['preview'] = $urlGenerator->imagePath($app, 'app.svg');
788 788
 							$info['previewAsIcon'] = true;
@@ -907,7 +907,7 @@  discard block
 block discarded – undo
907 907
 	public static function getAppVersions() {
908 908
 		static $versions;
909 909
 
910
-		if(!$versions) {
910
+		if (!$versions) {
911 911
 			$appConfig = \OC::$server->getAppConfig();
912 912
 			$versions = $appConfig->getValues(false, 'installed_version');
913 913
 		}
@@ -922,7 +922,7 @@  discard block
 block discarded – undo
922 922
 	 */
923 923
 	public static function updateApp($appId) {
924 924
 		$appPath = self::getAppPath($appId);
925
-		if($appPath === false) {
925
+		if ($appPath === false) {
926 926
 			return false;
927 927
 		}
928 928
 		self::registerAutoloading($appId, $appPath);
@@ -930,8 +930,8 @@  discard block
 block discarded – undo
930 930
 		$appData = self::getAppInfo($appId);
931 931
 		self::executeRepairSteps($appId, $appData['repair-steps']['pre-migration']);
932 932
 
933
-		if (file_exists($appPath . '/appinfo/database.xml')) {
934
-			OC_DB::updateDbFromStructure($appPath . '/appinfo/database.xml');
933
+		if (file_exists($appPath.'/appinfo/database.xml')) {
934
+			OC_DB::updateDbFromStructure($appPath.'/appinfo/database.xml');
935 935
 		} else {
936 936
 			$ms = new MigrationService($appId, \OC::$server->getDatabaseConnection());
937 937
 			$ms->migrate();
@@ -943,26 +943,26 @@  discard block
 block discarded – undo
943 943
 		\OC::$server->getAppManager()->getAppVersion($appId, false);
944 944
 
945 945
 		// run upgrade code
946
-		if (file_exists($appPath . '/appinfo/update.php')) {
946
+		if (file_exists($appPath.'/appinfo/update.php')) {
947 947
 			self::loadApp($appId);
948
-			include $appPath . '/appinfo/update.php';
948
+			include $appPath.'/appinfo/update.php';
949 949
 		}
950 950
 		self::setupBackgroundJobs($appData['background-jobs']);
951
-		if(isset($appData['settings']) && is_array($appData['settings'])) {
951
+		if (isset($appData['settings']) && is_array($appData['settings'])) {
952 952
 			\OC::$server->getSettingsManager()->setupSettings($appData['settings']);
953 953
 		}
954 954
 
955 955
 		//set remote/public handlers
956 956
 		if (array_key_exists('ocsid', $appData)) {
957 957
 			\OC::$server->getConfig()->setAppValue($appId, 'ocsid', $appData['ocsid']);
958
-		} elseif(\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
958
+		} elseif (\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
959 959
 			\OC::$server->getConfig()->deleteAppValue($appId, 'ocsid');
960 960
 		}
961 961
 		foreach ($appData['remote'] as $name => $path) {
962
-			\OC::$server->getConfig()->setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
962
+			\OC::$server->getConfig()->setAppValue('core', 'remote_'.$name, $appId.'/'.$path);
963 963
 		}
964 964
 		foreach ($appData['public'] as $name => $path) {
965
-			\OC::$server->getConfig()->setAppValue('core', 'public_' . $name, $appId . '/' . $path);
965
+			\OC::$server->getConfig()->setAppValue('core', 'public_'.$name, $appId.'/'.$path);
966 966
 		}
967 967
 
968 968
 		self::setAppTypes($appId);
@@ -1032,17 +1032,17 @@  discard block
 block discarded – undo
1032 1032
 	public static function getStorage($appId) {
1033 1033
 		if (\OC::$server->getAppManager()->isEnabledForUser($appId)) { //sanity check
1034 1034
 			if (\OC::$server->getUserSession()->isLoggedIn()) {
1035
-				$view = new \OC\Files\View('/' . OC_User::getUser());
1035
+				$view = new \OC\Files\View('/'.OC_User::getUser());
1036 1036
 				if (!$view->file_exists($appId)) {
1037 1037
 					$view->mkdir($appId);
1038 1038
 				}
1039
-				return new \OC\Files\View('/' . OC_User::getUser() . '/' . $appId);
1039
+				return new \OC\Files\View('/'.OC_User::getUser().'/'.$appId);
1040 1040
 			} else {
1041
-				\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ', user not logged in', \OCP\Util::ERROR);
1041
+				\OCP\Util::writeLog('core', 'Can\'t get app storage, app '.$appId.', user not logged in', \OCP\Util::ERROR);
1042 1042
 				return false;
1043 1043
 			}
1044 1044
 		} else {
1045
-			\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ' not enabled', \OCP\Util::ERROR);
1045
+			\OCP\Util::writeLog('core', 'Can\'t get app storage, app '.$appId.' not enabled', \OCP\Util::ERROR);
1046 1046
 			return false;
1047 1047
 		}
1048 1048
 	}
@@ -1074,9 +1074,9 @@  discard block
 block discarded – undo
1074 1074
 
1075 1075
 				if ($attributeLang === $similarLang) {
1076 1076
 					$similarLangFallback = $option['@value'];
1077
-				} else if (strpos($attributeLang, $similarLang . '_') === 0) {
1077
+				} else if (strpos($attributeLang, $similarLang.'_') === 0) {
1078 1078
 					if ($similarLangFallback === false) {
1079
-						$similarLangFallback =  $option['@value'];
1079
+						$similarLangFallback = $option['@value'];
1080 1080
 					}
1081 1081
 				}
1082 1082
 			} else {
@@ -1111,7 +1111,7 @@  discard block
 block discarded – undo
1111 1111
 			$data['description'] = trim(self::findBestL10NOption($data['description'], $lang));
1112 1112
 		} else if (isset($data['description']) && is_string($data['description'])) {
1113 1113
 			$data['description'] = trim($data['description']);
1114
-		} else  {
1114
+		} else {
1115 1115
 			$data['description'] = '';
1116 1116
 		}
1117 1117
 
Please login to merge, or discard this patch.
apps/files_trashbin/lib/Storage.php 1 patch
Indentation   +279 added lines, -279 removed lines patch added patch discarded remove patch
@@ -40,284 +40,284 @@
 block discarded – undo
40 40
 
41 41
 class Storage extends Wrapper {
42 42
 
43
-	private $mountPoint;
44
-	// remember already deleted files to avoid infinite loops if the trash bin
45
-	// move files across storages
46
-	private $deletedFiles = array();
47
-
48
-	/**
49
-	 * Disable trash logic
50
-	 *
51
-	 * @var bool
52
-	 */
53
-	private static $disableTrash = false;
54
-
55
-	/**
56
-	 * remember which file/folder was moved out of s shared folder
57
-	 * in this case we want to add a copy to the owners trash bin
58
-	 *
59
-	 * @var array
60
-	 */
61
-	private static $moveOutOfSharedFolder = [];
62
-
63
-	/** @var  IUserManager */
64
-	private $userManager;
65
-
66
-	/** @var ILogger */
67
-	private $logger;
68
-
69
-	/** @var EventDispatcher */
70
-	private $eventDispatcher;
71
-
72
-	/** @var IRootFolder */
73
-	private $rootFolder;
74
-
75
-	/**
76
-	 * Storage constructor.
77
-	 *
78
-	 * @param array $parameters
79
-	 * @param IUserManager|null $userManager
80
-	 * @param ILogger|null $logger
81
-	 * @param EventDispatcher|null $eventDispatcher
82
-	 * @param IRootFolder|null $rootFolder
83
-	 */
84
-	public function __construct($parameters,
85
-								IUserManager $userManager = null,
86
-								ILogger $logger = null,
87
-								EventDispatcher $eventDispatcher = null,
88
-								IRootFolder $rootFolder = null) {
89
-		$this->mountPoint = $parameters['mountPoint'];
90
-		$this->userManager = $userManager;
91
-		$this->logger = $logger;
92
-		$this->eventDispatcher = $eventDispatcher;
93
-		$this->rootFolder = $rootFolder;
94
-		parent::__construct($parameters);
95
-	}
96
-
97
-	/**
98
-	 * @internal
99
-	 */
100
-	public static function preRenameHook($params) {
101
-		// in cross-storage cases, a rename is a copy + unlink,
102
-		// that last unlink must not go to trash, only exception:
103
-		// if the file was moved from a shared storage to a local folder,
104
-		// in this case the owner should get a copy in his trash bin so that
105
-		// they can restore the files again
106
-
107
-		$oldPath = $params['oldpath'];
108
-		$newPath = dirname($params['newpath']);
109
-		$currentUser = \OC::$server->getUserSession()->getUser();
110
-
111
-		$fileMovedOutOfSharedFolder = false;
112
-
113
-		try {
114
-			if ($currentUser) {
115
-				$currentUserId = $currentUser->getUID();
116
-
117
-				$view = new View($currentUserId . '/files');
118
-				$fileInfo = $view->getFileInfo($oldPath);
119
-				if ($fileInfo) {
120
-					$sourceStorage = $fileInfo->getStorage();
121
-					$sourceOwner = $view->getOwner($oldPath);
122
-					$targetOwner = $view->getOwner($newPath);
123
-
124
-					if ($sourceOwner !== $targetOwner
125
-						&& $sourceStorage->instanceOfStorage('OCA\Files_Sharing\SharedStorage')
126
-					) {
127
-						$fileMovedOutOfSharedFolder = true;
128
-					}
129
-				}
130
-			}
131
-		} catch (\Exception $e) {
132
-			// do nothing, in this case we just disable the trashbin and continue
133
-			\OC::$server->getLogger()->logException($e, [
134
-				'message' => 'Trashbin storage could not check if a file was moved out of a shared folder.',
135
-				'level' => \OCP\Util::DEBUG,
136
-				'app' => 'files_trashbin',
137
-			]);
138
-		}
139
-
140
-		if($fileMovedOutOfSharedFolder) {
141
-			self::$moveOutOfSharedFolder['/' . $currentUserId . '/files' . $oldPath] = true;
142
-		} else {
143
-			self::$disableTrash = true;
144
-		}
145
-
146
-	}
147
-
148
-	/**
149
-	 * @internal
150
-	 */
151
-	public static function postRenameHook($params) {
152
-		self::$disableTrash = false;
153
-	}
154
-
155
-	/**
156
-	 * Rename path1 to path2 by calling the wrapped storage.
157
-	 *
158
-	 * @param string $path1 first path
159
-	 * @param string $path2 second path
160
-	 * @return bool
161
-	 */
162
-	public function rename($path1, $path2) {
163
-		$result = $this->storage->rename($path1, $path2);
164
-		if ($result === false) {
165
-			// when rename failed, the post_rename hook isn't triggered,
166
-			// but we still want to reenable the trash logic
167
-			self::$disableTrash = false;
168
-		}
169
-		return $result;
170
-	}
171
-
172
-	/**
173
-	 * Deletes the given file by moving it into the trashbin.
174
-	 *
175
-	 * @param string $path path of file or folder to delete
176
-	 *
177
-	 * @return bool true if the operation succeeded, false otherwise
178
-	 */
179
-	public function unlink($path) {
180
-		try {
181
-			if (isset(self::$moveOutOfSharedFolder[$this->mountPoint . $path])) {
182
-				$result = $this->doDelete($path, 'unlink', true);
183
-				unset(self::$moveOutOfSharedFolder[$this->mountPoint . $path]);
184
-			} else {
185
-				$result = $this->doDelete($path, 'unlink');
186
-			}
187
-		} catch (GenericEncryptionException $e) {
188
-			// in case of a encryption exception we delete the file right away
189
-			$this->logger->info(
190
-				"Can't move file" .  $path .
191
-				"to the trash bin, therefore it was deleted right away");
192
-
193
-			$result = $this->storage->unlink($path);
194
-		}
195
-
196
-		return $result;
197
-	}
198
-
199
-	/**
200
-	 * Deletes the given folder by moving it into the trashbin.
201
-	 *
202
-	 * @param string $path path of folder to delete
203
-	 *
204
-	 * @return bool true if the operation succeeded, false otherwise
205
-	 */
206
-	public function rmdir($path) {
207
-		if (isset(self::$moveOutOfSharedFolder[$this->mountPoint . $path])) {
208
-			$result = $this->doDelete($path, 'rmdir', true);
209
-			unset(self::$moveOutOfSharedFolder[$this->mountPoint . $path]);
210
-		} else {
211
-			$result = $this->doDelete($path, 'rmdir');
212
-		}
213
-
214
-		return $result;
215
-	}
216
-
217
-	/**
218
-	 * check if it is a file located in data/user/files only files in the
219
-	 * 'files' directory should be moved to the trash
220
-	 *
221
-	 * @param $path
222
-	 * @return bool
223
-	 */
224
-	protected function shouldMoveToTrash($path){
225
-
226
-		// check if there is a app which want to disable the trash bin for this file
227
-		$fileId = $this->storage->getCache()->getId($path);
228
-		$nodes = $this->rootFolder->getById($fileId);
229
-		foreach ($nodes as $node) {
230
-			$event = $this->createMoveToTrashEvent($node);
231
-			$this->eventDispatcher->dispatch('OCA\Files_Trashbin::moveToTrash', $event);
232
-			if ($event->shouldMoveToTrashBin() === false) {
233
-				return false;
234
-			}
235
-		}
236
-
237
-		$normalized = Filesystem::normalizePath($this->mountPoint . '/' . $path);
238
-		$parts = explode('/', $normalized);
239
-		if (count($parts) < 4) {
240
-			return false;
241
-		}
242
-
243
-		if ($parts[2] === 'files' && $this->userManager->userExists($parts[1])) {
244
-			return true;
245
-		}
246
-
247
-		return false;
248
-	}
249
-
250
-	/**
251
-	 * get move to trash event
252
-	 *
253
-	 * @param Node $node
254
-	 * @return MoveToTrashEvent
255
-	 */
256
-	protected function createMoveToTrashEvent(Node $node) {
257
-		return new MoveToTrashEvent($node);
258
-	}
259
-
260
-	/**
261
-	 * Run the delete operation with the given method
262
-	 *
263
-	 * @param string $path path of file or folder to delete
264
-	 * @param string $method either "unlink" or "rmdir"
265
-	 * @param bool $ownerOnly delete for owner only (if file gets moved out of a shared folder)
266
-	 *
267
-	 * @return bool true if the operation succeeded, false otherwise
268
-	 */
269
-	private function doDelete($path, $method, $ownerOnly = false) {
270
-		if (self::$disableTrash
271
-			|| !\OC::$server->getAppManager()->isEnabledForUser('files_trashbin')
272
-			|| (pathinfo($path, PATHINFO_EXTENSION) === 'part')
273
-			|| $this->shouldMoveToTrash($path) === false
274
-		) {
275
-			return call_user_func_array([$this->storage, $method], [$path]);
276
-		}
277
-
278
-		// check permissions before we continue, this is especially important for
279
-		// shared files
280
-		if (!$this->isDeletable($path)) {
281
-			return false;
282
-		}
283
-
284
-		$normalized = Filesystem::normalizePath($this->mountPoint . '/' . $path, true, false, true);
285
-		$result = true;
286
-		$view = Filesystem::getView();
287
-		if (!isset($this->deletedFiles[$normalized]) && $view instanceof View) {
288
-			$this->deletedFiles[$normalized] = $normalized;
289
-			if ($filesPath = $view->getRelativePath($normalized)) {
290
-				$filesPath = trim($filesPath, '/');
291
-				$result = \OCA\Files_Trashbin\Trashbin::move2trash($filesPath, $ownerOnly);
292
-				// in cross-storage cases the file will be copied
293
-				// but not deleted, so we delete it here
294
-				if ($result) {
295
-					call_user_func_array([$this->storage, $method], [$path]);
296
-				}
297
-			} else {
298
-				$result = call_user_func_array([$this->storage, $method], [$path]);
299
-			}
300
-			unset($this->deletedFiles[$normalized]);
301
-		} else if ($this->storage->file_exists($path)) {
302
-			$result = call_user_func_array([$this->storage, $method], [$path]);
303
-		}
304
-
305
-		return $result;
306
-	}
307
-
308
-	/**
309
-	 * Setup the storate wrapper callback
310
-	 */
311
-	public static function setupStorage() {
312
-		\OC\Files\Filesystem::addStorageWrapper('oc_trashbin', function ($mountPoint, $storage) {
313
-			return new \OCA\Files_Trashbin\Storage(
314
-				array('storage' => $storage, 'mountPoint' => $mountPoint),
315
-				\OC::$server->getUserManager(),
316
-				\OC::$server->getLogger(),
317
-				\OC::$server->getEventDispatcher(),
318
-				\OC::$server->getLazyRootFolder()
319
-			);
320
-		}, 1);
321
-	}
43
+    private $mountPoint;
44
+    // remember already deleted files to avoid infinite loops if the trash bin
45
+    // move files across storages
46
+    private $deletedFiles = array();
47
+
48
+    /**
49
+     * Disable trash logic
50
+     *
51
+     * @var bool
52
+     */
53
+    private static $disableTrash = false;
54
+
55
+    /**
56
+     * remember which file/folder was moved out of s shared folder
57
+     * in this case we want to add a copy to the owners trash bin
58
+     *
59
+     * @var array
60
+     */
61
+    private static $moveOutOfSharedFolder = [];
62
+
63
+    /** @var  IUserManager */
64
+    private $userManager;
65
+
66
+    /** @var ILogger */
67
+    private $logger;
68
+
69
+    /** @var EventDispatcher */
70
+    private $eventDispatcher;
71
+
72
+    /** @var IRootFolder */
73
+    private $rootFolder;
74
+
75
+    /**
76
+     * Storage constructor.
77
+     *
78
+     * @param array $parameters
79
+     * @param IUserManager|null $userManager
80
+     * @param ILogger|null $logger
81
+     * @param EventDispatcher|null $eventDispatcher
82
+     * @param IRootFolder|null $rootFolder
83
+     */
84
+    public function __construct($parameters,
85
+                                IUserManager $userManager = null,
86
+                                ILogger $logger = null,
87
+                                EventDispatcher $eventDispatcher = null,
88
+                                IRootFolder $rootFolder = null) {
89
+        $this->mountPoint = $parameters['mountPoint'];
90
+        $this->userManager = $userManager;
91
+        $this->logger = $logger;
92
+        $this->eventDispatcher = $eventDispatcher;
93
+        $this->rootFolder = $rootFolder;
94
+        parent::__construct($parameters);
95
+    }
96
+
97
+    /**
98
+     * @internal
99
+     */
100
+    public static function preRenameHook($params) {
101
+        // in cross-storage cases, a rename is a copy + unlink,
102
+        // that last unlink must not go to trash, only exception:
103
+        // if the file was moved from a shared storage to a local folder,
104
+        // in this case the owner should get a copy in his trash bin so that
105
+        // they can restore the files again
106
+
107
+        $oldPath = $params['oldpath'];
108
+        $newPath = dirname($params['newpath']);
109
+        $currentUser = \OC::$server->getUserSession()->getUser();
110
+
111
+        $fileMovedOutOfSharedFolder = false;
112
+
113
+        try {
114
+            if ($currentUser) {
115
+                $currentUserId = $currentUser->getUID();
116
+
117
+                $view = new View($currentUserId . '/files');
118
+                $fileInfo = $view->getFileInfo($oldPath);
119
+                if ($fileInfo) {
120
+                    $sourceStorage = $fileInfo->getStorage();
121
+                    $sourceOwner = $view->getOwner($oldPath);
122
+                    $targetOwner = $view->getOwner($newPath);
123
+
124
+                    if ($sourceOwner !== $targetOwner
125
+                        && $sourceStorage->instanceOfStorage('OCA\Files_Sharing\SharedStorage')
126
+                    ) {
127
+                        $fileMovedOutOfSharedFolder = true;
128
+                    }
129
+                }
130
+            }
131
+        } catch (\Exception $e) {
132
+            // do nothing, in this case we just disable the trashbin and continue
133
+            \OC::$server->getLogger()->logException($e, [
134
+                'message' => 'Trashbin storage could not check if a file was moved out of a shared folder.',
135
+                'level' => \OCP\Util::DEBUG,
136
+                'app' => 'files_trashbin',
137
+            ]);
138
+        }
139
+
140
+        if($fileMovedOutOfSharedFolder) {
141
+            self::$moveOutOfSharedFolder['/' . $currentUserId . '/files' . $oldPath] = true;
142
+        } else {
143
+            self::$disableTrash = true;
144
+        }
145
+
146
+    }
147
+
148
+    /**
149
+     * @internal
150
+     */
151
+    public static function postRenameHook($params) {
152
+        self::$disableTrash = false;
153
+    }
154
+
155
+    /**
156
+     * Rename path1 to path2 by calling the wrapped storage.
157
+     *
158
+     * @param string $path1 first path
159
+     * @param string $path2 second path
160
+     * @return bool
161
+     */
162
+    public function rename($path1, $path2) {
163
+        $result = $this->storage->rename($path1, $path2);
164
+        if ($result === false) {
165
+            // when rename failed, the post_rename hook isn't triggered,
166
+            // but we still want to reenable the trash logic
167
+            self::$disableTrash = false;
168
+        }
169
+        return $result;
170
+    }
171
+
172
+    /**
173
+     * Deletes the given file by moving it into the trashbin.
174
+     *
175
+     * @param string $path path of file or folder to delete
176
+     *
177
+     * @return bool true if the operation succeeded, false otherwise
178
+     */
179
+    public function unlink($path) {
180
+        try {
181
+            if (isset(self::$moveOutOfSharedFolder[$this->mountPoint . $path])) {
182
+                $result = $this->doDelete($path, 'unlink', true);
183
+                unset(self::$moveOutOfSharedFolder[$this->mountPoint . $path]);
184
+            } else {
185
+                $result = $this->doDelete($path, 'unlink');
186
+            }
187
+        } catch (GenericEncryptionException $e) {
188
+            // in case of a encryption exception we delete the file right away
189
+            $this->logger->info(
190
+                "Can't move file" .  $path .
191
+                "to the trash bin, therefore it was deleted right away");
192
+
193
+            $result = $this->storage->unlink($path);
194
+        }
195
+
196
+        return $result;
197
+    }
198
+
199
+    /**
200
+     * Deletes the given folder by moving it into the trashbin.
201
+     *
202
+     * @param string $path path of folder to delete
203
+     *
204
+     * @return bool true if the operation succeeded, false otherwise
205
+     */
206
+    public function rmdir($path) {
207
+        if (isset(self::$moveOutOfSharedFolder[$this->mountPoint . $path])) {
208
+            $result = $this->doDelete($path, 'rmdir', true);
209
+            unset(self::$moveOutOfSharedFolder[$this->mountPoint . $path]);
210
+        } else {
211
+            $result = $this->doDelete($path, 'rmdir');
212
+        }
213
+
214
+        return $result;
215
+    }
216
+
217
+    /**
218
+     * check if it is a file located in data/user/files only files in the
219
+     * 'files' directory should be moved to the trash
220
+     *
221
+     * @param $path
222
+     * @return bool
223
+     */
224
+    protected function shouldMoveToTrash($path){
225
+
226
+        // check if there is a app which want to disable the trash bin for this file
227
+        $fileId = $this->storage->getCache()->getId($path);
228
+        $nodes = $this->rootFolder->getById($fileId);
229
+        foreach ($nodes as $node) {
230
+            $event = $this->createMoveToTrashEvent($node);
231
+            $this->eventDispatcher->dispatch('OCA\Files_Trashbin::moveToTrash', $event);
232
+            if ($event->shouldMoveToTrashBin() === false) {
233
+                return false;
234
+            }
235
+        }
236
+
237
+        $normalized = Filesystem::normalizePath($this->mountPoint . '/' . $path);
238
+        $parts = explode('/', $normalized);
239
+        if (count($parts) < 4) {
240
+            return false;
241
+        }
242
+
243
+        if ($parts[2] === 'files' && $this->userManager->userExists($parts[1])) {
244
+            return true;
245
+        }
246
+
247
+        return false;
248
+    }
249
+
250
+    /**
251
+     * get move to trash event
252
+     *
253
+     * @param Node $node
254
+     * @return MoveToTrashEvent
255
+     */
256
+    protected function createMoveToTrashEvent(Node $node) {
257
+        return new MoveToTrashEvent($node);
258
+    }
259
+
260
+    /**
261
+     * Run the delete operation with the given method
262
+     *
263
+     * @param string $path path of file or folder to delete
264
+     * @param string $method either "unlink" or "rmdir"
265
+     * @param bool $ownerOnly delete for owner only (if file gets moved out of a shared folder)
266
+     *
267
+     * @return bool true if the operation succeeded, false otherwise
268
+     */
269
+    private function doDelete($path, $method, $ownerOnly = false) {
270
+        if (self::$disableTrash
271
+            || !\OC::$server->getAppManager()->isEnabledForUser('files_trashbin')
272
+            || (pathinfo($path, PATHINFO_EXTENSION) === 'part')
273
+            || $this->shouldMoveToTrash($path) === false
274
+        ) {
275
+            return call_user_func_array([$this->storage, $method], [$path]);
276
+        }
277
+
278
+        // check permissions before we continue, this is especially important for
279
+        // shared files
280
+        if (!$this->isDeletable($path)) {
281
+            return false;
282
+        }
283
+
284
+        $normalized = Filesystem::normalizePath($this->mountPoint . '/' . $path, true, false, true);
285
+        $result = true;
286
+        $view = Filesystem::getView();
287
+        if (!isset($this->deletedFiles[$normalized]) && $view instanceof View) {
288
+            $this->deletedFiles[$normalized] = $normalized;
289
+            if ($filesPath = $view->getRelativePath($normalized)) {
290
+                $filesPath = trim($filesPath, '/');
291
+                $result = \OCA\Files_Trashbin\Trashbin::move2trash($filesPath, $ownerOnly);
292
+                // in cross-storage cases the file will be copied
293
+                // but not deleted, so we delete it here
294
+                if ($result) {
295
+                    call_user_func_array([$this->storage, $method], [$path]);
296
+                }
297
+            } else {
298
+                $result = call_user_func_array([$this->storage, $method], [$path]);
299
+            }
300
+            unset($this->deletedFiles[$normalized]);
301
+        } else if ($this->storage->file_exists($path)) {
302
+            $result = call_user_func_array([$this->storage, $method], [$path]);
303
+        }
304
+
305
+        return $result;
306
+    }
307
+
308
+    /**
309
+     * Setup the storate wrapper callback
310
+     */
311
+    public static function setupStorage() {
312
+        \OC\Files\Filesystem::addStorageWrapper('oc_trashbin', function ($mountPoint, $storage) {
313
+            return new \OCA\Files_Trashbin\Storage(
314
+                array('storage' => $storage, 'mountPoint' => $mountPoint),
315
+                \OC::$server->getUserManager(),
316
+                \OC::$server->getLogger(),
317
+                \OC::$server->getEventDispatcher(),
318
+                \OC::$server->getLazyRootFolder()
319
+            );
320
+        }, 1);
321
+    }
322 322
 
323 323
 }
Please login to merge, or discard this patch.
settings/ajax/uninstallapp.php 2 patches
Indentation   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -27,14 +27,14 @@  discard block
 block discarded – undo
27 27
 
28 28
 $lastConfirm = (int) \OC::$server->getSession()->get('last-password-confirm');
29 29
 if ($lastConfirm < (time() - 30 * 60 + 15)) { // allow 15 seconds delay
30
-	$l = \OC::$server->getL10N('core');
31
-	OC_JSON::error(array( 'data' => array( 'message' => $l->t('Password confirmation is required'))));
32
-	exit();
30
+    $l = \OC::$server->getL10N('core');
31
+    OC_JSON::error(array( 'data' => array( 'message' => $l->t('Password confirmation is required'))));
32
+    exit();
33 33
 }
34 34
 
35 35
 if (!array_key_exists('appid', $_POST)) {
36
-	OC_JSON::error();
37
-	exit;
36
+    OC_JSON::error();
37
+    exit;
38 38
 }
39 39
 
40 40
 $appId = (string)$_POST['appid'];
@@ -45,11 +45,11 @@  discard block
 block discarded – undo
45 45
 $installer = \OC::$server->query(\OC\Installer::class);
46 46
 $result = $installer->removeApp($app);
47 47
 if($result !== false) {
48
-	// FIXME: Clear the cache - move that into some sane helper method
49
-	\OC::$server->getMemCacheFactory()->createDistributed('settings')->remove('listApps-0');
50
-	\OC::$server->getMemCacheFactory()->createDistributed('settings')->remove('listApps-1');
51
-	OC_JSON::success(array('data' => array('appid' => $appId)));
48
+    // FIXME: Clear the cache - move that into some sane helper method
49
+    \OC::$server->getMemCacheFactory()->createDistributed('settings')->remove('listApps-0');
50
+    \OC::$server->getMemCacheFactory()->createDistributed('settings')->remove('listApps-1');
51
+    OC_JSON::success(array('data' => array('appid' => $appId)));
52 52
 } else {
53
-	$l = \OC::$server->getL10N('settings');
54
-	OC_JSON::error(array('data' => array( 'message' => $l->t("Couldn't remove app.") )));
53
+    $l = \OC::$server->getL10N('settings');
54
+    OC_JSON::error(array('data' => array( 'message' => $l->t("Couldn't remove app.") )));
55 55
 }
Please login to merge, or discard this patch.
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -28,7 +28,7 @@  discard block
 block discarded – undo
28 28
 $lastConfirm = (int) \OC::$server->getSession()->get('last-password-confirm');
29 29
 if ($lastConfirm < (time() - 30 * 60 + 15)) { // allow 15 seconds delay
30 30
 	$l = \OC::$server->getL10N('core');
31
-	OC_JSON::error(array( 'data' => array( 'message' => $l->t('Password confirmation is required'))));
31
+	OC_JSON::error(array('data' => array('message' => $l->t('Password confirmation is required'))));
32 32
 	exit();
33 33
 }
34 34
 
@@ -37,19 +37,19 @@  discard block
 block discarded – undo
37 37
 	exit;
38 38
 }
39 39
 
40
-$appId = (string)$_POST['appid'];
40
+$appId = (string) $_POST['appid'];
41 41
 $appId = OC_App::cleanAppId($appId);
42 42
 
43 43
 // FIXME: move to controller
44 44
 /** @var \OC\Installer $installer */
45 45
 $installer = \OC::$server->query(\OC\Installer::class);
46 46
 $result = $installer->removeApp($app);
47
-if($result !== false) {
47
+if ($result !== false) {
48 48
 	// FIXME: Clear the cache - move that into some sane helper method
49 49
 	\OC::$server->getMemCacheFactory()->createDistributed('settings')->remove('listApps-0');
50 50
 	\OC::$server->getMemCacheFactory()->createDistributed('settings')->remove('listApps-1');
51 51
 	OC_JSON::success(array('data' => array('appid' => $appId)));
52 52
 } else {
53 53
 	$l = \OC::$server->getL10N('settings');
54
-	OC_JSON::error(array('data' => array( 'message' => $l->t("Couldn't remove app.") )));
54
+	OC_JSON::error(array('data' => array('message' => $l->t("Couldn't remove app."))));
55 55
 }
Please login to merge, or discard this patch.
lib/private/App/AppManager.php 2 patches
Spacing   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -114,11 +114,11 @@  discard block
 block discarded – undo
114 114
 			$values = $this->appConfig->getValues(false, 'enabled');
115 115
 
116 116
 			$alwaysEnabledApps = $this->getAlwaysEnabledApps();
117
-			foreach($alwaysEnabledApps as $appId) {
117
+			foreach ($alwaysEnabledApps as $appId) {
118 118
 				$values[$appId] = 'yes';
119 119
 			}
120 120
 
121
-			$this->installedAppsCache = array_filter($values, function ($value) {
121
+			$this->installedAppsCache = array_filter($values, function($value) {
122 122
 				return $value !== 'no';
123 123
 			});
124 124
 			ksort($this->installedAppsCache);
@@ -143,7 +143,7 @@  discard block
 block discarded – undo
143 143
 	 */
144 144
 	public function getEnabledAppsForUser(IUser $user) {
145 145
 		$apps = $this->getInstalledAppsValues();
146
-		$appsForUser = array_filter($apps, function ($enabled) use ($user) {
146
+		$appsForUser = array_filter($apps, function($enabled) use ($user) {
147 147
 			return $this->checkAppForUser($enabled, $user);
148 148
 		});
149 149
 		return array_keys($appsForUser);
@@ -182,7 +182,7 @@  discard block
 block discarded – undo
182 182
 		} elseif ($user === null) {
183 183
 			return false;
184 184
 		} else {
185
-			if(empty($enabled)){
185
+			if (empty($enabled)) {
186 186
 				return false;
187 187
 			}
188 188
 
@@ -190,7 +190,7 @@  discard block
 block discarded – undo
190 190
 
191 191
 			if (!is_array($groupIds)) {
192 192
 				$jsonError = json_last_error();
193
-				\OC::$server->getLogger()->warning('AppManger::checkAppForUser - can\'t decode group IDs: ' . print_r($enabled, true) . ' - json error code: ' . $jsonError, ['app' => 'lib']);
193
+				\OC::$server->getLogger()->warning('AppManger::checkAppForUser - can\'t decode group IDs: '.print_r($enabled, true).' - json error code: '.$jsonError, ['app' => 'lib']);
194 194
 				return false;
195 195
 			}
196 196
 
@@ -264,7 +264,7 @@  discard block
 block discarded – undo
264 264
 			}
265 265
 		}
266 266
 
267
-		$groupIds = array_map(function ($group) {
267
+		$groupIds = array_map(function($group) {
268 268
 			/** @var \OCP\IGroup $group */
269 269
 			return $group->getGID();
270 270
 		}, $groups);
@@ -303,8 +303,8 @@  discard block
 block discarded – undo
303 303
 	 */
304 304
 	public function getAppPath($appId) {
305 305
 		$appPath = \OC_App::getAppPath($appId);
306
-		if($appPath === false) {
307
-			throw new AppPathNotFoundException('Could not find path for ' . $appId);
306
+		if ($appPath === false) {
307
+			throw new AppPathNotFoundException('Could not find path for '.$appId);
308 308
 		}
309 309
 		return $appPath;
310 310
 	}
@@ -364,7 +364,7 @@  discard block
 block discarded – undo
364 364
 			} catch (AppPathNotFoundException $e) {
365 365
 				return null;
366 366
 			}
367
-			$file = $appPath . '/appinfo/info.xml';
367
+			$file = $appPath.'/appinfo/info.xml';
368 368
 		}
369 369
 
370 370
 		$parser = new InfoParser($this->memCacheFactory->createLocal('core.appinfo'));
@@ -382,7 +382,7 @@  discard block
 block discarded – undo
382 382
 	}
383 383
 
384 384
 	public function getAppVersion(string $appId, bool $useCache = true) {
385
-		if(!$useCache || !isset($this->appVersions[$appId])) {
385
+		if (!$useCache || !isset($this->appVersions[$appId])) {
386 386
 			$appInfo = \OC::$server->getAppManager()->getAppInfo($appId);
387 387
 			$this->appVersions[$appId] = ($appInfo !== null) ? $appInfo['version'] : '0';
388 388
 		}
@@ -425,7 +425,7 @@  discard block
 block discarded – undo
425 425
 
426 426
 	private function loadShippedJson() {
427 427
 		if ($this->shippedApps === null) {
428
-			$shippedJson = \OC::$SERVERROOT . '/core/shipped.json';
428
+			$shippedJson = \OC::$SERVERROOT.'/core/shipped.json';
429 429
 			if (!file_exists($shippedJson)) {
430 430
 				throw new \Exception("File not found: $shippedJson");
431 431
 			}
Please login to merge, or discard this patch.
Indentation   +397 added lines, -397 removed lines patch added patch discarded remove patch
@@ -44,401 +44,401 @@
 block discarded – undo
44 44
 
45 45
 class AppManager implements IAppManager {
46 46
 
47
-	/**
48
-	 * Apps with these types can not be enabled for certain groups only
49
-	 * @var string[]
50
-	 */
51
-	protected $protectedAppTypes = [
52
-		'filesystem',
53
-		'prelogin',
54
-		'authentication',
55
-		'logging',
56
-		'prevent_group_restriction',
57
-	];
58
-
59
-	/** @var IUserSession */
60
-	private $userSession;
61
-
62
-	/** @var AppConfig */
63
-	private $appConfig;
64
-
65
-	/** @var IGroupManager */
66
-	private $groupManager;
67
-
68
-	/** @var ICacheFactory */
69
-	private $memCacheFactory;
70
-
71
-	/** @var EventDispatcherInterface */
72
-	private $dispatcher;
73
-
74
-	/** @var string[] $appId => $enabled */
75
-	private $installedAppsCache;
76
-
77
-	/** @var string[] */
78
-	private $shippedApps;
79
-
80
-	/** @var string[] */
81
-	private $alwaysEnabled;
82
-
83
-	/** @var array */
84
-	private $appInfos = [];
85
-
86
-	/** @var array */
87
-	private $appVersions = [];
88
-
89
-	/**
90
-	 * @param IUserSession $userSession
91
-	 * @param AppConfig $appConfig
92
-	 * @param IGroupManager $groupManager
93
-	 * @param ICacheFactory $memCacheFactory
94
-	 * @param EventDispatcherInterface $dispatcher
95
-	 */
96
-	public function __construct(IUserSession $userSession,
97
-								AppConfig $appConfig,
98
-								IGroupManager $groupManager,
99
-								ICacheFactory $memCacheFactory,
100
-								EventDispatcherInterface $dispatcher) {
101
-		$this->userSession = $userSession;
102
-		$this->appConfig = $appConfig;
103
-		$this->groupManager = $groupManager;
104
-		$this->memCacheFactory = $memCacheFactory;
105
-		$this->dispatcher = $dispatcher;
106
-	}
107
-
108
-	/**
109
-	 * @return string[] $appId => $enabled
110
-	 */
111
-	private function getInstalledAppsValues() {
112
-		if (!$this->installedAppsCache) {
113
-			$values = $this->appConfig->getValues(false, 'enabled');
114
-
115
-			$alwaysEnabledApps = $this->getAlwaysEnabledApps();
116
-			foreach($alwaysEnabledApps as $appId) {
117
-				$values[$appId] = 'yes';
118
-			}
119
-
120
-			$this->installedAppsCache = array_filter($values, function ($value) {
121
-				return $value !== 'no';
122
-			});
123
-			ksort($this->installedAppsCache);
124
-		}
125
-		return $this->installedAppsCache;
126
-	}
127
-
128
-	/**
129
-	 * List all installed apps
130
-	 *
131
-	 * @return string[]
132
-	 */
133
-	public function getInstalledApps() {
134
-		return array_keys($this->getInstalledAppsValues());
135
-	}
136
-
137
-	/**
138
-	 * List all apps enabled for a user
139
-	 *
140
-	 * @param \OCP\IUser $user
141
-	 * @return string[]
142
-	 */
143
-	public function getEnabledAppsForUser(IUser $user) {
144
-		$apps = $this->getInstalledAppsValues();
145
-		$appsForUser = array_filter($apps, function ($enabled) use ($user) {
146
-			return $this->checkAppForUser($enabled, $user);
147
-		});
148
-		return array_keys($appsForUser);
149
-	}
150
-
151
-	/**
152
-	 * Check if an app is enabled for user
153
-	 *
154
-	 * @param string $appId
155
-	 * @param \OCP\IUser $user (optional) if not defined, the currently logged in user will be used
156
-	 * @return bool
157
-	 */
158
-	public function isEnabledForUser($appId, $user = null) {
159
-		if ($this->isAlwaysEnabled($appId)) {
160
-			return true;
161
-		}
162
-		if ($user === null) {
163
-			$user = $this->userSession->getUser();
164
-		}
165
-		$installedApps = $this->getInstalledAppsValues();
166
-		if (isset($installedApps[$appId])) {
167
-			return $this->checkAppForUser($installedApps[$appId], $user);
168
-		} else {
169
-			return false;
170
-		}
171
-	}
172
-
173
-	/**
174
-	 * @param string $enabled
175
-	 * @param IUser $user
176
-	 * @return bool
177
-	 */
178
-	private function checkAppForUser($enabled, $user) {
179
-		if ($enabled === 'yes') {
180
-			return true;
181
-		} elseif ($user === null) {
182
-			return false;
183
-		} else {
184
-			if(empty($enabled)){
185
-				return false;
186
-			}
187
-
188
-			$groupIds = json_decode($enabled);
189
-
190
-			if (!is_array($groupIds)) {
191
-				$jsonError = json_last_error();
192
-				\OC::$server->getLogger()->warning('AppManger::checkAppForUser - can\'t decode group IDs: ' . print_r($enabled, true) . ' - json error code: ' . $jsonError, ['app' => 'lib']);
193
-				return false;
194
-			}
195
-
196
-			$userGroups = $this->groupManager->getUserGroupIds($user);
197
-			foreach ($userGroups as $groupId) {
198
-				if (in_array($groupId, $groupIds, true)) {
199
-					return true;
200
-				}
201
-			}
202
-			return false;
203
-		}
204
-	}
205
-
206
-	/**
207
-	 * Check if an app is installed in the instance
208
-	 *
209
-	 * @param string $appId
210
-	 * @return bool
211
-	 */
212
-	public function isInstalled($appId) {
213
-		$installedApps = $this->getInstalledAppsValues();
214
-		return isset($installedApps[$appId]);
215
-	}
216
-
217
-	/**
218
-	 * Enable an app for every user
219
-	 *
220
-	 * @param string $appId
221
-	 * @throws AppPathNotFoundException
222
-	 */
223
-	public function enableApp($appId) {
224
-		// Check if app exists
225
-		$this->getAppPath($appId);
226
-
227
-		$this->installedAppsCache[$appId] = 'yes';
228
-		$this->appConfig->setValue($appId, 'enabled', 'yes');
229
-		$this->dispatcher->dispatch(ManagerEvent::EVENT_APP_ENABLE, new ManagerEvent(
230
-			ManagerEvent::EVENT_APP_ENABLE, $appId
231
-		));
232
-		$this->clearAppsCache();
233
-	}
234
-
235
-	/**
236
-	 * Whether a list of types contains a protected app type
237
-	 *
238
-	 * @param string[] $types
239
-	 * @return bool
240
-	 */
241
-	public function hasProtectedAppType($types) {
242
-		if (empty($types)) {
243
-			return false;
244
-		}
245
-
246
-		$protectedTypes = array_intersect($this->protectedAppTypes, $types);
247
-		return !empty($protectedTypes);
248
-	}
249
-
250
-	/**
251
-	 * Enable an app only for specific groups
252
-	 *
253
-	 * @param string $appId
254
-	 * @param \OCP\IGroup[] $groups
255
-	 * @throws \Exception if app can't be enabled for groups
256
-	 */
257
-	public function enableAppForGroups($appId, $groups) {
258
-		$info = $this->getAppInfo($appId);
259
-		if (!empty($info['types'])) {
260
-			$protectedTypes = array_intersect($this->protectedAppTypes, $info['types']);
261
-			if (!empty($protectedTypes)) {
262
-				throw new \Exception("$appId can't be enabled for groups.");
263
-			}
264
-		}
265
-
266
-		$groupIds = array_map(function ($group) {
267
-			/** @var \OCP\IGroup $group */
268
-			return $group->getGID();
269
-		}, $groups);
270
-		$this->installedAppsCache[$appId] = json_encode($groupIds);
271
-		$this->appConfig->setValue($appId, 'enabled', json_encode($groupIds));
272
-		$this->dispatcher->dispatch(ManagerEvent::EVENT_APP_ENABLE_FOR_GROUPS, new ManagerEvent(
273
-			ManagerEvent::EVENT_APP_ENABLE_FOR_GROUPS, $appId, $groups
274
-		));
275
-		$this->clearAppsCache();
276
-	}
277
-
278
-	/**
279
-	 * Disable an app for every user
280
-	 *
281
-	 * @param string $appId
282
-	 * @throws \Exception if app can't be disabled
283
-	 */
284
-	public function disableApp($appId) {
285
-		if ($this->isAlwaysEnabled($appId)) {
286
-			throw new \Exception("$appId can't be disabled.");
287
-		}
288
-		unset($this->installedAppsCache[$appId]);
289
-		$this->appConfig->setValue($appId, 'enabled', 'no');
290
-		$this->dispatcher->dispatch(ManagerEvent::EVENT_APP_DISABLE, new ManagerEvent(
291
-			ManagerEvent::EVENT_APP_DISABLE, $appId
292
-		));
293
-		$this->clearAppsCache();
294
-	}
295
-
296
-	/**
297
-	 * Get the directory for the given app.
298
-	 *
299
-	 * @param string $appId
300
-	 * @return string
301
-	 * @throws AppPathNotFoundException if app folder can't be found
302
-	 */
303
-	public function getAppPath($appId) {
304
-		$appPath = \OC_App::getAppPath($appId);
305
-		if($appPath === false) {
306
-			throw new AppPathNotFoundException('Could not find path for ' . $appId);
307
-		}
308
-		return $appPath;
309
-	}
310
-
311
-	/**
312
-	 * Clear the cached list of apps when enabling/disabling an app
313
-	 */
314
-	public function clearAppsCache() {
315
-		$settingsMemCache = $this->memCacheFactory->createDistributed('settings');
316
-		$settingsMemCache->clear('listApps');
317
-	}
318
-
319
-	/**
320
-	 * Returns a list of apps that need upgrade
321
-	 *
322
-	 * @param string $version Nextcloud version as array of version components
323
-	 * @return array list of app info from apps that need an upgrade
324
-	 *
325
-	 * @internal
326
-	 */
327
-	public function getAppsNeedingUpgrade($version) {
328
-		$appsToUpgrade = [];
329
-		$apps = $this->getInstalledApps();
330
-		foreach ($apps as $appId) {
331
-			$appInfo = $this->getAppInfo($appId);
332
-			$appDbVersion = $this->appConfig->getValue($appId, 'installed_version');
333
-			if ($appDbVersion
334
-				&& isset($appInfo['version'])
335
-				&& version_compare($appInfo['version'], $appDbVersion, '>')
336
-				&& \OC_App::isAppCompatible($version, $appInfo)
337
-			) {
338
-				$appsToUpgrade[] = $appInfo;
339
-			}
340
-		}
341
-
342
-		return $appsToUpgrade;
343
-	}
344
-
345
-	/**
346
-	 * Returns the app information from "appinfo/info.xml".
347
-	 *
348
-	 * @param string $appId app id
349
-	 *
350
-	 * @param bool $path
351
-	 * @param null $lang
352
-	 * @return array app info
353
-	 */
354
-	public function getAppInfo(string $appId, bool $path = false, $lang = null) {
355
-		if ($path) {
356
-			$file = $appId;
357
-		} else {
358
-			if ($lang === null && isset($this->appInfos[$appId])) {
359
-				return $this->appInfos[$appId];
360
-			}
361
-			try {
362
-				$appPath = $this->getAppPath($appId);
363
-			} catch (AppPathNotFoundException $e) {
364
-				return null;
365
-			}
366
-			$file = $appPath . '/appinfo/info.xml';
367
-		}
368
-
369
-		$parser = new InfoParser($this->memCacheFactory->createLocal('core.appinfo'));
370
-		$data = $parser->parse($file);
371
-
372
-		if (is_array($data)) {
373
-			$data = \OC_App::parseAppInfo($data, $lang);
374
-		}
375
-
376
-		if ($lang === null) {
377
-			$this->appInfos[$appId] = $data;
378
-		}
379
-
380
-		return $data;
381
-	}
382
-
383
-	public function getAppVersion(string $appId, bool $useCache = true) {
384
-		if(!$useCache || !isset($this->appVersions[$appId])) {
385
-			$appInfo = \OC::$server->getAppManager()->getAppInfo($appId);
386
-			$this->appVersions[$appId] = ($appInfo !== null) ? $appInfo['version'] : '0';
387
-		}
388
-		return $this->appVersions[$appId];
389
-	}
390
-
391
-	/**
392
-	 * Returns a list of apps incompatible with the given version
393
-	 *
394
-	 * @param string $version Nextcloud version as array of version components
395
-	 *
396
-	 * @return array list of app info from incompatible apps
397
-	 *
398
-	 * @internal
399
-	 */
400
-	public function getIncompatibleApps($version) {
401
-		$apps = $this->getInstalledApps();
402
-		$incompatibleApps = array();
403
-		foreach ($apps as $appId) {
404
-			$info = $this->getAppInfo($appId);
405
-			if (!\OC_App::isAppCompatible($version, $info)) {
406
-				$incompatibleApps[] = $info;
407
-			}
408
-		}
409
-		return $incompatibleApps;
410
-	}
411
-
412
-	/**
413
-	 * @inheritdoc
414
-	 */
415
-	public function isShipped($appId) {
416
-		$this->loadShippedJson();
417
-		return in_array($appId, $this->shippedApps, true);
418
-	}
419
-
420
-	private function isAlwaysEnabled($appId) {
421
-		$alwaysEnabled = $this->getAlwaysEnabledApps();
422
-		return in_array($appId, $alwaysEnabled, true);
423
-	}
424
-
425
-	private function loadShippedJson() {
426
-		if ($this->shippedApps === null) {
427
-			$shippedJson = \OC::$SERVERROOT . '/core/shipped.json';
428
-			if (!file_exists($shippedJson)) {
429
-				throw new \Exception("File not found: $shippedJson");
430
-			}
431
-			$content = json_decode(file_get_contents($shippedJson), true);
432
-			$this->shippedApps = $content['shippedApps'];
433
-			$this->alwaysEnabled = $content['alwaysEnabled'];
434
-		}
435
-	}
436
-
437
-	/**
438
-	 * @inheritdoc
439
-	 */
440
-	public function getAlwaysEnabledApps() {
441
-		$this->loadShippedJson();
442
-		return $this->alwaysEnabled;
443
-	}
47
+    /**
48
+     * Apps with these types can not be enabled for certain groups only
49
+     * @var string[]
50
+     */
51
+    protected $protectedAppTypes = [
52
+        'filesystem',
53
+        'prelogin',
54
+        'authentication',
55
+        'logging',
56
+        'prevent_group_restriction',
57
+    ];
58
+
59
+    /** @var IUserSession */
60
+    private $userSession;
61
+
62
+    /** @var AppConfig */
63
+    private $appConfig;
64
+
65
+    /** @var IGroupManager */
66
+    private $groupManager;
67
+
68
+    /** @var ICacheFactory */
69
+    private $memCacheFactory;
70
+
71
+    /** @var EventDispatcherInterface */
72
+    private $dispatcher;
73
+
74
+    /** @var string[] $appId => $enabled */
75
+    private $installedAppsCache;
76
+
77
+    /** @var string[] */
78
+    private $shippedApps;
79
+
80
+    /** @var string[] */
81
+    private $alwaysEnabled;
82
+
83
+    /** @var array */
84
+    private $appInfos = [];
85
+
86
+    /** @var array */
87
+    private $appVersions = [];
88
+
89
+    /**
90
+     * @param IUserSession $userSession
91
+     * @param AppConfig $appConfig
92
+     * @param IGroupManager $groupManager
93
+     * @param ICacheFactory $memCacheFactory
94
+     * @param EventDispatcherInterface $dispatcher
95
+     */
96
+    public function __construct(IUserSession $userSession,
97
+                                AppConfig $appConfig,
98
+                                IGroupManager $groupManager,
99
+                                ICacheFactory $memCacheFactory,
100
+                                EventDispatcherInterface $dispatcher) {
101
+        $this->userSession = $userSession;
102
+        $this->appConfig = $appConfig;
103
+        $this->groupManager = $groupManager;
104
+        $this->memCacheFactory = $memCacheFactory;
105
+        $this->dispatcher = $dispatcher;
106
+    }
107
+
108
+    /**
109
+     * @return string[] $appId => $enabled
110
+     */
111
+    private function getInstalledAppsValues() {
112
+        if (!$this->installedAppsCache) {
113
+            $values = $this->appConfig->getValues(false, 'enabled');
114
+
115
+            $alwaysEnabledApps = $this->getAlwaysEnabledApps();
116
+            foreach($alwaysEnabledApps as $appId) {
117
+                $values[$appId] = 'yes';
118
+            }
119
+
120
+            $this->installedAppsCache = array_filter($values, function ($value) {
121
+                return $value !== 'no';
122
+            });
123
+            ksort($this->installedAppsCache);
124
+        }
125
+        return $this->installedAppsCache;
126
+    }
127
+
128
+    /**
129
+     * List all installed apps
130
+     *
131
+     * @return string[]
132
+     */
133
+    public function getInstalledApps() {
134
+        return array_keys($this->getInstalledAppsValues());
135
+    }
136
+
137
+    /**
138
+     * List all apps enabled for a user
139
+     *
140
+     * @param \OCP\IUser $user
141
+     * @return string[]
142
+     */
143
+    public function getEnabledAppsForUser(IUser $user) {
144
+        $apps = $this->getInstalledAppsValues();
145
+        $appsForUser = array_filter($apps, function ($enabled) use ($user) {
146
+            return $this->checkAppForUser($enabled, $user);
147
+        });
148
+        return array_keys($appsForUser);
149
+    }
150
+
151
+    /**
152
+     * Check if an app is enabled for user
153
+     *
154
+     * @param string $appId
155
+     * @param \OCP\IUser $user (optional) if not defined, the currently logged in user will be used
156
+     * @return bool
157
+     */
158
+    public function isEnabledForUser($appId, $user = null) {
159
+        if ($this->isAlwaysEnabled($appId)) {
160
+            return true;
161
+        }
162
+        if ($user === null) {
163
+            $user = $this->userSession->getUser();
164
+        }
165
+        $installedApps = $this->getInstalledAppsValues();
166
+        if (isset($installedApps[$appId])) {
167
+            return $this->checkAppForUser($installedApps[$appId], $user);
168
+        } else {
169
+            return false;
170
+        }
171
+    }
172
+
173
+    /**
174
+     * @param string $enabled
175
+     * @param IUser $user
176
+     * @return bool
177
+     */
178
+    private function checkAppForUser($enabled, $user) {
179
+        if ($enabled === 'yes') {
180
+            return true;
181
+        } elseif ($user === null) {
182
+            return false;
183
+        } else {
184
+            if(empty($enabled)){
185
+                return false;
186
+            }
187
+
188
+            $groupIds = json_decode($enabled);
189
+
190
+            if (!is_array($groupIds)) {
191
+                $jsonError = json_last_error();
192
+                \OC::$server->getLogger()->warning('AppManger::checkAppForUser - can\'t decode group IDs: ' . print_r($enabled, true) . ' - json error code: ' . $jsonError, ['app' => 'lib']);
193
+                return false;
194
+            }
195
+
196
+            $userGroups = $this->groupManager->getUserGroupIds($user);
197
+            foreach ($userGroups as $groupId) {
198
+                if (in_array($groupId, $groupIds, true)) {
199
+                    return true;
200
+                }
201
+            }
202
+            return false;
203
+        }
204
+    }
205
+
206
+    /**
207
+     * Check if an app is installed in the instance
208
+     *
209
+     * @param string $appId
210
+     * @return bool
211
+     */
212
+    public function isInstalled($appId) {
213
+        $installedApps = $this->getInstalledAppsValues();
214
+        return isset($installedApps[$appId]);
215
+    }
216
+
217
+    /**
218
+     * Enable an app for every user
219
+     *
220
+     * @param string $appId
221
+     * @throws AppPathNotFoundException
222
+     */
223
+    public function enableApp($appId) {
224
+        // Check if app exists
225
+        $this->getAppPath($appId);
226
+
227
+        $this->installedAppsCache[$appId] = 'yes';
228
+        $this->appConfig->setValue($appId, 'enabled', 'yes');
229
+        $this->dispatcher->dispatch(ManagerEvent::EVENT_APP_ENABLE, new ManagerEvent(
230
+            ManagerEvent::EVENT_APP_ENABLE, $appId
231
+        ));
232
+        $this->clearAppsCache();
233
+    }
234
+
235
+    /**
236
+     * Whether a list of types contains a protected app type
237
+     *
238
+     * @param string[] $types
239
+     * @return bool
240
+     */
241
+    public function hasProtectedAppType($types) {
242
+        if (empty($types)) {
243
+            return false;
244
+        }
245
+
246
+        $protectedTypes = array_intersect($this->protectedAppTypes, $types);
247
+        return !empty($protectedTypes);
248
+    }
249
+
250
+    /**
251
+     * Enable an app only for specific groups
252
+     *
253
+     * @param string $appId
254
+     * @param \OCP\IGroup[] $groups
255
+     * @throws \Exception if app can't be enabled for groups
256
+     */
257
+    public function enableAppForGroups($appId, $groups) {
258
+        $info = $this->getAppInfo($appId);
259
+        if (!empty($info['types'])) {
260
+            $protectedTypes = array_intersect($this->protectedAppTypes, $info['types']);
261
+            if (!empty($protectedTypes)) {
262
+                throw new \Exception("$appId can't be enabled for groups.");
263
+            }
264
+        }
265
+
266
+        $groupIds = array_map(function ($group) {
267
+            /** @var \OCP\IGroup $group */
268
+            return $group->getGID();
269
+        }, $groups);
270
+        $this->installedAppsCache[$appId] = json_encode($groupIds);
271
+        $this->appConfig->setValue($appId, 'enabled', json_encode($groupIds));
272
+        $this->dispatcher->dispatch(ManagerEvent::EVENT_APP_ENABLE_FOR_GROUPS, new ManagerEvent(
273
+            ManagerEvent::EVENT_APP_ENABLE_FOR_GROUPS, $appId, $groups
274
+        ));
275
+        $this->clearAppsCache();
276
+    }
277
+
278
+    /**
279
+     * Disable an app for every user
280
+     *
281
+     * @param string $appId
282
+     * @throws \Exception if app can't be disabled
283
+     */
284
+    public function disableApp($appId) {
285
+        if ($this->isAlwaysEnabled($appId)) {
286
+            throw new \Exception("$appId can't be disabled.");
287
+        }
288
+        unset($this->installedAppsCache[$appId]);
289
+        $this->appConfig->setValue($appId, 'enabled', 'no');
290
+        $this->dispatcher->dispatch(ManagerEvent::EVENT_APP_DISABLE, new ManagerEvent(
291
+            ManagerEvent::EVENT_APP_DISABLE, $appId
292
+        ));
293
+        $this->clearAppsCache();
294
+    }
295
+
296
+    /**
297
+     * Get the directory for the given app.
298
+     *
299
+     * @param string $appId
300
+     * @return string
301
+     * @throws AppPathNotFoundException if app folder can't be found
302
+     */
303
+    public function getAppPath($appId) {
304
+        $appPath = \OC_App::getAppPath($appId);
305
+        if($appPath === false) {
306
+            throw new AppPathNotFoundException('Could not find path for ' . $appId);
307
+        }
308
+        return $appPath;
309
+    }
310
+
311
+    /**
312
+     * Clear the cached list of apps when enabling/disabling an app
313
+     */
314
+    public function clearAppsCache() {
315
+        $settingsMemCache = $this->memCacheFactory->createDistributed('settings');
316
+        $settingsMemCache->clear('listApps');
317
+    }
318
+
319
+    /**
320
+     * Returns a list of apps that need upgrade
321
+     *
322
+     * @param string $version Nextcloud version as array of version components
323
+     * @return array list of app info from apps that need an upgrade
324
+     *
325
+     * @internal
326
+     */
327
+    public function getAppsNeedingUpgrade($version) {
328
+        $appsToUpgrade = [];
329
+        $apps = $this->getInstalledApps();
330
+        foreach ($apps as $appId) {
331
+            $appInfo = $this->getAppInfo($appId);
332
+            $appDbVersion = $this->appConfig->getValue($appId, 'installed_version');
333
+            if ($appDbVersion
334
+                && isset($appInfo['version'])
335
+                && version_compare($appInfo['version'], $appDbVersion, '>')
336
+                && \OC_App::isAppCompatible($version, $appInfo)
337
+            ) {
338
+                $appsToUpgrade[] = $appInfo;
339
+            }
340
+        }
341
+
342
+        return $appsToUpgrade;
343
+    }
344
+
345
+    /**
346
+     * Returns the app information from "appinfo/info.xml".
347
+     *
348
+     * @param string $appId app id
349
+     *
350
+     * @param bool $path
351
+     * @param null $lang
352
+     * @return array app info
353
+     */
354
+    public function getAppInfo(string $appId, bool $path = false, $lang = null) {
355
+        if ($path) {
356
+            $file = $appId;
357
+        } else {
358
+            if ($lang === null && isset($this->appInfos[$appId])) {
359
+                return $this->appInfos[$appId];
360
+            }
361
+            try {
362
+                $appPath = $this->getAppPath($appId);
363
+            } catch (AppPathNotFoundException $e) {
364
+                return null;
365
+            }
366
+            $file = $appPath . '/appinfo/info.xml';
367
+        }
368
+
369
+        $parser = new InfoParser($this->memCacheFactory->createLocal('core.appinfo'));
370
+        $data = $parser->parse($file);
371
+
372
+        if (is_array($data)) {
373
+            $data = \OC_App::parseAppInfo($data, $lang);
374
+        }
375
+
376
+        if ($lang === null) {
377
+            $this->appInfos[$appId] = $data;
378
+        }
379
+
380
+        return $data;
381
+    }
382
+
383
+    public function getAppVersion(string $appId, bool $useCache = true) {
384
+        if(!$useCache || !isset($this->appVersions[$appId])) {
385
+            $appInfo = \OC::$server->getAppManager()->getAppInfo($appId);
386
+            $this->appVersions[$appId] = ($appInfo !== null) ? $appInfo['version'] : '0';
387
+        }
388
+        return $this->appVersions[$appId];
389
+    }
390
+
391
+    /**
392
+     * Returns a list of apps incompatible with the given version
393
+     *
394
+     * @param string $version Nextcloud version as array of version components
395
+     *
396
+     * @return array list of app info from incompatible apps
397
+     *
398
+     * @internal
399
+     */
400
+    public function getIncompatibleApps($version) {
401
+        $apps = $this->getInstalledApps();
402
+        $incompatibleApps = array();
403
+        foreach ($apps as $appId) {
404
+            $info = $this->getAppInfo($appId);
405
+            if (!\OC_App::isAppCompatible($version, $info)) {
406
+                $incompatibleApps[] = $info;
407
+            }
408
+        }
409
+        return $incompatibleApps;
410
+    }
411
+
412
+    /**
413
+     * @inheritdoc
414
+     */
415
+    public function isShipped($appId) {
416
+        $this->loadShippedJson();
417
+        return in_array($appId, $this->shippedApps, true);
418
+    }
419
+
420
+    private function isAlwaysEnabled($appId) {
421
+        $alwaysEnabled = $this->getAlwaysEnabledApps();
422
+        return in_array($appId, $alwaysEnabled, true);
423
+    }
424
+
425
+    private function loadShippedJson() {
426
+        if ($this->shippedApps === null) {
427
+            $shippedJson = \OC::$SERVERROOT . '/core/shipped.json';
428
+            if (!file_exists($shippedJson)) {
429
+                throw new \Exception("File not found: $shippedJson");
430
+            }
431
+            $content = json_decode(file_get_contents($shippedJson), true);
432
+            $this->shippedApps = $content['shippedApps'];
433
+            $this->alwaysEnabled = $content['alwaysEnabled'];
434
+        }
435
+    }
436
+
437
+    /**
438
+     * @inheritdoc
439
+     */
440
+    public function getAlwaysEnabledApps() {
441
+        $this->loadShippedJson();
442
+        return $this->alwaysEnabled;
443
+    }
444 444
 }
Please login to merge, or discard this patch.
lib/private/Installer.php 2 patches
Indentation   +568 added lines, -568 removed lines patch added patch discarded remove patch
@@ -57,572 +57,572 @@
 block discarded – undo
57 57
  * This class provides the functionality needed to install, update and remove apps
58 58
  */
59 59
 class Installer {
60
-	/** @var AppFetcher */
61
-	private $appFetcher;
62
-	/** @var IClientService */
63
-	private $clientService;
64
-	/** @var ITempManager */
65
-	private $tempManager;
66
-	/** @var ILogger */
67
-	private $logger;
68
-	/** @var IConfig */
69
-	private $config;
70
-	/** @var array - for caching the result of app fetcher */
71
-	private $apps = null;
72
-	/** @var bool|null - for caching the result of the ready status */
73
-	private $isInstanceReadyForUpdates = null;
74
-
75
-	/**
76
-	 * @param AppFetcher $appFetcher
77
-	 * @param IClientService $clientService
78
-	 * @param ITempManager $tempManager
79
-	 * @param ILogger $logger
80
-	 * @param IConfig $config
81
-	 */
82
-	public function __construct(AppFetcher $appFetcher,
83
-								IClientService $clientService,
84
-								ITempManager $tempManager,
85
-								ILogger $logger,
86
-								IConfig $config) {
87
-		$this->appFetcher = $appFetcher;
88
-		$this->clientService = $clientService;
89
-		$this->tempManager = $tempManager;
90
-		$this->logger = $logger;
91
-		$this->config = $config;
92
-	}
93
-
94
-	/**
95
-	 * Installs an app that is located in one of the app folders already
96
-	 *
97
-	 * @param string $appId App to install
98
-	 * @throws \Exception
99
-	 * @return string app ID
100
-	 */
101
-	public function installApp($appId) {
102
-		$app = \OC_App::findAppInDirectories($appId);
103
-		if($app === false) {
104
-			throw new \Exception('App not found in any app directory');
105
-		}
106
-
107
-		$basedir = $app['path'].'/'.$appId;
108
-		$info = OC_App::getAppInfo($basedir.'/appinfo/info.xml', true);
109
-
110
-		$l = \OC::$server->getL10N('core');
111
-
112
-		if(!is_array($info)) {
113
-			throw new \Exception(
114
-				$l->t('App "%s" cannot be installed because appinfo file cannot be read.',
115
-					[$info['name']]
116
-				)
117
-			);
118
-		}
119
-
120
-		$version = \OCP\Util::getVersion();
121
-		if (!\OC_App::isAppCompatible($version, $info)) {
122
-			throw new \Exception(
123
-				// TODO $l
124
-				$l->t('App "%s" cannot be installed because it is not compatible with this version of the server.',
125
-					[$info['name']]
126
-				)
127
-			);
128
-		}
129
-
130
-		// check for required dependencies
131
-		\OC_App::checkAppDependencies($this->config, $l, $info);
132
-		\OC_App::registerAutoloading($appId, $basedir);
133
-
134
-		//install the database
135
-		if(is_file($basedir.'/appinfo/database.xml')) {
136
-			if (\OC::$server->getConfig()->getAppValue($info['id'], 'installed_version') === null) {
137
-				OC_DB::createDbFromStructure($basedir.'/appinfo/database.xml');
138
-			} else {
139
-				OC_DB::updateDbFromStructure($basedir.'/appinfo/database.xml');
140
-			}
141
-		} else {
142
-			$ms = new \OC\DB\MigrationService($info['id'], \OC::$server->getDatabaseConnection());
143
-			$ms->migrate();
144
-		}
145
-
146
-		\OC_App::setupBackgroundJobs($info['background-jobs']);
147
-		if(isset($info['settings']) && is_array($info['settings'])) {
148
-			\OC::$server->getSettingsManager()->setupSettings($info['settings']);
149
-		}
150
-
151
-		//run appinfo/install.php
152
-		if(!isset($data['noinstall']) or $data['noinstall']==false) {
153
-			self::includeAppScript($basedir . '/appinfo/install.php');
154
-		}
155
-
156
-		$appData = OC_App::getAppInfo($appId);
157
-		OC_App::executeRepairSteps($appId, $appData['repair-steps']['install']);
158
-
159
-		//set the installed version
160
-		\OC::$server->getConfig()->setAppValue($info['id'], 'installed_version', OC_App::getAppVersion($info['id'], false));
161
-		\OC::$server->getConfig()->setAppValue($info['id'], 'enabled', 'no');
162
-
163
-		//set remote/public handlers
164
-		foreach($info['remote'] as $name=>$path) {
165
-			\OC::$server->getConfig()->setAppValue('core', 'remote_'.$name, $info['id'].'/'.$path);
166
-		}
167
-		foreach($info['public'] as $name=>$path) {
168
-			\OC::$server->getConfig()->setAppValue('core', 'public_'.$name, $info['id'].'/'.$path);
169
-		}
170
-
171
-		OC_App::setAppTypes($info['id']);
172
-
173
-		return $info['id'];
174
-	}
175
-
176
-	/**
177
-	 * @brief checks whether or not an app is installed
178
-	 * @param string $app app
179
-	 * @returns bool
180
-	 *
181
-	 * Checks whether or not an app is installed, i.e. registered in apps table.
182
-	 */
183
-	public static function isInstalled( $app ) {
184
-		return (\OC::$server->getConfig()->getAppValue($app, "installed_version", null) !== null);
185
-	}
186
-
187
-	/**
188
-	 * Updates the specified app from the appstore
189
-	 *
190
-	 * @param string $appId
191
-	 * @return bool
192
-	 */
193
-	public function updateAppstoreApp($appId) {
194
-		if($this->isUpdateAvailable($appId)) {
195
-			try {
196
-				$this->downloadApp($appId);
197
-			} catch (\Exception $e) {
198
-				$this->logger->logException($e, [
199
-					'level' => \OCP\Util::ERROR,
200
-					'app' => 'core',
201
-				]);
202
-				return false;
203
-			}
204
-			return OC_App::updateApp($appId);
205
-		}
206
-
207
-		return false;
208
-	}
209
-
210
-	/**
211
-	 * Downloads an app and puts it into the app directory
212
-	 *
213
-	 * @param string $appId
214
-	 *
215
-	 * @throws \Exception If the installation was not successful
216
-	 */
217
-	public function downloadApp($appId) {
218
-		$appId = strtolower($appId);
219
-
220
-		$apps = $this->appFetcher->get();
221
-		foreach($apps as $app) {
222
-			if($app['id'] === $appId) {
223
-				// Load the certificate
224
-				$certificate = new X509();
225
-				$certificate->loadCA(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crt'));
226
-				$loadedCertificate = $certificate->loadX509($app['certificate']);
227
-
228
-				// Verify if the certificate has been revoked
229
-				$crl = new X509();
230
-				$crl->loadCA(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crt'));
231
-				$crl->loadCRL(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crl'));
232
-				if($crl->validateSignature() !== true) {
233
-					throw new \Exception('Could not validate CRL signature');
234
-				}
235
-				$csn = $loadedCertificate['tbsCertificate']['serialNumber']->toString();
236
-				$revoked = $crl->getRevoked($csn);
237
-				if ($revoked !== false) {
238
-					throw new \Exception(
239
-						sprintf(
240
-							'Certificate "%s" has been revoked',
241
-							$csn
242
-						)
243
-					);
244
-				}
245
-
246
-				// Verify if the certificate has been issued by the Nextcloud Code Authority CA
247
-				if($certificate->validateSignature() !== true) {
248
-					throw new \Exception(
249
-						sprintf(
250
-							'App with id %s has a certificate not issued by a trusted Code Signing Authority',
251
-							$appId
252
-						)
253
-					);
254
-				}
255
-
256
-				// Verify if the certificate is issued for the requested app id
257
-				$certInfo = openssl_x509_parse($app['certificate']);
258
-				if(!isset($certInfo['subject']['CN'])) {
259
-					throw new \Exception(
260
-						sprintf(
261
-							'App with id %s has a cert with no CN',
262
-							$appId
263
-						)
264
-					);
265
-				}
266
-				if($certInfo['subject']['CN'] !== $appId) {
267
-					throw new \Exception(
268
-						sprintf(
269
-							'App with id %s has a cert issued to %s',
270
-							$appId,
271
-							$certInfo['subject']['CN']
272
-						)
273
-					);
274
-				}
275
-
276
-				// Download the release
277
-				$tempFile = $this->tempManager->getTemporaryFile('.tar.gz');
278
-				$client = $this->clientService->newClient();
279
-				$client->get($app['releases'][0]['download'], ['save_to' => $tempFile]);
280
-
281
-				// Check if the signature actually matches the downloaded content
282
-				$certificate = openssl_get_publickey($app['certificate']);
283
-				$verified = (bool)openssl_verify(file_get_contents($tempFile), base64_decode($app['releases'][0]['signature']), $certificate, OPENSSL_ALGO_SHA512);
284
-				openssl_free_key($certificate);
285
-
286
-				if($verified === true) {
287
-					// Seems to match, let's proceed
288
-					$extractDir = $this->tempManager->getTemporaryFolder();
289
-					$archive = new TAR($tempFile);
290
-
291
-					if($archive) {
292
-						if (!$archive->extract($extractDir)) {
293
-							throw new \Exception(
294
-								sprintf(
295
-									'Could not extract app %s',
296
-									$appId
297
-								)
298
-							);
299
-						}
300
-						$allFiles = scandir($extractDir);
301
-						$folders = array_diff($allFiles, ['.', '..']);
302
-						$folders = array_values($folders);
303
-
304
-						if(count($folders) > 1) {
305
-							throw new \Exception(
306
-								sprintf(
307
-									'Extracted app %s has more than 1 folder',
308
-									$appId
309
-								)
310
-							);
311
-						}
312
-
313
-						// Check if appinfo/info.xml has the same app ID as well
314
-						$loadEntities = libxml_disable_entity_loader(false);
315
-						$xml = simplexml_load_file($extractDir . '/' . $folders[0] . '/appinfo/info.xml');
316
-						libxml_disable_entity_loader($loadEntities);
317
-						if((string)$xml->id !== $appId) {
318
-							throw new \Exception(
319
-								sprintf(
320
-									'App for id %s has a wrong app ID in info.xml: %s',
321
-									$appId,
322
-									(string)$xml->id
323
-								)
324
-							);
325
-						}
326
-
327
-						// Check if the version is lower than before
328
-						$currentVersion = OC_App::getAppVersion($appId);
329
-						$newVersion = (string)$xml->version;
330
-						if(version_compare($currentVersion, $newVersion) === 1) {
331
-							throw new \Exception(
332
-								sprintf(
333
-									'App for id %s has version %s and tried to update to lower version %s',
334
-									$appId,
335
-									$currentVersion,
336
-									$newVersion
337
-								)
338
-							);
339
-						}
340
-
341
-						$baseDir = OC_App::getInstallPath() . '/' . $appId;
342
-						// Remove old app with the ID if existent
343
-						OC_Helper::rmdirr($baseDir);
344
-						// Move to app folder
345
-						if(@mkdir($baseDir)) {
346
-							$extractDir .= '/' . $folders[0];
347
-							OC_Helper::copyr($extractDir, $baseDir);
348
-						}
349
-						OC_Helper::copyr($extractDir, $baseDir);
350
-						OC_Helper::rmdirr($extractDir);
351
-						return;
352
-					} else {
353
-						throw new \Exception(
354
-							sprintf(
355
-								'Could not extract app with ID %s to %s',
356
-								$appId,
357
-								$extractDir
358
-							)
359
-						);
360
-					}
361
-				} else {
362
-					// Signature does not match
363
-					throw new \Exception(
364
-						sprintf(
365
-							'App with id %s has invalid signature',
366
-							$appId
367
-						)
368
-					);
369
-				}
370
-			}
371
-		}
372
-
373
-		throw new \Exception(
374
-			sprintf(
375
-				'Could not download app %s',
376
-				$appId
377
-			)
378
-		);
379
-	}
380
-
381
-	/**
382
-	 * Check if an update for the app is available
383
-	 *
384
-	 * @param string $appId
385
-	 * @return string|false false or the version number of the update
386
-	 */
387
-	public function isUpdateAvailable($appId) {
388
-		if ($this->isInstanceReadyForUpdates === null) {
389
-			$installPath = OC_App::getInstallPath();
390
-			if ($installPath === false || $installPath === null) {
391
-				$this->isInstanceReadyForUpdates = false;
392
-			} else {
393
-				$this->isInstanceReadyForUpdates = true;
394
-			}
395
-		}
396
-
397
-		if ($this->isInstanceReadyForUpdates === false) {
398
-			return false;
399
-		}
400
-
401
-		if ($this->isInstalledFromGit($appId) === true) {
402
-			return false;
403
-		}
404
-
405
-		if ($this->apps === null) {
406
-			$this->apps = $this->appFetcher->get();
407
-		}
408
-
409
-		foreach($this->apps as $app) {
410
-			if($app['id'] === $appId) {
411
-				$currentVersion = OC_App::getAppVersion($appId);
412
-				$newestVersion = $app['releases'][0]['version'];
413
-				if (version_compare($newestVersion, $currentVersion, '>')) {
414
-					return $newestVersion;
415
-				} else {
416
-					return false;
417
-				}
418
-			}
419
-		}
420
-
421
-		return false;
422
-	}
423
-
424
-	/**
425
-	 * Check if app has been installed from git
426
-	 * @param string $name name of the application to remove
427
-	 * @return boolean
428
-	 *
429
-	 * The function will check if the path contains a .git folder
430
-	 */
431
-	private function isInstalledFromGit($appId) {
432
-		$app = \OC_App::findAppInDirectories($appId);
433
-		if($app === false) {
434
-			return false;
435
-		}
436
-		$basedir = $app['path'].'/'.$appId;
437
-		return file_exists($basedir.'/.git/');
438
-	}
439
-
440
-	/**
441
-	 * Check if app is already downloaded
442
-	 * @param string $name name of the application to remove
443
-	 * @return boolean
444
-	 *
445
-	 * The function will check if the app is already downloaded in the apps repository
446
-	 */
447
-	public function isDownloaded($name) {
448
-		foreach(\OC::$APPSROOTS as $dir) {
449
-			$dirToTest  = $dir['path'];
450
-			$dirToTest .= '/';
451
-			$dirToTest .= $name;
452
-			$dirToTest .= '/';
453
-
454
-			if (is_dir($dirToTest)) {
455
-				return true;
456
-			}
457
-		}
458
-
459
-		return false;
460
-	}
461
-
462
-	/**
463
-	 * Removes an app
464
-	 * @param string $appId ID of the application to remove
465
-	 * @return boolean
466
-	 *
467
-	 *
468
-	 * This function works as follows
469
-	 *   -# call uninstall repair steps
470
-	 *   -# removing the files
471
-	 *
472
-	 * The function will not delete preferences, tables and the configuration,
473
-	 * this has to be done by the function oc_app_uninstall().
474
-	 */
475
-	public function removeApp($appId) {
476
-		if($this->isDownloaded( $appId )) {
477
-			if (\OC::$server->getAppManager()->isShipped($appId)) {
478
-				return false;
479
-			}
480
-			$appDir = OC_App::getInstallPath() . '/' . $appId;
481
-			OC_Helper::rmdirr($appDir);
482
-			return true;
483
-		}else{
484
-			\OCP\Util::writeLog('core', 'can\'t remove app '.$appId.'. It is not installed.', \OCP\Util::ERROR);
485
-
486
-			return false;
487
-		}
488
-
489
-	}
490
-
491
-	/**
492
-	 * Installs the app within the bundle and marks the bundle as installed
493
-	 *
494
-	 * @param Bundle $bundle
495
-	 * @throws \Exception If app could not get installed
496
-	 */
497
-	public function installAppBundle(Bundle $bundle) {
498
-		$appIds = $bundle->getAppIdentifiers();
499
-		foreach($appIds as $appId) {
500
-			if(!$this->isDownloaded($appId)) {
501
-				$this->downloadApp($appId);
502
-			}
503
-			$this->installApp($appId);
504
-			$app = new OC_App();
505
-			$app->enable($appId);
506
-		}
507
-		$bundles = json_decode($this->config->getAppValue('core', 'installed.bundles', json_encode([])), true);
508
-		$bundles[] = $bundle->getIdentifier();
509
-		$this->config->setAppValue('core', 'installed.bundles', json_encode($bundles));
510
-	}
511
-
512
-	/**
513
-	 * Installs shipped apps
514
-	 *
515
-	 * This function installs all apps found in the 'apps' directory that should be enabled by default;
516
-	 * @param bool $softErrors When updating we ignore errors and simply log them, better to have a
517
-	 *                         working ownCloud at the end instead of an aborted update.
518
-	 * @return array Array of error messages (appid => Exception)
519
-	 */
520
-	public static function installShippedApps($softErrors = false) {
521
-		$errors = [];
522
-		foreach(\OC::$APPSROOTS as $app_dir) {
523
-			if($dir = opendir( $app_dir['path'] )) {
524
-				while( false !== ( $filename = readdir( $dir ))) {
525
-					if( $filename[0] !== '.' and is_dir($app_dir['path']."/$filename") ) {
526
-						if( file_exists( $app_dir['path']."/$filename/appinfo/info.xml" )) {
527
-							if(!Installer::isInstalled($filename)) {
528
-								$info=OC_App::getAppInfo($filename);
529
-								$enabled = isset($info['default_enable']);
530
-								if (($enabled || in_array($filename, \OC::$server->getAppManager()->getAlwaysEnabledApps()))
531
-									  && \OC::$server->getConfig()->getAppValue($filename, 'enabled') !== 'no') {
532
-									if ($softErrors) {
533
-										try {
534
-											Installer::installShippedApp($filename);
535
-										} catch (HintException $e) {
536
-											if ($e->getPrevious() instanceof TableExistsException) {
537
-												$errors[$filename] = $e;
538
-												continue;
539
-											}
540
-											throw $e;
541
-										}
542
-									} else {
543
-										Installer::installShippedApp($filename);
544
-									}
545
-									\OC::$server->getConfig()->setAppValue($filename, 'enabled', 'yes');
546
-								}
547
-							}
548
-						}
549
-					}
550
-				}
551
-				closedir( $dir );
552
-			}
553
-		}
554
-
555
-		return $errors;
556
-	}
557
-
558
-	/**
559
-	 * install an app already placed in the app folder
560
-	 * @param string $app id of the app to install
561
-	 * @return integer
562
-	 */
563
-	public static function installShippedApp($app) {
564
-		//install the database
565
-		$appPath = OC_App::getAppPath($app);
566
-		\OC_App::registerAutoloading($app, $appPath);
567
-
568
-		if(is_file("$appPath/appinfo/database.xml")) {
569
-			try {
570
-				OC_DB::createDbFromStructure("$appPath/appinfo/database.xml");
571
-			} catch (TableExistsException $e) {
572
-				throw new HintException(
573
-					'Failed to enable app ' . $app,
574
-					'Please ask for help via one of our <a href="https://nextcloud.com/support/" target="_blank" rel="noreferrer noopener">support channels</a>.',
575
-					0, $e
576
-				);
577
-			}
578
-		} else {
579
-			$ms = new \OC\DB\MigrationService($app, \OC::$server->getDatabaseConnection());
580
-			$ms->migrate();
581
-		}
582
-
583
-		//run appinfo/install.php
584
-		self::includeAppScript("$appPath/appinfo/install.php");
585
-
586
-		$info = OC_App::getAppInfo($app);
587
-		if (is_null($info)) {
588
-			return false;
589
-		}
590
-		\OC_App::setupBackgroundJobs($info['background-jobs']);
591
-
592
-		OC_App::executeRepairSteps($app, $info['repair-steps']['install']);
593
-
594
-		$config = \OC::$server->getConfig();
595
-
596
-		$config->setAppValue($app, 'installed_version', OC_App::getAppVersion($app));
597
-		if (array_key_exists('ocsid', $info)) {
598
-			$config->setAppValue($app, 'ocsid', $info['ocsid']);
599
-		}
600
-
601
-		//set remote/public handlers
602
-		foreach($info['remote'] as $name=>$path) {
603
-			$config->setAppValue('core', 'remote_'.$name, $app.'/'.$path);
604
-		}
605
-		foreach($info['public'] as $name=>$path) {
606
-			$config->setAppValue('core', 'public_'.$name, $app.'/'.$path);
607
-		}
608
-
609
-		OC_App::setAppTypes($info['id']);
610
-
611
-		if(isset($info['settings']) && is_array($info['settings'])) {
612
-			// requires that autoloading was registered for the app,
613
-			// as happens before running the install.php some lines above
614
-			\OC::$server->getSettingsManager()->setupSettings($info['settings']);
615
-		}
616
-
617
-		return $info['id'];
618
-	}
619
-
620
-	/**
621
-	 * @param string $script
622
-	 */
623
-	private static function includeAppScript($script) {
624
-		if ( file_exists($script) ){
625
-			include $script;
626
-		}
627
-	}
60
+    /** @var AppFetcher */
61
+    private $appFetcher;
62
+    /** @var IClientService */
63
+    private $clientService;
64
+    /** @var ITempManager */
65
+    private $tempManager;
66
+    /** @var ILogger */
67
+    private $logger;
68
+    /** @var IConfig */
69
+    private $config;
70
+    /** @var array - for caching the result of app fetcher */
71
+    private $apps = null;
72
+    /** @var bool|null - for caching the result of the ready status */
73
+    private $isInstanceReadyForUpdates = null;
74
+
75
+    /**
76
+     * @param AppFetcher $appFetcher
77
+     * @param IClientService $clientService
78
+     * @param ITempManager $tempManager
79
+     * @param ILogger $logger
80
+     * @param IConfig $config
81
+     */
82
+    public function __construct(AppFetcher $appFetcher,
83
+                                IClientService $clientService,
84
+                                ITempManager $tempManager,
85
+                                ILogger $logger,
86
+                                IConfig $config) {
87
+        $this->appFetcher = $appFetcher;
88
+        $this->clientService = $clientService;
89
+        $this->tempManager = $tempManager;
90
+        $this->logger = $logger;
91
+        $this->config = $config;
92
+    }
93
+
94
+    /**
95
+     * Installs an app that is located in one of the app folders already
96
+     *
97
+     * @param string $appId App to install
98
+     * @throws \Exception
99
+     * @return string app ID
100
+     */
101
+    public function installApp($appId) {
102
+        $app = \OC_App::findAppInDirectories($appId);
103
+        if($app === false) {
104
+            throw new \Exception('App not found in any app directory');
105
+        }
106
+
107
+        $basedir = $app['path'].'/'.$appId;
108
+        $info = OC_App::getAppInfo($basedir.'/appinfo/info.xml', true);
109
+
110
+        $l = \OC::$server->getL10N('core');
111
+
112
+        if(!is_array($info)) {
113
+            throw new \Exception(
114
+                $l->t('App "%s" cannot be installed because appinfo file cannot be read.',
115
+                    [$info['name']]
116
+                )
117
+            );
118
+        }
119
+
120
+        $version = \OCP\Util::getVersion();
121
+        if (!\OC_App::isAppCompatible($version, $info)) {
122
+            throw new \Exception(
123
+                // TODO $l
124
+                $l->t('App "%s" cannot be installed because it is not compatible with this version of the server.',
125
+                    [$info['name']]
126
+                )
127
+            );
128
+        }
129
+
130
+        // check for required dependencies
131
+        \OC_App::checkAppDependencies($this->config, $l, $info);
132
+        \OC_App::registerAutoloading($appId, $basedir);
133
+
134
+        //install the database
135
+        if(is_file($basedir.'/appinfo/database.xml')) {
136
+            if (\OC::$server->getConfig()->getAppValue($info['id'], 'installed_version') === null) {
137
+                OC_DB::createDbFromStructure($basedir.'/appinfo/database.xml');
138
+            } else {
139
+                OC_DB::updateDbFromStructure($basedir.'/appinfo/database.xml');
140
+            }
141
+        } else {
142
+            $ms = new \OC\DB\MigrationService($info['id'], \OC::$server->getDatabaseConnection());
143
+            $ms->migrate();
144
+        }
145
+
146
+        \OC_App::setupBackgroundJobs($info['background-jobs']);
147
+        if(isset($info['settings']) && is_array($info['settings'])) {
148
+            \OC::$server->getSettingsManager()->setupSettings($info['settings']);
149
+        }
150
+
151
+        //run appinfo/install.php
152
+        if(!isset($data['noinstall']) or $data['noinstall']==false) {
153
+            self::includeAppScript($basedir . '/appinfo/install.php');
154
+        }
155
+
156
+        $appData = OC_App::getAppInfo($appId);
157
+        OC_App::executeRepairSteps($appId, $appData['repair-steps']['install']);
158
+
159
+        //set the installed version
160
+        \OC::$server->getConfig()->setAppValue($info['id'], 'installed_version', OC_App::getAppVersion($info['id'], false));
161
+        \OC::$server->getConfig()->setAppValue($info['id'], 'enabled', 'no');
162
+
163
+        //set remote/public handlers
164
+        foreach($info['remote'] as $name=>$path) {
165
+            \OC::$server->getConfig()->setAppValue('core', 'remote_'.$name, $info['id'].'/'.$path);
166
+        }
167
+        foreach($info['public'] as $name=>$path) {
168
+            \OC::$server->getConfig()->setAppValue('core', 'public_'.$name, $info['id'].'/'.$path);
169
+        }
170
+
171
+        OC_App::setAppTypes($info['id']);
172
+
173
+        return $info['id'];
174
+    }
175
+
176
+    /**
177
+     * @brief checks whether or not an app is installed
178
+     * @param string $app app
179
+     * @returns bool
180
+     *
181
+     * Checks whether or not an app is installed, i.e. registered in apps table.
182
+     */
183
+    public static function isInstalled( $app ) {
184
+        return (\OC::$server->getConfig()->getAppValue($app, "installed_version", null) !== null);
185
+    }
186
+
187
+    /**
188
+     * Updates the specified app from the appstore
189
+     *
190
+     * @param string $appId
191
+     * @return bool
192
+     */
193
+    public function updateAppstoreApp($appId) {
194
+        if($this->isUpdateAvailable($appId)) {
195
+            try {
196
+                $this->downloadApp($appId);
197
+            } catch (\Exception $e) {
198
+                $this->logger->logException($e, [
199
+                    'level' => \OCP\Util::ERROR,
200
+                    'app' => 'core',
201
+                ]);
202
+                return false;
203
+            }
204
+            return OC_App::updateApp($appId);
205
+        }
206
+
207
+        return false;
208
+    }
209
+
210
+    /**
211
+     * Downloads an app and puts it into the app directory
212
+     *
213
+     * @param string $appId
214
+     *
215
+     * @throws \Exception If the installation was not successful
216
+     */
217
+    public function downloadApp($appId) {
218
+        $appId = strtolower($appId);
219
+
220
+        $apps = $this->appFetcher->get();
221
+        foreach($apps as $app) {
222
+            if($app['id'] === $appId) {
223
+                // Load the certificate
224
+                $certificate = new X509();
225
+                $certificate->loadCA(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crt'));
226
+                $loadedCertificate = $certificate->loadX509($app['certificate']);
227
+
228
+                // Verify if the certificate has been revoked
229
+                $crl = new X509();
230
+                $crl->loadCA(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crt'));
231
+                $crl->loadCRL(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crl'));
232
+                if($crl->validateSignature() !== true) {
233
+                    throw new \Exception('Could not validate CRL signature');
234
+                }
235
+                $csn = $loadedCertificate['tbsCertificate']['serialNumber']->toString();
236
+                $revoked = $crl->getRevoked($csn);
237
+                if ($revoked !== false) {
238
+                    throw new \Exception(
239
+                        sprintf(
240
+                            'Certificate "%s" has been revoked',
241
+                            $csn
242
+                        )
243
+                    );
244
+                }
245
+
246
+                // Verify if the certificate has been issued by the Nextcloud Code Authority CA
247
+                if($certificate->validateSignature() !== true) {
248
+                    throw new \Exception(
249
+                        sprintf(
250
+                            'App with id %s has a certificate not issued by a trusted Code Signing Authority',
251
+                            $appId
252
+                        )
253
+                    );
254
+                }
255
+
256
+                // Verify if the certificate is issued for the requested app id
257
+                $certInfo = openssl_x509_parse($app['certificate']);
258
+                if(!isset($certInfo['subject']['CN'])) {
259
+                    throw new \Exception(
260
+                        sprintf(
261
+                            'App with id %s has a cert with no CN',
262
+                            $appId
263
+                        )
264
+                    );
265
+                }
266
+                if($certInfo['subject']['CN'] !== $appId) {
267
+                    throw new \Exception(
268
+                        sprintf(
269
+                            'App with id %s has a cert issued to %s',
270
+                            $appId,
271
+                            $certInfo['subject']['CN']
272
+                        )
273
+                    );
274
+                }
275
+
276
+                // Download the release
277
+                $tempFile = $this->tempManager->getTemporaryFile('.tar.gz');
278
+                $client = $this->clientService->newClient();
279
+                $client->get($app['releases'][0]['download'], ['save_to' => $tempFile]);
280
+
281
+                // Check if the signature actually matches the downloaded content
282
+                $certificate = openssl_get_publickey($app['certificate']);
283
+                $verified = (bool)openssl_verify(file_get_contents($tempFile), base64_decode($app['releases'][0]['signature']), $certificate, OPENSSL_ALGO_SHA512);
284
+                openssl_free_key($certificate);
285
+
286
+                if($verified === true) {
287
+                    // Seems to match, let's proceed
288
+                    $extractDir = $this->tempManager->getTemporaryFolder();
289
+                    $archive = new TAR($tempFile);
290
+
291
+                    if($archive) {
292
+                        if (!$archive->extract($extractDir)) {
293
+                            throw new \Exception(
294
+                                sprintf(
295
+                                    'Could not extract app %s',
296
+                                    $appId
297
+                                )
298
+                            );
299
+                        }
300
+                        $allFiles = scandir($extractDir);
301
+                        $folders = array_diff($allFiles, ['.', '..']);
302
+                        $folders = array_values($folders);
303
+
304
+                        if(count($folders) > 1) {
305
+                            throw new \Exception(
306
+                                sprintf(
307
+                                    'Extracted app %s has more than 1 folder',
308
+                                    $appId
309
+                                )
310
+                            );
311
+                        }
312
+
313
+                        // Check if appinfo/info.xml has the same app ID as well
314
+                        $loadEntities = libxml_disable_entity_loader(false);
315
+                        $xml = simplexml_load_file($extractDir . '/' . $folders[0] . '/appinfo/info.xml');
316
+                        libxml_disable_entity_loader($loadEntities);
317
+                        if((string)$xml->id !== $appId) {
318
+                            throw new \Exception(
319
+                                sprintf(
320
+                                    'App for id %s has a wrong app ID in info.xml: %s',
321
+                                    $appId,
322
+                                    (string)$xml->id
323
+                                )
324
+                            );
325
+                        }
326
+
327
+                        // Check if the version is lower than before
328
+                        $currentVersion = OC_App::getAppVersion($appId);
329
+                        $newVersion = (string)$xml->version;
330
+                        if(version_compare($currentVersion, $newVersion) === 1) {
331
+                            throw new \Exception(
332
+                                sprintf(
333
+                                    'App for id %s has version %s and tried to update to lower version %s',
334
+                                    $appId,
335
+                                    $currentVersion,
336
+                                    $newVersion
337
+                                )
338
+                            );
339
+                        }
340
+
341
+                        $baseDir = OC_App::getInstallPath() . '/' . $appId;
342
+                        // Remove old app with the ID if existent
343
+                        OC_Helper::rmdirr($baseDir);
344
+                        // Move to app folder
345
+                        if(@mkdir($baseDir)) {
346
+                            $extractDir .= '/' . $folders[0];
347
+                            OC_Helper::copyr($extractDir, $baseDir);
348
+                        }
349
+                        OC_Helper::copyr($extractDir, $baseDir);
350
+                        OC_Helper::rmdirr($extractDir);
351
+                        return;
352
+                    } else {
353
+                        throw new \Exception(
354
+                            sprintf(
355
+                                'Could not extract app with ID %s to %s',
356
+                                $appId,
357
+                                $extractDir
358
+                            )
359
+                        );
360
+                    }
361
+                } else {
362
+                    // Signature does not match
363
+                    throw new \Exception(
364
+                        sprintf(
365
+                            'App with id %s has invalid signature',
366
+                            $appId
367
+                        )
368
+                    );
369
+                }
370
+            }
371
+        }
372
+
373
+        throw new \Exception(
374
+            sprintf(
375
+                'Could not download app %s',
376
+                $appId
377
+            )
378
+        );
379
+    }
380
+
381
+    /**
382
+     * Check if an update for the app is available
383
+     *
384
+     * @param string $appId
385
+     * @return string|false false or the version number of the update
386
+     */
387
+    public function isUpdateAvailable($appId) {
388
+        if ($this->isInstanceReadyForUpdates === null) {
389
+            $installPath = OC_App::getInstallPath();
390
+            if ($installPath === false || $installPath === null) {
391
+                $this->isInstanceReadyForUpdates = false;
392
+            } else {
393
+                $this->isInstanceReadyForUpdates = true;
394
+            }
395
+        }
396
+
397
+        if ($this->isInstanceReadyForUpdates === false) {
398
+            return false;
399
+        }
400
+
401
+        if ($this->isInstalledFromGit($appId) === true) {
402
+            return false;
403
+        }
404
+
405
+        if ($this->apps === null) {
406
+            $this->apps = $this->appFetcher->get();
407
+        }
408
+
409
+        foreach($this->apps as $app) {
410
+            if($app['id'] === $appId) {
411
+                $currentVersion = OC_App::getAppVersion($appId);
412
+                $newestVersion = $app['releases'][0]['version'];
413
+                if (version_compare($newestVersion, $currentVersion, '>')) {
414
+                    return $newestVersion;
415
+                } else {
416
+                    return false;
417
+                }
418
+            }
419
+        }
420
+
421
+        return false;
422
+    }
423
+
424
+    /**
425
+     * Check if app has been installed from git
426
+     * @param string $name name of the application to remove
427
+     * @return boolean
428
+     *
429
+     * The function will check if the path contains a .git folder
430
+     */
431
+    private function isInstalledFromGit($appId) {
432
+        $app = \OC_App::findAppInDirectories($appId);
433
+        if($app === false) {
434
+            return false;
435
+        }
436
+        $basedir = $app['path'].'/'.$appId;
437
+        return file_exists($basedir.'/.git/');
438
+    }
439
+
440
+    /**
441
+     * Check if app is already downloaded
442
+     * @param string $name name of the application to remove
443
+     * @return boolean
444
+     *
445
+     * The function will check if the app is already downloaded in the apps repository
446
+     */
447
+    public function isDownloaded($name) {
448
+        foreach(\OC::$APPSROOTS as $dir) {
449
+            $dirToTest  = $dir['path'];
450
+            $dirToTest .= '/';
451
+            $dirToTest .= $name;
452
+            $dirToTest .= '/';
453
+
454
+            if (is_dir($dirToTest)) {
455
+                return true;
456
+            }
457
+        }
458
+
459
+        return false;
460
+    }
461
+
462
+    /**
463
+     * Removes an app
464
+     * @param string $appId ID of the application to remove
465
+     * @return boolean
466
+     *
467
+     *
468
+     * This function works as follows
469
+     *   -# call uninstall repair steps
470
+     *   -# removing the files
471
+     *
472
+     * The function will not delete preferences, tables and the configuration,
473
+     * this has to be done by the function oc_app_uninstall().
474
+     */
475
+    public function removeApp($appId) {
476
+        if($this->isDownloaded( $appId )) {
477
+            if (\OC::$server->getAppManager()->isShipped($appId)) {
478
+                return false;
479
+            }
480
+            $appDir = OC_App::getInstallPath() . '/' . $appId;
481
+            OC_Helper::rmdirr($appDir);
482
+            return true;
483
+        }else{
484
+            \OCP\Util::writeLog('core', 'can\'t remove app '.$appId.'. It is not installed.', \OCP\Util::ERROR);
485
+
486
+            return false;
487
+        }
488
+
489
+    }
490
+
491
+    /**
492
+     * Installs the app within the bundle and marks the bundle as installed
493
+     *
494
+     * @param Bundle $bundle
495
+     * @throws \Exception If app could not get installed
496
+     */
497
+    public function installAppBundle(Bundle $bundle) {
498
+        $appIds = $bundle->getAppIdentifiers();
499
+        foreach($appIds as $appId) {
500
+            if(!$this->isDownloaded($appId)) {
501
+                $this->downloadApp($appId);
502
+            }
503
+            $this->installApp($appId);
504
+            $app = new OC_App();
505
+            $app->enable($appId);
506
+        }
507
+        $bundles = json_decode($this->config->getAppValue('core', 'installed.bundles', json_encode([])), true);
508
+        $bundles[] = $bundle->getIdentifier();
509
+        $this->config->setAppValue('core', 'installed.bundles', json_encode($bundles));
510
+    }
511
+
512
+    /**
513
+     * Installs shipped apps
514
+     *
515
+     * This function installs all apps found in the 'apps' directory that should be enabled by default;
516
+     * @param bool $softErrors When updating we ignore errors and simply log them, better to have a
517
+     *                         working ownCloud at the end instead of an aborted update.
518
+     * @return array Array of error messages (appid => Exception)
519
+     */
520
+    public static function installShippedApps($softErrors = false) {
521
+        $errors = [];
522
+        foreach(\OC::$APPSROOTS as $app_dir) {
523
+            if($dir = opendir( $app_dir['path'] )) {
524
+                while( false !== ( $filename = readdir( $dir ))) {
525
+                    if( $filename[0] !== '.' and is_dir($app_dir['path']."/$filename") ) {
526
+                        if( file_exists( $app_dir['path']."/$filename/appinfo/info.xml" )) {
527
+                            if(!Installer::isInstalled($filename)) {
528
+                                $info=OC_App::getAppInfo($filename);
529
+                                $enabled = isset($info['default_enable']);
530
+                                if (($enabled || in_array($filename, \OC::$server->getAppManager()->getAlwaysEnabledApps()))
531
+                                      && \OC::$server->getConfig()->getAppValue($filename, 'enabled') !== 'no') {
532
+                                    if ($softErrors) {
533
+                                        try {
534
+                                            Installer::installShippedApp($filename);
535
+                                        } catch (HintException $e) {
536
+                                            if ($e->getPrevious() instanceof TableExistsException) {
537
+                                                $errors[$filename] = $e;
538
+                                                continue;
539
+                                            }
540
+                                            throw $e;
541
+                                        }
542
+                                    } else {
543
+                                        Installer::installShippedApp($filename);
544
+                                    }
545
+                                    \OC::$server->getConfig()->setAppValue($filename, 'enabled', 'yes');
546
+                                }
547
+                            }
548
+                        }
549
+                    }
550
+                }
551
+                closedir( $dir );
552
+            }
553
+        }
554
+
555
+        return $errors;
556
+    }
557
+
558
+    /**
559
+     * install an app already placed in the app folder
560
+     * @param string $app id of the app to install
561
+     * @return integer
562
+     */
563
+    public static function installShippedApp($app) {
564
+        //install the database
565
+        $appPath = OC_App::getAppPath($app);
566
+        \OC_App::registerAutoloading($app, $appPath);
567
+
568
+        if(is_file("$appPath/appinfo/database.xml")) {
569
+            try {
570
+                OC_DB::createDbFromStructure("$appPath/appinfo/database.xml");
571
+            } catch (TableExistsException $e) {
572
+                throw new HintException(
573
+                    'Failed to enable app ' . $app,
574
+                    'Please ask for help via one of our <a href="https://nextcloud.com/support/" target="_blank" rel="noreferrer noopener">support channels</a>.',
575
+                    0, $e
576
+                );
577
+            }
578
+        } else {
579
+            $ms = new \OC\DB\MigrationService($app, \OC::$server->getDatabaseConnection());
580
+            $ms->migrate();
581
+        }
582
+
583
+        //run appinfo/install.php
584
+        self::includeAppScript("$appPath/appinfo/install.php");
585
+
586
+        $info = OC_App::getAppInfo($app);
587
+        if (is_null($info)) {
588
+            return false;
589
+        }
590
+        \OC_App::setupBackgroundJobs($info['background-jobs']);
591
+
592
+        OC_App::executeRepairSteps($app, $info['repair-steps']['install']);
593
+
594
+        $config = \OC::$server->getConfig();
595
+
596
+        $config->setAppValue($app, 'installed_version', OC_App::getAppVersion($app));
597
+        if (array_key_exists('ocsid', $info)) {
598
+            $config->setAppValue($app, 'ocsid', $info['ocsid']);
599
+        }
600
+
601
+        //set remote/public handlers
602
+        foreach($info['remote'] as $name=>$path) {
603
+            $config->setAppValue('core', 'remote_'.$name, $app.'/'.$path);
604
+        }
605
+        foreach($info['public'] as $name=>$path) {
606
+            $config->setAppValue('core', 'public_'.$name, $app.'/'.$path);
607
+        }
608
+
609
+        OC_App::setAppTypes($info['id']);
610
+
611
+        if(isset($info['settings']) && is_array($info['settings'])) {
612
+            // requires that autoloading was registered for the app,
613
+            // as happens before running the install.php some lines above
614
+            \OC::$server->getSettingsManager()->setupSettings($info['settings']);
615
+        }
616
+
617
+        return $info['id'];
618
+    }
619
+
620
+    /**
621
+     * @param string $script
622
+     */
623
+    private static function includeAppScript($script) {
624
+        if ( file_exists($script) ){
625
+            include $script;
626
+        }
627
+    }
628 628
 }
Please login to merge, or discard this patch.
Spacing   +54 added lines, -54 removed lines patch added patch discarded remove patch
@@ -100,7 +100,7 @@  discard block
 block discarded – undo
100 100
 	 */
101 101
 	public function installApp($appId) {
102 102
 		$app = \OC_App::findAppInDirectories($appId);
103
-		if($app === false) {
103
+		if ($app === false) {
104 104
 			throw new \Exception('App not found in any app directory');
105 105
 		}
106 106
 
@@ -109,7 +109,7 @@  discard block
 block discarded – undo
109 109
 
110 110
 		$l = \OC::$server->getL10N('core');
111 111
 
112
-		if(!is_array($info)) {
112
+		if (!is_array($info)) {
113 113
 			throw new \Exception(
114 114
 				$l->t('App "%s" cannot be installed because appinfo file cannot be read.',
115 115
 					[$info['name']]
@@ -132,7 +132,7 @@  discard block
 block discarded – undo
132 132
 		\OC_App::registerAutoloading($appId, $basedir);
133 133
 
134 134
 		//install the database
135
-		if(is_file($basedir.'/appinfo/database.xml')) {
135
+		if (is_file($basedir.'/appinfo/database.xml')) {
136 136
 			if (\OC::$server->getConfig()->getAppValue($info['id'], 'installed_version') === null) {
137 137
 				OC_DB::createDbFromStructure($basedir.'/appinfo/database.xml');
138 138
 			} else {
@@ -144,13 +144,13 @@  discard block
 block discarded – undo
144 144
 		}
145 145
 
146 146
 		\OC_App::setupBackgroundJobs($info['background-jobs']);
147
-		if(isset($info['settings']) && is_array($info['settings'])) {
147
+		if (isset($info['settings']) && is_array($info['settings'])) {
148 148
 			\OC::$server->getSettingsManager()->setupSettings($info['settings']);
149 149
 		}
150 150
 
151 151
 		//run appinfo/install.php
152
-		if(!isset($data['noinstall']) or $data['noinstall']==false) {
153
-			self::includeAppScript($basedir . '/appinfo/install.php');
152
+		if (!isset($data['noinstall']) or $data['noinstall'] == false) {
153
+			self::includeAppScript($basedir.'/appinfo/install.php');
154 154
 		}
155 155
 
156 156
 		$appData = OC_App::getAppInfo($appId);
@@ -161,10 +161,10 @@  discard block
 block discarded – undo
161 161
 		\OC::$server->getConfig()->setAppValue($info['id'], 'enabled', 'no');
162 162
 
163 163
 		//set remote/public handlers
164
-		foreach($info['remote'] as $name=>$path) {
164
+		foreach ($info['remote'] as $name=>$path) {
165 165
 			\OC::$server->getConfig()->setAppValue('core', 'remote_'.$name, $info['id'].'/'.$path);
166 166
 		}
167
-		foreach($info['public'] as $name=>$path) {
167
+		foreach ($info['public'] as $name=>$path) {
168 168
 			\OC::$server->getConfig()->setAppValue('core', 'public_'.$name, $info['id'].'/'.$path);
169 169
 		}
170 170
 
@@ -180,7 +180,7 @@  discard block
 block discarded – undo
180 180
 	 *
181 181
 	 * Checks whether or not an app is installed, i.e. registered in apps table.
182 182
 	 */
183
-	public static function isInstalled( $app ) {
183
+	public static function isInstalled($app) {
184 184
 		return (\OC::$server->getConfig()->getAppValue($app, "installed_version", null) !== null);
185 185
 	}
186 186
 
@@ -191,7 +191,7 @@  discard block
 block discarded – undo
191 191
 	 * @return bool
192 192
 	 */
193 193
 	public function updateAppstoreApp($appId) {
194
-		if($this->isUpdateAvailable($appId)) {
194
+		if ($this->isUpdateAvailable($appId)) {
195 195
 			try {
196 196
 				$this->downloadApp($appId);
197 197
 			} catch (\Exception $e) {
@@ -218,18 +218,18 @@  discard block
 block discarded – undo
218 218
 		$appId = strtolower($appId);
219 219
 
220 220
 		$apps = $this->appFetcher->get();
221
-		foreach($apps as $app) {
222
-			if($app['id'] === $appId) {
221
+		foreach ($apps as $app) {
222
+			if ($app['id'] === $appId) {
223 223
 				// Load the certificate
224 224
 				$certificate = new X509();
225
-				$certificate->loadCA(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crt'));
225
+				$certificate->loadCA(file_get_contents(__DIR__.'/../../resources/codesigning/root.crt'));
226 226
 				$loadedCertificate = $certificate->loadX509($app['certificate']);
227 227
 
228 228
 				// Verify if the certificate has been revoked
229 229
 				$crl = new X509();
230
-				$crl->loadCA(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crt'));
231
-				$crl->loadCRL(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crl'));
232
-				if($crl->validateSignature() !== true) {
230
+				$crl->loadCA(file_get_contents(__DIR__.'/../../resources/codesigning/root.crt'));
231
+				$crl->loadCRL(file_get_contents(__DIR__.'/../../resources/codesigning/root.crl'));
232
+				if ($crl->validateSignature() !== true) {
233 233
 					throw new \Exception('Could not validate CRL signature');
234 234
 				}
235 235
 				$csn = $loadedCertificate['tbsCertificate']['serialNumber']->toString();
@@ -244,7 +244,7 @@  discard block
 block discarded – undo
244 244
 				}
245 245
 
246 246
 				// Verify if the certificate has been issued by the Nextcloud Code Authority CA
247
-				if($certificate->validateSignature() !== true) {
247
+				if ($certificate->validateSignature() !== true) {
248 248
 					throw new \Exception(
249 249
 						sprintf(
250 250
 							'App with id %s has a certificate not issued by a trusted Code Signing Authority',
@@ -255,7 +255,7 @@  discard block
 block discarded – undo
255 255
 
256 256
 				// Verify if the certificate is issued for the requested app id
257 257
 				$certInfo = openssl_x509_parse($app['certificate']);
258
-				if(!isset($certInfo['subject']['CN'])) {
258
+				if (!isset($certInfo['subject']['CN'])) {
259 259
 					throw new \Exception(
260 260
 						sprintf(
261 261
 							'App with id %s has a cert with no CN',
@@ -263,7 +263,7 @@  discard block
 block discarded – undo
263 263
 						)
264 264
 					);
265 265
 				}
266
-				if($certInfo['subject']['CN'] !== $appId) {
266
+				if ($certInfo['subject']['CN'] !== $appId) {
267 267
 					throw new \Exception(
268 268
 						sprintf(
269 269
 							'App with id %s has a cert issued to %s',
@@ -280,15 +280,15 @@  discard block
 block discarded – undo
280 280
 
281 281
 				// Check if the signature actually matches the downloaded content
282 282
 				$certificate = openssl_get_publickey($app['certificate']);
283
-				$verified = (bool)openssl_verify(file_get_contents($tempFile), base64_decode($app['releases'][0]['signature']), $certificate, OPENSSL_ALGO_SHA512);
283
+				$verified = (bool) openssl_verify(file_get_contents($tempFile), base64_decode($app['releases'][0]['signature']), $certificate, OPENSSL_ALGO_SHA512);
284 284
 				openssl_free_key($certificate);
285 285
 
286
-				if($verified === true) {
286
+				if ($verified === true) {
287 287
 					// Seems to match, let's proceed
288 288
 					$extractDir = $this->tempManager->getTemporaryFolder();
289 289
 					$archive = new TAR($tempFile);
290 290
 
291
-					if($archive) {
291
+					if ($archive) {
292 292
 						if (!$archive->extract($extractDir)) {
293 293
 							throw new \Exception(
294 294
 								sprintf(
@@ -301,7 +301,7 @@  discard block
 block discarded – undo
301 301
 						$folders = array_diff($allFiles, ['.', '..']);
302 302
 						$folders = array_values($folders);
303 303
 
304
-						if(count($folders) > 1) {
304
+						if (count($folders) > 1) {
305 305
 							throw new \Exception(
306 306
 								sprintf(
307 307
 									'Extracted app %s has more than 1 folder',
@@ -312,22 +312,22 @@  discard block
 block discarded – undo
312 312
 
313 313
 						// Check if appinfo/info.xml has the same app ID as well
314 314
 						$loadEntities = libxml_disable_entity_loader(false);
315
-						$xml = simplexml_load_file($extractDir . '/' . $folders[0] . '/appinfo/info.xml');
315
+						$xml = simplexml_load_file($extractDir.'/'.$folders[0].'/appinfo/info.xml');
316 316
 						libxml_disable_entity_loader($loadEntities);
317
-						if((string)$xml->id !== $appId) {
317
+						if ((string) $xml->id !== $appId) {
318 318
 							throw new \Exception(
319 319
 								sprintf(
320 320
 									'App for id %s has a wrong app ID in info.xml: %s',
321 321
 									$appId,
322
-									(string)$xml->id
322
+									(string) $xml->id
323 323
 								)
324 324
 							);
325 325
 						}
326 326
 
327 327
 						// Check if the version is lower than before
328 328
 						$currentVersion = OC_App::getAppVersion($appId);
329
-						$newVersion = (string)$xml->version;
330
-						if(version_compare($currentVersion, $newVersion) === 1) {
329
+						$newVersion = (string) $xml->version;
330
+						if (version_compare($currentVersion, $newVersion) === 1) {
331 331
 							throw new \Exception(
332 332
 								sprintf(
333 333
 									'App for id %s has version %s and tried to update to lower version %s',
@@ -338,12 +338,12 @@  discard block
 block discarded – undo
338 338
 							);
339 339
 						}
340 340
 
341
-						$baseDir = OC_App::getInstallPath() . '/' . $appId;
341
+						$baseDir = OC_App::getInstallPath().'/'.$appId;
342 342
 						// Remove old app with the ID if existent
343 343
 						OC_Helper::rmdirr($baseDir);
344 344
 						// Move to app folder
345
-						if(@mkdir($baseDir)) {
346
-							$extractDir .= '/' . $folders[0];
345
+						if (@mkdir($baseDir)) {
346
+							$extractDir .= '/'.$folders[0];
347 347
 							OC_Helper::copyr($extractDir, $baseDir);
348 348
 						}
349 349
 						OC_Helper::copyr($extractDir, $baseDir);
@@ -406,8 +406,8 @@  discard block
 block discarded – undo
406 406
 			$this->apps = $this->appFetcher->get();
407 407
 		}
408 408
 
409
-		foreach($this->apps as $app) {
410
-			if($app['id'] === $appId) {
409
+		foreach ($this->apps as $app) {
410
+			if ($app['id'] === $appId) {
411 411
 				$currentVersion = OC_App::getAppVersion($appId);
412 412
 				$newestVersion = $app['releases'][0]['version'];
413 413
 				if (version_compare($newestVersion, $currentVersion, '>')) {
@@ -430,7 +430,7 @@  discard block
 block discarded – undo
430 430
 	 */
431 431
 	private function isInstalledFromGit($appId) {
432 432
 		$app = \OC_App::findAppInDirectories($appId);
433
-		if($app === false) {
433
+		if ($app === false) {
434 434
 			return false;
435 435
 		}
436 436
 		$basedir = $app['path'].'/'.$appId;
@@ -445,7 +445,7 @@  discard block
 block discarded – undo
445 445
 	 * The function will check if the app is already downloaded in the apps repository
446 446
 	 */
447 447
 	public function isDownloaded($name) {
448
-		foreach(\OC::$APPSROOTS as $dir) {
448
+		foreach (\OC::$APPSROOTS as $dir) {
449 449
 			$dirToTest  = $dir['path'];
450 450
 			$dirToTest .= '/';
451 451
 			$dirToTest .= $name;
@@ -473,14 +473,14 @@  discard block
 block discarded – undo
473 473
 	 * this has to be done by the function oc_app_uninstall().
474 474
 	 */
475 475
 	public function removeApp($appId) {
476
-		if($this->isDownloaded( $appId )) {
476
+		if ($this->isDownloaded($appId)) {
477 477
 			if (\OC::$server->getAppManager()->isShipped($appId)) {
478 478
 				return false;
479 479
 			}
480
-			$appDir = OC_App::getInstallPath() . '/' . $appId;
480
+			$appDir = OC_App::getInstallPath().'/'.$appId;
481 481
 			OC_Helper::rmdirr($appDir);
482 482
 			return true;
483
-		}else{
483
+		} else {
484 484
 			\OCP\Util::writeLog('core', 'can\'t remove app '.$appId.'. It is not installed.', \OCP\Util::ERROR);
485 485
 
486 486
 			return false;
@@ -496,8 +496,8 @@  discard block
 block discarded – undo
496 496
 	 */
497 497
 	public function installAppBundle(Bundle $bundle) {
498 498
 		$appIds = $bundle->getAppIdentifiers();
499
-		foreach($appIds as $appId) {
500
-			if(!$this->isDownloaded($appId)) {
499
+		foreach ($appIds as $appId) {
500
+			if (!$this->isDownloaded($appId)) {
501 501
 				$this->downloadApp($appId);
502 502
 			}
503 503
 			$this->installApp($appId);
@@ -519,13 +519,13 @@  discard block
 block discarded – undo
519 519
 	 */
520 520
 	public static function installShippedApps($softErrors = false) {
521 521
 		$errors = [];
522
-		foreach(\OC::$APPSROOTS as $app_dir) {
523
-			if($dir = opendir( $app_dir['path'] )) {
524
-				while( false !== ( $filename = readdir( $dir ))) {
525
-					if( $filename[0] !== '.' and is_dir($app_dir['path']."/$filename") ) {
526
-						if( file_exists( $app_dir['path']."/$filename/appinfo/info.xml" )) {
527
-							if(!Installer::isInstalled($filename)) {
528
-								$info=OC_App::getAppInfo($filename);
522
+		foreach (\OC::$APPSROOTS as $app_dir) {
523
+			if ($dir = opendir($app_dir['path'])) {
524
+				while (false !== ($filename = readdir($dir))) {
525
+					if ($filename[0] !== '.' and is_dir($app_dir['path']."/$filename")) {
526
+						if (file_exists($app_dir['path']."/$filename/appinfo/info.xml")) {
527
+							if (!Installer::isInstalled($filename)) {
528
+								$info = OC_App::getAppInfo($filename);
529 529
 								$enabled = isset($info['default_enable']);
530 530
 								if (($enabled || in_array($filename, \OC::$server->getAppManager()->getAlwaysEnabledApps()))
531 531
 									  && \OC::$server->getConfig()->getAppValue($filename, 'enabled') !== 'no') {
@@ -548,7 +548,7 @@  discard block
 block discarded – undo
548 548
 						}
549 549
 					}
550 550
 				}
551
-				closedir( $dir );
551
+				closedir($dir);
552 552
 			}
553 553
 		}
554 554
 
@@ -565,12 +565,12 @@  discard block
 block discarded – undo
565 565
 		$appPath = OC_App::getAppPath($app);
566 566
 		\OC_App::registerAutoloading($app, $appPath);
567 567
 
568
-		if(is_file("$appPath/appinfo/database.xml")) {
568
+		if (is_file("$appPath/appinfo/database.xml")) {
569 569
 			try {
570 570
 				OC_DB::createDbFromStructure("$appPath/appinfo/database.xml");
571 571
 			} catch (TableExistsException $e) {
572 572
 				throw new HintException(
573
-					'Failed to enable app ' . $app,
573
+					'Failed to enable app '.$app,
574 574
 					'Please ask for help via one of our <a href="https://nextcloud.com/support/" target="_blank" rel="noreferrer noopener">support channels</a>.',
575 575
 					0, $e
576 576
 				);
@@ -599,16 +599,16 @@  discard block
 block discarded – undo
599 599
 		}
600 600
 
601 601
 		//set remote/public handlers
602
-		foreach($info['remote'] as $name=>$path) {
602
+		foreach ($info['remote'] as $name=>$path) {
603 603
 			$config->setAppValue('core', 'remote_'.$name, $app.'/'.$path);
604 604
 		}
605
-		foreach($info['public'] as $name=>$path) {
605
+		foreach ($info['public'] as $name=>$path) {
606 606
 			$config->setAppValue('core', 'public_'.$name, $app.'/'.$path);
607 607
 		}
608 608
 
609 609
 		OC_App::setAppTypes($info['id']);
610 610
 
611
-		if(isset($info['settings']) && is_array($info['settings'])) {
611
+		if (isset($info['settings']) && is_array($info['settings'])) {
612 612
 			// requires that autoloading was registered for the app,
613 613
 			// as happens before running the install.php some lines above
614 614
 			\OC::$server->getSettingsManager()->setupSettings($info['settings']);
@@ -621,7 +621,7 @@  discard block
 block discarded – undo
621 621
 	 * @param string $script
622 622
 	 */
623 623
 	private static function includeAppScript($script) {
624
-		if ( file_exists($script) ){
624
+		if (file_exists($script)) {
625 625
 			include $script;
626 626
 		}
627 627
 	}
Please login to merge, or discard this patch.
lib/public/App/IAppManager.php 1 patch
Indentation   +118 added lines, -118 removed lines patch added patch discarded remove patch
@@ -37,122 +37,122 @@
 block discarded – undo
37 37
  */
38 38
 interface IAppManager {
39 39
 
40
-	/**
41
-	 * Returns the app information from "appinfo/info.xml".
42
-	 *
43
-	 * @param string $appId
44
-	 * @return mixed
45
-	 * @since 14.0.0
46
-	 */
47
-	public function getAppInfo(string $appId, bool $path = false, $lang = null);
48
-
49
-	/**
50
-	 * Returns the app information from "appinfo/info.xml".
51
-	 *
52
-	 * @param string $appId
53
-	 * @param bool $useCache
54
-	 * @return mixed
55
-	 * @since 14.0.0
56
-	 */
57
-	public function getAppVersion(string $appId, bool $useCache = true);
58
-
59
-	/**
60
-	 * Check if an app is enabled for user
61
-	 *
62
-	 * @param string $appId
63
-	 * @param \OCP\IUser $user (optional) if not defined, the currently loggedin user will be used
64
-	 * @return bool
65
-	 * @since 8.0.0
66
-	 */
67
-	public function isEnabledForUser($appId, $user = null);
68
-
69
-	/**
70
-	 * Check if an app is installed in the instance
71
-	 *
72
-	 * @param string $appId
73
-	 * @return bool
74
-	 * @since 8.0.0
75
-	 */
76
-	public function isInstalled($appId);
77
-
78
-	/**
79
-	 * Enable an app for every user
80
-	 *
81
-	 * @param string $appId
82
-	 * @throws AppPathNotFoundException
83
-	 * @since 8.0.0
84
-	 */
85
-	public function enableApp($appId);
86
-
87
-	/**
88
-	 * Whether a list of types contains a protected app type
89
-	 *
90
-	 * @param string[] $types
91
-	 * @return bool
92
-	 * @since 12.0.0
93
-	 */
94
-	public function hasProtectedAppType($types);
95
-
96
-	/**
97
-	 * Enable an app only for specific groups
98
-	 *
99
-	 * @param string $appId
100
-	 * @param \OCP\IGroup[] $groups
101
-	 * @since 8.0.0
102
-	 */
103
-	public function enableAppForGroups($appId, $groups);
104
-
105
-	/**
106
-	 * Disable an app for every user
107
-	 *
108
-	 * @param string $appId
109
-	 * @since 8.0.0
110
-	 */
111
-	public function disableApp($appId);
112
-
113
-	/**
114
-	 * Get the directory for the given app.
115
-	 *
116
-	 * @param string $appId
117
-	 * @return string
118
-	 * @since 11.0.0
119
-	 * @throws AppPathNotFoundException
120
-	 */
121
-	public function getAppPath($appId);
122
-
123
-	/**
124
-	 * List all apps enabled for a user
125
-	 *
126
-	 * @param \OCP\IUser $user
127
-	 * @return string[]
128
-	 * @since 8.1.0
129
-	 */
130
-	public function getEnabledAppsForUser(IUser $user);
131
-
132
-	/**
133
-	 * List all installed apps
134
-	 *
135
-	 * @return string[]
136
-	 * @since 8.1.0
137
-	 */
138
-	public function getInstalledApps();
139
-
140
-	/**
141
-	 * Clear the cached list of apps when enabling/disabling an app
142
-	 * @since 8.1.0
143
-	 */
144
-	public function clearAppsCache();
145
-
146
-	/**
147
-	 * @param string $appId
148
-	 * @return boolean
149
-	 * @since 9.0.0
150
-	 */
151
-	public function isShipped($appId);
152
-
153
-	/**
154
-	 * @return string[]
155
-	 * @since 9.0.0
156
-	 */
157
-	public function getAlwaysEnabledApps();
40
+    /**
41
+     * Returns the app information from "appinfo/info.xml".
42
+     *
43
+     * @param string $appId
44
+     * @return mixed
45
+     * @since 14.0.0
46
+     */
47
+    public function getAppInfo(string $appId, bool $path = false, $lang = null);
48
+
49
+    /**
50
+     * Returns the app information from "appinfo/info.xml".
51
+     *
52
+     * @param string $appId
53
+     * @param bool $useCache
54
+     * @return mixed
55
+     * @since 14.0.0
56
+     */
57
+    public function getAppVersion(string $appId, bool $useCache = true);
58
+
59
+    /**
60
+     * Check if an app is enabled for user
61
+     *
62
+     * @param string $appId
63
+     * @param \OCP\IUser $user (optional) if not defined, the currently loggedin user will be used
64
+     * @return bool
65
+     * @since 8.0.0
66
+     */
67
+    public function isEnabledForUser($appId, $user = null);
68
+
69
+    /**
70
+     * Check if an app is installed in the instance
71
+     *
72
+     * @param string $appId
73
+     * @return bool
74
+     * @since 8.0.0
75
+     */
76
+    public function isInstalled($appId);
77
+
78
+    /**
79
+     * Enable an app for every user
80
+     *
81
+     * @param string $appId
82
+     * @throws AppPathNotFoundException
83
+     * @since 8.0.0
84
+     */
85
+    public function enableApp($appId);
86
+
87
+    /**
88
+     * Whether a list of types contains a protected app type
89
+     *
90
+     * @param string[] $types
91
+     * @return bool
92
+     * @since 12.0.0
93
+     */
94
+    public function hasProtectedAppType($types);
95
+
96
+    /**
97
+     * Enable an app only for specific groups
98
+     *
99
+     * @param string $appId
100
+     * @param \OCP\IGroup[] $groups
101
+     * @since 8.0.0
102
+     */
103
+    public function enableAppForGroups($appId, $groups);
104
+
105
+    /**
106
+     * Disable an app for every user
107
+     *
108
+     * @param string $appId
109
+     * @since 8.0.0
110
+     */
111
+    public function disableApp($appId);
112
+
113
+    /**
114
+     * Get the directory for the given app.
115
+     *
116
+     * @param string $appId
117
+     * @return string
118
+     * @since 11.0.0
119
+     * @throws AppPathNotFoundException
120
+     */
121
+    public function getAppPath($appId);
122
+
123
+    /**
124
+     * List all apps enabled for a user
125
+     *
126
+     * @param \OCP\IUser $user
127
+     * @return string[]
128
+     * @since 8.1.0
129
+     */
130
+    public function getEnabledAppsForUser(IUser $user);
131
+
132
+    /**
133
+     * List all installed apps
134
+     *
135
+     * @return string[]
136
+     * @since 8.1.0
137
+     */
138
+    public function getInstalledApps();
139
+
140
+    /**
141
+     * Clear the cached list of apps when enabling/disabling an app
142
+     * @since 8.1.0
143
+     */
144
+    public function clearAppsCache();
145
+
146
+    /**
147
+     * @param string $appId
148
+     * @return boolean
149
+     * @since 9.0.0
150
+     */
151
+    public function isShipped($appId);
152
+
153
+    /**
154
+     * @return string[]
155
+     * @since 9.0.0
156
+     */
157
+    public function getAlwaysEnabledApps();
158 158
 }
Please login to merge, or discard this patch.
lib/public/App.php 2 patches
Indentation   +64 added lines, -64 removed lines patch added patch discarded remove patch
@@ -45,73 +45,73 @@
 block discarded – undo
45 45
 class App {
46 46
 
47 47
 
48
-	/**
49
-	 * Register a Configuration Screen that should appear in the personal settings section.
50
-	 * @param string $app appid
51
-	 * @param string $page page to be included
52
-	 * @return void
53
-	 * @since 4.0.0
54
-	 * @deprecated 14.0.0 Use settings section in appinfo.xml to register personal admin sections
55
-	*/
56
-	public static function registerPersonal( $app, $page ) {
57
-		\OC_App::registerPersonal( $app, $page );
58
-	}
48
+    /**
49
+     * Register a Configuration Screen that should appear in the personal settings section.
50
+     * @param string $app appid
51
+     * @param string $page page to be included
52
+     * @return void
53
+     * @since 4.0.0
54
+     * @deprecated 14.0.0 Use settings section in appinfo.xml to register personal admin sections
55
+     */
56
+    public static function registerPersonal( $app, $page ) {
57
+        \OC_App::registerPersonal( $app, $page );
58
+    }
59 59
 
60
-	/**
61
-	 * Register a Configuration Screen that should appear in the Admin section.
62
-	 * @param string $app string appid
63
-	 * @param string $page string page to be included
64
-	 * @return void
65
-	 * @since 4.0.0
66
-	 * @deprecated 14.0.0 Use settings section in appinfo.xml to register admin sections
67
-	 */
68
-	public static function registerAdmin( $app, $page ) {
69
-		\OC_App::registerAdmin( $app, $page );
70
-	}
60
+    /**
61
+     * Register a Configuration Screen that should appear in the Admin section.
62
+     * @param string $app string appid
63
+     * @param string $page string page to be included
64
+     * @return void
65
+     * @since 4.0.0
66
+     * @deprecated 14.0.0 Use settings section in appinfo.xml to register admin sections
67
+     */
68
+    public static function registerAdmin( $app, $page ) {
69
+        \OC_App::registerAdmin( $app, $page );
70
+    }
71 71
 
72
-	/**
73
-	 * Read app metadata from the info.xml file
74
-	 * @param string $app id of the app or the path of the info.xml file
75
-	 * @param boolean $path (optional)
76
-	 * @return array|null
77
-	 * @deprecated 14.0.0 ise \OC::$server->getAppManager()->getAppInfo($appId)
78
-	 * @since 4.0.0
79
-	*/
80
-	public static function getAppInfo( $app, $path=false ) {
81
-		return \OC_App::getAppInfo( $app, $path);
82
-	}
72
+    /**
73
+     * Read app metadata from the info.xml file
74
+     * @param string $app id of the app or the path of the info.xml file
75
+     * @param boolean $path (optional)
76
+     * @return array|null
77
+     * @deprecated 14.0.0 ise \OC::$server->getAppManager()->getAppInfo($appId)
78
+     * @since 4.0.0
79
+     */
80
+    public static function getAppInfo( $app, $path=false ) {
81
+        return \OC_App::getAppInfo( $app, $path);
82
+    }
83 83
 
84
-	/**
85
-	 * checks whether or not an app is enabled
86
-	 * @param string $app
87
-	 * @return boolean
88
-	 *
89
-	 * This function checks whether or not an app is enabled.
90
-	 * @since 4.0.0
91
-	 * @deprecated 13.0.0 use \OC::$server->getAppManager()->isEnabledForUser($appId)
92
-	 */
93
-	public static function isEnabled( $app ) {
94
-		return \OC::$server->getAppManager()->isEnabledForUser( $app );
95
-	}
84
+    /**
85
+     * checks whether or not an app is enabled
86
+     * @param string $app
87
+     * @return boolean
88
+     *
89
+     * This function checks whether or not an app is enabled.
90
+     * @since 4.0.0
91
+     * @deprecated 13.0.0 use \OC::$server->getAppManager()->isEnabledForUser($appId)
92
+     */
93
+    public static function isEnabled( $app ) {
94
+        return \OC::$server->getAppManager()->isEnabledForUser( $app );
95
+    }
96 96
 
97
-	/**
98
-	 * Check if the app is enabled, redirects to home if not
99
-	 * @param string $app
100
-	 * @return void
101
-	 * @since 4.0.0
102
-	 * @deprecated 9.0.0 ownCloud core will handle disabled apps and redirects to valid URLs
103
-	*/
104
-	public static function checkAppEnabled( $app ) {
105
-	}
97
+    /**
98
+     * Check if the app is enabled, redirects to home if not
99
+     * @param string $app
100
+     * @return void
101
+     * @since 4.0.0
102
+     * @deprecated 9.0.0 ownCloud core will handle disabled apps and redirects to valid URLs
103
+     */
104
+    public static function checkAppEnabled( $app ) {
105
+    }
106 106
 
107
-	/**
108
-	 * Get the last version of the app from appinfo/info.xml
109
-	 * @param string $app
110
-	 * @return string
111
-	 * @since 4.0.0
112
-	 * @deprecated 14.0.0 use \OC::$server->getAppManager()->getAppVersion($appId)
113
-	 */
114
-	public static function getAppVersion( $app ) {
115
-		return \OC::$server->getAppManager()->getAppVersion($app);
116
-	}
107
+    /**
108
+     * Get the last version of the app from appinfo/info.xml
109
+     * @param string $app
110
+     * @return string
111
+     * @since 4.0.0
112
+     * @deprecated 14.0.0 use \OC::$server->getAppManager()->getAppVersion($appId)
113
+     */
114
+    public static function getAppVersion( $app ) {
115
+        return \OC::$server->getAppManager()->getAppVersion($app);
116
+    }
117 117
 }
Please login to merge, or discard this patch.
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -53,8 +53,8 @@  discard block
 block discarded – undo
53 53
 	 * @since 4.0.0
54 54
 	 * @deprecated 14.0.0 Use settings section in appinfo.xml to register personal admin sections
55 55
 	*/
56
-	public static function registerPersonal( $app, $page ) {
57
-		\OC_App::registerPersonal( $app, $page );
56
+	public static function registerPersonal($app, $page) {
57
+		\OC_App::registerPersonal($app, $page);
58 58
 	}
59 59
 
60 60
 	/**
@@ -65,8 +65,8 @@  discard block
 block discarded – undo
65 65
 	 * @since 4.0.0
66 66
 	 * @deprecated 14.0.0 Use settings section in appinfo.xml to register admin sections
67 67
 	 */
68
-	public static function registerAdmin( $app, $page ) {
69
-		\OC_App::registerAdmin( $app, $page );
68
+	public static function registerAdmin($app, $page) {
69
+		\OC_App::registerAdmin($app, $page);
70 70
 	}
71 71
 
72 72
 	/**
@@ -77,8 +77,8 @@  discard block
 block discarded – undo
77 77
 	 * @deprecated 14.0.0 ise \OC::$server->getAppManager()->getAppInfo($appId)
78 78
 	 * @since 4.0.0
79 79
 	*/
80
-	public static function getAppInfo( $app, $path=false ) {
81
-		return \OC_App::getAppInfo( $app, $path);
80
+	public static function getAppInfo($app, $path = false) {
81
+		return \OC_App::getAppInfo($app, $path);
82 82
 	}
83 83
 
84 84
 	/**
@@ -90,8 +90,8 @@  discard block
 block discarded – undo
90 90
 	 * @since 4.0.0
91 91
 	 * @deprecated 13.0.0 use \OC::$server->getAppManager()->isEnabledForUser($appId)
92 92
 	 */
93
-	public static function isEnabled( $app ) {
94
-		return \OC::$server->getAppManager()->isEnabledForUser( $app );
93
+	public static function isEnabled($app) {
94
+		return \OC::$server->getAppManager()->isEnabledForUser($app);
95 95
 	}
96 96
 
97 97
 	/**
@@ -101,7 +101,7 @@  discard block
 block discarded – undo
101 101
 	 * @since 4.0.0
102 102
 	 * @deprecated 9.0.0 ownCloud core will handle disabled apps and redirects to valid URLs
103 103
 	*/
104
-	public static function checkAppEnabled( $app ) {
104
+	public static function checkAppEnabled($app) {
105 105
 	}
106 106
 
107 107
 	/**
@@ -111,7 +111,7 @@  discard block
 block discarded – undo
111 111
 	 * @since 4.0.0
112 112
 	 * @deprecated 14.0.0 use \OC::$server->getAppManager()->getAppVersion($appId)
113 113
 	 */
114
-	public static function getAppVersion( $app ) {
114
+	public static function getAppVersion($app) {
115 115
 		return \OC::$server->getAppManager()->getAppVersion($app);
116 116
 	}
117 117
 }
Please login to merge, or discard this patch.
lib/private/TemplateLayout.php 1 patch
Indentation   +280 added lines, -280 removed lines patch added patch discarded remove patch
@@ -45,284 +45,284 @@
 block discarded – undo
45 45
 
46 46
 class TemplateLayout extends \OC_Template {
47 47
 
48
-	private static $versionHash = '';
49
-
50
-	/**
51
-	 * @var \OCP\IConfig
52
-	 */
53
-	private $config;
54
-
55
-	/**
56
-	 * @param string $renderAs
57
-	 * @param string $appId application id
58
-	 */
59
-	public function __construct( $renderAs, $appId = '' ) {
60
-
61
-		// yes - should be injected ....
62
-		$this->config = \OC::$server->getConfig();
63
-
64
-
65
-		// Decide which page we show
66
-		if($renderAs == 'user') {
67
-			parent::__construct( 'core', 'layout.user' );
68
-			if(in_array(\OC_App::getCurrentApp(), ['settings','admin', 'help']) !== false) {
69
-				$this->assign('bodyid', 'body-settings');
70
-			}else{
71
-				$this->assign('bodyid', 'body-user');
72
-			}
73
-
74
-			// Code integrity notification
75
-			$integrityChecker = \OC::$server->getIntegrityCodeChecker();
76
-			if(\OC_User::isAdminUser(\OC_User::getUser()) && $integrityChecker->isCodeCheckEnforced() && !$integrityChecker->hasPassedCheck()) {
77
-				\OCP\Util::addScript('core', 'integritycheck-failed-notification');
78
-			}
79
-
80
-			// Add navigation entry
81
-			$this->assign( 'application', '');
82
-			$this->assign( 'appid', $appId );
83
-			$navigation = \OC_App::getNavigation();
84
-			$this->assign( 'navigation', $navigation);
85
-			$settingsNavigation = \OC_App::getSettingsNavigation();
86
-			$this->assign( 'settingsnavigation', $settingsNavigation);
87
-			foreach($navigation as $entry) {
88
-				if ($entry['active']) {
89
-					$this->assign( 'application', $entry['name'] );
90
-					break;
91
-				}
92
-			}
93
-
94
-			foreach($settingsNavigation as $entry) {
95
-				if ($entry['active']) {
96
-					$this->assign( 'application', $entry['name'] );
97
-					break;
98
-				}
99
-			}
100
-			$userDisplayName = \OC_User::getDisplayName();
101
-			$this->assign('user_displayname', $userDisplayName);
102
-			$this->assign('user_uid', \OC_User::getUser());
103
-
104
-			if (\OC_User::getUser() === false) {
105
-				$this->assign('userAvatarSet', false);
106
-			} else {
107
-				$this->assign('userAvatarSet', \OC::$server->getAvatarManager()->getAvatar(\OC_User::getUser())->exists());
108
-				$this->assign('userAvatarVersion', $this->config->getUserValue(\OC_User::getUser(), 'avatar', 'version', 0));
109
-			}
110
-
111
-			// check if app menu icons should be inverted
112
-			try {
113
-				/** @var \OCA\Theming\Util $util */
114
-				$util = \OC::$server->query(\OCA\Theming\Util::class);
115
-				$this->assign('themingInvertMenu', $util->invertTextColor(\OC::$server->getThemingDefaults()->getColorPrimary()));
116
-			} catch (\OCP\AppFramework\QueryException $e) {
117
-				$this->assign('themingInvertMenu', false);
118
-			}
119
-
120
-		} else if ($renderAs == 'error') {
121
-			parent::__construct('core', 'layout.guest', '', false);
122
-			\OC_Util::addStyle('guest');
123
-			$this->assign('bodyid', 'body-login');
124
-		} else if ($renderAs == 'guest') {
125
-			parent::__construct('core', 'layout.guest');
126
-			\OC_Util::addStyle('guest');
127
-			$this->assign('bodyid', 'body-login');
128
-		} else {
129
-			parent::__construct('core', 'layout.base');
130
-
131
-		}
132
-		// Send the language to our layouts
133
-		$this->assign('language', \OC::$server->getL10NFactory()->findLanguage());
134
-
135
-		if(\OC::$server->getSystemConfig()->getValue('installed', false)) {
136
-			if (empty(self::$versionHash)) {
137
-				$v = \OC_App::getAppVersions();
138
-				$v['core'] = implode('.', \OCP\Util::getVersion());
139
-				self::$versionHash = substr(md5(implode(',', $v)), 0, 8);
140
-			}
141
-		} else {
142
-			self::$versionHash = md5('not installed');
143
-		}
144
-
145
-		// Add the js files
146
-		$jsFiles = self::findJavascriptFiles(\OC_Util::$scripts);
147
-		$this->assign('jsfiles', array());
148
-		if ($this->config->getSystemValue('installed', false) && $renderAs != 'error') {
149
-			if (\OC::$server->getContentSecurityPolicyNonceManager()->browserSupportsCspV3()) {
150
-				$jsConfigHelper = new JSConfigHelper(
151
-					\OC::$server->getL10N('lib'),
152
-					\OC::$server->query(Defaults::class),
153
-					\OC::$server->getAppManager(),
154
-					\OC::$server->getSession(),
155
-					\OC::$server->getUserSession()->getUser(),
156
-					$this->config,
157
-					\OC::$server->getGroupManager(),
158
-					\OC::$server->getIniWrapper(),
159
-					\OC::$server->getURLGenerator()
160
-				);
161
-				$this->assign('inline_ocjs', $jsConfigHelper->getConfig());
162
-			} else {
163
-				$this->append('jsfiles', \OC::$server->getURLGenerator()->linkToRoute('core.OCJS.getConfig', ['v' => self::$versionHash]));
164
-			}
165
-		}
166
-		foreach($jsFiles as $info) {
167
-			$web = $info[1];
168
-			$file = $info[2];
169
-			$this->append( 'jsfiles', $web.'/'.$file . $this->getVersionHashSuffix() );
170
-		}
171
-
172
-		try {
173
-			$pathInfo = \OC::$server->getRequest()->getPathInfo();
174
-		} catch (\Exception $e) {
175
-			$pathInfo = '';
176
-		}
177
-
178
-		// Do not initialise scss appdata until we have a fully installed instance
179
-		// Do not load scss for update, errors, installation or login page
180
-		if(\OC::$server->getSystemConfig()->getValue('installed', false)
181
-			&& !\OCP\Util::needUpgrade()
182
-			&& $pathInfo !== ''
183
-			&& !preg_match('/^\/login/', $pathInfo)) {
184
-			$cssFiles = self::findStylesheetFiles(\OC_Util::$styles);
185
-		} else {
186
-			// If we ignore the scss compiler,
187
-			// we need to load the guest css fallback
188
-			\OC_Util::addStyle('guest');
189
-			$cssFiles = self::findStylesheetFiles(\OC_Util::$styles, false);
190
-		}
191
-
192
-		$this->assign('cssfiles', array());
193
-		$this->assign('printcssfiles', []);
194
-		$this->assign('versionHash', self::$versionHash);
195
-		foreach($cssFiles as $info) {
196
-			$web = $info[1];
197
-			$file = $info[2];
198
-
199
-			if (substr($file, -strlen('print.css')) === 'print.css') {
200
-				$this->append( 'printcssfiles', $web.'/'.$file . $this->getVersionHashSuffix() );
201
-			} else {
202
-				$this->append( 'cssfiles', $web.'/'.$file . $this->getVersionHashSuffix($web, $file)  );
203
-			}
204
-		}
205
-	}
206
-
207
-	/**
208
-	 * @param string $path
209
- 	 * @param string $file
210
-	 * @return string
211
-	 */
212
-	protected function getVersionHashSuffix($path = false, $file = false) {
213
-		if ($this->config->getSystemValue('debug', false)) {
214
-			// allows chrome workspace mapping in debug mode
215
-			return "";
216
-		}
217
-		$themingSuffix = '';
218
-		$v = [];
219
-
220
-		if ($this->config->getSystemValue('installed', false)) {
221
-			if (\OC::$server->getAppManager()->isInstalled('theming')) {
222
-				$themingSuffix = '-' . $this->config->getAppValue('theming', 'cachebuster', '0');
223
-			}
224
-			$v = \OC_App::getAppVersions();
225
-		}
226
-
227
-		// Try the webroot path for a match
228
-		if ($path !== false && $path !== '') {
229
-			$appName = $this->getAppNamefromPath($path);
230
-			if(array_key_exists($appName, $v)) {
231
-				$appVersion = $v[$appName];
232
-				return '?v=' . substr(md5($appVersion), 0, 8) . $themingSuffix;
233
-			}
234
-		}
235
-		// fallback to the file path instead
236
-		if ($file !== false && $file !== '') {
237
-			$appName = $this->getAppNamefromPath($file);
238
-			if(array_key_exists($appName, $v)) {
239
-				$appVersion = $v[$appName];
240
-				return '?v=' . substr(md5($appVersion), 0, 8) . $themingSuffix;
241
-			}
242
-		}
243
-
244
-		return '?v=' . self::$versionHash . $themingSuffix;
245
-	}
246
-
247
-	/**
248
-	 * @param array $styles
249
-	 * @return array
250
-	 */
251
-	static public function findStylesheetFiles($styles, $compileScss = true) {
252
-		// Read the selected theme from the config file
253
-		$theme = \OC_Util::getTheme();
254
-
255
-		if($compileScss) {
256
-			$SCSSCacher = \OC::$server->query(SCSSCacher::class);
257
-		} else {
258
-			$SCSSCacher = null;
259
-		}
260
-
261
-		$locator = new \OC\Template\CSSResourceLocator(
262
-			\OC::$server->getLogger(),
263
-			$theme,
264
-			array( \OC::$SERVERROOT => \OC::$WEBROOT ),
265
-			array( \OC::$SERVERROOT => \OC::$WEBROOT ),
266
-			$SCSSCacher
267
-		);
268
-		$locator->find($styles);
269
-		return $locator->getResources();
270
-	}
271
-
272
-	/**
273
-	 * @param string $path
274
-	 * @return string|boolean
275
-	 */
276
-	public function getAppNamefromPath($path) {
277
-		if ($path !== '' && is_string($path)) {
278
-			$pathParts = explode('/', $path);
279
-			if ($pathParts[0] === 'css') {
280
-				// This is a scss request
281
-				return $pathParts[1];
282
-			}
283
-			return end($pathParts);
284
-		}
285
-		return false;
286
-
287
-	}
288
-
289
-	/**
290
-	 * @param array $scripts
291
-	 * @return array
292
-	 */
293
-	static public function findJavascriptFiles($scripts) {
294
-		// Read the selected theme from the config file
295
-		$theme = \OC_Util::getTheme();
296
-
297
-		$locator = new \OC\Template\JSResourceLocator(
298
-			\OC::$server->getLogger(),
299
-			$theme,
300
-			array( \OC::$SERVERROOT => \OC::$WEBROOT ),
301
-			array( \OC::$SERVERROOT => \OC::$WEBROOT ),
302
-			new JSCombiner(
303
-				\OC::$server->getAppDataDir('js'),
304
-				\OC::$server->getURLGenerator(),
305
-				\OC::$server->getMemCacheFactory()->createDistributed('JS'),
306
-				\OC::$server->getSystemConfig(),
307
-				\OC::$server->getLogger()
308
-			)
309
-			);
310
-		$locator->find($scripts);
311
-		return $locator->getResources();
312
-	}
313
-
314
-	/**
315
-	 * Converts the absolute file path to a relative path from \OC::$SERVERROOT
316
-	 * @param string $filePath Absolute path
317
-	 * @return string Relative path
318
-	 * @throws \Exception If $filePath is not under \OC::$SERVERROOT
319
-	 */
320
-	public static function convertToRelativePath($filePath) {
321
-		$relativePath = explode(\OC::$SERVERROOT, $filePath);
322
-		if(count($relativePath) !== 2) {
323
-			throw new \Exception('$filePath is not under the \OC::$SERVERROOT');
324
-		}
325
-
326
-		return $relativePath[1];
327
-	}
48
+    private static $versionHash = '';
49
+
50
+    /**
51
+     * @var \OCP\IConfig
52
+     */
53
+    private $config;
54
+
55
+    /**
56
+     * @param string $renderAs
57
+     * @param string $appId application id
58
+     */
59
+    public function __construct( $renderAs, $appId = '' ) {
60
+
61
+        // yes - should be injected ....
62
+        $this->config = \OC::$server->getConfig();
63
+
64
+
65
+        // Decide which page we show
66
+        if($renderAs == 'user') {
67
+            parent::__construct( 'core', 'layout.user' );
68
+            if(in_array(\OC_App::getCurrentApp(), ['settings','admin', 'help']) !== false) {
69
+                $this->assign('bodyid', 'body-settings');
70
+            }else{
71
+                $this->assign('bodyid', 'body-user');
72
+            }
73
+
74
+            // Code integrity notification
75
+            $integrityChecker = \OC::$server->getIntegrityCodeChecker();
76
+            if(\OC_User::isAdminUser(\OC_User::getUser()) && $integrityChecker->isCodeCheckEnforced() && !$integrityChecker->hasPassedCheck()) {
77
+                \OCP\Util::addScript('core', 'integritycheck-failed-notification');
78
+            }
79
+
80
+            // Add navigation entry
81
+            $this->assign( 'application', '');
82
+            $this->assign( 'appid', $appId );
83
+            $navigation = \OC_App::getNavigation();
84
+            $this->assign( 'navigation', $navigation);
85
+            $settingsNavigation = \OC_App::getSettingsNavigation();
86
+            $this->assign( 'settingsnavigation', $settingsNavigation);
87
+            foreach($navigation as $entry) {
88
+                if ($entry['active']) {
89
+                    $this->assign( 'application', $entry['name'] );
90
+                    break;
91
+                }
92
+            }
93
+
94
+            foreach($settingsNavigation as $entry) {
95
+                if ($entry['active']) {
96
+                    $this->assign( 'application', $entry['name'] );
97
+                    break;
98
+                }
99
+            }
100
+            $userDisplayName = \OC_User::getDisplayName();
101
+            $this->assign('user_displayname', $userDisplayName);
102
+            $this->assign('user_uid', \OC_User::getUser());
103
+
104
+            if (\OC_User::getUser() === false) {
105
+                $this->assign('userAvatarSet', false);
106
+            } else {
107
+                $this->assign('userAvatarSet', \OC::$server->getAvatarManager()->getAvatar(\OC_User::getUser())->exists());
108
+                $this->assign('userAvatarVersion', $this->config->getUserValue(\OC_User::getUser(), 'avatar', 'version', 0));
109
+            }
110
+
111
+            // check if app menu icons should be inverted
112
+            try {
113
+                /** @var \OCA\Theming\Util $util */
114
+                $util = \OC::$server->query(\OCA\Theming\Util::class);
115
+                $this->assign('themingInvertMenu', $util->invertTextColor(\OC::$server->getThemingDefaults()->getColorPrimary()));
116
+            } catch (\OCP\AppFramework\QueryException $e) {
117
+                $this->assign('themingInvertMenu', false);
118
+            }
119
+
120
+        } else if ($renderAs == 'error') {
121
+            parent::__construct('core', 'layout.guest', '', false);
122
+            \OC_Util::addStyle('guest');
123
+            $this->assign('bodyid', 'body-login');
124
+        } else if ($renderAs == 'guest') {
125
+            parent::__construct('core', 'layout.guest');
126
+            \OC_Util::addStyle('guest');
127
+            $this->assign('bodyid', 'body-login');
128
+        } else {
129
+            parent::__construct('core', 'layout.base');
130
+
131
+        }
132
+        // Send the language to our layouts
133
+        $this->assign('language', \OC::$server->getL10NFactory()->findLanguage());
134
+
135
+        if(\OC::$server->getSystemConfig()->getValue('installed', false)) {
136
+            if (empty(self::$versionHash)) {
137
+                $v = \OC_App::getAppVersions();
138
+                $v['core'] = implode('.', \OCP\Util::getVersion());
139
+                self::$versionHash = substr(md5(implode(',', $v)), 0, 8);
140
+            }
141
+        } else {
142
+            self::$versionHash = md5('not installed');
143
+        }
144
+
145
+        // Add the js files
146
+        $jsFiles = self::findJavascriptFiles(\OC_Util::$scripts);
147
+        $this->assign('jsfiles', array());
148
+        if ($this->config->getSystemValue('installed', false) && $renderAs != 'error') {
149
+            if (\OC::$server->getContentSecurityPolicyNonceManager()->browserSupportsCspV3()) {
150
+                $jsConfigHelper = new JSConfigHelper(
151
+                    \OC::$server->getL10N('lib'),
152
+                    \OC::$server->query(Defaults::class),
153
+                    \OC::$server->getAppManager(),
154
+                    \OC::$server->getSession(),
155
+                    \OC::$server->getUserSession()->getUser(),
156
+                    $this->config,
157
+                    \OC::$server->getGroupManager(),
158
+                    \OC::$server->getIniWrapper(),
159
+                    \OC::$server->getURLGenerator()
160
+                );
161
+                $this->assign('inline_ocjs', $jsConfigHelper->getConfig());
162
+            } else {
163
+                $this->append('jsfiles', \OC::$server->getURLGenerator()->linkToRoute('core.OCJS.getConfig', ['v' => self::$versionHash]));
164
+            }
165
+        }
166
+        foreach($jsFiles as $info) {
167
+            $web = $info[1];
168
+            $file = $info[2];
169
+            $this->append( 'jsfiles', $web.'/'.$file . $this->getVersionHashSuffix() );
170
+        }
171
+
172
+        try {
173
+            $pathInfo = \OC::$server->getRequest()->getPathInfo();
174
+        } catch (\Exception $e) {
175
+            $pathInfo = '';
176
+        }
177
+
178
+        // Do not initialise scss appdata until we have a fully installed instance
179
+        // Do not load scss for update, errors, installation or login page
180
+        if(\OC::$server->getSystemConfig()->getValue('installed', false)
181
+            && !\OCP\Util::needUpgrade()
182
+            && $pathInfo !== ''
183
+            && !preg_match('/^\/login/', $pathInfo)) {
184
+            $cssFiles = self::findStylesheetFiles(\OC_Util::$styles);
185
+        } else {
186
+            // If we ignore the scss compiler,
187
+            // we need to load the guest css fallback
188
+            \OC_Util::addStyle('guest');
189
+            $cssFiles = self::findStylesheetFiles(\OC_Util::$styles, false);
190
+        }
191
+
192
+        $this->assign('cssfiles', array());
193
+        $this->assign('printcssfiles', []);
194
+        $this->assign('versionHash', self::$versionHash);
195
+        foreach($cssFiles as $info) {
196
+            $web = $info[1];
197
+            $file = $info[2];
198
+
199
+            if (substr($file, -strlen('print.css')) === 'print.css') {
200
+                $this->append( 'printcssfiles', $web.'/'.$file . $this->getVersionHashSuffix() );
201
+            } else {
202
+                $this->append( 'cssfiles', $web.'/'.$file . $this->getVersionHashSuffix($web, $file)  );
203
+            }
204
+        }
205
+    }
206
+
207
+    /**
208
+     * @param string $path
209
+     * @param string $file
210
+     * @return string
211
+     */
212
+    protected function getVersionHashSuffix($path = false, $file = false) {
213
+        if ($this->config->getSystemValue('debug', false)) {
214
+            // allows chrome workspace mapping in debug mode
215
+            return "";
216
+        }
217
+        $themingSuffix = '';
218
+        $v = [];
219
+
220
+        if ($this->config->getSystemValue('installed', false)) {
221
+            if (\OC::$server->getAppManager()->isInstalled('theming')) {
222
+                $themingSuffix = '-' . $this->config->getAppValue('theming', 'cachebuster', '0');
223
+            }
224
+            $v = \OC_App::getAppVersions();
225
+        }
226
+
227
+        // Try the webroot path for a match
228
+        if ($path !== false && $path !== '') {
229
+            $appName = $this->getAppNamefromPath($path);
230
+            if(array_key_exists($appName, $v)) {
231
+                $appVersion = $v[$appName];
232
+                return '?v=' . substr(md5($appVersion), 0, 8) . $themingSuffix;
233
+            }
234
+        }
235
+        // fallback to the file path instead
236
+        if ($file !== false && $file !== '') {
237
+            $appName = $this->getAppNamefromPath($file);
238
+            if(array_key_exists($appName, $v)) {
239
+                $appVersion = $v[$appName];
240
+                return '?v=' . substr(md5($appVersion), 0, 8) . $themingSuffix;
241
+            }
242
+        }
243
+
244
+        return '?v=' . self::$versionHash . $themingSuffix;
245
+    }
246
+
247
+    /**
248
+     * @param array $styles
249
+     * @return array
250
+     */
251
+    static public function findStylesheetFiles($styles, $compileScss = true) {
252
+        // Read the selected theme from the config file
253
+        $theme = \OC_Util::getTheme();
254
+
255
+        if($compileScss) {
256
+            $SCSSCacher = \OC::$server->query(SCSSCacher::class);
257
+        } else {
258
+            $SCSSCacher = null;
259
+        }
260
+
261
+        $locator = new \OC\Template\CSSResourceLocator(
262
+            \OC::$server->getLogger(),
263
+            $theme,
264
+            array( \OC::$SERVERROOT => \OC::$WEBROOT ),
265
+            array( \OC::$SERVERROOT => \OC::$WEBROOT ),
266
+            $SCSSCacher
267
+        );
268
+        $locator->find($styles);
269
+        return $locator->getResources();
270
+    }
271
+
272
+    /**
273
+     * @param string $path
274
+     * @return string|boolean
275
+     */
276
+    public function getAppNamefromPath($path) {
277
+        if ($path !== '' && is_string($path)) {
278
+            $pathParts = explode('/', $path);
279
+            if ($pathParts[0] === 'css') {
280
+                // This is a scss request
281
+                return $pathParts[1];
282
+            }
283
+            return end($pathParts);
284
+        }
285
+        return false;
286
+
287
+    }
288
+
289
+    /**
290
+     * @param array $scripts
291
+     * @return array
292
+     */
293
+    static public function findJavascriptFiles($scripts) {
294
+        // Read the selected theme from the config file
295
+        $theme = \OC_Util::getTheme();
296
+
297
+        $locator = new \OC\Template\JSResourceLocator(
298
+            \OC::$server->getLogger(),
299
+            $theme,
300
+            array( \OC::$SERVERROOT => \OC::$WEBROOT ),
301
+            array( \OC::$SERVERROOT => \OC::$WEBROOT ),
302
+            new JSCombiner(
303
+                \OC::$server->getAppDataDir('js'),
304
+                \OC::$server->getURLGenerator(),
305
+                \OC::$server->getMemCacheFactory()->createDistributed('JS'),
306
+                \OC::$server->getSystemConfig(),
307
+                \OC::$server->getLogger()
308
+            )
309
+            );
310
+        $locator->find($scripts);
311
+        return $locator->getResources();
312
+    }
313
+
314
+    /**
315
+     * Converts the absolute file path to a relative path from \OC::$SERVERROOT
316
+     * @param string $filePath Absolute path
317
+     * @return string Relative path
318
+     * @throws \Exception If $filePath is not under \OC::$SERVERROOT
319
+     */
320
+    public static function convertToRelativePath($filePath) {
321
+        $relativePath = explode(\OC::$SERVERROOT, $filePath);
322
+        if(count($relativePath) !== 2) {
323
+            throw new \Exception('$filePath is not under the \OC::$SERVERROOT');
324
+        }
325
+
326
+        return $relativePath[1];
327
+    }
328 328
 }
Please login to merge, or discard this patch.