2011-03-03 15:55:32 -05:00
< ? php
2019-12-03 13:57:53 -05:00
2018-02-17 09:37:57 -05:00
declare ( strict_types = 1 );
2011-03-11 09:25:48 -05:00
/**
2024-05-23 03:26:56 -04:00
* SPDX - FileCopyrightText : 2016 Nextcloud GmbH and Nextcloud contributors
* SPDX - FileCopyrightText : 2016 ownCloud , Inc .
* SPDX - License - Identifier : AGPL - 3.0 - only
2011-03-11 09:25:48 -05:00
*/
2014-12-11 11:02:07 -05:00
use OC\App\DependencyAnalyzer ;
use OC\App\Platform ;
2022-08-22 11:59:26 -04:00
use OC\AppFramework\Bootstrap\Coordinator ;
2017-06-01 10:56:34 -04:00
use OC\DB\MigrationService ;
2016-04-28 09:15:34 -04:00
use OC\Installer ;
2016-04-19 09:36:11 -04:00
use OC\Repair ;
2022-08-22 11:59:26 -04:00
use OC\Repair\Events\RepairErrorEvent ;
2022-12-08 04:55:19 -05:00
use OCP\App\Events\AppUpdateEvent ;
2023-02-07 10:56:04 -05:00
use OCP\App\IAppManager ;
2022-08-22 11:59:26 -04:00
use OCP\App\ManagerEvent ;
use OCP\Authentication\IAlternativeLogin ;
2022-12-08 04:55:19 -05:00
use OCP\EventDispatcher\IEventDispatcher ;
2024-01-11 11:32:58 -05:00
use OCP\IAppConfig ;
2024-06-18 05:55:08 -04:00
use OCP\Server ;
2023-06-06 05:09:24 -04:00
use Psr\Container\ContainerExceptionInterface ;
2021-02-01 08:56:56 -05:00
use Psr\Log\LoggerInterface ;
2024-06-18 05:55:08 -04:00
use function OCP\Log\logger ;
2011-03-11 09:25:48 -05:00
2011-03-12 04:28:10 -05:00
/**
* This class manages the apps . It allows them to register and integrate in the
2024-09-17 08:41:25 -04:00
* Nextcloud ecosystem . Furthermore , this class is responsible for installing ,
2011-03-12 04:28:10 -05:00
* upgrading and removing apps .
*/
2014-04-17 09:30:27 -04:00
class OC_App {
2020-04-10 10:48:31 -04:00
private static $altLogin = [];
private static $alreadyRegistered = [];
2020-04-10 10:54:27 -04:00
public const supportedApp = 300 ;
public const officialApp = 200 ;
2011-03-03 15:55:32 -05:00
2013-02-09 09:03:47 -05:00
/**
2014-07-09 04:20:17 -04:00
* clean the appId
2015-02-02 08:47:38 -05:00
*
2020-11-20 06:19:59 -05:00
* @ psalm - taint - escape file
2020-11-20 19:57:25 -05:00
* @ psalm - taint - escape include
2022-08-31 15:15:02 -04:00
* @ psalm - taint - escape html
* @ psalm - taint - escape has_quotes
2020-11-20 06:19:59 -05:00
*
2024-09-12 10:17:19 -04:00
* @ deprecated 31.0 . 0 use IAppManager :: cleanAppId
2013-02-09 09:03:47 -05:00
*/
2018-02-17 09:37:57 -05:00
public static function cleanAppId ( string $app ) : string {
2022-08-31 15:15:02 -04:00
return str_replace ([ '<' , '>' , '"' , " ' " , '\0' , '/' , '\\' , '..' ], '' , $app );
2013-02-09 09:03:47 -05:00
}
2015-08-18 04:18:36 -04:00
/**
* Check if an app is loaded
*
* @ param string $app
* @ return bool
2023-03-27 08:27:23 -04:00
* @ deprecated 27.0 . 0 use IAppManager :: isAppLoaded
2015-08-18 04:18:36 -04:00
*/
2018-02-17 09:37:57 -05:00
public static function isAppLoaded ( string $app ) : bool {
2023-02-07 10:56:04 -05:00
return \OC :: $server -> get ( IAppManager :: class ) -> isAppLoaded ( $app );
2015-08-18 04:18:36 -04:00
}
2011-03-03 15:55:32 -05:00
/**
2014-05-19 11:50:53 -04:00
* loads all apps
2015-02-02 08:47:38 -05:00
*
2018-02-17 09:22:00 -05:00
* @ param string [] $types
2012-09-22 20:39:11 -04:00
* @ return bool
2011-03-03 15:55:32 -05:00
*
2024-09-17 08:41:25 -04:00
* This function walks through the Nextcloud directory and loads all apps
2015-03-17 10:33:55 -04:00
* it can find . A directory contains an app if the file / appinfo / info . xml
2011-03-11 08:59:24 -05:00
* exists .
2012-03-30 08:39:07 -04:00
*
2018-02-17 09:22:00 -05:00
* if $types is set to non - empty array , only apps of those types will be loaded
2024-02-08 08:34:01 -05:00
*
* @ deprecated 29.0 . 0 use IAppManager :: loadApps instead
2011-03-03 15:55:32 -05:00
*/
2018-02-17 09:22:00 -05:00
public static function loadApps ( array $types = []) : bool {
2023-02-08 06:35:57 -05:00
if ( ! \OC :: $server -> getSystemConfig () -> getValue ( 'installed' , false )) {
// This should be done before calling this method so that appmanager can be used
2014-07-24 11:51:28 -04:00
return false ;
}
2023-02-08 06:35:57 -05:00
return \OC :: $server -> get ( IAppManager :: class ) -> loadApps ( $types );
2013-02-09 11:27:57 -05:00
}
2011-03-03 15:55:32 -05:00
2012-05-13 18:28:22 -04:00
/**
* load a single app
2014-04-17 09:30:27 -04:00
*
2012-09-22 20:39:11 -04:00
* @ param string $app
2018-02-15 05:20:22 -05:00
* @ throws Exception
2023-03-27 08:27:23 -04:00
* @ deprecated 27.0 . 0 use IAppManager :: loadApp
2012-05-13 18:28:22 -04:00
*/
2023-02-07 10:06:32 -05:00
public static function loadApp ( string $app ) : void {
2023-02-07 10:56:04 -05:00
\OC :: $server -> get ( IAppManager :: class ) -> loadApp ( $app );
2012-05-13 18:28:22 -04:00
}
2016-05-02 08:11:34 -04:00
/**
2016-05-10 05:49:55 -04:00
* @ internal
2016-05-02 08:11:34 -04:00
* @ param string $app
* @ param string $path
2020-01-13 09:14:56 -05:00
* @ param bool $force
2016-05-02 08:11:34 -04:00
*/
2020-01-13 09:14:56 -05:00
public static function registerAutoloading ( string $app , string $path , bool $force = false ) {
2016-08-22 17:49:46 -04:00
$key = $app . '-' . $path ;
2020-01-13 09:14:56 -05:00
if ( ! $force && isset ( self :: $alreadyRegistered [ $key ])) {
2016-08-22 17:49:46 -04:00
return ;
}
2017-10-17 05:49:32 -04:00
2016-08-22 17:49:46 -04:00
self :: $alreadyRegistered [ $key ] = true ;
2017-10-17 05:49:32 -04:00
2016-05-02 08:11:34 -04:00
// Register on PSR-4 composer autoloader
$appNamespace = \OC\AppFramework\App :: buildAppNamespace ( $app );
2017-03-22 06:50:58 -04:00
\OC :: $server -> registerNamespace ( $app , $appNamespace );
2017-10-17 05:49:32 -04:00
if ( file_exists ( $path . '/composer/autoload.php' )) {
require_once $path . '/composer/autoload.php' ;
} else {
\OC :: $composerAutoloader -> addPsr4 ( $appNamespace . '\\' , $path . '/lib/' , true );
}
// Register Test namespace only when testing
2016-07-25 04:58:03 -04:00
if ( defined ( 'PHPUNIT_RUN' ) || defined ( 'CLI_TEST_RUN' )) {
2016-05-02 08:11:34 -04:00
\OC :: $composerAutoloader -> addPsr4 ( $appNamespace . '\\Tests\\' , $path . '/tests/' , true );
}
}
2012-03-30 08:39:07 -04:00
/**
2012-05-14 11:58:50 -04:00
* check if an app is of a specific type
2014-04-17 09:30:27 -04:00
*
2012-03-30 08:39:07 -04:00
* @ param string $app
2018-02-17 09:22:00 -05:00
* @ param array $types
2012-09-22 20:39:11 -04:00
* @ return bool
2023-03-27 08:27:23 -04:00
* @ deprecated 27.0 . 0 use IAppManager :: isType
2012-03-30 08:39:07 -04:00
*/
2018-02-17 09:22:00 -05:00
public static function isType ( string $app , array $types ) : bool {
2023-02-08 05:46:07 -05:00
return \OC :: $server -> get ( IAppManager :: class ) -> isType ( $app , $types );
2012-05-14 16:49:20 -04:00
}
2012-05-02 05:14:11 -04:00
2012-05-14 16:49:20 -04:00
/**
* read app types from info . xml and cache them in the database
*/
2018-02-17 09:29:15 -05:00
public static function setAppTypes ( string $app ) {
$appManager = \OC :: $server -> getAppManager ();
$appData = $appManager -> getAppInfo ( $app );
2016-03-30 17:29:26 -04:00
if ( ! is_array ( $appData )) {
return ;
}
2012-06-04 15:30:58 -04:00
2014-04-17 09:30:27 -04:00
if ( isset ( $appData [ 'types' ])) {
$appTypes = implode ( ',' , $appData [ 'types' ]);
} else {
$appTypes = '' ;
2017-01-04 04:40:14 -05:00
$appData [ 'types' ] = [];
2012-04-14 11:53:02 -04:00
}
2012-05-02 05:14:11 -04:00
2018-02-17 09:29:15 -05:00
$config = \OC :: $server -> getConfig ();
$config -> setAppValue ( $app , 'types' , $appTypes );
2017-01-04 04:40:14 -05:00
2018-02-17 09:29:15 -05:00
if ( $appManager -> hasProtectedAppType ( $appData [ 'types' ])) {
$enabled = $config -> getAppValue ( $app , 'enabled' , 'yes' );
2017-01-04 04:40:14 -05:00
if ( $enabled !== 'yes' && $enabled !== 'no' ) {
2018-02-17 09:29:15 -05:00
$config -> setAppValue ( $app , 'enabled' , 'yes' );
2017-01-04 04:40:14 -05:00
}
}
2012-04-14 11:53:02 -04:00
}
2013-01-14 14:30:39 -05:00
2014-09-02 08:30:46 -04:00
/**
* Returns apps enabled for the current user .
*
* @ 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
2015-02-02 08:47:38 -05:00
* @ return string []
2014-09-02 08:30:46 -04:00
*/
2018-02-17 09:37:57 -05:00
public static function getEnabledApps ( bool $forceRefresh = false , bool $all = false ) : array {
2015-12-18 05:42:09 -05:00
if ( ! \OC :: $server -> getSystemConfig () -> getValue ( 'installed' , false )) {
2018-02-17 09:18:34 -05:00
return [];
2013-02-09 16:43:35 -05:00
}
2014-09-02 08:30:46 -04:00
// in incognito mode or when logged out, $user will be false,
// which is also the case during an upgrade
2015-02-02 08:47:38 -05:00
$appManager = \OC :: $server -> getAppManager ();
if ( $all ) {
$user = null ;
} else {
$user = \OC :: $server -> getUserSession () -> getUser ();
2013-10-05 13:18:18 -04:00
}
2015-02-02 08:47:38 -05:00
if ( is_null ( $user )) {
$apps = $appManager -> getInstalledApps ();
} else {
2015-02-05 09:11:07 -05:00
$apps = $appManager -> getEnabledAppsForUser ( $user );
2012-03-30 08:00:24 -04:00
}
2015-02-02 08:47:38 -05:00
$apps = array_filter ( $apps , function ( $app ) {
return $app !== 'files' ; //we add this manually
});
2014-04-21 07:38:08 -04:00
sort ( $apps );
array_unshift ( $apps , 'files' );
2012-03-30 08:00:24 -04:00
return $apps ;
}
2011-06-19 09:18:52 -04:00
/**
2014-05-19 11:50:53 -04:00
* enables an app
2015-02-02 08:47:38 -05:00
*
2016-10-27 11:41:15 -04:00
* @ param string $appId
2014-04-18 08:29:45 -04:00
* @ param array $groups ( optional ) when set , only these groups will have access to the app
2013-08-06 11:19:18 -04:00
* @ throws \Exception
* @ return void
2011-06-19 09:18:52 -04:00
*
* This function set an app as enabled in appconfig .
*/
2018-02-17 09:36:16 -05:00
public function enable ( string $appId ,
array $groups = []) {
2016-10-27 11:41:15 -04:00
// Check if app is already downloaded
2018-02-22 10:00:26 -05:00
/** @var Installer $installer */
2023-06-06 05:09:24 -04:00
$installer = \OCP\Server :: get ( Installer :: class );
2016-10-27 11:41:15 -04:00
$isDownloaded = $installer -> isDownloaded ( $appId );
if ( ! $isDownloaded ) {
2016-10-31 06:07:54 -04:00
$installer -> downloadApp ( $appId );
2016-10-27 11:41:15 -04:00
}
2017-05-15 01:03:35 -04:00
$installer -> installApp ( $appId );
2014-05-21 06:14:10 -04:00
2015-02-16 10:44:51 -05:00
$appManager = \OC :: $server -> getAppManager ();
2018-02-17 09:36:16 -05:00
if ( $groups !== []) {
2015-03-24 07:56:42 -04:00
$groupManager = \OC :: $server -> getGroupManager ();
$groupsList = [];
foreach ( $groups as $group ) {
$groupItem = $groupManager -> get ( $group );
if ( $groupItem instanceof \OCP\IGroup ) {
$groupsList [] = $groupManager -> get ( $group );
}
}
2016-10-27 11:41:15 -04:00
$appManager -> enableAppForGroups ( $appId , $groupsList );
2015-02-02 08:47:38 -05:00
} else {
2016-10-27 11:41:15 -04:00
$appManager -> enableApp ( $appId );
2014-06-05 16:54:27 -04:00
}
2014-05-21 06:14:10 -04:00
}
2012-06-14 17:00:02 -04:00
/**
2012-07-23 18:39:59 -04:00
* Get the path where to install apps
*/
2024-01-29 10:10:31 -05:00
public static function getInstallPath () : ? string {
2014-04-17 09:30:27 -04:00
foreach ( OC :: $APPSROOTS as $dir ) {
if ( isset ( $dir [ 'writable' ]) && $dir [ 'writable' ] === true ) {
2012-06-14 17:00:02 -04:00
return $dir [ 'path' ];
2013-02-09 16:43:35 -05:00
}
2012-06-14 17:00:02 -04:00
}
2023-09-21 11:25:52 -04:00
\OCP\Server :: get ( LoggerInterface :: class ) -> error ( 'No application directories are marked as writable.' , [ 'app' => 'core' ]);
2012-06-14 17:00:02 -04:00
return null ;
}
2014-05-21 06:14:10 -04:00
/**
2024-07-11 06:05:14 -04:00
* Find the apps root for an app id .
*
* If multiple copies are found , the apps root the latest version is returned .
2015-02-02 08:47:38 -05:00
*
2015-04-07 07:49:16 -04:00
* @ param string $appId
2023-01-26 06:38:20 -05:00
* @ param bool $ignoreCache ignore cache and rebuild it
2024-07-11 06:05:14 -04:00
* @ return false | array { path : string , url : string } the apps root shape
2014-05-21 06:14:10 -04:00
*/
2023-01-26 06:38:20 -05:00
public static function findAppInDirectories ( string $appId , bool $ignoreCache = false ) {
2015-12-08 04:01:09 -05:00
$sanitizedAppId = self :: cleanAppId ( $appId );
if ( $sanitizedAppId !== $appId ) {
return false ;
}
2018-02-17 09:18:34 -05:00
static $app_dir = [];
2014-05-21 06:14:10 -04:00
2023-01-26 06:38:20 -05:00
if ( isset ( $app_dir [ $appId ]) && ! $ignoreCache ) {
2014-05-21 06:14:10 -04:00
return $app_dir [ $appId ];
2012-06-28 15:54:33 -04:00
}
2014-05-21 06:14:10 -04:00
2018-02-17 09:18:34 -05:00
$possibleApps = [];
2015-02-02 08:47:38 -05:00
foreach ( OC :: $APPSROOTS as $dir ) {
if ( file_exists ( $dir [ 'path' ] . '/' . $appId )) {
2014-05-21 06:14:10 -04:00
$possibleApps [] = $dir ;
2012-06-14 17:00:02 -04:00
}
}
2014-05-21 06:14:10 -04:00
2014-06-02 15:37:39 -04:00
if ( empty ( $possibleApps )) {
2014-05-21 06:14:10 -04:00
return false ;
2015-02-02 08:47:38 -05:00
} elseif ( count ( $possibleApps ) === 1 ) {
2014-06-02 15:37:39 -04:00
$dir = array_shift ( $possibleApps );
2014-05-21 06:14:10 -04:00
$app_dir [ $appId ] = $dir ;
return $dir ;
} else {
2018-02-17 09:18:34 -05:00
$versionToLoad = [];
2015-02-02 08:47:38 -05:00
foreach ( $possibleApps as $possibleApp ) {
2018-05-03 02:22:03 -04:00
$version = self :: getAppVersionByPath ( $possibleApp [ 'path' ] . '/' . $appId );
2014-05-21 06:14:10 -04:00
if ( empty ( $versionToLoad ) || version_compare ( $version , $versionToLoad [ 'version' ], '>' )) {
2020-03-26 04:30:18 -04:00
$versionToLoad = [
2014-05-21 06:14:10 -04:00
'dir' => $possibleApp ,
'version' => $version ,
2020-03-26 04:30:18 -04:00
];
2014-05-21 06:14:10 -04:00
}
}
$app_dir [ $appId ] = $versionToLoad [ 'dir' ];
return $versionToLoad [ 'dir' ];
//TODO - write test
}
2012-06-14 17:00:02 -04:00
}
2014-05-21 06:14:10 -04:00
2012-06-01 18:05:20 -04:00
/**
2014-04-15 16:55:20 -04:00
* Get the directory for the given app .
* If the app is defined in multiple directories , the first one is taken . ( false if not found )
2014-07-09 04:20:17 -04:00
*
2020-11-20 20:11:37 -05:00
* @ psalm - taint - specialize
*
2014-07-09 04:20:52 -04:00
* @ param string $appId
2023-01-26 06:38:20 -05:00
* @ param bool $refreshAppPath should be set to true only during install / upgrade
2014-04-15 16:55:20 -04:00
* @ return string | false
2024-03-06 05:54:58 -05:00
* @ deprecated 11.0 . 0 use \OCP\Server :: get ( IAppManager ) -> getAppPath ()
2014-04-15 16:55:20 -04:00
*/
2023-01-26 06:38:20 -05:00
public static function getAppPath ( string $appId , bool $refreshAppPath = false ) {
2024-10-07 16:10:09 -04:00
$appId = self :: cleanAppId ( $appId );
if ( $appId === '' ) {
2014-06-25 10:24:55 -04:00
return false ;
}
2023-01-26 06:38:20 -05:00
if (( $dir = self :: findAppInDirectories ( $appId , $refreshAppPath )) != false ) {
2014-07-09 04:20:17 -04:00
return $dir [ 'path' ] . '/' . $appId ;
2012-06-03 17:13:30 -04:00
}
2012-09-22 20:39:11 -04:00
return false ;
2012-06-03 17:13:30 -04:00
}
/**
2014-04-15 16:55:20 -04:00
* Get the path for the given app on the access
* If the app is defined in multiple directories , the first one is taken . ( false if not found )
2014-07-09 04:20:17 -04:00
*
* @ param string $appId
2014-04-15 16:55:20 -04:00
* @ return string | false
2019-09-05 12:35:40 -04:00
* @ deprecated 18.0 . 0 use \OC :: $server -> getAppManager () -> getAppWebPath ()
2014-04-15 16:55:20 -04:00
*/
2018-02-17 09:37:57 -05:00
public static function getAppWebPath ( string $appId ) {
2014-07-09 04:20:17 -04:00
if (( $dir = self :: findAppInDirectories ( $appId )) != false ) {
return OC :: $WEBROOT . $dir [ 'url' ] . '/' . $appId ;
2012-06-01 18:05:20 -04:00
}
2012-09-22 20:39:11 -04:00
return false ;
2012-06-01 18:05:20 -04:00
}
2014-05-21 06:14:10 -04:00
/**
* get app 's version based on it' s path
2015-02-02 08:47:38 -05:00
*
2014-05-21 06:14:10 -04:00
* @ param string $path
* @ return string
*/
2018-02-17 09:37:57 -05:00
public static function getAppVersionByPath ( string $path ) : string {
2014-05-21 06:14:10 -04:00
$infoFile = $path . '/appinfo/info.xml' ;
2024-10-07 16:10:09 -04:00
$appData = \OCP\Server :: get ( IAppManager :: class ) -> getAppInfoByPath ( $infoFile );
2023-07-07 06:13:21 -04:00
return $appData [ 'version' ] ? ? '' ;
2012-04-14 10:27:58 -04:00
}
2011-10-05 06:31:33 -04:00
2011-07-25 14:12:35 -04:00
/**
* get the id of loaded app
2014-04-17 09:30:27 -04:00
*
2011-07-25 14:12:35 -04:00
* @ return string
*/
2018-02-17 09:37:32 -05:00
public static function getCurrentApp () : string {
2022-04-07 08:08:37 -04:00
if ( \OC :: $CLI ) {
return '' ;
}
2015-02-10 07:02:48 -05:00
$request = \OC :: $server -> getRequest ();
$script = substr ( $request -> getScriptName (), strlen ( OC :: $WEBROOT ) + 1 );
2018-01-12 09:01:45 -05:00
$topFolder = substr ( $script , 0 , strpos ( $script , '/' ) ? : 0 );
2012-09-28 17:15:19 -04:00
if ( empty ( $topFolder )) {
2022-04-07 08:08:37 -04:00
try {
$path_info = $request -> getPathInfo ();
} catch ( Exception $e ) {
// Can happen from unit tests because the script name is `./vendor/bin/phpunit` or something a like then.
2022-04-07 08:45:58 -04:00
\OC :: $server -> get ( LoggerInterface :: class ) -> error ( 'Failed to detect current app from script path' , [ 'exception' => $e ]);
2022-04-07 08:08:37 -04:00
return '' ;
}
2012-09-28 17:15:19 -04:00
if ( $path_info ) {
2014-04-17 09:30:27 -04:00
$topFolder = substr ( $path_info , 1 , strpos ( $path_info , '/' , 1 ) - 1 );
2012-09-28 17:15:19 -04:00
}
}
2014-04-17 09:30:27 -04:00
if ( $topFolder == 'apps' ) {
$length = strlen ( $topFolder );
2018-02-17 09:37:32 -05:00
return substr ( $script , $length + 1 , strpos ( $script , '/' , $length + 1 ) - $length - 1 ) ? : '' ;
2014-04-17 09:30:27 -04:00
} else {
2011-07-25 14:12:35 -04:00
return $topFolder ;
}
}
2011-10-05 06:31:33 -04:00
2015-02-11 18:11:38 -05:00
/**
* @ param array $entry
2020-07-15 11:06:27 -04:00
* @ 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
2015-02-11 18:11:38 -05:00
*/
public static function registerLogIn ( array $entry ) {
2024-09-14 19:34:47 -04:00
\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' );
2013-01-29 11:28:08 -05:00
self :: $altLogin [] = $entry ;
}
2015-02-11 18:11:38 -05:00
/**
* @ return array
*/
2018-02-17 09:37:57 -05:00
public static function getAlternativeLogIns () : array {
2020-07-15 11:06:27 -04:00
/** @var Coordinator $bootstrapCoordinator */
2023-06-06 05:09:24 -04:00
$bootstrapCoordinator = \OCP\Server :: get ( Coordinator :: class );
2020-07-15 11:06:27 -04:00
foreach ( $bootstrapCoordinator -> getRegistrationContext () -> getAlternativeLogins () as $registration ) {
2021-01-28 08:08:38 -05:00
if ( ! in_array ( IAlternativeLogin :: class , class_implements ( $registration -> getService ()), true )) {
2024-09-14 19:34:47 -04:00
\OCP\Server :: get ( LoggerInterface :: class ) -> error ( 'Alternative login option {option} does not implement {interface} and is therefore ignored.' , [
2021-01-28 08:08:38 -05:00
'option' => $registration -> getService (),
2020-07-15 11:06:27 -04:00
'interface' => IAlternativeLogin :: class ,
2021-01-28 08:08:38 -05:00
'app' => $registration -> getAppId (),
2020-07-15 11:06:27 -04:00
]);
continue ;
}
try {
/** @var IAlternativeLogin $provider */
2023-06-06 05:09:24 -04:00
$provider = \OCP\Server :: get ( $registration -> getService ());
} catch ( ContainerExceptionInterface $e ) {
2024-09-14 19:34:47 -04:00
\OCP\Server :: get ( LoggerInterface :: class ) -> error ( 'Alternative login option {option} can not be initialized.' ,
[
'exception' => $e ,
'option' => $registration -> getService (),
'app' => $registration -> getAppId (),
]);
2020-07-15 11:06:27 -04:00
}
try {
$provider -> load ();
self :: $altLogin [] = [
'name' => $provider -> getLabel (),
'href' => $provider -> getLink (),
2022-10-20 00:32:13 -04:00
'class' => $provider -> getClass (),
2020-07-15 11:06:27 -04:00
];
} catch ( Throwable $e ) {
2024-09-14 19:34:47 -04:00
\OCP\Server :: get ( LoggerInterface :: class ) -> error ( 'Alternative login option {option} had an error while loading.' ,
[
'exception' => $e ,
'option' => $registration -> getService (),
'app' => $registration -> getAppId (),
]);
2020-07-15 11:06:27 -04:00
}
}
2013-01-29 11:28:08 -05:00
return self :: $altLogin ;
}
2011-08-10 06:20:43 -04:00
/**
2014-05-19 11:50:53 -04:00
* get a list of all apps in the apps folder
2015-02-02 08:47:38 -05:00
*
2020-05-28 14:37:24 -04:00
* @ return string [] an array of app names ( string IDs )
2024-09-12 10:38:35 -04:00
* @ deprecated 31.0 . 0 Use IAppManager :: getAllAppsInAppsFolders instead
2011-08-10 06:20:43 -04:00
*/
2018-02-17 09:37:57 -05:00
public static function getAllApps () : array {
2024-09-12 10:38:35 -04:00
return \OCP\Server :: get ( IAppManager :: class ) -> getAllAppsInAppsFolders ();
2011-08-10 06:20:43 -04:00
}
2012-10-14 15:04:08 -04:00
2021-09-08 17:43:17 -04:00
/**
* List all supported apps
*
* @ return array
*/
public function getSupportedApps () : array {
/** @var \OCP\Support\Subscription\IRegistry $subscriptionRegistry */
2023-06-06 05:09:24 -04:00
$subscriptionRegistry = \OCP\Server :: get ( \OCP\Support\Subscription\IRegistry :: class );
2021-09-08 17:43:17 -04:00
$supportedApps = $subscriptionRegistry -> delegateGetSupportedApps ();
return $supportedApps ;
}
2013-01-21 16:18:11 -05:00
/**
2015-03-30 09:58:20 -04:00
* List all apps , this is used in apps . php
2015-02-02 08:47:38 -05:00
*
2013-01-21 16:18:11 -05:00
* @ return array
*/
2018-02-17 09:37:57 -05:00
public function listAllApps () : array {
2017-08-01 12:57:00 -04:00
$appManager = \OC :: $server -> getAppManager ();
2024-09-12 10:38:35 -04:00
$installedApps = $appManager -> getAllAppsInAppsFolders ();
2015-10-16 10:38:43 -04:00
//we don't want to show configuration for these
2017-08-01 12:57:00 -04:00
$blacklist = $appManager -> getAlwaysEnabledApps ();
2018-02-17 09:18:34 -05:00
$appList = [];
2016-09-30 05:00:58 -04:00
$langCode = \OC :: $server -> getL10N ( 'core' ) -> getLanguageCode ();
2016-09-23 15:47:47 -04:00
$urlGenerator = \OC :: $server -> getURLGenerator ();
2021-09-08 17:43:17 -04:00
$supportedApps = $this -> getSupportedApps ();
2013-01-21 16:18:11 -05:00
2014-04-17 09:30:27 -04:00
foreach ( $installedApps as $app ) {
2023-09-17 04:43:23 -04:00
if ( ! in_array ( $app , $blacklist )) {
2023-05-31 15:15:51 -04:00
$info = $appManager -> getAppInfo ( $app , false , $langCode );
2016-03-30 17:29:26 -04:00
if ( ! is_array ( $info )) {
2023-09-21 11:25:52 -04:00
\OCP\Server :: get ( LoggerInterface :: class ) -> error ( 'Could not read app info file for app "' . $app . '"' , [ 'app' => 'core' ]);
2016-03-30 17:29:26 -04:00
continue ;
}
2013-01-21 16:18:11 -05:00
if ( ! isset ( $info [ 'name' ])) {
2023-09-21 11:25:52 -04:00
\OCP\Server :: get ( LoggerInterface :: class ) -> error ( 'App id "' . $app . '" has no name in appinfo' , [ 'app' => 'core' ]);
2013-01-21 16:18:11 -05:00
continue ;
}
2018-01-17 15:10:40 -05:00
$enabled = \OC :: $server -> getConfig () -> getAppValue ( $app , 'enabled' , 'no' );
2014-04-18 08:29:45 -04:00
$info [ 'groups' ] = null ;
if ( $enabled === 'yes' ) {
2013-01-21 16:18:11 -05:00
$active = true ;
2020-04-10 04:35:09 -04:00
} elseif ( $enabled === 'no' ) {
2013-01-21 16:18:11 -05:00
$active = false ;
2014-04-18 08:29:45 -04:00
} else {
$active = true ;
$info [ 'groups' ] = $enabled ;
2013-01-21 16:18:11 -05:00
}
$info [ 'active' ] = $active ;
2017-08-01 12:57:00 -04:00
if ( $appManager -> isShipped ( $app )) {
2014-04-17 09:30:27 -04:00
$info [ 'internal' ] = true ;
2015-03-30 09:58:20 -04:00
$info [ 'level' ] = self :: officialApp ;
2014-05-31 11:50:39 -04:00
$info [ 'removable' ] = false ;
2013-01-21 16:18:11 -05:00
} else {
2014-04-17 09:30:27 -04:00
$info [ 'internal' ] = false ;
2014-05-31 11:50:39 -04:00
$info [ 'removable' ] = true ;
2013-01-21 16:18:11 -05:00
}
2019-05-10 08:50:24 -04:00
if ( in_array ( $app , $supportedApps )) {
$info [ 'level' ] = self :: supportedApp ;
}
2016-02-14 14:57:09 -05:00
$appPath = self :: getAppPath ( $app );
if ( $appPath !== false ) {
$appIcon = $appPath . '/img/' . $app . '.svg' ;
2014-08-14 09:48:38 -04:00
if ( file_exists ( $appIcon )) {
2017-08-01 12:57:00 -04:00
$info [ 'preview' ] = $urlGenerator -> imagePath ( $app , $app . '.svg' );
2014-08-14 09:48:38 -04:00
$info [ 'previewAsIcon' ] = true ;
2016-02-14 14:57:09 -05:00
} else {
$appIcon = $appPath . '/img/app.svg' ;
if ( file_exists ( $appIcon )) {
2017-08-01 12:57:00 -04:00
$info [ 'preview' ] = $urlGenerator -> imagePath ( $app , 'app.svg' );
2016-02-14 14:57:09 -05:00
$info [ 'previewAsIcon' ] = true ;
}
2014-08-14 09:48:38 -04:00
}
}
2016-09-23 15:47:47 -04:00
// fix documentation
if ( isset ( $info [ 'documentation' ]) && is_array ( $info [ 'documentation' ])) {
foreach ( $info [ 'documentation' ] as $key => $url ) {
// If it is not an absolute URL we assume it is a key
// i.e. admin-ldap will get converted to go.php?to=admin-ldap
if ( stripos ( $url , 'https://' ) !== 0 && stripos ( $url , 'http://' ) !== 0 ) {
$url = $urlGenerator -> linkToDocs ( $url );
}
$info [ 'documentation' ][ $key ] = $url ;
}
}
2023-05-31 15:13:58 -04:00
$info [ 'version' ] = $appManager -> getAppVersion ( $app );
2013-01-21 16:18:11 -05:00
$appList [] = $info ;
}
}
2013-10-14 04:54:38 -04:00
2016-10-27 11:41:15 -04:00
return $appList ;
2013-10-14 04:54:38 -04:00
}
2018-02-17 09:37:57 -05:00
public static function shouldUpgrade ( string $app ) : bool {
2014-06-04 10:40:53 -04:00
$versions = self :: getAppVersions ();
2023-05-31 15:13:58 -04:00
$currentVersion = \OCP\Server :: get ( \OCP\App\IAppManager :: class ) -> getAppVersion ( $app );
2014-10-30 12:24:25 -04:00
if ( $currentVersion && isset ( $versions [ $app ])) {
2014-06-04 10:40:53 -04:00
$installedVersion = $versions [ $app ];
2016-07-22 08:44:00 -04:00
if ( ! version_compare ( $currentVersion , $installedVersion , '=' )) {
2014-06-04 10:40:53 -04:00
return true ;
}
}
return false ;
}
2014-05-27 05:54:12 -04:00
/**
2014-07-09 04:20:17 -04:00
* Adjust the number of version parts of $version1 to match
2014-05-27 05:54:12 -04:00
* the number of version parts of $version2 .
*
* @ param string $version1 version to adjust
* @ param string $version2 version to take the number of parts from
* @ return string shortened $version1
*/
2018-02-17 09:37:57 -05:00
private static function adjustVersionParts ( string $version1 , string $version2 ) : string {
2014-05-27 05:54:12 -04:00
$version1 = explode ( '.' , $version1 );
$version2 = explode ( '.' , $version2 );
// reduce $version1 to match the number of parts in $version2
while ( count ( $version1 ) > count ( $version2 )) {
array_pop ( $version1 );
}
// if $version1 does not have enough parts, add some
while ( count ( $version1 ) < count ( $version2 )) {
$version1 [] = '0' ;
}
return implode ( '.' , $version1 );
}
2013-02-25 06:38:00 -05:00
/**
2024-09-17 08:41:25 -04:00
* Check whether the current Nextcloud version matches the given
2014-05-27 05:54:12 -04:00
* application ' s version requirements .
*
* The comparison is made based on the number of parts that the
* app info version has . For example for ownCloud 6.0 . 3 if the
* app info version is expecting version 6.0 , the comparison is
* made on the first two parts of the ownCloud version .
* This means that it ' s possible to specify " requiremin " => 6
* and " requiremax " => 6 and it will still match ownCloud 6.0 . 3.
*
2024-09-17 08:41:25 -04:00
* @ param string $ocVersion Nextcloud version to check against
2015-02-02 08:47:38 -05:00
* @ param array $appInfo app info ( from xml )
2014-05-27 05:54:12 -04:00
*
2013-02-25 06:38:00 -05:00
* @ return boolean true if compatible , otherwise false
*/
2019-03-06 13:59:15 -05:00
public static function isAppCompatible ( string $ocVersion , array $appInfo , bool $ignoreMax = false ) : bool {
2014-05-27 05:54:12 -04:00
$requireMin = '' ;
$requireMax = '' ;
2016-10-31 06:07:54 -04:00
if ( isset ( $appInfo [ 'dependencies' ][ 'nextcloud' ][ '@attributes' ][ 'min-version' ])) {
$requireMin = $appInfo [ 'dependencies' ][ 'nextcloud' ][ '@attributes' ][ 'min-version' ];
} elseif ( isset ( $appInfo [ 'dependencies' ][ 'owncloud' ][ '@attributes' ][ 'min-version' ])) {
2015-01-14 06:48:59 -05:00
$requireMin = $appInfo [ 'dependencies' ][ 'owncloud' ][ '@attributes' ][ 'min-version' ];
2020-04-10 04:35:09 -04:00
} elseif ( isset ( $appInfo [ 'requiremin' ])) {
2014-05-27 05:54:12 -04:00
$requireMin = $appInfo [ 'requiremin' ];
2020-04-10 04:35:09 -04:00
} elseif ( isset ( $appInfo [ 'require' ])) {
2014-05-27 05:54:12 -04:00
$requireMin = $appInfo [ 'require' ];
}
2013-02-25 06:38:00 -05:00
2016-10-31 06:07:54 -04:00
if ( isset ( $appInfo [ 'dependencies' ][ 'nextcloud' ][ '@attributes' ][ 'max-version' ])) {
$requireMax = $appInfo [ 'dependencies' ][ 'nextcloud' ][ '@attributes' ][ 'max-version' ];
} elseif ( isset ( $appInfo [ 'dependencies' ][ 'owncloud' ][ '@attributes' ][ 'max-version' ])) {
2015-01-14 06:48:59 -05:00
$requireMax = $appInfo [ 'dependencies' ][ 'owncloud' ][ '@attributes' ][ 'max-version' ];
2020-04-10 04:35:09 -04:00
} elseif ( isset ( $appInfo [ 'requiremax' ])) {
2014-05-27 05:54:12 -04:00
$requireMax = $appInfo [ 'requiremax' ];
}
2013-02-25 06:38:00 -05:00
2014-05-27 05:54:12 -04:00
if ( ! empty ( $requireMin )
&& version_compare ( self :: adjustVersionParts ( $ocVersion , $requireMin ), $requireMin , '<' )
) {
return false ;
}
2019-03-06 13:59:15 -05:00
if ( ! $ignoreMax && ! empty ( $requireMax )
2014-05-27 05:54:12 -04:00
&& version_compare ( self :: adjustVersionParts ( $ocVersion , $requireMax ), $requireMax , '>' )
) {
return false ;
2013-02-25 06:38:00 -05:00
}
return true ;
}
2012-03-30 07:48:44 -04:00
/**
2012-06-28 16:01:46 -04:00
* get the installed version of all apps
2012-03-30 07:48:44 -04:00
*/
2012-09-07 09:22:01 -04:00
public static function getAppVersions () {
2012-06-26 14:53:28 -04:00
static $versions ;
2016-01-03 10:53:30 -05:00
if ( ! $versions ) {
2024-01-11 11:32:58 -05:00
/** @var IAppConfig $appConfig */
$appConfig = \OCP\Server :: get ( IAppConfig :: class );
$versions = $appConfig -> searchValues ( 'installed_version' );
2012-03-30 07:48:44 -04:00
}
2016-01-03 10:53:30 -05:00
return $versions ;
2012-03-30 07:48:44 -04:00
}
2011-12-11 16:08:01 -05:00
/**
* update the database for the app and call the update script
2014-04-17 09:30:27 -04:00
*
2014-07-09 04:20:17 -04:00
* @ param string $appId
2014-05-21 06:14:10 -04:00
* @ return bool
2011-12-11 16:08:01 -05:00
*/
2018-02-19 04:28:41 -05:00
public static function updateApp ( string $appId ) : bool {
2023-01-26 06:38:20 -05:00
// for apps distributed with core, we refresh app path in case the downloaded version
// have been installed in custom apps and not in the default path
$appPath = self :: getAppPath ( $appId , true );
2016-02-14 14:57:09 -05:00
if ( $appPath === false ) {
return false ;
}
2017-06-09 08:49:40 -04:00
2020-06-30 15:47:31 -04:00
if ( is_file ( $appPath . '/appinfo/database.xml' )) {
2024-09-14 19:34:47 -04:00
\OCP\Server :: get ( LoggerInterface :: class ) -> error ( 'The appinfo/database.xml file is not longer supported. Used in ' . $appId );
2020-06-30 15:47:31 -04:00
return false ;
}
2018-05-30 10:06:18 -04:00
\OC :: $server -> getAppManager () -> clearAppsCache ();
2021-09-30 03:08:17 -04:00
$l = \OC :: $server -> getL10N ( 'core' );
2023-05-31 15:15:51 -04:00
$appData = \OCP\Server :: get ( \OCP\App\IAppManager :: class ) -> getAppInfo ( $appId , false , $l -> getLanguageCode ());
2020-01-13 09:12:04 -05:00
2020-11-26 10:44:20 -05:00
$ignoreMaxApps = \OC :: $server -> getConfig () -> getSystemValue ( 'app_install_overwrite' , []);
$ignoreMax = in_array ( $appId , $ignoreMaxApps , true );
\OC_App :: checkAppDependencies (
\OC :: $server -> getConfig (),
2021-09-30 03:08:17 -04:00
$l ,
2020-11-26 10:44:20 -05:00
$appData ,
$ignoreMax
);
2020-01-13 09:14:56 -05:00
self :: registerAutoloading ( $appId , $appPath , true );
2016-04-19 09:36:11 -04:00
self :: executeRepairSteps ( $appId , $appData [ 'repair-steps' ][ 'pre-migration' ]);
2017-06-01 10:56:34 -04:00
2020-06-30 15:47:31 -04:00
$ms = new MigrationService ( $appId , \OC :: $server -> get ( \OC\DB\Connection :: class ));
$ms -> migrate ();
2017-06-01 10:56:34 -04:00
2016-04-19 09:36:11 -04:00
self :: executeRepairSteps ( $appId , $appData [ 'repair-steps' ][ 'post-migration' ]);
2016-04-26 05:56:56 -04:00
self :: setupLiveMigrations ( $appId , $appData [ 'repair-steps' ][ 'live-migration' ]);
2018-01-29 07:09:32 -05:00
// update appversion in app manager
2018-06-02 02:48:33 -04:00
\OC :: $server -> getAppManager () -> clearAppsCache ();
2018-01-29 07:09:32 -05:00
\OC :: $server -> getAppManager () -> getAppVersion ( $appId , false );
2017-06-01 10:56:34 -04:00
2016-05-02 09:26:12 -04:00
self :: setupBackgroundJobs ( $appData [ 'background-jobs' ]);
2012-05-11 14:32:37 -04:00
2012-09-22 20:39:11 -04:00
//set remote/public handlers
2014-07-07 10:57:50 -04:00
if ( array_key_exists ( 'ocsid' , $appData )) {
2015-07-09 06:37:57 -04:00
\OC :: $server -> getConfig () -> setAppValue ( $appId , 'ocsid' , $appData [ 'ocsid' ]);
} elseif ( \OC :: $server -> getConfig () -> getAppValue ( $appId , 'ocsid' , null ) !== null ) {
\OC :: $server -> getConfig () -> deleteAppValue ( $appId , 'ocsid' );
2014-07-07 10:57:50 -04:00
}
2014-04-17 09:30:27 -04:00
foreach ( $appData [ 'remote' ] as $name => $path ) {
2015-07-09 06:37:57 -04:00
\OC :: $server -> getConfig () -> setAppValue ( 'core' , 'remote_' . $name , $appId . '/' . $path );
2012-05-11 14:32:37 -04:00
}
2014-04-17 09:30:27 -04:00
foreach ( $appData [ 'public' ] as $name => $path ) {
2015-07-09 06:37:57 -04:00
\OC :: $server -> getConfig () -> setAppValue ( 'core' , 'public_' . $name , $appId . '/' . $path );
2012-05-11 14:32:37 -04:00
}
2012-05-14 16:49:20 -04:00
2014-07-09 04:20:17 -04:00
self :: setAppTypes ( $appId );
2014-05-21 06:14:10 -04:00
2023-05-31 15:13:58 -04:00
$version = \OCP\Server :: get ( \OCP\App\IAppManager :: class ) -> getAppVersion ( $appId );
2018-01-17 15:14:09 -05:00
\OC :: $server -> getConfig () -> setAppValue ( $appId , 'installed_version' , $version );
2014-07-25 07:38:44 -04:00
2022-12-08 04:55:19 -05:00
\OC :: $server -> get ( IEventDispatcher :: class ) -> dispatchTyped ( new AppUpdateEvent ( $appId ));
2023-07-28 08:10:27 -04:00
\OC :: $server -> get ( IEventDispatcher :: class ) -> dispatch ( ManagerEvent :: EVENT_APP_UPDATE , new ManagerEvent (
2016-08-15 18:52:41 -04:00
ManagerEvent :: EVENT_APP_UPDATE , $appId
));
2014-05-21 06:14:10 -04:00
return true ;
2011-12-11 16:08:01 -05:00
}
2012-02-08 15:01:09 -05:00
2016-04-19 09:36:11 -04:00
/**
* @ param string $appId
* @ param string [] $steps
* @ throws \OC\NeedsUpdateException
*/
2018-02-17 09:37:57 -05:00
public static function executeRepairSteps ( string $appId , array $steps ) {
2016-04-19 09:36:11 -04:00
if ( empty ( $steps )) {
return ;
}
// load the app
2017-03-13 20:07:41 -04:00
self :: loadApp ( $appId );
2016-04-19 09:36:11 -04:00
2024-06-18 05:55:08 -04:00
$dispatcher = Server :: get ( IEventDispatcher :: class );
2016-04-19 09:36:11 -04:00
// load the steps
2024-06-18 05:55:08 -04:00
$r = Server :: get ( Repair :: class );
2016-04-19 09:36:11 -04:00
foreach ( $steps as $step ) {
try {
$r -> addStep ( $step );
} catch ( Exception $ex ) {
2022-08-22 11:59:26 -04:00
$dispatcher -> dispatchTyped ( new RepairErrorEvent ( $ex -> getMessage ()));
2024-06-18 05:55:08 -04:00
logger ( 'core' ) -> error ( 'Failed to add app migration step ' . $step , [ 'exception' => $ex ]);
2016-04-19 09:36:11 -04:00
}
}
// run the steps
$r -> run ();
}
2016-05-02 09:26:12 -04:00
public static function setupBackgroundJobs ( array $jobs ) {
$queue = \OC :: $server -> getJobList ();
foreach ( $jobs as $job ) {
$queue -> add ( $job );
}
}
2016-04-26 05:56:56 -04:00
/**
* @ param string $appId
* @ param string [] $steps
*/
2018-02-17 09:37:57 -05:00
private static function setupLiveMigrations ( string $appId , array $steps ) {
2016-04-26 05:56:56 -04:00
$queue = \OC :: $server -> getJobList ();
foreach ( $steps as $step ) {
$queue -> add ( 'OC\Migration\BackgroundRepair' , [
'app' => $appId ,
'step' => $step ]);
}
}
2012-02-08 15:01:09 -05:00
/**
2014-07-09 04:20:17 -04:00
* @ param string $appId
2015-01-16 13:31:15 -05:00
* @ return \OC\Files\View | false
2012-02-08 15:01:09 -05:00
*/
2018-02-17 09:37:57 -05:00
public static function getStorage ( string $appId ) {
2017-10-23 17:31:17 -04:00
if ( \OC :: $server -> getAppManager () -> isEnabledForUser ( $appId )) { //sanity check
2017-03-02 10:52:05 -05:00
if ( \OC :: $server -> getUserSession () -> isLoggedIn ()) {
2014-04-17 09:30:27 -04:00
$view = new \OC\Files\View ( '/' . OC_User :: getUser ());
2014-07-09 04:20:17 -04:00
if ( ! $view -> file_exists ( $appId )) {
$view -> mkdir ( $appId );
2012-04-23 18:26:33 -04:00
}
2014-07-09 04:20:17 -04:00
return new \OC\Files\View ( '/' . OC_User :: getUser () . '/' . $appId );
2014-04-17 09:30:27 -04:00
} else {
2023-09-21 11:25:52 -04:00
\OCP\Server :: get ( LoggerInterface :: class ) -> error ( 'Can\'t get app storage, app ' . $appId . ', user not logged in' , [ 'app' => 'core' ]);
2012-02-08 15:01:09 -05:00
return false ;
}
2014-04-17 09:30:27 -04:00
} else {
2023-09-21 11:25:52 -04:00
\OCP\Server :: get ( LoggerInterface :: class ) -> error ( 'Can\'t get app storage, app ' . $appId . ' not enabled' , [ 'app' => 'core' ]);
2012-09-18 09:35:27 -04:00
return false ;
2012-02-08 15:01:09 -05:00
}
}
2015-01-13 08:48:30 -05:00
2018-02-17 09:37:57 -05:00
protected static function findBestL10NOption ( array $options , string $lang ) : string {
2018-04-12 06:28:25 -04:00
// only a single option
if ( isset ( $options [ '@value' ])) {
return $options [ '@value' ];
}
2016-10-04 07:29:54 -04:00
$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 , '_' ));
}
2016-09-30 05:00:58 -04:00
foreach ( $options as $option ) {
if ( is_array ( $option )) {
if ( $fallback === false ) {
$fallback = $option [ '@value' ];
}
2016-10-04 07:29:54 -04:00
if ( ! isset ( $option [ '@attributes' ][ 'lang' ])) {
continue ;
}
$attributeLang = strtolower ( $option [ '@attributes' ][ 'lang' ]);
if ( $attributeLang === $lang ) {
2016-09-30 05:00:58 -04:00
return $option [ '@value' ];
}
2016-10-04 07:29:54 -04:00
if ( $attributeLang === $similarLang ) {
$similarLangFallback = $option [ '@value' ];
2023-05-15 07:47:19 -04:00
} elseif ( str_starts_with ( $attributeLang , $similarLang . '_' )) {
2016-10-04 07:29:54 -04:00
if ( $similarLangFallback === false ) {
2020-10-05 09:12:57 -04:00
$similarLangFallback = $option [ '@value' ];
2016-10-04 07:29:54 -04:00
}
}
2016-09-30 05:00:58 -04:00
} else {
$englishFallback = $option ;
}
}
2016-10-04 07:29:54 -04:00
if ( $similarLangFallback !== false ) {
return $similarLangFallback ;
2020-04-10 04:35:09 -04:00
} elseif ( $englishFallback !== false ) {
2016-10-04 07:29:54 -04:00
return $englishFallback ;
}
return ( string ) $fallback ;
2016-09-30 05:00:58 -04:00
}
2015-01-13 08:48:30 -05:00
/**
* parses the app data array and enhanced the 'description' value
*
* @ param array $data the app data
2016-09-30 05:00:58 -04:00
* @ param string $lang
2015-01-13 08:48:30 -05:00
* @ return array improved app data
*/
2018-02-17 09:37:57 -05:00
public static function parseAppInfo ( array $data , $lang = null ) : array {
2016-09-30 05:00:58 -04:00
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' ])) {
2017-01-11 04:57:26 -05:00
$data [ 'description' ] = trim ( self :: findBestL10NOption ( $data [ 'description' ], $lang ));
2020-04-10 04:35:09 -04:00
} elseif ( isset ( $data [ 'description' ]) && is_string ( $data [ 'description' ])) {
2017-01-11 04:57:26 -05:00
$data [ 'description' ] = trim ( $data [ 'description' ]);
} else {
2016-09-30 08:41:37 -04:00
$data [ 'description' ] = '' ;
2015-01-13 08:48:30 -05:00
}
return $data ;
}
2016-10-07 05:27:33 -04:00
/**
2017-01-11 04:57:26 -05:00
* @ param \OCP\IConfig $config
* @ param \OCP\IL10N $l
* @ param array $info
* @ throws \Exception
2016-10-07 05:27:33 -04:00
*/
2019-03-06 13:59:15 -05:00
public static function checkAppDependencies ( \OCP\IConfig $config , \OCP\IL10N $l , array $info , bool $ignoreMax ) {
2016-10-07 05:27:33 -04:00
$dependencyAnalyzer = new DependencyAnalyzer ( new Platform ( $config ), $l );
2019-03-06 13:59:15 -05:00
$missing = $dependencyAnalyzer -> analyze ( $info , $ignoreMax );
2016-10-07 05:27:33 -04:00
if ( ! empty ( $missing )) {
2017-07-23 15:03:26 -04:00
$missingMsg = implode ( PHP_EOL , $missing );
2016-10-07 05:27:33 -04:00
throw new \Exception (
2018-10-09 08:32:14 -04:00
$l -> t ( 'App "%1$s" cannot be installed because the following dependencies are not fulfilled: %2$s' ,
2016-10-07 05:27:33 -04:00
[ $info [ 'name' ], $missingMsg ]
)
);
}
}
2011-03-03 15:55:32 -05:00
}