aboutsummaryrefslogtreecommitdiffstats
path: root/lib/private/legacy/OC_App.php
diff options
context:
space:
mode:
Diffstat (limited to 'lib/private/legacy/OC_App.php')
-rw-r--r--lib/private/legacy/OC_App.php321
1 files changed, 63 insertions, 258 deletions
diff --git a/lib/private/legacy/OC_App.php b/lib/private/legacy/OC_App.php
index ea79cc3ea76..10b78e2a7ef 100644
--- a/lib/private/legacy/OC_App.php
+++ b/lib/private/legacy/OC_App.php
@@ -1,59 +1,15 @@
<?php
declare(strict_types=1);
-
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- * @copyright Copyright (c) 2016, Lukas Reschke <lukas@statuscode.ch>
- *
- * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
- * @author Bart Visscher <bartv@thisnet.nl>
- * @author Bernhard Posselt <dev@bernhard-posselt.com>
- * @author Borjan Tchakaloff <borjan@tchakaloff.fr>
- * @author Brice Maron <brice@bmaron.net>
- * @author Christopher Schäpers <kondou@ts.unde.re>
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Daniel Rudolf <github.com@daniel-rudolf.de>
- * @author Frank Karlitschek <frank@karlitschek.de>
- * @author Georg Ehrke <oc.list@georgehrke.com>
- * @author Jakob Sack <mail@jakobsack.de>
- * @author Joas Schilling <coding@schilljs.com>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Julius Haertl <jus@bitgrid.net>
- * @author Julius Härtl <jus@bitgrid.net>
- * @author Kamil Domanski <kdomanski@kdemail.net>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Markus Goetz <markus@woboq.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author RealRancor <Fisch.666@gmx.de>
- * @author Robin Appelman <robin@icewind.nl>
- * @author Robin McCorkell <robin@mccorkell.me.uk>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Sam Tuke <mail@samtuke.com>
- * @author Sebastian Wessalowski <sebastian@wessalowski.org>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Thomas Tanghus <thomas@tanghus.net>
- * @author Vincent Petry <vincent@nextcloud.com>
- *
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
+ * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
-
use OC\App\DependencyAnalyzer;
use OC\App\Platform;
use OC\AppFramework\Bootstrap\Coordinator;
+use OC\Config\ConfigManager;
use OC\DB\MigrationService;
use OC\Installer;
use OC\Repair;
@@ -64,17 +20,17 @@ use OCP\App\ManagerEvent;
use OCP\Authentication\IAlternativeLogin;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IAppConfig;
+use OCP\Server;
use Psr\Container\ContainerExceptionInterface;
use Psr\Log\LoggerInterface;
+use function OCP\Log\logger;
/**
* This class manages the apps. It allows them to register and integrate in the
- * ownCloud ecosystem. Furthermore, this class is responsible for installing,
+ * Nextcloud ecosystem. Furthermore, this class is responsible for installing,
* upgrading and removing apps.
*/
class OC_App {
- private static $adminForms = [];
- private static $personalForms = [];
private static $altLogin = [];
private static $alreadyRegistered = [];
public const supportedApp = 300;
@@ -88,8 +44,7 @@ class OC_App {
* @psalm-taint-escape html
* @psalm-taint-escape has_quotes
*
- * @param string $app AppId that needs to be cleaned
- * @return string
+ * @deprecated 31.0.0 use IAppManager::cleanAppId
*/
public static function cleanAppId(string $app): string {
return str_replace(['<', '>', '"', "'", '\0', '/', '\\', '..'], '', $app);
@@ -112,7 +67,7 @@ class OC_App {
* @param string[] $types
* @return bool
*
- * This function walks through the ownCloud directory and loads all apps
+ * This function walks through the Nextcloud directory and loads all apps
* it can find. A directory contains an app if the file /appinfo/info.xml
* exists.
*
@@ -214,8 +169,8 @@ class OC_App {
*
* @param bool $forceRefresh whether to refresh the cache
* @param bool $all whether to return apps for all users, not only the
- * currently logged in one
- * @return string[]
+ * currently logged in one
+ * @return list<string>
*/
public static function getEnabledApps(bool $forceRefresh = false, bool $all = false): array {
if (!\OC::$server->getSystemConfig()->getValue('installed', false)) {
@@ -231,7 +186,7 @@ class OC_App {
}
if (is_null($user)) {
- $apps = $appManager->getInstalledApps();
+ $apps = $appManager->getEnabledApps();
} else {
$apps = $appManager->getEnabledAppsForUser($user);
}
@@ -257,7 +212,7 @@ class OC_App {
array $groups = []) {
// Check if app is already downloaded
/** @var Installer $installer */
- $installer = \OCP\Server::get(Installer::class);
+ $installer = Server::get(Installer::class);
$isDownloaded = $installer->isDownloaded($appId);
if (!$isDownloaded) {
@@ -283,26 +238,13 @@ class OC_App {
}
/**
- * Get the path where to install apps
- */
- public static function getInstallPath(): string|null {
- foreach (OC::$APPSROOTS as $dir) {
- if (isset($dir['writable']) && $dir['writable'] === true) {
- return $dir['path'];
- }
- }
-
- \OCP\Server::get(LoggerInterface::class)->error('No application directories are marked as writable.', ['app' => 'core']);
- return null;
- }
-
-
- /**
- * search for an app in all app-directories
+ * Find the apps root for an app id.
+ *
+ * If multiple copies are found, the apps root the latest version is returned.
*
* @param string $appId
* @param bool $ignoreCache ignore cache and rebuild it
- * @return false|string
+ * @return false|array{path: string, url: string} the apps root shape
*/
public static function findAppInDirectories(string $appId, bool $ignoreCache = false) {
$sanitizedAppId = self::cleanAppId($appId);
@@ -354,11 +296,14 @@ class OC_App {
* @param string $appId
* @param bool $refreshAppPath should be set to true only during install/upgrade
* @return string|false
- * @deprecated 11.0.0 use \OCP\Server::get(IAppManager)->getAppPath()
+ * @deprecated 11.0.0 use Server::get(IAppManager)->getAppPath()
*/
public static function getAppPath(string $appId, bool $refreshAppPath = false) {
- if ($appId === null || trim($appId) === '') {
+ $appId = self::cleanAppId($appId);
+ if ($appId === '') {
return false;
+ } elseif ($appId === 'core') {
+ return __DIR__ . '/../../../core';
}
if (($dir = self::findAppInDirectories($appId, $refreshAppPath)) != false) {
@@ -390,7 +335,7 @@ class OC_App {
*/
public static function getAppVersionByPath(string $path): string {
$infoFile = $path . '/appinfo/info.xml';
- $appData = \OC::$server->getAppManager()->getAppInfo($infoFile, true);
+ $appData = Server::get(IAppManager::class)->getAppInfoByPath($infoFile);
return $appData['version'] ?? '';
}
@@ -428,33 +373,11 @@ class OC_App {
}
/**
- * @param string $type
- * @return array
- */
- public static function getForms(string $type): array {
- $forms = [];
- switch ($type) {
- case 'admin':
- $source = self::$adminForms;
- break;
- case 'personal':
- $source = self::$personalForms;
- break;
- default:
- return [];
- }
- foreach ($source as $form) {
- $forms[] = include $form;
- }
- return $forms;
- }
-
- /**
* @param array $entry
* @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
*/
public static function registerLogIn(array $entry) {
- \OC::$server->getLogger()->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');
+ 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');
self::$altLogin[] = $entry;
}
@@ -463,11 +386,11 @@ class OC_App {
*/
public static function getAlternativeLogIns(): array {
/** @var Coordinator $bootstrapCoordinator */
- $bootstrapCoordinator = \OCP\Server::get(Coordinator::class);
+ $bootstrapCoordinator = Server::get(Coordinator::class);
foreach ($bootstrapCoordinator->getRegistrationContext()->getAlternativeLogins() as $registration) {
if (!in_array(IAlternativeLogin::class, class_implements($registration->getService()), true)) {
- \OC::$server->getLogger()->error('Alternative login option {option} does not implement {interface} and is therefore ignored.', [
+ Server::get(LoggerInterface::class)->error('Alternative login option {option} does not implement {interface} and is therefore ignored.', [
'option' => $registration->getService(),
'interface' => IAlternativeLogin::class,
'app' => $registration->getAppId(),
@@ -477,13 +400,14 @@ class OC_App {
try {
/** @var IAlternativeLogin $provider */
- $provider = \OCP\Server::get($registration->getService());
+ $provider = Server::get($registration->getService());
} catch (ContainerExceptionInterface $e) {
- \OC::$server->getLogger()->logException($e, [
- 'message' => 'Alternative login option {option} can not be initialised.',
- 'option' => $registration->getService(),
- 'app' => $registration->getAppId(),
- ]);
+ Server::get(LoggerInterface::class)->error('Alternative login option {option} can not be initialized.',
+ [
+ 'exception' => $e,
+ 'option' => $registration->getService(),
+ 'app' => $registration->getAppId(),
+ ]);
}
try {
@@ -495,11 +419,12 @@ class OC_App {
'class' => $provider->getClass(),
];
} catch (Throwable $e) {
- \OC::$server->getLogger()->logException($e, [
- 'message' => 'Alternative login option {option} had an error while loading.',
- 'option' => $registration->getService(),
- 'app' => $registration->getAppId(),
- ]);
+ Server::get(LoggerInterface::class)->error('Alternative login option {option} had an error while loading.',
+ [
+ 'exception' => $e,
+ 'option' => $registration->getService(),
+ 'app' => $registration->getAppId(),
+ ]);
}
}
@@ -510,40 +435,19 @@ class OC_App {
* get a list of all apps in the apps folder
*
* @return string[] an array of app names (string IDs)
- * @todo: change the name of this method to getInstalledApps, which is more accurate
+ * @deprecated 31.0.0 Use IAppManager::getAllAppsInAppsFolders instead
*/
public static function getAllApps(): array {
- $apps = [];
-
- foreach (OC::$APPSROOTS as $apps_dir) {
- if (!is_readable($apps_dir['path'])) {
- \OCP\Server::get(LoggerInterface::class)->warning('unable to read app folder : ' . $apps_dir['path'], ['app' => 'core']);
- continue;
- }
- $dh = opendir($apps_dir['path']);
-
- if (is_resource($dh)) {
- while (($file = readdir($dh)) !== false) {
- if ($file[0] != '.' and is_dir($apps_dir['path'] . '/' . $file) and is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml')) {
- $apps[] = $file;
- }
- }
- }
- }
-
- $apps = array_unique($apps);
-
- return $apps;
+ return Server::get(IAppManager::class)->getAllAppsInAppsFolders();
}
/**
* List all supported apps
*
- * @return array
+ * @deprecated 32.0.0 Use \OCP\Support\Subscription\IRegistry::delegateGetSupportedApps instead
*/
public function getSupportedApps(): array {
- /** @var \OCP\Support\Subscription\IRegistry $subscriptionRegistry */
- $subscriptionRegistry = \OCP\Server::get(\OCP\Support\Subscription\IRegistry::class);
+ $subscriptionRegistry = Server::get(\OCP\Support\Subscription\IRegistry::class);
$supportedApps = $subscriptionRegistry->delegateGetSupportedApps();
return $supportedApps;
}
@@ -554,9 +458,9 @@ class OC_App {
* @return array
*/
public function listAllApps(): array {
- $installedApps = OC_App::getAllApps();
-
$appManager = \OC::$server->getAppManager();
+
+ $installedApps = $appManager->getAllAppsInAppsFolders();
//we don't want to show configuration for these
$blacklist = $appManager->getAlwaysEnabledApps();
$appList = [];
@@ -568,12 +472,12 @@ class OC_App {
if (!in_array($app, $blacklist)) {
$info = $appManager->getAppInfo($app, false, $langCode);
if (!is_array($info)) {
- \OCP\Server::get(LoggerInterface::class)->error('Could not read app info file for app "' . $app . '"', ['app' => 'core']);
+ Server::get(LoggerInterface::class)->error('Could not read app info file for app "' . $app . '"', ['app' => 'core']);
continue;
}
if (!isset($info['name'])) {
- \OCP\Server::get(LoggerInterface::class)->error('App id "' . $app . '" has no name in appinfo', ['app' => 'core']);
+ Server::get(LoggerInterface::class)->error('App id "' . $app . '" has no name in appinfo', ['app' => 'core']);
continue;
}
@@ -640,7 +544,7 @@ class OC_App {
public static function shouldUpgrade(string $app): bool {
$versions = self::getAppVersions();
- $currentVersion = \OCP\Server::get(\OCP\App\IAppManager::class)->getAppVersion($app);
+ $currentVersion = Server::get(\OCP\App\IAppManager::class)->getAppVersion($app);
if ($currentVersion && isset($versions[$app])) {
$installedVersion = $versions[$app];
if (!version_compare($currentVersion, $installedVersion, '=')) {
@@ -673,7 +577,7 @@ class OC_App {
}
/**
- * Check whether the current ownCloud version matches the given
+ * Check whether the current Nextcloud version matches the given
* application's version requirements.
*
* The comparison is made based on the number of parts that the
@@ -683,7 +587,7 @@ class OC_App {
* This means that it's possible to specify "requiremin" => 6
* and "requiremax" => 6 and it will still match ownCloud 6.0.3.
*
- * @param string $ocVersion ownCloud version to check against
+ * @param string $ocVersion Nextcloud version to check against
* @param array $appInfo app info (from xml)
*
* @return boolean true if compatible, otherwise false
@@ -726,16 +630,10 @@ class OC_App {
/**
* get the installed version of all apps
+ * @deprecated 32.0.0 Use IAppManager::getAppInstalledVersions or IAppConfig::getAppInstalledVersions instead
*/
- public static function getAppVersions() {
- static $versions;
-
- if (!$versions) {
- /** @var IAppConfig $appConfig */
- $appConfig = \OCP\Server::get(IAppConfig::class);
- $versions = $appConfig->searchValues('installed_version');
- }
- return $versions;
+ public static function getAppVersions(): array {
+ return Server::get(IAppConfig::class)->getAppInstalledVersions();
}
/**
@@ -753,13 +651,13 @@ class OC_App {
}
if (is_file($appPath . '/appinfo/database.xml')) {
- \OC::$server->getLogger()->error('The appinfo/database.xml file is not longer supported. Used in ' . $appId);
+ Server::get(LoggerInterface::class)->error('The appinfo/database.xml file is not longer supported. Used in ' . $appId);
return false;
}
\OC::$server->getAppManager()->clearAppsCache();
$l = \OC::$server->getL10N('core');
- $appData = \OCP\Server::get(\OCP\App\IAppManager::class)->getAppInfo($appId, false, $l->getLanguageCode());
+ $appData = Server::get(\OCP\App\IAppManager::class)->getAppInfo($appId, false, $l->getLanguageCode());
$ignoreMaxApps = \OC::$server->getConfig()->getSystemValue('app_install_overwrite', []);
$ignoreMax = in_array($appId, $ignoreMaxApps, true);
@@ -799,9 +697,13 @@ class OC_App {
self::setAppTypes($appId);
- $version = \OCP\Server::get(\OCP\App\IAppManager::class)->getAppVersion($appId);
+ $version = Server::get(\OCP\App\IAppManager::class)->getAppVersion($appId);
\OC::$server->getConfig()->setAppValue($appId, 'installed_version', $version);
+ // migrate eventual new config keys in the process
+ /** @psalm-suppress InternalMethod */
+ Server::get(ConfigManager::class)->migrateConfigLexiconKeys($appId);
+
\OC::$server->get(IEventDispatcher::class)->dispatchTyped(new AppUpdateEvent($appId));
\OC::$server->get(IEventDispatcher::class)->dispatch(ManagerEvent::EVENT_APP_UPDATE, new ManagerEvent(
ManagerEvent::EVENT_APP_UPDATE, $appId
@@ -822,16 +724,16 @@ class OC_App {
// load the app
self::loadApp($appId);
- $dispatcher = \OC::$server->get(IEventDispatcher::class);
+ $dispatcher = Server::get(IEventDispatcher::class);
// load the steps
- $r = \OCP\Server::get(Repair::class);
+ $r = Server::get(Repair::class);
foreach ($steps as $step) {
try {
$r->addStep($step);
} catch (Exception $ex) {
$dispatcher->dispatchTyped(new RepairErrorEvent($ex->getMessage()));
- \OC::$server->getLogger()->logException($ex);
+ logger('core')->error('Failed to add app migration step ' . $step, ['exception' => $ex]);
}
}
// run the steps
@@ -859,103 +761,6 @@ class OC_App {
}
/**
- * @param string $appId
- * @return \OC\Files\View|false
- */
- public static function getStorage(string $appId) {
- if (\OC::$server->getAppManager()->isEnabledForUser($appId)) { //sanity check
- if (\OC::$server->getUserSession()->isLoggedIn()) {
- $view = new \OC\Files\View('/' . OC_User::getUser());
- if (!$view->file_exists($appId)) {
- $view->mkdir($appId);
- }
- return new \OC\Files\View('/' . OC_User::getUser() . '/' . $appId);
- } else {
- \OCP\Server::get(LoggerInterface::class)->error('Can\'t get app storage, app ' . $appId . ', user not logged in', ['app' => 'core']);
- return false;
- }
- } else {
- \OCP\Server::get(LoggerInterface::class)->error('Can\'t get app storage, app ' . $appId . ' not enabled', ['app' => 'core']);
- return false;
- }
- }
-
- protected static function findBestL10NOption(array $options, string $lang): string {
- // only a single option
- if (isset($options['@value'])) {
- return $options['@value'];
- }
-
- $fallback = $similarLangFallback = $englishFallback = false;
-
- $lang = strtolower($lang);
- $similarLang = $lang;
- if (strpos($similarLang, '_')) {
- // For "de_DE" we want to find "de" and the other way around
- $similarLang = substr($lang, 0, strpos($lang, '_'));
- }
-
- foreach ($options as $option) {
- if (is_array($option)) {
- if ($fallback === false) {
- $fallback = $option['@value'];
- }
-
- if (!isset($option['@attributes']['lang'])) {
- continue;
- }
-
- $attributeLang = strtolower($option['@attributes']['lang']);
- if ($attributeLang === $lang) {
- return $option['@value'];
- }
-
- if ($attributeLang === $similarLang) {
- $similarLangFallback = $option['@value'];
- } elseif (str_starts_with($attributeLang, $similarLang . '_')) {
- if ($similarLangFallback === false) {
- $similarLangFallback = $option['@value'];
- }
- }
- } else {
- $englishFallback = $option;
- }
- }
-
- if ($similarLangFallback !== false) {
- return $similarLangFallback;
- } elseif ($englishFallback !== false) {
- return $englishFallback;
- }
- return (string) $fallback;
- }
-
- /**
- * parses the app data array and enhanced the 'description' value
- *
- * @param array $data the app data
- * @param string $lang
- * @return array improved app data
- */
- public static function parseAppInfo(array $data, $lang = null): array {
- if ($lang && isset($data['name']) && is_array($data['name'])) {
- $data['name'] = self::findBestL10NOption($data['name'], $lang);
- }
- if ($lang && isset($data['summary']) && is_array($data['summary'])) {
- $data['summary'] = self::findBestL10NOption($data['summary'], $lang);
- }
- if ($lang && isset($data['description']) && is_array($data['description'])) {
- $data['description'] = trim(self::findBestL10NOption($data['description'], $lang));
- } elseif (isset($data['description']) && is_string($data['description'])) {
- $data['description'] = trim($data['description']);
- } else {
- $data['description'] = '';
- }
-
- return $data;
- }
-
- /**
* @param \OCP\IConfig $config
* @param \OCP\IL10N $l
* @param array $info