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 );
2019-12-03 13:57:53 -05:00
2011-03-11 09:25:48 -05:00
/**
2016-07-21 11:07:57 -04:00
* @ copyright Copyright ( c ) 2016 , ownCloud , Inc .
2016-10-27 11:41:15 -04:00
* @ copyright Copyright ( c ) 2016 , Lukas Reschke < lukas @ statuscode . ch >
2016-07-21 11:07:57 -04:00
*
2016-05-26 13:56:05 -04:00
* @ author Arthur Schiwon < blizzz @ arthur - schiwon . de >
2015-03-26 06:44:34 -04:00
* @ 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 >
2019-12-03 13:57:53 -05:00
* @ author Christoph Wurst < christoph @ winzerhof - wurst . at >
* @ author Daniel Rudolf < github . com @ daniel - rudolf . de >
2016-05-26 13:56:05 -04:00
* @ author Frank Karlitschek < frank @ karlitschek . de >
2017-11-06 14:15:27 -05:00
* @ author Georg Ehrke < oc . list @ georgehrke . com >
2015-03-26 06:44:34 -04:00
* @ author Jakob Sack < mail @ jakobsack . de >
2016-07-21 11:07:57 -04:00
* @ author Joas Schilling < coding @ schilljs . com >
2019-12-03 13:57:53 -05:00
* @ author Jörn Friedrich Dreyer < jfd @ butonic . de >
2017-11-06 09:56:42 -05:00
* @ author Julius Haertl < jus @ bitgrid . net >
* @ author Julius Härtl < jus @ bitgrid . net >
2015-03-26 06:44:34 -04:00
* @ author Kamil Domanski < kdomanski @ kdemail . net >
2016-05-26 13:56:05 -04:00
* @ author Lukas Reschke < lukas @ statuscode . ch >
2015-03-26 06:44:34 -04:00
* @ author Markus Goetz < markus @ woboq . com >
* @ author Morris Jobke < hey @ morrisjobke . de >
2015-10-05 14:54:56 -04:00
* @ author RealRancor < Fisch . 666 @ gmx . de >
2016-07-21 12:13:36 -04:00
* @ author Robin Appelman < robin @ icewind . nl >
2016-01-12 09:02:16 -05:00
* @ author Robin McCorkell < robin @ mccorkell . me . uk >
2016-07-21 11:07:57 -04:00
* @ author Roeland Jago Douma < roeland @ famdouma . nl >
2015-03-26 06:44:34 -04:00
* @ author Sam Tuke < mail @ samtuke . com >
2017-11-06 09:56:42 -05:00
* @ author Sebastian Wessalowski < sebastian @ wessalowski . org >
2015-03-26 06:44:34 -04:00
* @ author Thomas Müller < thomas . mueller @ tmit . eu >
* @ author Thomas Tanghus < thomas @ tanghus . net >
* @ author Vincent Petry < pvince81 @ owncloud . com >
2011-03-11 09:25:48 -05:00
*
2015-03-26 06:44:34 -04:00
* @ license AGPL - 3.0
2014-05-21 06:14:10 -04:00
*
2015-03-26 06:44:34 -04:00
* 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 .
2014-05-21 06:14:10 -04:00
*
2015-03-26 06:44:34 -04:00
* This program is distributed in the hope that it will be useful ,
2011-03-11 09:25:48 -05:00
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
2015-03-26 06:44:34 -04:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Affero General Public License for more details .
2011-03-11 09:25:48 -05:00
*
2015-03-26 06:44:34 -04:00
* You should have received a copy of the GNU Affero General Public License , version 3 ,
2019-12-03 13:57:53 -05:00
* along with this program . If not , see < http :// www . gnu . org / licenses />
2011-03-11 09:25:48 -05:00
*
*/
2014-12-11 11:02:07 -05:00
use OC\App\DependencyAnalyzer ;
use OC\App\Platform ;
2020-07-15 11:06:27 -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 ;
2019-11-14 11:20:14 -05:00
use OC\ServerNotAvailableException ;
2016-08-15 18:52:41 -04:00
use OCP\App\ManagerEvent ;
2020-07-15 11:06:27 -04:00
use OCP\AppFramework\QueryException ;
use OCP\Authentication\IAlternativeLogin ;
2018-04-25 09:22:28 -04:00
use OCP\ILogger ;
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
2014-07-09 04:20:17 -04:00
* ownCloud 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 $adminForms = [];
private static $personalForms = [];
private static $appTypes = [];
private static $loadedApps = [];
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
*
2018-02-17 09:37:57 -05:00
* @ param string $app AppId that needs to be cleaned
2013-02-09 09:03:47 -05:00
* @ return string
*/
2018-02-17 09:37:57 -05:00
public static function cleanAppId ( string $app ) : string {
2020-03-26 04:30:18 -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
*/
2018-02-17 09:37:57 -05:00
public static function isAppLoaded ( string $app ) : bool {
2015-08-18 04:18:36 -04:00
return in_array ( $app , self :: $loadedApps , true );
}
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
*
2014-07-09 04:20:17 -04:00
* This function walks through the ownCloud 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
2011-03-03 15:55:32 -05:00
*/
2018-02-17 09:22:00 -05:00
public static function loadApps ( array $types = []) : bool {
2019-02-06 11:08:41 -05:00
if (( bool ) \OC :: $server -> getSystemConfig () -> getValue ( 'maintenance' , false )) {
2014-07-24 11:51:28 -04:00
return false ;
}
2012-05-31 07:00:58 -04:00
// Load the enabled apps here
2012-03-30 08:00:24 -04:00
$apps = self :: getEnabledApps ();
2015-09-15 05:55:23 -04:00
// Add each apps' folder as allowed class path
2020-04-10 08:19:56 -04:00
foreach ( $apps as $app ) {
2015-09-15 06:09:48 -04:00
$path = self :: getAppPath ( $app );
2020-04-10 08:19:56 -04:00
if ( $path !== false ) {
2016-05-02 08:11:34 -04:00
self :: registerAutoloading ( $app , $path );
2015-09-15 06:09:48 -04:00
}
2015-09-15 05:55:23 -04:00
}
2012-05-26 14:40:12 -04:00
// prevent app.php from printing output
ob_start ();
2014-04-17 09:30:27 -04:00
foreach ( $apps as $app ) {
2018-02-17 09:22:00 -05:00
if (( $types === [] or self :: isType ( $app , $types )) && ! in_array ( $app , self :: $loadedApps )) {
2014-01-31 09:12:21 -05:00
self :: loadApp ( $app );
2011-06-19 09:18:52 -04:00
}
2011-03-03 15:55:32 -05:00
}
2012-05-26 14:40:12 -04:00
ob_end_clean ();
2011-03-03 15:55:32 -05:00
2013-02-09 11:27:57 -05:00
return true ;
}
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
2012-05-13 18:28:22 -04:00
*/
2018-02-17 09:37:57 -05:00
public static function loadApp ( string $app ) {
2015-09-04 17:11:45 -04:00
self :: $loadedApps [] = $app ;
2016-02-14 14:57:09 -05:00
$appPath = self :: getAppPath ( $app );
2020-04-10 08:19:56 -04:00
if ( $appPath === false ) {
2016-02-14 14:57:09 -05:00
return ;
}
2016-05-02 08:11:34 -04:00
// in case someone calls loadApp() directly
self :: registerAutoloading ( $app , $appPath );
2020-07-15 11:06:27 -04:00
/** @var Coordinator $coordinator */
$coordinator = \OC :: $server -> query ( Coordinator :: class );
2020-07-13 08:58:52 -04:00
$isBootable = $coordinator -> isBootable ( $app );
$hasAppPhpFile = is_file ( $appPath . '/appinfo/app.php' );
if ( $isBootable && $hasAppPhpFile ) {
\OC :: $server -> getLogger () -> error ( '/appinfo/app.php is not loaded when \OCP\AppFramework\Bootstrap\IBootstrap on the application class is used. Migrate everything from app.php to the Application class.' , [
'app' => $app ,
]);
} elseif ( $hasAppPhpFile ) {
2020-06-30 03:43:40 -04:00
\OC :: $server -> getLogger () -> debug ( '/appinfo/app.php is deprecated, use \OCP\AppFramework\Bootstrap\IBootstrap on the application class instead.' , [
'app' => $app ,
]);
2014-10-03 16:13:55 -04:00
\OC :: $server -> getEventLogger () -> start ( 'load_app_' . $app , 'Load app: ' . $app );
2018-02-15 05:20:22 -05:00
try {
self :: requireAppFile ( $app );
2018-08-24 11:16:54 -04:00
} catch ( Throwable $ex ) {
2020-04-10 08:19:56 -04:00
if ( $ex instanceof ServerNotAvailableException ) {
2019-11-14 11:20:14 -05:00
throw $ex ;
}
2019-12-10 03:01:35 -05:00
if ( ! \OC :: $server -> getAppManager () -> isShipped ( $app ) && ! self :: isType ( $app , [ 'authentication' ])) {
2020-05-19 04:48:57 -04:00
\OC :: $server -> getLogger () -> logException ( $ex , [
'message' => " App $app threw an error during app.php load and will be disabled: " . $ex -> getMessage (),
]);
2019-12-10 03:01:35 -05:00
// Only disable apps which are not shipped and that are not authentication apps
2019-07-23 04:28:47 -04:00
\OC :: $server -> getAppManager () -> disableApp ( $app , true );
2020-05-19 04:48:57 -04:00
} else {
\OC :: $server -> getLogger () -> logException ( $ex , [
'message' => " App $app threw an error during app.php load: " . $ex -> getMessage (),
]);
2018-02-15 05:20:22 -05:00
}
}
2014-10-03 16:13:55 -04:00
\OC :: $server -> getEventLogger () -> end ( 'load_app_' . $app );
2012-05-13 18:28:22 -04:00
}
2020-06-17 08:44:02 -04:00
$coordinator -> bootApp ( $app );
2016-10-20 11:57:44 -04:00
$info = self :: getAppInfo ( $app );
if ( ! empty ( $info [ 'activity' ][ 'filters' ])) {
foreach ( $info [ 'activity' ][ 'filters' ] as $filter ) {
\OC :: $server -> getActivityManager () -> registerFilter ( $filter );
}
}
2016-10-25 12:00:25 -04:00
if ( ! empty ( $info [ 'activity' ][ 'settings' ])) {
foreach ( $info [ 'activity' ][ 'settings' ] as $setting ) {
\OC :: $server -> getActivityManager () -> registerSetting ( $setting );
}
}
2016-11-04 06:33:33 -04:00
if ( ! empty ( $info [ 'activity' ][ 'providers' ])) {
foreach ( $info [ 'activity' ][ 'providers' ] as $provider ) {
\OC :: $server -> getActivityManager () -> registerProvider ( $provider );
}
}
2018-01-29 07:14:56 -05:00
if ( ! empty ( $info [ 'settings' ][ 'admin' ])) {
foreach ( $info [ 'settings' ][ 'admin' ] as $setting ) {
\OC :: $server -> getSettingsManager () -> registerSetting ( 'admin' , $setting );
}
}
if ( ! empty ( $info [ 'settings' ][ 'admin-section' ])) {
foreach ( $info [ 'settings' ][ 'admin-section' ] as $section ) {
\OC :: $server -> getSettingsManager () -> registerSection ( 'admin' , $section );
}
}
if ( ! empty ( $info [ 'settings' ][ 'personal' ])) {
foreach ( $info [ 'settings' ][ 'personal' ] as $setting ) {
\OC :: $server -> getSettingsManager () -> registerSetting ( 'personal' , $setting );
}
}
if ( ! empty ( $info [ 'settings' ][ 'personal-section' ])) {
foreach ( $info [ 'settings' ][ 'personal-section' ] as $section ) {
\OC :: $server -> getSettingsManager () -> registerSection ( 'personal' , $section );
}
}
2017-09-26 19:22:17 -04:00
if ( ! empty ( $info [ 'collaboration' ][ 'plugins' ])) {
// deal with one or many plugin entries
$plugins = isset ( $info [ 'collaboration' ][ 'plugins' ][ 'plugin' ][ '@value' ]) ?
[ $info [ 'collaboration' ][ 'plugins' ][ 'plugin' ]] : $info [ 'collaboration' ][ 'plugins' ][ 'plugin' ];
foreach ( $plugins as $plugin ) {
2020-04-10 08:19:56 -04:00
if ( $plugin [ '@attributes' ][ 'type' ] === 'collaborator-search' ) {
2017-09-26 19:22:17 -04:00
$pluginInfo = [
2017-09-27 07:22:59 -04:00
'shareType' => $plugin [ '@attributes' ][ 'share-type' ],
2017-09-26 19:22:17 -04:00
'class' => $plugin [ '@value' ],
];
\OC :: $server -> getCollaboratorSearch () -> registerPlugin ( $pluginInfo );
2020-04-10 04:35:09 -04:00
} elseif ( $plugin [ '@attributes' ][ 'type' ] === 'autocomplete-sort' ) {
2017-08-30 04:56:02 -04:00
\OC :: $server -> getAutoCompleteManager () -> registerSorter ( $plugin [ '@value' ]);
2017-09-26 19:22:17 -04:00
}
2017-09-06 15:57:00 -04:00
}
}
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 on legacy autoloader
\OC :: $loader -> addValidRoot ( $path );
}
// 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 );
}
}
2014-10-17 06:28:27 -04:00
/**
* Load app . php from the given app
*
* @ param string $app app name
2018-02-15 06:23:49 -05:00
* @ throws Error
2014-10-17 06:28:27 -04:00
*/
2018-02-17 09:37:57 -05:00
private static function requireAppFile ( string $app ) {
2018-02-15 05:20:22 -05:00
// encapsulated here to avoid variable scope conflicts
require_once $app . '/appinfo/app.php' ;
2014-10-17 06:28:27 -04:00
}
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
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 {
2014-04-17 09:30:27 -04:00
$appTypes = self :: getAppTypes ( $app );
foreach ( $types as $type ) {
if ( array_search ( $type , $appTypes ) !== false ) {
2012-03-30 08:39:07 -04:00
return true ;
}
}
return false ;
}
2012-05-02 05:14:11 -04:00
2012-04-14 11:53:02 -04:00
/**
* get the types of an app
2014-04-17 09:30:27 -04:00
*
2012-04-14 11:53:02 -04:00
* @ param string $app
* @ return array
*/
2018-02-17 09:37:57 -05:00
private static function getAppTypes ( string $app ) : array {
2012-04-14 11:53:02 -04:00
//load the cache
2014-04-17 09:30:27 -04:00
if ( count ( self :: $appTypes ) == 0 ) {
2015-07-03 08:16:29 -04:00
self :: $appTypes = \OC :: $server -> getAppConfig () -> getValues ( false , 'types' );
2012-04-14 11:53:02 -04:00
}
2012-05-02 05:14:11 -04:00
2014-04-17 09:30:27 -04:00
if ( isset ( self :: $appTypes [ $app ])) {
2012-09-04 06:32:27 -04:00
return explode ( ',' , self :: $appTypes [ $app ]);
2012-05-20 12:51:45 -04:00
}
2018-02-17 09:18:34 -05:00
return [];
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 );
2020-04-10 08:19:56 -04:00
if ( ! is_array ( $appData )) {
2016-03-30 17:29:26 -04:00
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
* checks whether or not an app is enabled
2015-02-02 08:47:38 -05:00
*
2012-09-22 20:39:11 -04:00
* @ param string $app app
* @ return bool
2017-10-24 08:05:46 -04:00
* @ deprecated 13.0 . 0 use \OC :: $server -> getAppManager () -> isEnabledForUser ( $appId )
2011-06-19 09:18:52 -04:00
*
* This function checks whether or not an app is enabled .
*/
2018-02-17 09:37:57 -05:00
public static function isEnabled ( string $app ) : bool {
2015-02-02 08:47:38 -05:00
return \OC :: $server -> getAppManager () -> isEnabledForUser ( $app );
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 */
2017-11-24 04:27:58 -05:00
$installer = \OC :: $server -> query ( Installer :: class );
2016-10-27 11:41:15 -04:00
$isDownloaded = $installer -> isDownloaded ( $appId );
2020-04-10 08:19:56 -04:00
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
2014-04-17 09:30:27 -04:00
*
2015-01-16 13:31:15 -05:00
* @ return string | false
2012-07-23 18:39:59 -04:00
*/
2012-06-14 17:00:02 -04:00
public static function getInstallPath () {
2015-12-18 05:42:09 -05:00
if ( \OC :: $server -> getSystemConfig () -> getValue ( 'appstoreenabled' , true ) == false ) {
2012-06-14 17:00:02 -04:00
return false ;
}
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
}
2018-04-25 09:22:28 -04:00
\OCP\Util :: writeLog ( 'core' , 'No application directories are marked as writable.' , ILogger :: ERROR );
2012-06-14 17:00:02 -04:00
return null ;
}
2014-05-21 06:14:10 -04:00
/**
* search for an app in all app - directories
2015-02-02 08:47:38 -05:00
*
2015-04-07 07:49:16 -04:00
* @ param string $appId
2015-12-08 04:01:09 -05:00
* @ return false | string
2014-05-21 06:14:10 -04:00
*/
2018-02-17 09:37:57 -05:00
public static function findAppInDirectories ( string $appId ) {
2015-12-08 04:01:09 -05:00
$sanitizedAppId = self :: cleanAppId ( $appId );
2020-04-10 08:19:56 -04:00
if ( $sanitizedAppId !== $appId ) {
2015-12-08 04:01:09 -05:00
return false ;
}
2018-02-17 09:18:34 -05:00
static $app_dir = [];
2014-05-21 06:14:10 -04:00
if ( isset ( $app_dir [ $appId ])) {
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
*
2014-07-09 04:20:52 -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 11.0 . 0 use \OC :: $server -> getAppManager () -> getAppPath ()
2014-04-15 16:55:20 -04:00
*/
2018-02-17 09:37:57 -05:00
public static function getAppPath ( string $appId ) {
2014-07-09 04:20:17 -04:00
if ( $appId === null || trim ( $appId ) === '' ) {
2014-06-25 10:24:55 -04:00
return false ;
}
2014-07-09 04:20:17 -04:00
if (( $dir = self :: findAppInDirectories ( $appId )) != false ) {
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
}
2012-04-14 10:27:58 -04:00
/**
2016-02-10 05:04:12 -05:00
* get the last version of the app from appinfo / info . xml
2014-07-09 04:20:17 -04:00
*
* @ param string $appId
2016-12-09 11:46:05 -05:00
* @ param bool $useCache
2014-02-06 10:30:58 -05:00
* @ return string
2018-01-29 07:09:32 -05:00
* @ deprecated 14.0 . 0 use \OC :: $server -> getAppManager () -> getAppVersion ()
2012-04-14 10:27:58 -04:00
*/
2018-02-17 09:37:57 -05:00
public static function getAppVersion ( string $appId , bool $useCache = true ) : string {
2018-01-29 07:09:32 -05:00
return \OC :: $server -> getAppManager () -> getAppVersion ( $appId , $useCache );
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' ;
2018-01-29 07:09:32 -05:00
$appData = \OC :: $server -> getAppManager () -> getAppInfo ( $infoFile , true );
2016-02-10 05:04:12 -05:00
return isset ( $appData [ 'version' ]) ? $appData [ 'version' ] : '' ;
2012-04-14 10:27:58 -04:00
}
2011-10-05 06:31:33 -04:00
2014-05-21 06:14:10 -04:00
2011-03-11 08:59:24 -05:00
/**
2014-05-19 11:50:53 -04:00
* Read all app metadata from the info . xml file
2014-07-09 04:20:17 -04:00
*
* @ param string $appId id of the app or the path of the info . xml file
2016-09-30 05:00:58 -04:00
* @ param bool $path
* @ param string $lang
2014-07-05 07:32:21 -04:00
* @ return array | null
2012-09-18 09:35:27 -04:00
* @ note all data is read from info . xml , not just pre - defined fields
2018-01-29 07:09:32 -05:00
* @ deprecated 14.0 . 0 use \OC :: $server -> getAppManager () -> getAppInfo ()
2014-04-17 09:30:27 -04:00
*/
2018-02-17 09:37:57 -05:00
public static function getAppInfo ( string $appId , bool $path = false , string $lang = null ) {
2018-01-29 07:09:32 -05:00
return \OC :: $server -> getAppManager () -> getAppInfo ( $appId , $path , $lang );
2011-03-11 08:59:24 -05:00
}
2011-10-05 06:31:33 -04:00
2011-08-08 15:42:25 -04:00
/**
2014-05-19 11:50:53 -04:00
* Returns the navigation
2015-02-02 08:47:38 -05:00
*
2014-04-21 09:44:54 -04:00
* @ return array
2018-02-09 02:42:27 -05:00
* @ deprecated 14.0 . 0 use \OC :: $server -> getNavigationManager () -> getAll ()
2011-08-08 15:42:25 -04:00
*
* This function returns an array containing all entries added . The
* entries are sorted by the key 'order' ascending . Additional to the keys
* given for each app the following keys exist :
* - active : boolean , signals if the user is on this navigation entry
*/
2018-02-17 09:37:57 -05:00
public static function getNavigation () : array {
2018-01-29 04:07:12 -05:00
return OC :: $server -> getNavigationManager () -> getAll ();
2011-08-08 15:42:25 -04:00
}
2011-10-05 06:31:33 -04:00
2017-03-26 13:40:41 -04:00
/**
* Returns the Settings Navigation
*
* @ return string []
2018-02-09 02:42:27 -05:00
* @ deprecated 14.0 . 0 use \OC :: $server -> getNavigationManager () -> getAll ( 'settings' )
2017-03-26 13:40:41 -04:00
*
* This function returns an array containing all settings pages added . The
* entries are sorted by the key 'order' ascending .
*/
2018-02-17 09:37:57 -05:00
public static function getSettingsNavigation () : array {
2018-01-29 04:07:12 -05:00
return OC :: $server -> getNavigationManager () -> getAll ( 'settings' );
2017-03-01 17:04:27 -05: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 {
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 )) {
2015-02-10 07:02:48 -05:00
$path_info = $request -> getPathInfo ();
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
2011-08-08 17:32:54 -04:00
/**
2015-02-11 18:11:38 -05:00
* @ param string $type
* @ return array
2011-08-08 17:32:54 -04:00
*/
2018-02-17 09:37:57 -05:00
public static function getForms ( string $type ) : array {
2018-02-17 09:18:34 -05:00
$forms = [];
2014-04-17 09:30:27 -04:00
switch ( $type ) {
2011-08-08 17:32:54 -04:00
case 'admin' :
2014-04-17 09:30:27 -04:00
$source = self :: $adminForms ;
2013-02-09 11:27:57 -05:00
break ;
2011-08-08 17:32:54 -04:00
case 'personal' :
2014-04-17 09:30:27 -04:00
$source = self :: $personalForms ;
2013-02-09 11:27:57 -05:00
break ;
2012-09-22 20:39:11 -04:00
default :
2018-02-17 09:18:34 -05:00
return [];
2011-08-08 17:32:54 -04:00
}
2014-04-17 09:30:27 -04:00
foreach ( $source as $form ) {
$forms [] = include $form ;
2011-08-08 17:32:54 -04:00
}
return $forms ;
}
2011-10-05 06:31:33 -04:00
2011-08-08 17:32:54 -04:00
/**
* register an admin form to be shown
2014-04-17 09:30:27 -04:00
*
2014-02-19 03:31:54 -05:00
* @ param string $app
* @ param string $page
2011-08-08 17:32:54 -04:00
*/
2018-02-17 09:37:57 -05:00
public static function registerAdmin ( string $app , string $page ) {
2014-04-17 09:30:27 -04:00
self :: $adminForms [] = $app . '/' . $page . '.php' ;
2011-08-08 17:32:54 -04:00
}
2011-10-05 06:31:33 -04:00
2011-08-08 17:32:54 -04:00
/**
* register a personal form to be shown
2015-04-07 07:49:16 -04:00
* @ param string $app
* @ param string $page
2011-08-08 17:32:54 -04:00
*/
2018-02-17 09:37:57 -05:00
public static function registerPersonal ( string $app , string $page ) {
2014-04-17 09:30:27 -04:00
self :: $personalForms [] = $app . '/' . $page . '.php' ;
2011-08-08 17:32:54 -04:00
}
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 ) {
2020-07-15 11:06:27 -04:00
\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' );
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 */
$bootstrapCoordinator = \OC :: $server -> query ( Coordinator :: class );
foreach ( $bootstrapCoordinator -> getRegistrationContext () -> getAlternativeLogins () as $registration ) {
if ( ! in_array ( IAlternativeLogin :: class , class_implements ( $registration [ 'class' ]), true )) {
\OC :: $server -> getLogger () -> error ( 'Alternative login option {option} does not implement {interface} and is therefore ignored.' , [
'option' => $registration [ 'class' ],
'interface' => IAlternativeLogin :: class ,
'app' => $registration [ 'app' ],
]);
continue ;
}
try {
/** @var IAlternativeLogin $provider */
$provider = \OC :: $server -> query ( $registration [ 'class' ]);
} catch ( QueryException $e ) {
\OC :: $server -> getLogger () -> logException ( $e , [
'message' => 'Alternative login option {option} can not be initialised.' ,
'option' => $registration [ 'class' ],
'app' => $registration [ 'app' ],
]);
}
try {
$provider -> load ();
self :: $altLogin [] = [
'name' => $provider -> getLabel (),
'href' => $provider -> getLink (),
'style' => $provider -> getClass (),
];
} catch ( Throwable $e ) {
\OC :: $server -> getLogger () -> logException ( $e , [
'message' => 'Alternative login option {option} had an error while loading.' ,
'option' => $registration [ 'class' ],
'app' => $registration [ 'app' ],
]);
}
}
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 )
2012-09-18 09:35:27 -04:00
* @ todo : change the name of this method to getInstalledApps , which is more accurate
2011-08-10 06:20:43 -04:00
*/
2018-02-17 09:37:57 -05:00
public static function getAllApps () : array {
2018-02-17 09:18:34 -05:00
$apps = [];
2012-10-14 15:04:08 -04:00
2014-04-17 09:30:27 -04:00
foreach ( OC :: $APPSROOTS as $apps_dir ) {
if ( ! is_readable ( $apps_dir [ 'path' ])) {
2018-04-25 09:22:28 -04:00
\OCP\Util :: writeLog ( 'core' , 'unable to read app folder : ' . $apps_dir [ 'path' ], ILogger :: WARN );
2012-09-19 15:26:57 -04:00
continue ;
}
2014-04-17 09:30:27 -04:00
$dh = opendir ( $apps_dir [ 'path' ]);
2012-10-14 15:04:08 -04:00
2014-04-17 09:30:27 -04:00
if ( is_resource ( $dh )) {
2013-09-04 07:06:04 -04:00
while (( $file = readdir ( $dh )) !== false ) {
2015-07-08 04:25:39 -04:00
if ( $file [ 0 ] != '.' and is_dir ( $apps_dir [ 'path' ] . '/' . $file ) and is_file ( $apps_dir [ 'path' ] . '/' . $file . '/appinfo/info.xml' )) {
2013-09-04 07:06:04 -04:00
$apps [] = $file ;
}
}
2011-08-10 06:20:43 -04:00
}
}
2012-10-14 15:04:08 -04:00
2017-10-03 09:03:11 -04:00
$apps = array_unique ( $apps );
2011-08-10 06:20:43 -04:00
return $apps ;
}
2012-10-14 15:04:08 -04:00
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 {
2013-01-21 16:18:11 -05:00
$installedApps = OC_App :: getAllApps ();
2017-08-01 12:57:00 -04:00
$appManager = \OC :: $server -> getAppManager ();
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 ();
2019-05-10 08:50:24 -04:00
/** @var \OCP\Support\Subscription\IRegistry $subscriptionRegistry */
$subscriptionRegistry = \OC :: $server -> query ( \OCP\Support\Subscription\IRegistry :: class );
$supportedApps = $subscriptionRegistry -> delegateGetSupportedApps ();
2013-01-21 16:18:11 -05:00
2014-04-17 09:30:27 -04:00
foreach ( $installedApps as $app ) {
if ( array_search ( $app , $blacklist ) === false ) {
2016-09-30 05:00:58 -04:00
$info = OC_App :: getAppInfo ( $app , false , $langCode );
2016-03-30 17:29:26 -04:00
if ( ! is_array ( $info )) {
2018-04-25 09:22:28 -04:00
\OCP\Util :: writeLog ( 'core' , 'Could not read app info file for app "' . $app . '"' , ILogger :: ERROR );
2016-03-30 17:29:26 -04:00
continue ;
}
2013-01-21 16:18:11 -05:00
if ( ! isset ( $info [ 'name' ])) {
2018-04-25 09:22:28 -04:00
\OCP\Util :: writeLog ( 'core' , 'App id "' . $app . '" has no name in appinfo' , ILogger :: ERROR );
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 );
2020-04-10 08:19:56 -04:00
if ( $appPath !== false ) {
2016-02-14 14:57:09 -05:00
$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 ;
}
}
2013-01-21 16:18:11 -05:00
$info [ 'version' ] = OC_App :: getAppVersion ( $app );
$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 ();
$currentVersion = OC_App :: 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
/**
2014-05-27 05:54:12 -04:00
* Check whether the current ownCloud version matches the given
* 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.
*
* @ param string $ocVersion ownCloud 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
2020-04-10 08:19:56 -04:00
if ( ! $versions ) {
2016-01-03 10:53:30 -05:00
$appConfig = \OC :: $server -> getAppConfig ();
$versions = $appConfig -> getValues ( false , '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 {
2016-02-14 14:57:09 -05:00
$appPath = self :: getAppPath ( $appId );
2020-04-10 08:19:56 -04:00
if ( $appPath === false ) {
2016-02-14 14:57:09 -05:00
return false ;
}
2017-06-09 08:49:40 -04:00
2018-05-30 10:06:18 -04:00
\OC :: $server -> getAppManager () -> clearAppsCache ();
2016-04-19 09:36:11 -04:00
$appData = self :: getAppInfo ( $appId );
2020-01-13 09:12:04 -05:00
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
2017-06-02 07:22:25 -04:00
if ( file_exists ( $appPath . '/appinfo/database.xml' )) {
OC_DB :: updateDbFromStructure ( $appPath . '/appinfo/database.xml' );
} else {
2017-06-01 10:56:34 -04:00
$ms = new MigrationService ( $appId , \OC :: $server -> getDatabaseConnection ());
$ms -> migrate ();
2011-12-11 16:08:01 -05:00
}
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
2015-07-09 06:37:57 -04:00
// run upgrade code
2016-02-14 14:57:09 -05:00
if ( file_exists ( $appPath . '/appinfo/update.php' )) {
2017-03-13 20:07:41 -04:00
self :: loadApp ( $appId );
2016-02-14 14:57:09 -05:00
include $appPath . '/appinfo/update.php' ;
2011-12-11 16:08:01 -05: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' ]);
2020-04-10 08:19:56 -04:00
} elseif ( \OC :: $server -> getConfig () -> getAppValue ( $appId , 'ocsid' , null ) !== null ) {
2015-07-09 06:37:57 -04:00
\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
2014-07-25 07:38:44 -04:00
$version = \OC_App :: 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
2016-08-15 18:52:41 -04:00
\OC :: $server -> getEventDispatcher () -> dispatch ( ManagerEvent :: EVENT_APP_UPDATE , new ManagerEvent (
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
$dispatcher = OC :: $server -> getEventDispatcher ();
// load the steps
$r = new Repair ([], $dispatcher );
foreach ( $steps as $step ) {
try {
$r -> addStep ( $step );
} catch ( Exception $ex ) {
$r -> emit ( '\OC\Repair' , 'error' , [ $ex -> getMessage ()]);
\OC :: $server -> getLogger () -> logException ( $ex );
}
}
// 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 {
2018-04-25 09:22:28 -04:00
\OCP\Util :: writeLog ( 'core' , 'Can\'t get app storage, app ' . $appId . ', user not logged in' , ILogger :: ERROR );
2012-02-08 15:01:09 -05:00
return false ;
}
2014-04-17 09:30:27 -04:00
} else {
2018-04-25 09:22:28 -04:00
\OCP\Util :: writeLog ( 'core' , 'Can\'t get app storage, app ' . $appId . ' not enabled' , ILogger :: ERROR );
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' ];
2020-04-10 04:35:09 -04:00
} elseif ( strpos ( $attributeLang , $similarLang . '_' ) === 0 ) {
2016-10-04 07:29:54 -04:00
if ( $similarLangFallback === false ) {
$similarLangFallback = $option [ '@value' ];
}
}
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' ]);
2020-04-10 08:19:56 -04:00
} 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
}