Completed
Push — master ( 3e4ff2...4aa497 )
by
unknown
27:55 queued 16s
created
lib/public/Files.php 1 patch
Indentation   +83 added lines, -83 removed lines patch added patch discarded remove patch
@@ -16,93 +16,93 @@
 block discarded – undo
16 16
  * @deprecated 14.0.0
17 17
  */
18 18
 class Files {
19
-	/**
20
-	 * Recursive deletion of folders
21
-	 *
22
-	 * @param string $dir path to the folder
23
-	 * @param bool $deleteSelf if set to false only the content of the folder will be deleted
24
-	 * @return bool
25
-	 * @since 5.0.0
26
-	 * @since 32.0.0 added the $deleteSelf parameter
27
-	 * @deprecated 14.0.0
28
-	 */
29
-	public static function rmdirr($dir, bool $deleteSelf = true) {
30
-		if (is_dir($dir)) {
31
-			$files = new \RecursiveIteratorIterator(
32
-				new \RecursiveDirectoryIterator($dir, \RecursiveDirectoryIterator::SKIP_DOTS),
33
-				\RecursiveIteratorIterator::CHILD_FIRST
34
-			);
19
+    /**
20
+     * Recursive deletion of folders
21
+     *
22
+     * @param string $dir path to the folder
23
+     * @param bool $deleteSelf if set to false only the content of the folder will be deleted
24
+     * @return bool
25
+     * @since 5.0.0
26
+     * @since 32.0.0 added the $deleteSelf parameter
27
+     * @deprecated 14.0.0
28
+     */
29
+    public static function rmdirr($dir, bool $deleteSelf = true) {
30
+        if (is_dir($dir)) {
31
+            $files = new \RecursiveIteratorIterator(
32
+                new \RecursiveDirectoryIterator($dir, \RecursiveDirectoryIterator::SKIP_DOTS),
33
+                \RecursiveIteratorIterator::CHILD_FIRST
34
+            );
35 35
 
36
-			foreach ($files as $fileInfo) {
37
-				/** @var \SplFileInfo $fileInfo */
38
-				if ($fileInfo->isLink()) {
39
-					unlink($fileInfo->getPathname());
40
-				} elseif ($fileInfo->isDir()) {
41
-					rmdir($fileInfo->getRealPath());
42
-				} else {
43
-					unlink($fileInfo->getRealPath());
44
-				}
45
-			}
46
-			if ($deleteSelf) {
47
-				rmdir($dir);
48
-			}
49
-		} elseif (file_exists($dir)) {
50
-			if ($deleteSelf) {
51
-				unlink($dir);
52
-			}
53
-		}
54
-		if (!$deleteSelf) {
55
-			return true;
56
-		}
36
+            foreach ($files as $fileInfo) {
37
+                /** @var \SplFileInfo $fileInfo */
38
+                if ($fileInfo->isLink()) {
39
+                    unlink($fileInfo->getPathname());
40
+                } elseif ($fileInfo->isDir()) {
41
+                    rmdir($fileInfo->getRealPath());
42
+                } else {
43
+                    unlink($fileInfo->getRealPath());
44
+                }
45
+            }
46
+            if ($deleteSelf) {
47
+                rmdir($dir);
48
+            }
49
+        } elseif (file_exists($dir)) {
50
+            if ($deleteSelf) {
51
+                unlink($dir);
52
+            }
53
+        }
54
+        if (!$deleteSelf) {
55
+            return true;
56
+        }
57 57
 
58
-		return !file_exists($dir);
59
-	}
58
+        return !file_exists($dir);
59
+    }
60 60
 
61
-	/**
62
-	 * Get the mimetype form a local file
63
-	 * @param string $path
64
-	 * @return string
65
-	 *                does NOT work for ownClouds filesystem, use OC_FileSystem::getMimeType instead
66
-	 * @since 5.0.0
67
-	 * @deprecated 14.0.0
68
-	 */
69
-	public static function getMimeType($path) {
70
-		return \OC::$server->getMimeTypeDetector()->detect($path);
71
-	}
61
+    /**
62
+     * Get the mimetype form a local file
63
+     * @param string $path
64
+     * @return string
65
+     *                does NOT work for ownClouds filesystem, use OC_FileSystem::getMimeType instead
66
+     * @since 5.0.0
67
+     * @deprecated 14.0.0
68
+     */
69
+    public static function getMimeType($path) {
70
+        return \OC::$server->getMimeTypeDetector()->detect($path);
71
+    }
72 72
 
73
-	/**
74
-	 * Search for files by mimetype
75
-	 * @param string $mimetype
76
-	 * @return array
77
-	 * @since 6.0.0
78
-	 * @deprecated 14.0.0
79
-	 */
80
-	public static function searchByMime($mimetype) {
81
-		return \OC\Files\Filesystem::searchByMime($mimetype);
82
-	}
73
+    /**
74
+     * Search for files by mimetype
75
+     * @param string $mimetype
76
+     * @return array
77
+     * @since 6.0.0
78
+     * @deprecated 14.0.0
79
+     */
80
+    public static function searchByMime($mimetype) {
81
+        return \OC\Files\Filesystem::searchByMime($mimetype);
82
+    }
83 83
 
84
-	/**
85
-	 * Copy the contents of one stream to another
86
-	 * @param resource $source
87
-	 * @param resource $target
88
-	 * @return int the number of bytes copied
89
-	 * @since 5.0.0
90
-	 * @deprecated 14.0.0
91
-	 */
92
-	public static function streamCopy($source, $target) {
93
-		[$count, ] = \OC_Helper::streamCopy($source, $target);
94
-		return $count;
95
-	}
84
+    /**
85
+     * Copy the contents of one stream to another
86
+     * @param resource $source
87
+     * @param resource $target
88
+     * @return int the number of bytes copied
89
+     * @since 5.0.0
90
+     * @deprecated 14.0.0
91
+     */
92
+    public static function streamCopy($source, $target) {
93
+        [$count, ] = \OC_Helper::streamCopy($source, $target);
94
+        return $count;
95
+    }
96 96
 
97
-	/**
98
-	 * Adds a suffix to the name in case the file exists
99
-	 * @param string $path
100
-	 * @param string $filename
101
-	 * @return string
102
-	 * @since 5.0.0
103
-	 * @deprecated 14.0.0 use getNonExistingName of the OCP\Files\Folder object
104
-	 */
105
-	public static function buildNotExistingFileName($path, $filename) {
106
-		return \OC_Helper::buildNotExistingFileName($path, $filename);
107
-	}
97
+    /**
98
+     * Adds a suffix to the name in case the file exists
99
+     * @param string $path
100
+     * @param string $filename
101
+     * @return string
102
+     * @since 5.0.0
103
+     * @deprecated 14.0.0 use getNonExistingName of the OCP\Files\Folder object
104
+     */
105
+    public static function buildNotExistingFileName($path, $filename) {
106
+        return \OC_Helper::buildNotExistingFileName($path, $filename);
107
+    }
108 108
 }
Please login to merge, or discard this patch.
lib/private/legacy/OC_App.php 2 patches
Indentation   +831 added lines, -831 removed lines patch added patch discarded remove patch
@@ -30,835 +30,835 @@
 block discarded – undo
30 30
  * upgrading and removing apps.
31 31
  */
32 32
 class OC_App {
33
-	private static $altLogin = [];
34
-	private static $alreadyRegistered = [];
35
-	public const supportedApp = 300;
36
-	public const officialApp = 200;
37
-
38
-	/**
39
-	 * clean the appId
40
-	 *
41
-	 * @psalm-taint-escape file
42
-	 * @psalm-taint-escape include
43
-	 * @psalm-taint-escape html
44
-	 * @psalm-taint-escape has_quotes
45
-	 *
46
-	 * @deprecated 31.0.0 use IAppManager::cleanAppId
47
-	 */
48
-	public static function cleanAppId(string $app): string {
49
-		return str_replace(['<', '>', '"', "'", '\0', '/', '\\', '..'], '', $app);
50
-	}
51
-
52
-	/**
53
-	 * Check if an app is loaded
54
-	 *
55
-	 * @param string $app
56
-	 * @return bool
57
-	 * @deprecated 27.0.0 use IAppManager::isAppLoaded
58
-	 */
59
-	public static function isAppLoaded(string $app): bool {
60
-		return \OC::$server->get(IAppManager::class)->isAppLoaded($app);
61
-	}
62
-
63
-	/**
64
-	 * loads all apps
65
-	 *
66
-	 * @param string[] $types
67
-	 * @return bool
68
-	 *
69
-	 * This function walks through the Nextcloud directory and loads all apps
70
-	 * it can find. A directory contains an app if the file /appinfo/info.xml
71
-	 * exists.
72
-	 *
73
-	 * if $types is set to non-empty array, only apps of those types will be loaded
74
-	 *
75
-	 * @deprecated 29.0.0 use IAppManager::loadApps instead
76
-	 */
77
-	public static function loadApps(array $types = []): bool {
78
-		if (!\OC::$server->getSystemConfig()->getValue('installed', false)) {
79
-			// This should be done before calling this method so that appmanager can be used
80
-			return false;
81
-		}
82
-		return \OC::$server->get(IAppManager::class)->loadApps($types);
83
-	}
84
-
85
-	/**
86
-	 * load a single app
87
-	 *
88
-	 * @param string $app
89
-	 * @throws Exception
90
-	 * @deprecated 27.0.0 use IAppManager::loadApp
91
-	 */
92
-	public static function loadApp(string $app): void {
93
-		\OC::$server->get(IAppManager::class)->loadApp($app);
94
-	}
95
-
96
-	/**
97
-	 * @internal
98
-	 * @param string $app
99
-	 * @param string $path
100
-	 * @param bool $force
101
-	 */
102
-	public static function registerAutoloading(string $app, string $path, bool $force = false) {
103
-		$key = $app . '-' . $path;
104
-		if (!$force && isset(self::$alreadyRegistered[$key])) {
105
-			return;
106
-		}
107
-
108
-		self::$alreadyRegistered[$key] = true;
109
-
110
-		// Register on PSR-4 composer autoloader
111
-		$appNamespace = \OC\AppFramework\App::buildAppNamespace($app);
112
-		\OC::$server->registerNamespace($app, $appNamespace);
113
-
114
-		if (file_exists($path . '/composer/autoload.php')) {
115
-			require_once $path . '/composer/autoload.php';
116
-		} else {
117
-			\OC::$composerAutoloader->addPsr4($appNamespace . '\\', $path . '/lib/', true);
118
-		}
119
-
120
-		// Register Test namespace only when testing
121
-		if (defined('PHPUNIT_RUN') || defined('CLI_TEST_RUN')) {
122
-			\OC::$composerAutoloader->addPsr4($appNamespace . '\\Tests\\', $path . '/tests/', true);
123
-		}
124
-	}
125
-
126
-	/**
127
-	 * check if an app is of a specific type
128
-	 *
129
-	 * @param string $app
130
-	 * @param array $types
131
-	 * @return bool
132
-	 * @deprecated 27.0.0 use IAppManager::isType
133
-	 */
134
-	public static function isType(string $app, array $types): bool {
135
-		return \OC::$server->get(IAppManager::class)->isType($app, $types);
136
-	}
137
-
138
-	/**
139
-	 * read app types from info.xml and cache them in the database
140
-	 */
141
-	public static function setAppTypes(string $app) {
142
-		$appManager = \OC::$server->getAppManager();
143
-		$appData = $appManager->getAppInfo($app);
144
-		if (!is_array($appData)) {
145
-			return;
146
-		}
147
-
148
-		if (isset($appData['types'])) {
149
-			$appTypes = implode(',', $appData['types']);
150
-		} else {
151
-			$appTypes = '';
152
-			$appData['types'] = [];
153
-		}
154
-
155
-		$config = \OC::$server->getConfig();
156
-		$config->setAppValue($app, 'types', $appTypes);
157
-
158
-		if ($appManager->hasProtectedAppType($appData['types'])) {
159
-			$enabled = $config->getAppValue($app, 'enabled', 'yes');
160
-			if ($enabled !== 'yes' && $enabled !== 'no') {
161
-				$config->setAppValue($app, 'enabled', 'yes');
162
-			}
163
-		}
164
-	}
165
-
166
-	/**
167
-	 * Returns apps enabled for the current user.
168
-	 *
169
-	 * @param bool $forceRefresh whether to refresh the cache
170
-	 * @param bool $all whether to return apps for all users, not only the
171
-	 *                  currently logged in one
172
-	 * @return list<string>
173
-	 */
174
-	public static function getEnabledApps(bool $forceRefresh = false, bool $all = false): array {
175
-		if (!\OC::$server->getSystemConfig()->getValue('installed', false)) {
176
-			return [];
177
-		}
178
-		// in incognito mode or when logged out, $user will be false,
179
-		// which is also the case during an upgrade
180
-		$appManager = \OC::$server->getAppManager();
181
-		if ($all) {
182
-			$user = null;
183
-		} else {
184
-			$user = \OC::$server->getUserSession()->getUser();
185
-		}
186
-
187
-		if (is_null($user)) {
188
-			$apps = $appManager->getEnabledApps();
189
-		} else {
190
-			$apps = $appManager->getEnabledAppsForUser($user);
191
-		}
192
-		$apps = array_filter($apps, function ($app) {
193
-			return $app !== 'files';//we add this manually
194
-		});
195
-		sort($apps);
196
-		array_unshift($apps, 'files');
197
-		return $apps;
198
-	}
199
-
200
-	/**
201
-	 * enables an app
202
-	 *
203
-	 * @param string $appId
204
-	 * @param array $groups (optional) when set, only these groups will have access to the app
205
-	 * @throws \Exception
206
-	 * @return void
207
-	 *
208
-	 * This function set an app as enabled in appconfig.
209
-	 */
210
-	public function enable(string $appId,
211
-		array $groups = []) {
212
-		// Check if app is already downloaded
213
-		/** @var Installer $installer */
214
-		$installer = \OCP\Server::get(Installer::class);
215
-		$isDownloaded = $installer->isDownloaded($appId);
216
-
217
-		if (!$isDownloaded) {
218
-			$installer->downloadApp($appId);
219
-		}
220
-
221
-		$installer->installApp($appId);
222
-
223
-		$appManager = \OC::$server->getAppManager();
224
-		if ($groups !== []) {
225
-			$groupManager = \OC::$server->getGroupManager();
226
-			$groupsList = [];
227
-			foreach ($groups as $group) {
228
-				$groupItem = $groupManager->get($group);
229
-				if ($groupItem instanceof \OCP\IGroup) {
230
-					$groupsList[] = $groupManager->get($group);
231
-				}
232
-			}
233
-			$appManager->enableAppForGroups($appId, $groupsList);
234
-		} else {
235
-			$appManager->enableApp($appId);
236
-		}
237
-	}
238
-
239
-	/**
240
-	 * Get the path where to install apps
241
-	 */
242
-	public static function getInstallPath(): ?string {
243
-		foreach (OC::$APPSROOTS as $dir) {
244
-			if (isset($dir['writable']) && $dir['writable'] === true) {
245
-				return $dir['path'];
246
-			}
247
-		}
248
-
249
-		\OCP\Server::get(LoggerInterface::class)->error('No application directories are marked as writable.', ['app' => 'core']);
250
-		return null;
251
-	}
252
-
253
-
254
-	/**
255
-	 * Find the apps root for an app id.
256
-	 *
257
-	 * If multiple copies are found, the apps root the latest version is returned.
258
-	 *
259
-	 * @param string $appId
260
-	 * @param bool $ignoreCache ignore cache and rebuild it
261
-	 * @return false|array{path: string, url: string} the apps root shape
262
-	 */
263
-	public static function findAppInDirectories(string $appId, bool $ignoreCache = false) {
264
-		$sanitizedAppId = self::cleanAppId($appId);
265
-		if ($sanitizedAppId !== $appId) {
266
-			return false;
267
-		}
268
-		static $app_dir = [];
269
-
270
-		if (isset($app_dir[$appId]) && !$ignoreCache) {
271
-			return $app_dir[$appId];
272
-		}
273
-
274
-		$possibleApps = [];
275
-		foreach (OC::$APPSROOTS as $dir) {
276
-			if (file_exists($dir['path'] . '/' . $appId)) {
277
-				$possibleApps[] = $dir;
278
-			}
279
-		}
280
-
281
-		if (empty($possibleApps)) {
282
-			return false;
283
-		} elseif (count($possibleApps) === 1) {
284
-			$dir = array_shift($possibleApps);
285
-			$app_dir[$appId] = $dir;
286
-			return $dir;
287
-		} else {
288
-			$versionToLoad = [];
289
-			foreach ($possibleApps as $possibleApp) {
290
-				$version = self::getAppVersionByPath($possibleApp['path'] . '/' . $appId);
291
-				if (empty($versionToLoad) || version_compare($version, $versionToLoad['version'], '>')) {
292
-					$versionToLoad = [
293
-						'dir' => $possibleApp,
294
-						'version' => $version,
295
-					];
296
-				}
297
-			}
298
-			$app_dir[$appId] = $versionToLoad['dir'];
299
-			return $versionToLoad['dir'];
300
-			//TODO - write test
301
-		}
302
-	}
303
-
304
-	/**
305
-	 * Get the directory for the given app.
306
-	 * If the app is defined in multiple directories, the first one is taken. (false if not found)
307
-	 *
308
-	 * @psalm-taint-specialize
309
-	 *
310
-	 * @param string $appId
311
-	 * @param bool $refreshAppPath should be set to true only during install/upgrade
312
-	 * @return string|false
313
-	 * @deprecated 11.0.0 use \OCP\Server::get(IAppManager)->getAppPath()
314
-	 */
315
-	public static function getAppPath(string $appId, bool $refreshAppPath = false) {
316
-		$appId = self::cleanAppId($appId);
317
-		if ($appId === '') {
318
-			return false;
319
-		}
320
-
321
-		if (($dir = self::findAppInDirectories($appId, $refreshAppPath)) != false) {
322
-			return $dir['path'] . '/' . $appId;
323
-		}
324
-		return false;
325
-	}
326
-
327
-	/**
328
-	 * Get the path for the given app on the access
329
-	 * If the app is defined in multiple directories, the first one is taken. (false if not found)
330
-	 *
331
-	 * @param string $appId
332
-	 * @return string|false
333
-	 * @deprecated 18.0.0 use \OC::$server->getAppManager()->getAppWebPath()
334
-	 */
335
-	public static function getAppWebPath(string $appId) {
336
-		if (($dir = self::findAppInDirectories($appId)) != false) {
337
-			return OC::$WEBROOT . $dir['url'] . '/' . $appId;
338
-		}
339
-		return false;
340
-	}
341
-
342
-	/**
343
-	 * get app's version based on it's path
344
-	 *
345
-	 * @param string $path
346
-	 * @return string
347
-	 */
348
-	public static function getAppVersionByPath(string $path): string {
349
-		$infoFile = $path . '/appinfo/info.xml';
350
-		$appData = \OCP\Server::get(IAppManager::class)->getAppInfoByPath($infoFile);
351
-		return $appData['version'] ?? '';
352
-	}
353
-
354
-	/**
355
-	 * get the id of loaded app
356
-	 *
357
-	 * @return string
358
-	 */
359
-	public static function getCurrentApp(): string {
360
-		if (\OC::$CLI) {
361
-			return '';
362
-		}
363
-
364
-		$request = \OC::$server->getRequest();
365
-		$script = substr($request->getScriptName(), strlen(OC::$WEBROOT) + 1);
366
-		$topFolder = substr($script, 0, strpos($script, '/') ?: 0);
367
-		if (empty($topFolder)) {
368
-			try {
369
-				$path_info = $request->getPathInfo();
370
-			} catch (Exception $e) {
371
-				// Can happen from unit tests because the script name is `./vendor/bin/phpunit` or something a like then.
372
-				\OC::$server->get(LoggerInterface::class)->error('Failed to detect current app from script path', ['exception' => $e]);
373
-				return '';
374
-			}
375
-			if ($path_info) {
376
-				$topFolder = substr($path_info, 1, strpos($path_info, '/', 1) - 1);
377
-			}
378
-		}
379
-		if ($topFolder == 'apps') {
380
-			$length = strlen($topFolder);
381
-			return substr($script, $length + 1, strpos($script, '/', $length + 1) - $length - 1) ?: '';
382
-		} else {
383
-			return $topFolder;
384
-		}
385
-	}
386
-
387
-	/**
388
-	 * @param array $entry
389
-	 * @deprecated 20.0.0 Please register your alternative login option using the registerAlternativeLogin() on the RegistrationContext in your Application class implementing the OCP\Authentication\IAlternativeLogin interface
390
-	 */
391
-	public static function registerLogIn(array $entry) {
392
-		\OCP\Server::get(LoggerInterface::class)->debug('OC_App::registerLogIn() is deprecated, please register your alternative login option using the registerAlternativeLogin() on the RegistrationContext in your Application class implementing the OCP\Authentication\IAlternativeLogin interface');
393
-		self::$altLogin[] = $entry;
394
-	}
395
-
396
-	/**
397
-	 * @return array
398
-	 */
399
-	public static function getAlternativeLogIns(): array {
400
-		/** @var Coordinator $bootstrapCoordinator */
401
-		$bootstrapCoordinator = \OCP\Server::get(Coordinator::class);
402
-
403
-		foreach ($bootstrapCoordinator->getRegistrationContext()->getAlternativeLogins() as $registration) {
404
-			if (!in_array(IAlternativeLogin::class, class_implements($registration->getService()), true)) {
405
-				\OCP\Server::get(LoggerInterface::class)->error('Alternative login option {option} does not implement {interface} and is therefore ignored.', [
406
-					'option' => $registration->getService(),
407
-					'interface' => IAlternativeLogin::class,
408
-					'app' => $registration->getAppId(),
409
-				]);
410
-				continue;
411
-			}
412
-
413
-			try {
414
-				/** @var IAlternativeLogin $provider */
415
-				$provider = \OCP\Server::get($registration->getService());
416
-			} catch (ContainerExceptionInterface $e) {
417
-				\OCP\Server::get(LoggerInterface::class)->error('Alternative login option {option} can not be initialized.',
418
-					[
419
-						'exception' => $e,
420
-						'option' => $registration->getService(),
421
-						'app' => $registration->getAppId(),
422
-					]);
423
-			}
424
-
425
-			try {
426
-				$provider->load();
427
-
428
-				self::$altLogin[] = [
429
-					'name' => $provider->getLabel(),
430
-					'href' => $provider->getLink(),
431
-					'class' => $provider->getClass(),
432
-				];
433
-			} catch (Throwable $e) {
434
-				\OCP\Server::get(LoggerInterface::class)->error('Alternative login option {option} had an error while loading.',
435
-					[
436
-						'exception' => $e,
437
-						'option' => $registration->getService(),
438
-						'app' => $registration->getAppId(),
439
-					]);
440
-			}
441
-		}
442
-
443
-		return self::$altLogin;
444
-	}
445
-
446
-	/**
447
-	 * get a list of all apps in the apps folder
448
-	 *
449
-	 * @return string[] an array of app names (string IDs)
450
-	 * @deprecated 31.0.0 Use IAppManager::getAllAppsInAppsFolders instead
451
-	 */
452
-	public static function getAllApps(): array {
453
-		return \OCP\Server::get(IAppManager::class)->getAllAppsInAppsFolders();
454
-	}
455
-
456
-	/**
457
-	 * List all supported apps
458
-	 *
459
-	 * @deprecated 32.0.0 Use \OCP\Support\Subscription\IRegistry::delegateGetSupportedApps instead
460
-	 */
461
-	public function getSupportedApps(): array {
462
-		$subscriptionRegistry = \OCP\Server::get(\OCP\Support\Subscription\IRegistry::class);
463
-		$supportedApps = $subscriptionRegistry->delegateGetSupportedApps();
464
-		return $supportedApps;
465
-	}
466
-
467
-	/**
468
-	 * List all apps, this is used in apps.php
469
-	 *
470
-	 * @return array
471
-	 */
472
-	public function listAllApps(): array {
473
-		$appManager = \OC::$server->getAppManager();
474
-
475
-		$installedApps = $appManager->getAllAppsInAppsFolders();
476
-		//we don't want to show configuration for these
477
-		$blacklist = $appManager->getAlwaysEnabledApps();
478
-		$appList = [];
479
-		$langCode = \OC::$server->getL10N('core')->getLanguageCode();
480
-		$urlGenerator = \OC::$server->getURLGenerator();
481
-		$supportedApps = $this->getSupportedApps();
482
-
483
-		foreach ($installedApps as $app) {
484
-			if (!in_array($app, $blacklist)) {
485
-				$info = $appManager->getAppInfo($app, false, $langCode);
486
-				if (!is_array($info)) {
487
-					\OCP\Server::get(LoggerInterface::class)->error('Could not read app info file for app "' . $app . '"', ['app' => 'core']);
488
-					continue;
489
-				}
490
-
491
-				if (!isset($info['name'])) {
492
-					\OCP\Server::get(LoggerInterface::class)->error('App id "' . $app . '" has no name in appinfo', ['app' => 'core']);
493
-					continue;
494
-				}
495
-
496
-				$enabled = \OC::$server->getConfig()->getAppValue($app, 'enabled', 'no');
497
-				$info['groups'] = null;
498
-				if ($enabled === 'yes') {
499
-					$active = true;
500
-				} elseif ($enabled === 'no') {
501
-					$active = false;
502
-				} else {
503
-					$active = true;
504
-					$info['groups'] = $enabled;
505
-				}
506
-
507
-				$info['active'] = $active;
508
-
509
-				if ($appManager->isShipped($app)) {
510
-					$info['internal'] = true;
511
-					$info['level'] = self::officialApp;
512
-					$info['removable'] = false;
513
-				} else {
514
-					$info['internal'] = false;
515
-					$info['removable'] = true;
516
-				}
517
-
518
-				if (in_array($app, $supportedApps)) {
519
-					$info['level'] = self::supportedApp;
520
-				}
521
-
522
-				$appPath = self::getAppPath($app);
523
-				if ($appPath !== false) {
524
-					$appIcon = $appPath . '/img/' . $app . '.svg';
525
-					if (file_exists($appIcon)) {
526
-						$info['preview'] = $urlGenerator->imagePath($app, $app . '.svg');
527
-						$info['previewAsIcon'] = true;
528
-					} else {
529
-						$appIcon = $appPath . '/img/app.svg';
530
-						if (file_exists($appIcon)) {
531
-							$info['preview'] = $urlGenerator->imagePath($app, 'app.svg');
532
-							$info['previewAsIcon'] = true;
533
-						}
534
-					}
535
-				}
536
-				// fix documentation
537
-				if (isset($info['documentation']) && is_array($info['documentation'])) {
538
-					foreach ($info['documentation'] as $key => $url) {
539
-						// If it is not an absolute URL we assume it is a key
540
-						// i.e. admin-ldap will get converted to go.php?to=admin-ldap
541
-						if (stripos($url, 'https://') !== 0 && stripos($url, 'http://') !== 0) {
542
-							$url = $urlGenerator->linkToDocs($url);
543
-						}
544
-
545
-						$info['documentation'][$key] = $url;
546
-					}
547
-				}
548
-
549
-				$info['version'] = $appManager->getAppVersion($app);
550
-				$appList[] = $info;
551
-			}
552
-		}
553
-
554
-		return $appList;
555
-	}
556
-
557
-	public static function shouldUpgrade(string $app): bool {
558
-		$versions = self::getAppVersions();
559
-		$currentVersion = \OCP\Server::get(\OCP\App\IAppManager::class)->getAppVersion($app);
560
-		if ($currentVersion && isset($versions[$app])) {
561
-			$installedVersion = $versions[$app];
562
-			if (!version_compare($currentVersion, $installedVersion, '=')) {
563
-				return true;
564
-			}
565
-		}
566
-		return false;
567
-	}
568
-
569
-	/**
570
-	 * Adjust the number of version parts of $version1 to match
571
-	 * the number of version parts of $version2.
572
-	 *
573
-	 * @param string $version1 version to adjust
574
-	 * @param string $version2 version to take the number of parts from
575
-	 * @return string shortened $version1
576
-	 */
577
-	private static function adjustVersionParts(string $version1, string $version2): string {
578
-		$version1 = explode('.', $version1);
579
-		$version2 = explode('.', $version2);
580
-		// reduce $version1 to match the number of parts in $version2
581
-		while (count($version1) > count($version2)) {
582
-			array_pop($version1);
583
-		}
584
-		// if $version1 does not have enough parts, add some
585
-		while (count($version1) < count($version2)) {
586
-			$version1[] = '0';
587
-		}
588
-		return implode('.', $version1);
589
-	}
590
-
591
-	/**
592
-	 * Check whether the current Nextcloud version matches the given
593
-	 * application's version requirements.
594
-	 *
595
-	 * The comparison is made based on the number of parts that the
596
-	 * app info version has. For example for ownCloud 6.0.3 if the
597
-	 * app info version is expecting version 6.0, the comparison is
598
-	 * made on the first two parts of the ownCloud version.
599
-	 * This means that it's possible to specify "requiremin" => 6
600
-	 * and "requiremax" => 6 and it will still match ownCloud 6.0.3.
601
-	 *
602
-	 * @param string $ocVersion Nextcloud version to check against
603
-	 * @param array $appInfo app info (from xml)
604
-	 *
605
-	 * @return boolean true if compatible, otherwise false
606
-	 */
607
-	public static function isAppCompatible(string $ocVersion, array $appInfo, bool $ignoreMax = false): bool {
608
-		$requireMin = '';
609
-		$requireMax = '';
610
-		if (isset($appInfo['dependencies']['nextcloud']['@attributes']['min-version'])) {
611
-			$requireMin = $appInfo['dependencies']['nextcloud']['@attributes']['min-version'];
612
-		} elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['min-version'])) {
613
-			$requireMin = $appInfo['dependencies']['owncloud']['@attributes']['min-version'];
614
-		} elseif (isset($appInfo['requiremin'])) {
615
-			$requireMin = $appInfo['requiremin'];
616
-		} elseif (isset($appInfo['require'])) {
617
-			$requireMin = $appInfo['require'];
618
-		}
619
-
620
-		if (isset($appInfo['dependencies']['nextcloud']['@attributes']['max-version'])) {
621
-			$requireMax = $appInfo['dependencies']['nextcloud']['@attributes']['max-version'];
622
-		} elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['max-version'])) {
623
-			$requireMax = $appInfo['dependencies']['owncloud']['@attributes']['max-version'];
624
-		} elseif (isset($appInfo['requiremax'])) {
625
-			$requireMax = $appInfo['requiremax'];
626
-		}
627
-
628
-		if (!empty($requireMin)
629
-			&& version_compare(self::adjustVersionParts($ocVersion, $requireMin), $requireMin, '<')
630
-		) {
631
-			return false;
632
-		}
633
-
634
-		if (!$ignoreMax && !empty($requireMax)
635
-			&& version_compare(self::adjustVersionParts($ocVersion, $requireMax), $requireMax, '>')
636
-		) {
637
-			return false;
638
-		}
639
-
640
-		return true;
641
-	}
642
-
643
-	/**
644
-	 * get the installed version of all apps
645
-	 * @deprecated 32.0.0 Use IAppManager::getAppInstalledVersions or IAppConfig::getAppInstalledVersions instead
646
-	 */
647
-	public static function getAppVersions(): array {
648
-		return \OCP\Server::get(IAppConfig::class)->getAppInstalledVersions();
649
-	}
650
-
651
-	/**
652
-	 * update the database for the app and call the update script
653
-	 *
654
-	 * @param string $appId
655
-	 * @return bool
656
-	 */
657
-	public static function updateApp(string $appId): bool {
658
-		// for apps distributed with core, we refresh app path in case the downloaded version
659
-		// have been installed in custom apps and not in the default path
660
-		$appPath = self::getAppPath($appId, true);
661
-		if ($appPath === false) {
662
-			return false;
663
-		}
664
-
665
-		if (is_file($appPath . '/appinfo/database.xml')) {
666
-			\OCP\Server::get(LoggerInterface::class)->error('The appinfo/database.xml file is not longer supported. Used in ' . $appId);
667
-			return false;
668
-		}
669
-
670
-		\OC::$server->getAppManager()->clearAppsCache();
671
-		$l = \OC::$server->getL10N('core');
672
-		$appData = \OCP\Server::get(\OCP\App\IAppManager::class)->getAppInfo($appId, false, $l->getLanguageCode());
673
-
674
-		$ignoreMaxApps = \OC::$server->getConfig()->getSystemValue('app_install_overwrite', []);
675
-		$ignoreMax = in_array($appId, $ignoreMaxApps, true);
676
-		\OC_App::checkAppDependencies(
677
-			\OC::$server->getConfig(),
678
-			$l,
679
-			$appData,
680
-			$ignoreMax
681
-		);
682
-
683
-		self::registerAutoloading($appId, $appPath, true);
684
-		self::executeRepairSteps($appId, $appData['repair-steps']['pre-migration']);
685
-
686
-		$ms = new MigrationService($appId, \OC::$server->get(\OC\DB\Connection::class));
687
-		$ms->migrate();
688
-
689
-		self::executeRepairSteps($appId, $appData['repair-steps']['post-migration']);
690
-		self::setupLiveMigrations($appId, $appData['repair-steps']['live-migration']);
691
-		// update appversion in app manager
692
-		\OC::$server->getAppManager()->clearAppsCache();
693
-		\OC::$server->getAppManager()->getAppVersion($appId, false);
694
-
695
-		self::setupBackgroundJobs($appData['background-jobs']);
696
-
697
-		//set remote/public handlers
698
-		if (array_key_exists('ocsid', $appData)) {
699
-			\OC::$server->getConfig()->setAppValue($appId, 'ocsid', $appData['ocsid']);
700
-		} elseif (\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
701
-			\OC::$server->getConfig()->deleteAppValue($appId, 'ocsid');
702
-		}
703
-		foreach ($appData['remote'] as $name => $path) {
704
-			\OC::$server->getConfig()->setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
705
-		}
706
-		foreach ($appData['public'] as $name => $path) {
707
-			\OC::$server->getConfig()->setAppValue('core', 'public_' . $name, $appId . '/' . $path);
708
-		}
709
-
710
-		self::setAppTypes($appId);
711
-
712
-		$version = \OCP\Server::get(\OCP\App\IAppManager::class)->getAppVersion($appId);
713
-		\OC::$server->getConfig()->setAppValue($appId, 'installed_version', $version);
714
-
715
-		\OC::$server->get(IEventDispatcher::class)->dispatchTyped(new AppUpdateEvent($appId));
716
-		\OC::$server->get(IEventDispatcher::class)->dispatch(ManagerEvent::EVENT_APP_UPDATE, new ManagerEvent(
717
-			ManagerEvent::EVENT_APP_UPDATE, $appId
718
-		));
719
-
720
-		return true;
721
-	}
722
-
723
-	/**
724
-	 * @param string $appId
725
-	 * @param string[] $steps
726
-	 * @throws \OC\NeedsUpdateException
727
-	 */
728
-	public static function executeRepairSteps(string $appId, array $steps) {
729
-		if (empty($steps)) {
730
-			return;
731
-		}
732
-		// load the app
733
-		self::loadApp($appId);
734
-
735
-		$dispatcher = Server::get(IEventDispatcher::class);
736
-
737
-		// load the steps
738
-		$r = Server::get(Repair::class);
739
-		foreach ($steps as $step) {
740
-			try {
741
-				$r->addStep($step);
742
-			} catch (Exception $ex) {
743
-				$dispatcher->dispatchTyped(new RepairErrorEvent($ex->getMessage()));
744
-				logger('core')->error('Failed to add app migration step ' . $step, ['exception' => $ex]);
745
-			}
746
-		}
747
-		// run the steps
748
-		$r->run();
749
-	}
750
-
751
-	public static function setupBackgroundJobs(array $jobs) {
752
-		$queue = \OC::$server->getJobList();
753
-		foreach ($jobs as $job) {
754
-			$queue->add($job);
755
-		}
756
-	}
757
-
758
-	/**
759
-	 * @param string $appId
760
-	 * @param string[] $steps
761
-	 */
762
-	private static function setupLiveMigrations(string $appId, array $steps) {
763
-		$queue = \OC::$server->getJobList();
764
-		foreach ($steps as $step) {
765
-			$queue->add('OC\Migration\BackgroundRepair', [
766
-				'app' => $appId,
767
-				'step' => $step]);
768
-		}
769
-	}
770
-
771
-	protected static function findBestL10NOption(array $options, string $lang): string {
772
-		// only a single option
773
-		if (isset($options['@value'])) {
774
-			return $options['@value'];
775
-		}
776
-
777
-		$fallback = $similarLangFallback = $englishFallback = false;
778
-
779
-		$lang = strtolower($lang);
780
-		$similarLang = $lang;
781
-		if (strpos($similarLang, '_')) {
782
-			// For "de_DE" we want to find "de" and the other way around
783
-			$similarLang = substr($lang, 0, strpos($lang, '_'));
784
-		}
785
-
786
-		foreach ($options as $option) {
787
-			if (is_array($option)) {
788
-				if ($fallback === false) {
789
-					$fallback = $option['@value'];
790
-				}
791
-
792
-				if (!isset($option['@attributes']['lang'])) {
793
-					continue;
794
-				}
795
-
796
-				$attributeLang = strtolower($option['@attributes']['lang']);
797
-				if ($attributeLang === $lang) {
798
-					return $option['@value'];
799
-				}
800
-
801
-				if ($attributeLang === $similarLang) {
802
-					$similarLangFallback = $option['@value'];
803
-				} elseif (str_starts_with($attributeLang, $similarLang . '_')) {
804
-					if ($similarLangFallback === false) {
805
-						$similarLangFallback = $option['@value'];
806
-					}
807
-				}
808
-			} else {
809
-				$englishFallback = $option;
810
-			}
811
-		}
812
-
813
-		if ($similarLangFallback !== false) {
814
-			return $similarLangFallback;
815
-		} elseif ($englishFallback !== false) {
816
-			return $englishFallback;
817
-		}
818
-		return (string)$fallback;
819
-	}
820
-
821
-	/**
822
-	 * parses the app data array and enhanced the 'description' value
823
-	 *
824
-	 * @param array $data the app data
825
-	 * @param string $lang
826
-	 * @return array improved app data
827
-	 */
828
-	public static function parseAppInfo(array $data, $lang = null): array {
829
-		if ($lang && isset($data['name']) && is_array($data['name'])) {
830
-			$data['name'] = self::findBestL10NOption($data['name'], $lang);
831
-		}
832
-		if ($lang && isset($data['summary']) && is_array($data['summary'])) {
833
-			$data['summary'] = self::findBestL10NOption($data['summary'], $lang);
834
-		}
835
-		if ($lang && isset($data['description']) && is_array($data['description'])) {
836
-			$data['description'] = trim(self::findBestL10NOption($data['description'], $lang));
837
-		} elseif (isset($data['description']) && is_string($data['description'])) {
838
-			$data['description'] = trim($data['description']);
839
-		} else {
840
-			$data['description'] = '';
841
-		}
842
-
843
-		return $data;
844
-	}
845
-
846
-	/**
847
-	 * @param \OCP\IConfig $config
848
-	 * @param \OCP\IL10N $l
849
-	 * @param array $info
850
-	 * @throws \Exception
851
-	 */
852
-	public static function checkAppDependencies(\OCP\IConfig $config, \OCP\IL10N $l, array $info, bool $ignoreMax) {
853
-		$dependencyAnalyzer = new DependencyAnalyzer(new Platform($config), $l);
854
-		$missing = $dependencyAnalyzer->analyze($info, $ignoreMax);
855
-		if (!empty($missing)) {
856
-			$missingMsg = implode(PHP_EOL, $missing);
857
-			throw new \Exception(
858
-				$l->t('App "%1$s" cannot be installed because the following dependencies are not fulfilled: %2$s',
859
-					[$info['name'], $missingMsg]
860
-				)
861
-			);
862
-		}
863
-	}
33
+    private static $altLogin = [];
34
+    private static $alreadyRegistered = [];
35
+    public const supportedApp = 300;
36
+    public const officialApp = 200;
37
+
38
+    /**
39
+     * clean the appId
40
+     *
41
+     * @psalm-taint-escape file
42
+     * @psalm-taint-escape include
43
+     * @psalm-taint-escape html
44
+     * @psalm-taint-escape has_quotes
45
+     *
46
+     * @deprecated 31.0.0 use IAppManager::cleanAppId
47
+     */
48
+    public static function cleanAppId(string $app): string {
49
+        return str_replace(['<', '>', '"', "'", '\0', '/', '\\', '..'], '', $app);
50
+    }
51
+
52
+    /**
53
+     * Check if an app is loaded
54
+     *
55
+     * @param string $app
56
+     * @return bool
57
+     * @deprecated 27.0.0 use IAppManager::isAppLoaded
58
+     */
59
+    public static function isAppLoaded(string $app): bool {
60
+        return \OC::$server->get(IAppManager::class)->isAppLoaded($app);
61
+    }
62
+
63
+    /**
64
+     * loads all apps
65
+     *
66
+     * @param string[] $types
67
+     * @return bool
68
+     *
69
+     * This function walks through the Nextcloud directory and loads all apps
70
+     * it can find. A directory contains an app if the file /appinfo/info.xml
71
+     * exists.
72
+     *
73
+     * if $types is set to non-empty array, only apps of those types will be loaded
74
+     *
75
+     * @deprecated 29.0.0 use IAppManager::loadApps instead
76
+     */
77
+    public static function loadApps(array $types = []): bool {
78
+        if (!\OC::$server->getSystemConfig()->getValue('installed', false)) {
79
+            // This should be done before calling this method so that appmanager can be used
80
+            return false;
81
+        }
82
+        return \OC::$server->get(IAppManager::class)->loadApps($types);
83
+    }
84
+
85
+    /**
86
+     * load a single app
87
+     *
88
+     * @param string $app
89
+     * @throws Exception
90
+     * @deprecated 27.0.0 use IAppManager::loadApp
91
+     */
92
+    public static function loadApp(string $app): void {
93
+        \OC::$server->get(IAppManager::class)->loadApp($app);
94
+    }
95
+
96
+    /**
97
+     * @internal
98
+     * @param string $app
99
+     * @param string $path
100
+     * @param bool $force
101
+     */
102
+    public static function registerAutoloading(string $app, string $path, bool $force = false) {
103
+        $key = $app . '-' . $path;
104
+        if (!$force && isset(self::$alreadyRegistered[$key])) {
105
+            return;
106
+        }
107
+
108
+        self::$alreadyRegistered[$key] = true;
109
+
110
+        // Register on PSR-4 composer autoloader
111
+        $appNamespace = \OC\AppFramework\App::buildAppNamespace($app);
112
+        \OC::$server->registerNamespace($app, $appNamespace);
113
+
114
+        if (file_exists($path . '/composer/autoload.php')) {
115
+            require_once $path . '/composer/autoload.php';
116
+        } else {
117
+            \OC::$composerAutoloader->addPsr4($appNamespace . '\\', $path . '/lib/', true);
118
+        }
119
+
120
+        // Register Test namespace only when testing
121
+        if (defined('PHPUNIT_RUN') || defined('CLI_TEST_RUN')) {
122
+            \OC::$composerAutoloader->addPsr4($appNamespace . '\\Tests\\', $path . '/tests/', true);
123
+        }
124
+    }
125
+
126
+    /**
127
+     * check if an app is of a specific type
128
+     *
129
+     * @param string $app
130
+     * @param array $types
131
+     * @return bool
132
+     * @deprecated 27.0.0 use IAppManager::isType
133
+     */
134
+    public static function isType(string $app, array $types): bool {
135
+        return \OC::$server->get(IAppManager::class)->isType($app, $types);
136
+    }
137
+
138
+    /**
139
+     * read app types from info.xml and cache them in the database
140
+     */
141
+    public static function setAppTypes(string $app) {
142
+        $appManager = \OC::$server->getAppManager();
143
+        $appData = $appManager->getAppInfo($app);
144
+        if (!is_array($appData)) {
145
+            return;
146
+        }
147
+
148
+        if (isset($appData['types'])) {
149
+            $appTypes = implode(',', $appData['types']);
150
+        } else {
151
+            $appTypes = '';
152
+            $appData['types'] = [];
153
+        }
154
+
155
+        $config = \OC::$server->getConfig();
156
+        $config->setAppValue($app, 'types', $appTypes);
157
+
158
+        if ($appManager->hasProtectedAppType($appData['types'])) {
159
+            $enabled = $config->getAppValue($app, 'enabled', 'yes');
160
+            if ($enabled !== 'yes' && $enabled !== 'no') {
161
+                $config->setAppValue($app, 'enabled', 'yes');
162
+            }
163
+        }
164
+    }
165
+
166
+    /**
167
+     * Returns apps enabled for the current user.
168
+     *
169
+     * @param bool $forceRefresh whether to refresh the cache
170
+     * @param bool $all whether to return apps for all users, not only the
171
+     *                  currently logged in one
172
+     * @return list<string>
173
+     */
174
+    public static function getEnabledApps(bool $forceRefresh = false, bool $all = false): array {
175
+        if (!\OC::$server->getSystemConfig()->getValue('installed', false)) {
176
+            return [];
177
+        }
178
+        // in incognito mode or when logged out, $user will be false,
179
+        // which is also the case during an upgrade
180
+        $appManager = \OC::$server->getAppManager();
181
+        if ($all) {
182
+            $user = null;
183
+        } else {
184
+            $user = \OC::$server->getUserSession()->getUser();
185
+        }
186
+
187
+        if (is_null($user)) {
188
+            $apps = $appManager->getEnabledApps();
189
+        } else {
190
+            $apps = $appManager->getEnabledAppsForUser($user);
191
+        }
192
+        $apps = array_filter($apps, function ($app) {
193
+            return $app !== 'files';//we add this manually
194
+        });
195
+        sort($apps);
196
+        array_unshift($apps, 'files');
197
+        return $apps;
198
+    }
199
+
200
+    /**
201
+     * enables an app
202
+     *
203
+     * @param string $appId
204
+     * @param array $groups (optional) when set, only these groups will have access to the app
205
+     * @throws \Exception
206
+     * @return void
207
+     *
208
+     * This function set an app as enabled in appconfig.
209
+     */
210
+    public function enable(string $appId,
211
+        array $groups = []) {
212
+        // Check if app is already downloaded
213
+        /** @var Installer $installer */
214
+        $installer = \OCP\Server::get(Installer::class);
215
+        $isDownloaded = $installer->isDownloaded($appId);
216
+
217
+        if (!$isDownloaded) {
218
+            $installer->downloadApp($appId);
219
+        }
220
+
221
+        $installer->installApp($appId);
222
+
223
+        $appManager = \OC::$server->getAppManager();
224
+        if ($groups !== []) {
225
+            $groupManager = \OC::$server->getGroupManager();
226
+            $groupsList = [];
227
+            foreach ($groups as $group) {
228
+                $groupItem = $groupManager->get($group);
229
+                if ($groupItem instanceof \OCP\IGroup) {
230
+                    $groupsList[] = $groupManager->get($group);
231
+                }
232
+            }
233
+            $appManager->enableAppForGroups($appId, $groupsList);
234
+        } else {
235
+            $appManager->enableApp($appId);
236
+        }
237
+    }
238
+
239
+    /**
240
+     * Get the path where to install apps
241
+     */
242
+    public static function getInstallPath(): ?string {
243
+        foreach (OC::$APPSROOTS as $dir) {
244
+            if (isset($dir['writable']) && $dir['writable'] === true) {
245
+                return $dir['path'];
246
+            }
247
+        }
248
+
249
+        \OCP\Server::get(LoggerInterface::class)->error('No application directories are marked as writable.', ['app' => 'core']);
250
+        return null;
251
+    }
252
+
253
+
254
+    /**
255
+     * Find the apps root for an app id.
256
+     *
257
+     * If multiple copies are found, the apps root the latest version is returned.
258
+     *
259
+     * @param string $appId
260
+     * @param bool $ignoreCache ignore cache and rebuild it
261
+     * @return false|array{path: string, url: string} the apps root shape
262
+     */
263
+    public static function findAppInDirectories(string $appId, bool $ignoreCache = false) {
264
+        $sanitizedAppId = self::cleanAppId($appId);
265
+        if ($sanitizedAppId !== $appId) {
266
+            return false;
267
+        }
268
+        static $app_dir = [];
269
+
270
+        if (isset($app_dir[$appId]) && !$ignoreCache) {
271
+            return $app_dir[$appId];
272
+        }
273
+
274
+        $possibleApps = [];
275
+        foreach (OC::$APPSROOTS as $dir) {
276
+            if (file_exists($dir['path'] . '/' . $appId)) {
277
+                $possibleApps[] = $dir;
278
+            }
279
+        }
280
+
281
+        if (empty($possibleApps)) {
282
+            return false;
283
+        } elseif (count($possibleApps) === 1) {
284
+            $dir = array_shift($possibleApps);
285
+            $app_dir[$appId] = $dir;
286
+            return $dir;
287
+        } else {
288
+            $versionToLoad = [];
289
+            foreach ($possibleApps as $possibleApp) {
290
+                $version = self::getAppVersionByPath($possibleApp['path'] . '/' . $appId);
291
+                if (empty($versionToLoad) || version_compare($version, $versionToLoad['version'], '>')) {
292
+                    $versionToLoad = [
293
+                        'dir' => $possibleApp,
294
+                        'version' => $version,
295
+                    ];
296
+                }
297
+            }
298
+            $app_dir[$appId] = $versionToLoad['dir'];
299
+            return $versionToLoad['dir'];
300
+            //TODO - write test
301
+        }
302
+    }
303
+
304
+    /**
305
+     * Get the directory for the given app.
306
+     * If the app is defined in multiple directories, the first one is taken. (false if not found)
307
+     *
308
+     * @psalm-taint-specialize
309
+     *
310
+     * @param string $appId
311
+     * @param bool $refreshAppPath should be set to true only during install/upgrade
312
+     * @return string|false
313
+     * @deprecated 11.0.0 use \OCP\Server::get(IAppManager)->getAppPath()
314
+     */
315
+    public static function getAppPath(string $appId, bool $refreshAppPath = false) {
316
+        $appId = self::cleanAppId($appId);
317
+        if ($appId === '') {
318
+            return false;
319
+        }
320
+
321
+        if (($dir = self::findAppInDirectories($appId, $refreshAppPath)) != false) {
322
+            return $dir['path'] . '/' . $appId;
323
+        }
324
+        return false;
325
+    }
326
+
327
+    /**
328
+     * Get the path for the given app on the access
329
+     * If the app is defined in multiple directories, the first one is taken. (false if not found)
330
+     *
331
+     * @param string $appId
332
+     * @return string|false
333
+     * @deprecated 18.0.0 use \OC::$server->getAppManager()->getAppWebPath()
334
+     */
335
+    public static function getAppWebPath(string $appId) {
336
+        if (($dir = self::findAppInDirectories($appId)) != false) {
337
+            return OC::$WEBROOT . $dir['url'] . '/' . $appId;
338
+        }
339
+        return false;
340
+    }
341
+
342
+    /**
343
+     * get app's version based on it's path
344
+     *
345
+     * @param string $path
346
+     * @return string
347
+     */
348
+    public static function getAppVersionByPath(string $path): string {
349
+        $infoFile = $path . '/appinfo/info.xml';
350
+        $appData = \OCP\Server::get(IAppManager::class)->getAppInfoByPath($infoFile);
351
+        return $appData['version'] ?? '';
352
+    }
353
+
354
+    /**
355
+     * get the id of loaded app
356
+     *
357
+     * @return string
358
+     */
359
+    public static function getCurrentApp(): string {
360
+        if (\OC::$CLI) {
361
+            return '';
362
+        }
363
+
364
+        $request = \OC::$server->getRequest();
365
+        $script = substr($request->getScriptName(), strlen(OC::$WEBROOT) + 1);
366
+        $topFolder = substr($script, 0, strpos($script, '/') ?: 0);
367
+        if (empty($topFolder)) {
368
+            try {
369
+                $path_info = $request->getPathInfo();
370
+            } catch (Exception $e) {
371
+                // Can happen from unit tests because the script name is `./vendor/bin/phpunit` or something a like then.
372
+                \OC::$server->get(LoggerInterface::class)->error('Failed to detect current app from script path', ['exception' => $e]);
373
+                return '';
374
+            }
375
+            if ($path_info) {
376
+                $topFolder = substr($path_info, 1, strpos($path_info, '/', 1) - 1);
377
+            }
378
+        }
379
+        if ($topFolder == 'apps') {
380
+            $length = strlen($topFolder);
381
+            return substr($script, $length + 1, strpos($script, '/', $length + 1) - $length - 1) ?: '';
382
+        } else {
383
+            return $topFolder;
384
+        }
385
+    }
386
+
387
+    /**
388
+     * @param array $entry
389
+     * @deprecated 20.0.0 Please register your alternative login option using the registerAlternativeLogin() on the RegistrationContext in your Application class implementing the OCP\Authentication\IAlternativeLogin interface
390
+     */
391
+    public static function registerLogIn(array $entry) {
392
+        \OCP\Server::get(LoggerInterface::class)->debug('OC_App::registerLogIn() is deprecated, please register your alternative login option using the registerAlternativeLogin() on the RegistrationContext in your Application class implementing the OCP\Authentication\IAlternativeLogin interface');
393
+        self::$altLogin[] = $entry;
394
+    }
395
+
396
+    /**
397
+     * @return array
398
+     */
399
+    public static function getAlternativeLogIns(): array {
400
+        /** @var Coordinator $bootstrapCoordinator */
401
+        $bootstrapCoordinator = \OCP\Server::get(Coordinator::class);
402
+
403
+        foreach ($bootstrapCoordinator->getRegistrationContext()->getAlternativeLogins() as $registration) {
404
+            if (!in_array(IAlternativeLogin::class, class_implements($registration->getService()), true)) {
405
+                \OCP\Server::get(LoggerInterface::class)->error('Alternative login option {option} does not implement {interface} and is therefore ignored.', [
406
+                    'option' => $registration->getService(),
407
+                    'interface' => IAlternativeLogin::class,
408
+                    'app' => $registration->getAppId(),
409
+                ]);
410
+                continue;
411
+            }
412
+
413
+            try {
414
+                /** @var IAlternativeLogin $provider */
415
+                $provider = \OCP\Server::get($registration->getService());
416
+            } catch (ContainerExceptionInterface $e) {
417
+                \OCP\Server::get(LoggerInterface::class)->error('Alternative login option {option} can not be initialized.',
418
+                    [
419
+                        'exception' => $e,
420
+                        'option' => $registration->getService(),
421
+                        'app' => $registration->getAppId(),
422
+                    ]);
423
+            }
424
+
425
+            try {
426
+                $provider->load();
427
+
428
+                self::$altLogin[] = [
429
+                    'name' => $provider->getLabel(),
430
+                    'href' => $provider->getLink(),
431
+                    'class' => $provider->getClass(),
432
+                ];
433
+            } catch (Throwable $e) {
434
+                \OCP\Server::get(LoggerInterface::class)->error('Alternative login option {option} had an error while loading.',
435
+                    [
436
+                        'exception' => $e,
437
+                        'option' => $registration->getService(),
438
+                        'app' => $registration->getAppId(),
439
+                    ]);
440
+            }
441
+        }
442
+
443
+        return self::$altLogin;
444
+    }
445
+
446
+    /**
447
+     * get a list of all apps in the apps folder
448
+     *
449
+     * @return string[] an array of app names (string IDs)
450
+     * @deprecated 31.0.0 Use IAppManager::getAllAppsInAppsFolders instead
451
+     */
452
+    public static function getAllApps(): array {
453
+        return \OCP\Server::get(IAppManager::class)->getAllAppsInAppsFolders();
454
+    }
455
+
456
+    /**
457
+     * List all supported apps
458
+     *
459
+     * @deprecated 32.0.0 Use \OCP\Support\Subscription\IRegistry::delegateGetSupportedApps instead
460
+     */
461
+    public function getSupportedApps(): array {
462
+        $subscriptionRegistry = \OCP\Server::get(\OCP\Support\Subscription\IRegistry::class);
463
+        $supportedApps = $subscriptionRegistry->delegateGetSupportedApps();
464
+        return $supportedApps;
465
+    }
466
+
467
+    /**
468
+     * List all apps, this is used in apps.php
469
+     *
470
+     * @return array
471
+     */
472
+    public function listAllApps(): array {
473
+        $appManager = \OC::$server->getAppManager();
474
+
475
+        $installedApps = $appManager->getAllAppsInAppsFolders();
476
+        //we don't want to show configuration for these
477
+        $blacklist = $appManager->getAlwaysEnabledApps();
478
+        $appList = [];
479
+        $langCode = \OC::$server->getL10N('core')->getLanguageCode();
480
+        $urlGenerator = \OC::$server->getURLGenerator();
481
+        $supportedApps = $this->getSupportedApps();
482
+
483
+        foreach ($installedApps as $app) {
484
+            if (!in_array($app, $blacklist)) {
485
+                $info = $appManager->getAppInfo($app, false, $langCode);
486
+                if (!is_array($info)) {
487
+                    \OCP\Server::get(LoggerInterface::class)->error('Could not read app info file for app "' . $app . '"', ['app' => 'core']);
488
+                    continue;
489
+                }
490
+
491
+                if (!isset($info['name'])) {
492
+                    \OCP\Server::get(LoggerInterface::class)->error('App id "' . $app . '" has no name in appinfo', ['app' => 'core']);
493
+                    continue;
494
+                }
495
+
496
+                $enabled = \OC::$server->getConfig()->getAppValue($app, 'enabled', 'no');
497
+                $info['groups'] = null;
498
+                if ($enabled === 'yes') {
499
+                    $active = true;
500
+                } elseif ($enabled === 'no') {
501
+                    $active = false;
502
+                } else {
503
+                    $active = true;
504
+                    $info['groups'] = $enabled;
505
+                }
506
+
507
+                $info['active'] = $active;
508
+
509
+                if ($appManager->isShipped($app)) {
510
+                    $info['internal'] = true;
511
+                    $info['level'] = self::officialApp;
512
+                    $info['removable'] = false;
513
+                } else {
514
+                    $info['internal'] = false;
515
+                    $info['removable'] = true;
516
+                }
517
+
518
+                if (in_array($app, $supportedApps)) {
519
+                    $info['level'] = self::supportedApp;
520
+                }
521
+
522
+                $appPath = self::getAppPath($app);
523
+                if ($appPath !== false) {
524
+                    $appIcon = $appPath . '/img/' . $app . '.svg';
525
+                    if (file_exists($appIcon)) {
526
+                        $info['preview'] = $urlGenerator->imagePath($app, $app . '.svg');
527
+                        $info['previewAsIcon'] = true;
528
+                    } else {
529
+                        $appIcon = $appPath . '/img/app.svg';
530
+                        if (file_exists($appIcon)) {
531
+                            $info['preview'] = $urlGenerator->imagePath($app, 'app.svg');
532
+                            $info['previewAsIcon'] = true;
533
+                        }
534
+                    }
535
+                }
536
+                // fix documentation
537
+                if (isset($info['documentation']) && is_array($info['documentation'])) {
538
+                    foreach ($info['documentation'] as $key => $url) {
539
+                        // If it is not an absolute URL we assume it is a key
540
+                        // i.e. admin-ldap will get converted to go.php?to=admin-ldap
541
+                        if (stripos($url, 'https://') !== 0 && stripos($url, 'http://') !== 0) {
542
+                            $url = $urlGenerator->linkToDocs($url);
543
+                        }
544
+
545
+                        $info['documentation'][$key] = $url;
546
+                    }
547
+                }
548
+
549
+                $info['version'] = $appManager->getAppVersion($app);
550
+                $appList[] = $info;
551
+            }
552
+        }
553
+
554
+        return $appList;
555
+    }
556
+
557
+    public static function shouldUpgrade(string $app): bool {
558
+        $versions = self::getAppVersions();
559
+        $currentVersion = \OCP\Server::get(\OCP\App\IAppManager::class)->getAppVersion($app);
560
+        if ($currentVersion && isset($versions[$app])) {
561
+            $installedVersion = $versions[$app];
562
+            if (!version_compare($currentVersion, $installedVersion, '=')) {
563
+                return true;
564
+            }
565
+        }
566
+        return false;
567
+    }
568
+
569
+    /**
570
+     * Adjust the number of version parts of $version1 to match
571
+     * the number of version parts of $version2.
572
+     *
573
+     * @param string $version1 version to adjust
574
+     * @param string $version2 version to take the number of parts from
575
+     * @return string shortened $version1
576
+     */
577
+    private static function adjustVersionParts(string $version1, string $version2): string {
578
+        $version1 = explode('.', $version1);
579
+        $version2 = explode('.', $version2);
580
+        // reduce $version1 to match the number of parts in $version2
581
+        while (count($version1) > count($version2)) {
582
+            array_pop($version1);
583
+        }
584
+        // if $version1 does not have enough parts, add some
585
+        while (count($version1) < count($version2)) {
586
+            $version1[] = '0';
587
+        }
588
+        return implode('.', $version1);
589
+    }
590
+
591
+    /**
592
+     * Check whether the current Nextcloud version matches the given
593
+     * application's version requirements.
594
+     *
595
+     * The comparison is made based on the number of parts that the
596
+     * app info version has. For example for ownCloud 6.0.3 if the
597
+     * app info version is expecting version 6.0, the comparison is
598
+     * made on the first two parts of the ownCloud version.
599
+     * This means that it's possible to specify "requiremin" => 6
600
+     * and "requiremax" => 6 and it will still match ownCloud 6.0.3.
601
+     *
602
+     * @param string $ocVersion Nextcloud version to check against
603
+     * @param array $appInfo app info (from xml)
604
+     *
605
+     * @return boolean true if compatible, otherwise false
606
+     */
607
+    public static function isAppCompatible(string $ocVersion, array $appInfo, bool $ignoreMax = false): bool {
608
+        $requireMin = '';
609
+        $requireMax = '';
610
+        if (isset($appInfo['dependencies']['nextcloud']['@attributes']['min-version'])) {
611
+            $requireMin = $appInfo['dependencies']['nextcloud']['@attributes']['min-version'];
612
+        } elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['min-version'])) {
613
+            $requireMin = $appInfo['dependencies']['owncloud']['@attributes']['min-version'];
614
+        } elseif (isset($appInfo['requiremin'])) {
615
+            $requireMin = $appInfo['requiremin'];
616
+        } elseif (isset($appInfo['require'])) {
617
+            $requireMin = $appInfo['require'];
618
+        }
619
+
620
+        if (isset($appInfo['dependencies']['nextcloud']['@attributes']['max-version'])) {
621
+            $requireMax = $appInfo['dependencies']['nextcloud']['@attributes']['max-version'];
622
+        } elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['max-version'])) {
623
+            $requireMax = $appInfo['dependencies']['owncloud']['@attributes']['max-version'];
624
+        } elseif (isset($appInfo['requiremax'])) {
625
+            $requireMax = $appInfo['requiremax'];
626
+        }
627
+
628
+        if (!empty($requireMin)
629
+            && version_compare(self::adjustVersionParts($ocVersion, $requireMin), $requireMin, '<')
630
+        ) {
631
+            return false;
632
+        }
633
+
634
+        if (!$ignoreMax && !empty($requireMax)
635
+            && version_compare(self::adjustVersionParts($ocVersion, $requireMax), $requireMax, '>')
636
+        ) {
637
+            return false;
638
+        }
639
+
640
+        return true;
641
+    }
642
+
643
+    /**
644
+     * get the installed version of all apps
645
+     * @deprecated 32.0.0 Use IAppManager::getAppInstalledVersions or IAppConfig::getAppInstalledVersions instead
646
+     */
647
+    public static function getAppVersions(): array {
648
+        return \OCP\Server::get(IAppConfig::class)->getAppInstalledVersions();
649
+    }
650
+
651
+    /**
652
+     * update the database for the app and call the update script
653
+     *
654
+     * @param string $appId
655
+     * @return bool
656
+     */
657
+    public static function updateApp(string $appId): bool {
658
+        // for apps distributed with core, we refresh app path in case the downloaded version
659
+        // have been installed in custom apps and not in the default path
660
+        $appPath = self::getAppPath($appId, true);
661
+        if ($appPath === false) {
662
+            return false;
663
+        }
664
+
665
+        if (is_file($appPath . '/appinfo/database.xml')) {
666
+            \OCP\Server::get(LoggerInterface::class)->error('The appinfo/database.xml file is not longer supported. Used in ' . $appId);
667
+            return false;
668
+        }
669
+
670
+        \OC::$server->getAppManager()->clearAppsCache();
671
+        $l = \OC::$server->getL10N('core');
672
+        $appData = \OCP\Server::get(\OCP\App\IAppManager::class)->getAppInfo($appId, false, $l->getLanguageCode());
673
+
674
+        $ignoreMaxApps = \OC::$server->getConfig()->getSystemValue('app_install_overwrite', []);
675
+        $ignoreMax = in_array($appId, $ignoreMaxApps, true);
676
+        \OC_App::checkAppDependencies(
677
+            \OC::$server->getConfig(),
678
+            $l,
679
+            $appData,
680
+            $ignoreMax
681
+        );
682
+
683
+        self::registerAutoloading($appId, $appPath, true);
684
+        self::executeRepairSteps($appId, $appData['repair-steps']['pre-migration']);
685
+
686
+        $ms = new MigrationService($appId, \OC::$server->get(\OC\DB\Connection::class));
687
+        $ms->migrate();
688
+
689
+        self::executeRepairSteps($appId, $appData['repair-steps']['post-migration']);
690
+        self::setupLiveMigrations($appId, $appData['repair-steps']['live-migration']);
691
+        // update appversion in app manager
692
+        \OC::$server->getAppManager()->clearAppsCache();
693
+        \OC::$server->getAppManager()->getAppVersion($appId, false);
694
+
695
+        self::setupBackgroundJobs($appData['background-jobs']);
696
+
697
+        //set remote/public handlers
698
+        if (array_key_exists('ocsid', $appData)) {
699
+            \OC::$server->getConfig()->setAppValue($appId, 'ocsid', $appData['ocsid']);
700
+        } elseif (\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
701
+            \OC::$server->getConfig()->deleteAppValue($appId, 'ocsid');
702
+        }
703
+        foreach ($appData['remote'] as $name => $path) {
704
+            \OC::$server->getConfig()->setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
705
+        }
706
+        foreach ($appData['public'] as $name => $path) {
707
+            \OC::$server->getConfig()->setAppValue('core', 'public_' . $name, $appId . '/' . $path);
708
+        }
709
+
710
+        self::setAppTypes($appId);
711
+
712
+        $version = \OCP\Server::get(\OCP\App\IAppManager::class)->getAppVersion($appId);
713
+        \OC::$server->getConfig()->setAppValue($appId, 'installed_version', $version);
714
+
715
+        \OC::$server->get(IEventDispatcher::class)->dispatchTyped(new AppUpdateEvent($appId));
716
+        \OC::$server->get(IEventDispatcher::class)->dispatch(ManagerEvent::EVENT_APP_UPDATE, new ManagerEvent(
717
+            ManagerEvent::EVENT_APP_UPDATE, $appId
718
+        ));
719
+
720
+        return true;
721
+    }
722
+
723
+    /**
724
+     * @param string $appId
725
+     * @param string[] $steps
726
+     * @throws \OC\NeedsUpdateException
727
+     */
728
+    public static function executeRepairSteps(string $appId, array $steps) {
729
+        if (empty($steps)) {
730
+            return;
731
+        }
732
+        // load the app
733
+        self::loadApp($appId);
734
+
735
+        $dispatcher = Server::get(IEventDispatcher::class);
736
+
737
+        // load the steps
738
+        $r = Server::get(Repair::class);
739
+        foreach ($steps as $step) {
740
+            try {
741
+                $r->addStep($step);
742
+            } catch (Exception $ex) {
743
+                $dispatcher->dispatchTyped(new RepairErrorEvent($ex->getMessage()));
744
+                logger('core')->error('Failed to add app migration step ' . $step, ['exception' => $ex]);
745
+            }
746
+        }
747
+        // run the steps
748
+        $r->run();
749
+    }
750
+
751
+    public static function setupBackgroundJobs(array $jobs) {
752
+        $queue = \OC::$server->getJobList();
753
+        foreach ($jobs as $job) {
754
+            $queue->add($job);
755
+        }
756
+    }
757
+
758
+    /**
759
+     * @param string $appId
760
+     * @param string[] $steps
761
+     */
762
+    private static function setupLiveMigrations(string $appId, array $steps) {
763
+        $queue = \OC::$server->getJobList();
764
+        foreach ($steps as $step) {
765
+            $queue->add('OC\Migration\BackgroundRepair', [
766
+                'app' => $appId,
767
+                'step' => $step]);
768
+        }
769
+    }
770
+
771
+    protected static function findBestL10NOption(array $options, string $lang): string {
772
+        // only a single option
773
+        if (isset($options['@value'])) {
774
+            return $options['@value'];
775
+        }
776
+
777
+        $fallback = $similarLangFallback = $englishFallback = false;
778
+
779
+        $lang = strtolower($lang);
780
+        $similarLang = $lang;
781
+        if (strpos($similarLang, '_')) {
782
+            // For "de_DE" we want to find "de" and the other way around
783
+            $similarLang = substr($lang, 0, strpos($lang, '_'));
784
+        }
785
+
786
+        foreach ($options as $option) {
787
+            if (is_array($option)) {
788
+                if ($fallback === false) {
789
+                    $fallback = $option['@value'];
790
+                }
791
+
792
+                if (!isset($option['@attributes']['lang'])) {
793
+                    continue;
794
+                }
795
+
796
+                $attributeLang = strtolower($option['@attributes']['lang']);
797
+                if ($attributeLang === $lang) {
798
+                    return $option['@value'];
799
+                }
800
+
801
+                if ($attributeLang === $similarLang) {
802
+                    $similarLangFallback = $option['@value'];
803
+                } elseif (str_starts_with($attributeLang, $similarLang . '_')) {
804
+                    if ($similarLangFallback === false) {
805
+                        $similarLangFallback = $option['@value'];
806
+                    }
807
+                }
808
+            } else {
809
+                $englishFallback = $option;
810
+            }
811
+        }
812
+
813
+        if ($similarLangFallback !== false) {
814
+            return $similarLangFallback;
815
+        } elseif ($englishFallback !== false) {
816
+            return $englishFallback;
817
+        }
818
+        return (string)$fallback;
819
+    }
820
+
821
+    /**
822
+     * parses the app data array and enhanced the 'description' value
823
+     *
824
+     * @param array $data the app data
825
+     * @param string $lang
826
+     * @return array improved app data
827
+     */
828
+    public static function parseAppInfo(array $data, $lang = null): array {
829
+        if ($lang && isset($data['name']) && is_array($data['name'])) {
830
+            $data['name'] = self::findBestL10NOption($data['name'], $lang);
831
+        }
832
+        if ($lang && isset($data['summary']) && is_array($data['summary'])) {
833
+            $data['summary'] = self::findBestL10NOption($data['summary'], $lang);
834
+        }
835
+        if ($lang && isset($data['description']) && is_array($data['description'])) {
836
+            $data['description'] = trim(self::findBestL10NOption($data['description'], $lang));
837
+        } elseif (isset($data['description']) && is_string($data['description'])) {
838
+            $data['description'] = trim($data['description']);
839
+        } else {
840
+            $data['description'] = '';
841
+        }
842
+
843
+        return $data;
844
+    }
845
+
846
+    /**
847
+     * @param \OCP\IConfig $config
848
+     * @param \OCP\IL10N $l
849
+     * @param array $info
850
+     * @throws \Exception
851
+     */
852
+    public static function checkAppDependencies(\OCP\IConfig $config, \OCP\IL10N $l, array $info, bool $ignoreMax) {
853
+        $dependencyAnalyzer = new DependencyAnalyzer(new Platform($config), $l);
854
+        $missing = $dependencyAnalyzer->analyze($info, $ignoreMax);
855
+        if (!empty($missing)) {
856
+            $missingMsg = implode(PHP_EOL, $missing);
857
+            throw new \Exception(
858
+                $l->t('App "%1$s" cannot be installed because the following dependencies are not fulfilled: %2$s',
859
+                    [$info['name'], $missingMsg]
860
+                )
861
+            );
862
+        }
863
+    }
864 864
 }
Please login to merge, or discard this patch.
Spacing   +24 added lines, -24 removed lines patch added patch discarded remove patch
@@ -100,7 +100,7 @@  discard block
 block discarded – undo
100 100
 	 * @param bool $force
101 101
 	 */
102 102
 	public static function registerAutoloading(string $app, string $path, bool $force = false) {
103
-		$key = $app . '-' . $path;
103
+		$key = $app.'-'.$path;
104 104
 		if (!$force && isset(self::$alreadyRegistered[$key])) {
105 105
 			return;
106 106
 		}
@@ -111,15 +111,15 @@  discard block
 block discarded – undo
111 111
 		$appNamespace = \OC\AppFramework\App::buildAppNamespace($app);
112 112
 		\OC::$server->registerNamespace($app, $appNamespace);
113 113
 
114
-		if (file_exists($path . '/composer/autoload.php')) {
115
-			require_once $path . '/composer/autoload.php';
114
+		if (file_exists($path.'/composer/autoload.php')) {
115
+			require_once $path.'/composer/autoload.php';
116 116
 		} else {
117
-			\OC::$composerAutoloader->addPsr4($appNamespace . '\\', $path . '/lib/', true);
117
+			\OC::$composerAutoloader->addPsr4($appNamespace.'\\', $path.'/lib/', true);
118 118
 		}
119 119
 
120 120
 		// Register Test namespace only when testing
121 121
 		if (defined('PHPUNIT_RUN') || defined('CLI_TEST_RUN')) {
122
-			\OC::$composerAutoloader->addPsr4($appNamespace . '\\Tests\\', $path . '/tests/', true);
122
+			\OC::$composerAutoloader->addPsr4($appNamespace.'\\Tests\\', $path.'/tests/', true);
123 123
 		}
124 124
 	}
125 125
 
@@ -189,8 +189,8 @@  discard block
 block discarded – undo
189 189
 		} else {
190 190
 			$apps = $appManager->getEnabledAppsForUser($user);
191 191
 		}
192
-		$apps = array_filter($apps, function ($app) {
193
-			return $app !== 'files';//we add this manually
192
+		$apps = array_filter($apps, function($app) {
193
+			return $app !== 'files'; //we add this manually
194 194
 		});
195 195
 		sort($apps);
196 196
 		array_unshift($apps, 'files');
@@ -273,7 +273,7 @@  discard block
 block discarded – undo
273 273
 
274 274
 		$possibleApps = [];
275 275
 		foreach (OC::$APPSROOTS as $dir) {
276
-			if (file_exists($dir['path'] . '/' . $appId)) {
276
+			if (file_exists($dir['path'].'/'.$appId)) {
277 277
 				$possibleApps[] = $dir;
278 278
 			}
279 279
 		}
@@ -287,7 +287,7 @@  discard block
 block discarded – undo
287 287
 		} else {
288 288
 			$versionToLoad = [];
289 289
 			foreach ($possibleApps as $possibleApp) {
290
-				$version = self::getAppVersionByPath($possibleApp['path'] . '/' . $appId);
290
+				$version = self::getAppVersionByPath($possibleApp['path'].'/'.$appId);
291 291
 				if (empty($versionToLoad) || version_compare($version, $versionToLoad['version'], '>')) {
292 292
 					$versionToLoad = [
293 293
 						'dir' => $possibleApp,
@@ -319,7 +319,7 @@  discard block
 block discarded – undo
319 319
 		}
320 320
 
321 321
 		if (($dir = self::findAppInDirectories($appId, $refreshAppPath)) != false) {
322
-			return $dir['path'] . '/' . $appId;
322
+			return $dir['path'].'/'.$appId;
323 323
 		}
324 324
 		return false;
325 325
 	}
@@ -334,7 +334,7 @@  discard block
 block discarded – undo
334 334
 	 */
335 335
 	public static function getAppWebPath(string $appId) {
336 336
 		if (($dir = self::findAppInDirectories($appId)) != false) {
337
-			return OC::$WEBROOT . $dir['url'] . '/' . $appId;
337
+			return OC::$WEBROOT.$dir['url'].'/'.$appId;
338 338
 		}
339 339
 		return false;
340 340
 	}
@@ -346,7 +346,7 @@  discard block
 block discarded – undo
346 346
 	 * @return string
347 347
 	 */
348 348
 	public static function getAppVersionByPath(string $path): string {
349
-		$infoFile = $path . '/appinfo/info.xml';
349
+		$infoFile = $path.'/appinfo/info.xml';
350 350
 		$appData = \OCP\Server::get(IAppManager::class)->getAppInfoByPath($infoFile);
351 351
 		return $appData['version'] ?? '';
352 352
 	}
@@ -484,12 +484,12 @@  discard block
 block discarded – undo
484 484
 			if (!in_array($app, $blacklist)) {
485 485
 				$info = $appManager->getAppInfo($app, false, $langCode);
486 486
 				if (!is_array($info)) {
487
-					\OCP\Server::get(LoggerInterface::class)->error('Could not read app info file for app "' . $app . '"', ['app' => 'core']);
487
+					\OCP\Server::get(LoggerInterface::class)->error('Could not read app info file for app "'.$app.'"', ['app' => 'core']);
488 488
 					continue;
489 489
 				}
490 490
 
491 491
 				if (!isset($info['name'])) {
492
-					\OCP\Server::get(LoggerInterface::class)->error('App id "' . $app . '" has no name in appinfo', ['app' => 'core']);
492
+					\OCP\Server::get(LoggerInterface::class)->error('App id "'.$app.'" has no name in appinfo', ['app' => 'core']);
493 493
 					continue;
494 494
 				}
495 495
 
@@ -521,12 +521,12 @@  discard block
 block discarded – undo
521 521
 
522 522
 				$appPath = self::getAppPath($app);
523 523
 				if ($appPath !== false) {
524
-					$appIcon = $appPath . '/img/' . $app . '.svg';
524
+					$appIcon = $appPath.'/img/'.$app.'.svg';
525 525
 					if (file_exists($appIcon)) {
526
-						$info['preview'] = $urlGenerator->imagePath($app, $app . '.svg');
526
+						$info['preview'] = $urlGenerator->imagePath($app, $app.'.svg');
527 527
 						$info['previewAsIcon'] = true;
528 528
 					} else {
529
-						$appIcon = $appPath . '/img/app.svg';
529
+						$appIcon = $appPath.'/img/app.svg';
530 530
 						if (file_exists($appIcon)) {
531 531
 							$info['preview'] = $urlGenerator->imagePath($app, 'app.svg');
532 532
 							$info['previewAsIcon'] = true;
@@ -662,8 +662,8 @@  discard block
 block discarded – undo
662 662
 			return false;
663 663
 		}
664 664
 
665
-		if (is_file($appPath . '/appinfo/database.xml')) {
666
-			\OCP\Server::get(LoggerInterface::class)->error('The appinfo/database.xml file is not longer supported. Used in ' . $appId);
665
+		if (is_file($appPath.'/appinfo/database.xml')) {
666
+			\OCP\Server::get(LoggerInterface::class)->error('The appinfo/database.xml file is not longer supported. Used in '.$appId);
667 667
 			return false;
668 668
 		}
669 669
 
@@ -701,10 +701,10 @@  discard block
 block discarded – undo
701 701
 			\OC::$server->getConfig()->deleteAppValue($appId, 'ocsid');
702 702
 		}
703 703
 		foreach ($appData['remote'] as $name => $path) {
704
-			\OC::$server->getConfig()->setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
704
+			\OC::$server->getConfig()->setAppValue('core', 'remote_'.$name, $appId.'/'.$path);
705 705
 		}
706 706
 		foreach ($appData['public'] as $name => $path) {
707
-			\OC::$server->getConfig()->setAppValue('core', 'public_' . $name, $appId . '/' . $path);
707
+			\OC::$server->getConfig()->setAppValue('core', 'public_'.$name, $appId.'/'.$path);
708 708
 		}
709 709
 
710 710
 		self::setAppTypes($appId);
@@ -741,7 +741,7 @@  discard block
 block discarded – undo
741 741
 				$r->addStep($step);
742 742
 			} catch (Exception $ex) {
743 743
 				$dispatcher->dispatchTyped(new RepairErrorEvent($ex->getMessage()));
744
-				logger('core')->error('Failed to add app migration step ' . $step, ['exception' => $ex]);
744
+				logger('core')->error('Failed to add app migration step '.$step, ['exception' => $ex]);
745 745
 			}
746 746
 		}
747 747
 		// run the steps
@@ -800,7 +800,7 @@  discard block
 block discarded – undo
800 800
 
801 801
 				if ($attributeLang === $similarLang) {
802 802
 					$similarLangFallback = $option['@value'];
803
-				} elseif (str_starts_with($attributeLang, $similarLang . '_')) {
803
+				} elseif (str_starts_with($attributeLang, $similarLang.'_')) {
804 804
 					if ($similarLangFallback === false) {
805 805
 						$similarLangFallback = $option['@value'];
806 806
 					}
@@ -815,7 +815,7 @@  discard block
 block discarded – undo
815 815
 		} elseif ($englishFallback !== false) {
816 816
 			return $englishFallback;
817 817
 		}
818
-		return (string)$fallback;
818
+		return (string) $fallback;
819 819
 	}
820 820
 
821 821
 	/**
Please login to merge, or discard this patch.