2011-03-03 20:55:32 +00:00
< ? php
2019-12-03 18:57:53 +00:00
2018-02-17 14:37:57 +00:00
declare ( strict_types = 1 );
2019-12-03 18:57:53 +00:00
2011-03-11 14:25:48 +00:00
/**
2016-07-21 15:07:57 +00:00
* @ copyright Copyright ( c ) 2016 , ownCloud , Inc .
2016-10-27 15:41:15 +00:00
* @ copyright Copyright ( c ) 2016 , Lukas Reschke < lukas @ statuscode . ch >
2016-07-21 15:07:57 +00:00
*
2016-05-26 17:56:05 +00:00
* @ author Arthur Schiwon < blizzz @ arthur - schiwon . de >
2015-03-26 10:44:34 +00: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 18:57:53 +00:00
* @ author Christoph Wurst < christoph @ winzerhof - wurst . at >
* @ author Daniel Rudolf < github . com @ daniel - rudolf . de >
2016-05-26 17:56:05 +00:00
* @ author Frank Karlitschek < frank @ karlitschek . de >
2017-11-06 19:15:27 +00:00
* @ author Georg Ehrke < oc . list @ georgehrke . com >
2015-03-26 10:44:34 +00:00
* @ author Jakob Sack < mail @ jakobsack . de >
2016-07-21 15:07:57 +00:00
* @ author Joas Schilling < coding @ schilljs . com >
2019-12-03 18:57:53 +00:00
* @ author Jörn Friedrich Dreyer < jfd @ butonic . de >
2017-11-06 14:56:42 +00:00
* @ author Julius Haertl < jus @ bitgrid . net >
* @ author Julius Härtl < jus @ bitgrid . net >
2015-03-26 10:44:34 +00:00
* @ author Kamil Domanski < kdomanski @ kdemail . net >
2016-05-26 17:56:05 +00:00
* @ author Lukas Reschke < lukas @ statuscode . ch >
2015-03-26 10:44:34 +00:00
* @ author Markus Goetz < markus @ woboq . com >
* @ author Morris Jobke < hey @ morrisjobke . de >
2015-10-05 18:54:56 +00:00
* @ author RealRancor < Fisch . 666 @ gmx . de >
2016-07-21 16:13:36 +00:00
* @ author Robin Appelman < robin @ icewind . nl >
2016-01-12 14:02:16 +00:00
* @ author Robin McCorkell < robin @ mccorkell . me . uk >
2016-07-21 15:07:57 +00:00
* @ author Roeland Jago Douma < roeland @ famdouma . nl >
2015-03-26 10:44:34 +00:00
* @ author Sam Tuke < mail @ samtuke . com >
2017-11-06 14:56:42 +00:00
* @ author Sebastian Wessalowski < sebastian @ wessalowski . org >
2015-03-26 10:44:34 +00:00
* @ author Thomas Müller < thomas . mueller @ tmit . eu >
* @ author Thomas Tanghus < thomas @ tanghus . net >
2020-12-16 13:54:15 +00:00
* @ author Vincent Petry < vincent @ nextcloud . com >
2011-03-11 14:25:48 +00:00
*
2015-03-26 10:44:34 +00:00
* @ license AGPL - 3.0
2014-05-21 10:14:10 +00:00
*
2015-03-26 10:44:34 +00: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 10:14:10 +00:00
*
2015-03-26 10:44:34 +00:00
* This program is distributed in the hope that it will be useful ,
2011-03-11 14:25:48 +00:00
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
2015-03-26 10:44:34 +00:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Affero General Public License for more details .
2011-03-11 14:25:48 +00:00
*
2015-03-26 10:44:34 +00:00
* You should have received a copy of the GNU Affero General Public License , version 3 ,
2019-12-03 18:57:53 +00:00
* along with this program . If not , see < http :// www . gnu . org / licenses />
2011-03-11 14:25:48 +00:00
*
*/
2022-12-08 09:55:19 +00:00
use OCP\App\Events\AppUpdateEvent ;
2023-02-07 15:56:04 +00:00
use OCP\App\IAppManager ;
2022-08-22 15:59:26 +00:00
use OCP\App\ManagerEvent ;
use OCP\Authentication\IAlternativeLogin ;
2022-12-08 09:55:19 +00:00
use OCP\EventDispatcher\IEventDispatcher ;
2022-08-22 15:59:26 +00:00
use OC\AppFramework\Bootstrap\Coordinator ;
2014-12-11 16:02:07 +00:00
use OC\App\DependencyAnalyzer ;
use OC\App\Platform ;
2017-06-01 14:56:34 +00:00
use OC\DB\MigrationService ;
2016-04-28 13:15:34 +00:00
use OC\Installer ;
2016-04-19 13:36:11 +00:00
use OC\Repair ;
2022-08-22 15:59:26 +00:00
use OC\Repair\Events\RepairErrorEvent ;
2023-06-06 09:09:24 +00:00
use Psr\Container\ContainerExceptionInterface ;
2021-02-01 13:56:56 +00:00
use Psr\Log\LoggerInterface ;
2011-03-11 14:25:48 +00:00
2011-03-12 09:28:10 +00:00
/**
* This class manages the apps . It allows them to register and integrate in the
2014-07-09 08:20:17 +00:00
* ownCloud ecosystem . Furthermore , this class is responsible for installing ,
2011-03-12 09:28:10 +00:00
* upgrading and removing apps .
*/
2014-04-17 13:30:27 +00:00
class OC_App {
2020-04-10 14:48:31 +00:00
private static $adminForms = [];
private static $personalForms = [];
private static $altLogin = [];
private static $alreadyRegistered = [];
2020-04-10 14:54:27 +00:00
public const supportedApp = 300 ;
public const officialApp = 200 ;
2011-03-03 20:55:32 +00:00
2013-02-09 14:03:47 +00:00
/**
2014-07-09 08:20:17 +00:00
* clean the appId
2015-02-02 13:47:38 +00:00
*
2020-11-20 11:19:59 +00:00
* @ psalm - taint - escape file
2020-11-21 00:57:25 +00:00
* @ psalm - taint - escape include
2022-08-31 19:15:02 +00:00
* @ psalm - taint - escape html
* @ psalm - taint - escape has_quotes
2020-11-20 11:19:59 +00:00
*
2018-02-17 14:37:57 +00:00
* @ param string $app AppId that needs to be cleaned
2013-02-09 14:03:47 +00:00
* @ return string
*/
2018-02-17 14:37:57 +00:00
public static function cleanAppId ( string $app ) : string {
2022-08-31 19:15:02 +00:00
return str_replace ([ '<' , '>' , '"' , " ' " , '\0' , '/' , '\\' , '..' ], '' , $app );
2013-02-09 14:03:47 +00:00
}
2015-08-18 08:18:36 +00:00
/**
* Check if an app is loaded
*
* @ param string $app
* @ return bool
2023-03-27 12:27:23 +00:00
* @ deprecated 27.0 . 0 use IAppManager :: isAppLoaded
2015-08-18 08:18:36 +00:00
*/
2018-02-17 14:37:57 +00:00
public static function isAppLoaded ( string $app ) : bool {
2023-02-07 15:56:04 +00:00
return \OC :: $server -> get ( IAppManager :: class ) -> isAppLoaded ( $app );
2015-08-18 08:18:36 +00:00
}
2011-03-03 20:55:32 +00:00
/**
2014-05-19 15:50:53 +00:00
* loads all apps
2015-02-02 13:47:38 +00:00
*
2018-02-17 14:22:00 +00:00
* @ param string [] $types
2012-09-23 00:39:11 +00:00
* @ return bool
2011-03-03 20:55:32 +00:00
*
2014-07-09 08:20:17 +00:00
* This function walks through the ownCloud directory and loads all apps
2015-03-17 14:33:55 +00:00
* it can find . A directory contains an app if the file / appinfo / info . xml
2011-03-11 13:59:24 +00:00
* exists .
2012-03-30 12:39:07 +00:00
*
2018-02-17 14:22:00 +00:00
* if $types is set to non - empty array , only apps of those types will be loaded
2011-03-03 20:55:32 +00:00
*/
2018-02-17 14:22:00 +00:00
public static function loadApps ( array $types = []) : bool {
2023-02-08 11:35:57 +00: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 15:51:28 +00:00
return false ;
}
2023-02-08 11:35:57 +00:00
return \OC :: $server -> get ( IAppManager :: class ) -> loadApps ( $types );
2013-02-09 16:27:57 +00:00
}
2011-03-03 20:55:32 +00:00
2012-05-13 22:28:22 +00:00
/**
* load a single app
2014-04-17 13:30:27 +00:00
*
2012-09-23 00:39:11 +00:00
* @ param string $app
2018-02-15 10:20:22 +00:00
* @ throws Exception
2023-03-27 12:27:23 +00:00
* @ deprecated 27.0 . 0 use IAppManager :: loadApp
2012-05-13 22:28:22 +00:00
*/
2023-02-07 15:06:32 +00:00
public static function loadApp ( string $app ) : void {
2023-02-07 15:56:04 +00:00
\OC :: $server -> get ( IAppManager :: class ) -> loadApp ( $app );
2012-05-13 22:28:22 +00:00
}
2016-05-02 12:11:34 +00:00
/**
2016-05-10 09:49:55 +00:00
* @ internal
2016-05-02 12:11:34 +00:00
* @ param string $app
* @ param string $path
2020-01-13 14:14:56 +00:00
* @ param bool $force
2016-05-02 12:11:34 +00:00
*/
2020-01-13 14:14:56 +00:00
public static function registerAutoloading ( string $app , string $path , bool $force = false ) {
2016-08-22 21:49:46 +00:00
$key = $app . '-' . $path ;
2020-01-13 14:14:56 +00:00
if ( ! $force && isset ( self :: $alreadyRegistered [ $key ])) {
2016-08-22 21:49:46 +00:00
return ;
}
2017-10-17 09:49:32 +00:00
2016-08-22 21:49:46 +00:00
self :: $alreadyRegistered [ $key ] = true ;
2017-10-17 09:49:32 +00:00
2016-05-02 12:11:34 +00:00
// Register on PSR-4 composer autoloader
$appNamespace = \OC\AppFramework\App :: buildAppNamespace ( $app );
2017-03-22 10:50:58 +00:00
\OC :: $server -> registerNamespace ( $app , $appNamespace );
2017-10-17 09:49:32 +00: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 08:58:03 +00:00
if ( defined ( 'PHPUNIT_RUN' ) || defined ( 'CLI_TEST_RUN' )) {
2016-05-02 12:11:34 +00:00
\OC :: $composerAutoloader -> addPsr4 ( $appNamespace . '\\Tests\\' , $path . '/tests/' , true );
}
}
2012-03-30 12:39:07 +00:00
/**
2012-05-14 15:58:50 +00:00
* check if an app is of a specific type
2014-04-17 13:30:27 +00:00
*
2012-03-30 12:39:07 +00:00
* @ param string $app
2018-02-17 14:22:00 +00:00
* @ param array $types
2012-09-23 00:39:11 +00:00
* @ return bool
2023-03-27 12:27:23 +00:00
* @ deprecated 27.0 . 0 use IAppManager :: isType
2012-03-30 12:39:07 +00:00
*/
2018-02-17 14:22:00 +00:00
public static function isType ( string $app , array $types ) : bool {
2023-02-08 10:46:07 +00:00
return \OC :: $server -> get ( IAppManager :: class ) -> isType ( $app , $types );
2012-05-14 20:49:20 +00:00
}
2012-05-02 09:14:11 +00:00
2012-05-14 20:49:20 +00:00
/**
* read app types from info . xml and cache them in the database
*/
2018-02-17 14:29:15 +00:00
public static function setAppTypes ( string $app ) {
$appManager = \OC :: $server -> getAppManager ();
$appData = $appManager -> getAppInfo ( $app );
2020-04-10 12:19:56 +00:00
if ( ! is_array ( $appData )) {
2016-03-30 21:29:26 +00:00
return ;
}
2012-06-04 19:30:58 +00:00
2014-04-17 13:30:27 +00:00
if ( isset ( $appData [ 'types' ])) {
$appTypes = implode ( ',' , $appData [ 'types' ]);
} else {
$appTypes = '' ;
2017-01-04 09:40:14 +00:00
$appData [ 'types' ] = [];
2012-04-14 15:53:02 +00:00
}
2012-05-02 09:14:11 +00:00
2018-02-17 14:29:15 +00:00
$config = \OC :: $server -> getConfig ();
$config -> setAppValue ( $app , 'types' , $appTypes );
2017-01-04 09:40:14 +00:00
2018-02-17 14:29:15 +00:00
if ( $appManager -> hasProtectedAppType ( $appData [ 'types' ])) {
$enabled = $config -> getAppValue ( $app , 'enabled' , 'yes' );
2017-01-04 09:40:14 +00:00
if ( $enabled !== 'yes' && $enabled !== 'no' ) {
2018-02-17 14:29:15 +00:00
$config -> setAppValue ( $app , 'enabled' , 'yes' );
2017-01-04 09:40:14 +00:00
}
}
2012-04-14 15:53:02 +00:00
}
2013-01-14 19:30:39 +00:00
2014-09-02 12:30:46 +00: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 13:47:38 +00:00
* @ return string []
2014-09-02 12:30:46 +00:00
*/
2018-02-17 14:37:57 +00:00
public static function getEnabledApps ( bool $forceRefresh = false , bool $all = false ) : array {
2015-12-18 10:42:09 +00:00
if ( ! \OC :: $server -> getSystemConfig () -> getValue ( 'installed' , false )) {
2018-02-17 14:18:34 +00:00
return [];
2013-02-09 21:43:35 +00:00
}
2014-09-02 12:30:46 +00:00
// in incognito mode or when logged out, $user will be false,
// which is also the case during an upgrade
2015-02-02 13:47:38 +00:00
$appManager = \OC :: $server -> getAppManager ();
if ( $all ) {
$user = null ;
} else {
$user = \OC :: $server -> getUserSession () -> getUser ();
2013-10-05 17:18:18 +00:00
}
2015-02-02 13:47:38 +00:00
if ( is_null ( $user )) {
$apps = $appManager -> getInstalledApps ();
} else {
2015-02-05 14:11:07 +00:00
$apps = $appManager -> getEnabledAppsForUser ( $user );
2012-03-30 12:00:24 +00:00
}
2015-02-02 13:47:38 +00:00
$apps = array_filter ( $apps , function ( $app ) {
return $app !== 'files' ; //we add this manually
});
2014-04-21 11:38:08 +00:00
sort ( $apps );
array_unshift ( $apps , 'files' );
2012-03-30 12:00:24 +00:00
return $apps ;
}
2011-06-19 13:18:52 +00:00
/**
2014-05-19 15:50:53 +00:00
* enables an app
2015-02-02 13:47:38 +00:00
*
2016-10-27 15:41:15 +00:00
* @ param string $appId
2014-04-18 12:29:45 +00:00
* @ param array $groups ( optional ) when set , only these groups will have access to the app
2013-08-06 15:19:18 +00:00
* @ throws \Exception
* @ return void
2011-06-19 13:18:52 +00:00
*
* This function set an app as enabled in appconfig .
*/
2018-02-17 14:36:16 +00:00
public function enable ( string $appId ,
array $groups = []) {
2016-10-27 15:41:15 +00:00
// Check if app is already downloaded
2018-02-22 15:00:26 +00:00
/** @var Installer $installer */
2023-06-06 09:09:24 +00:00
$installer = \OCP\Server :: get ( Installer :: class );
2016-10-27 15:41:15 +00:00
$isDownloaded = $installer -> isDownloaded ( $appId );
2020-04-10 12:19:56 +00:00
if ( ! $isDownloaded ) {
2016-10-31 10:07:54 +00:00
$installer -> downloadApp ( $appId );
2016-10-27 15:41:15 +00:00
}
2017-05-15 05:03:35 +00:00
$installer -> installApp ( $appId );
2014-05-21 10:14:10 +00:00
2015-02-16 15:44:51 +00:00
$appManager = \OC :: $server -> getAppManager ();
2018-02-17 14:36:16 +00:00
if ( $groups !== []) {
2015-03-24 11:56:42 +00: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 15:41:15 +00:00
$appManager -> enableAppForGroups ( $appId , $groupsList );
2015-02-02 13:47:38 +00:00
} else {
2016-10-27 15:41:15 +00:00
$appManager -> enableApp ( $appId );
2014-06-05 20:54:27 +00:00
}
2014-05-21 10:14:10 +00:00
}
2012-06-14 21:00:02 +00:00
/**
2012-07-23 22:39:59 +00:00
* Get the path where to install apps
2014-04-17 13:30:27 +00:00
*
2015-01-16 18:31:15 +00:00
* @ return string | false
2012-07-23 22:39:59 +00:00
*/
2012-06-14 21:00:02 +00:00
public static function getInstallPath () {
2014-04-17 13:30:27 +00:00
foreach ( OC :: $APPSROOTS as $dir ) {
if ( isset ( $dir [ 'writable' ]) && $dir [ 'writable' ] === true ) {
2012-06-14 21:00:02 +00:00
return $dir [ 'path' ];
2013-02-09 21:43:35 +00:00
}
2012-06-14 21:00:02 +00:00
}
2023-09-21 15:25:52 +00:00
\OCP\Server :: get ( LoggerInterface :: class ) -> error ( 'No application directories are marked as writable.' , [ 'app' => 'core' ]);
2012-06-14 21:00:02 +00:00
return null ;
}
2014-05-21 10:14:10 +00:00
/**
* search for an app in all app - directories
2015-02-02 13:47:38 +00:00
*
2015-04-07 11:49:16 +00:00
* @ param string $appId
2023-01-26 11:38:20 +00:00
* @ param bool $ignoreCache ignore cache and rebuild it
2015-12-08 09:01:09 +00:00
* @ return false | string
2014-05-21 10:14:10 +00:00
*/
2023-01-26 11:38:20 +00:00
public static function findAppInDirectories ( string $appId , bool $ignoreCache = false ) {
2015-12-08 09:01:09 +00:00
$sanitizedAppId = self :: cleanAppId ( $appId );
2020-04-10 12:19:56 +00:00
if ( $sanitizedAppId !== $appId ) {
2015-12-08 09:01:09 +00:00
return false ;
}
2018-02-17 14:18:34 +00:00
static $app_dir = [];
2014-05-21 10:14:10 +00:00
2023-01-26 11:38:20 +00:00
if ( isset ( $app_dir [ $appId ]) && ! $ignoreCache ) {
2014-05-21 10:14:10 +00:00
return $app_dir [ $appId ];
2012-06-28 19:54:33 +00:00
}
2014-05-21 10:14:10 +00:00
2018-02-17 14:18:34 +00:00
$possibleApps = [];
2015-02-02 13:47:38 +00:00
foreach ( OC :: $APPSROOTS as $dir ) {
if ( file_exists ( $dir [ 'path' ] . '/' . $appId )) {
2014-05-21 10:14:10 +00:00
$possibleApps [] = $dir ;
2012-06-14 21:00:02 +00:00
}
}
2014-05-21 10:14:10 +00:00
2014-06-02 19:37:39 +00:00
if ( empty ( $possibleApps )) {
2014-05-21 10:14:10 +00:00
return false ;
2015-02-02 13:47:38 +00:00
} elseif ( count ( $possibleApps ) === 1 ) {
2014-06-02 19:37:39 +00:00
$dir = array_shift ( $possibleApps );
2014-05-21 10:14:10 +00:00
$app_dir [ $appId ] = $dir ;
return $dir ;
} else {
2018-02-17 14:18:34 +00:00
$versionToLoad = [];
2015-02-02 13:47:38 +00:00
foreach ( $possibleApps as $possibleApp ) {
2018-05-03 06:22:03 +00:00
$version = self :: getAppVersionByPath ( $possibleApp [ 'path' ] . '/' . $appId );
2014-05-21 10:14:10 +00:00
if ( empty ( $versionToLoad ) || version_compare ( $version , $versionToLoad [ 'version' ], '>' )) {
2020-03-26 08:30:18 +00:00
$versionToLoad = [
2014-05-21 10:14:10 +00:00
'dir' => $possibleApp ,
'version' => $version ,
2020-03-26 08:30:18 +00:00
];
2014-05-21 10:14:10 +00:00
}
}
$app_dir [ $appId ] = $versionToLoad [ 'dir' ];
return $versionToLoad [ 'dir' ];
//TODO - write test
}
2012-06-14 21:00:02 +00:00
}
2014-05-21 10:14:10 +00:00
2012-06-01 22:05:20 +00:00
/**
2014-04-15 20:55:20 +00: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 08:20:17 +00:00
*
2020-11-21 01:11:37 +00:00
* @ psalm - taint - specialize
*
2014-07-09 08:20:52 +00:00
* @ param string $appId
2023-01-26 11:38:20 +00:00
* @ param bool $refreshAppPath should be set to true only during install / upgrade
2014-04-15 20:55:20 +00:00
* @ return string | false
2019-09-05 16:35:40 +00:00
* @ deprecated 11.0 . 0 use \OC :: $server -> getAppManager () -> getAppPath ()
2014-04-15 20:55:20 +00:00
*/
2023-01-26 11:38:20 +00:00
public static function getAppPath ( string $appId , bool $refreshAppPath = false ) {
2014-07-09 08:20:17 +00:00
if ( $appId === null || trim ( $appId ) === '' ) {
2014-06-25 14:24:55 +00:00
return false ;
}
2023-01-26 11:38:20 +00:00
if (( $dir = self :: findAppInDirectories ( $appId , $refreshAppPath )) != false ) {
2014-07-09 08:20:17 +00:00
return $dir [ 'path' ] . '/' . $appId ;
2012-06-03 21:13:30 +00:00
}
2012-09-23 00:39:11 +00:00
return false ;
2012-06-03 21:13:30 +00:00
}
/**
2014-04-15 20:55:20 +00: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 08:20:17 +00:00
*
* @ param string $appId
2014-04-15 20:55:20 +00:00
* @ return string | false
2019-09-05 16:35:40 +00:00
* @ deprecated 18.0 . 0 use \OC :: $server -> getAppManager () -> getAppWebPath ()
2014-04-15 20:55:20 +00:00
*/
2018-02-17 14:37:57 +00:00
public static function getAppWebPath ( string $appId ) {
2014-07-09 08:20:17 +00:00
if (( $dir = self :: findAppInDirectories ( $appId )) != false ) {
return OC :: $WEBROOT . $dir [ 'url' ] . '/' . $appId ;
2012-06-01 22:05:20 +00:00
}
2012-09-23 00:39:11 +00:00
return false ;
2012-06-01 22:05:20 +00:00
}
2014-05-21 10:14:10 +00:00
/**
* get app 's version based on it' s path
2015-02-02 13:47:38 +00:00
*
2014-05-21 10:14:10 +00:00
* @ param string $path
* @ return string
*/
2018-02-17 14:37:57 +00:00
public static function getAppVersionByPath ( string $path ) : string {
2014-05-21 10:14:10 +00:00
$infoFile = $path . '/appinfo/info.xml' ;
2018-01-29 12:09:32 +00:00
$appData = \OC :: $server -> getAppManager () -> getAppInfo ( $infoFile , true );
2016-02-10 10:04:12 +00:00
return isset ( $appData [ 'version' ]) ? $appData [ 'version' ] : '' ;
2012-04-14 14:27:58 +00:00
}
2011-10-05 10:31:33 +00:00
2011-07-25 18:12:35 +00:00
/**
* get the id of loaded app
2014-04-17 13:30:27 +00:00
*
2011-07-25 18:12:35 +00:00
* @ return string
*/
2018-02-17 14:37:32 +00:00
public static function getCurrentApp () : string {
2022-04-07 12:08:37 +00:00
if ( \OC :: $CLI ) {
return '' ;
}
2015-02-10 12:02:48 +00:00
$request = \OC :: $server -> getRequest ();
$script = substr ( $request -> getScriptName (), strlen ( OC :: $WEBROOT ) + 1 );
2018-01-12 14:01:45 +00:00
$topFolder = substr ( $script , 0 , strpos ( $script , '/' ) ? : 0 );
2012-09-28 21:15:19 +00:00
if ( empty ( $topFolder )) {
2022-04-07 12:08:37 +00: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 12:45:58 +00:00
\OC :: $server -> get ( LoggerInterface :: class ) -> error ( 'Failed to detect current app from script path' , [ 'exception' => $e ]);
2022-04-07 12:08:37 +00:00
return '' ;
}
2012-09-28 21:15:19 +00:00
if ( $path_info ) {
2014-04-17 13:30:27 +00:00
$topFolder = substr ( $path_info , 1 , strpos ( $path_info , '/' , 1 ) - 1 );
2012-09-28 21:15:19 +00:00
}
}
2014-04-17 13:30:27 +00:00
if ( $topFolder == 'apps' ) {
$length = strlen ( $topFolder );
2018-02-17 14:37:32 +00:00
return substr ( $script , $length + 1 , strpos ( $script , '/' , $length + 1 ) - $length - 1 ) ? : '' ;
2014-04-17 13:30:27 +00:00
} else {
2011-07-25 18:12:35 +00:00
return $topFolder ;
}
}
2011-10-05 10:31:33 +00:00
2011-08-08 21:32:54 +00:00
/**
2015-02-11 23:11:38 +00:00
* @ param string $type
* @ return array
2011-08-08 21:32:54 +00:00
*/
2018-02-17 14:37:57 +00:00
public static function getForms ( string $type ) : array {
2018-02-17 14:18:34 +00:00
$forms = [];
2014-04-17 13:30:27 +00:00
switch ( $type ) {
2011-08-08 21:32:54 +00:00
case 'admin' :
2014-04-17 13:30:27 +00:00
$source = self :: $adminForms ;
2013-02-09 16:27:57 +00:00
break ;
2011-08-08 21:32:54 +00:00
case 'personal' :
2014-04-17 13:30:27 +00:00
$source = self :: $personalForms ;
2013-02-09 16:27:57 +00:00
break ;
2012-09-23 00:39:11 +00:00
default :
2018-02-17 14:18:34 +00:00
return [];
2011-08-08 21:32:54 +00:00
}
2014-04-17 13:30:27 +00:00
foreach ( $source as $form ) {
$forms [] = include $form ;
2011-08-08 21:32:54 +00:00
}
return $forms ;
}
2011-10-05 10:31:33 +00:00
2015-02-11 23:11:38 +00:00
/**
* @ param array $entry
2020-07-15 15:06:27 +00: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 23:11:38 +00:00
*/
public static function registerLogIn ( array $entry ) {
2020-07-15 15:06:27 +00: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 16:28:08 +00:00
self :: $altLogin [] = $entry ;
}
2015-02-11 23:11:38 +00:00
/**
* @ return array
*/
2018-02-17 14:37:57 +00:00
public static function getAlternativeLogIns () : array {
2020-07-15 15:06:27 +00:00
/** @var Coordinator $bootstrapCoordinator */
2023-06-06 09:09:24 +00:00
$bootstrapCoordinator = \OCP\Server :: get ( Coordinator :: class );
2020-07-15 15:06:27 +00:00
foreach ( $bootstrapCoordinator -> getRegistrationContext () -> getAlternativeLogins () as $registration ) {
2021-01-28 13:08:38 +00:00
if ( ! in_array ( IAlternativeLogin :: class , class_implements ( $registration -> getService ()), true )) {
2020-07-15 15:06:27 +00:00
\OC :: $server -> getLogger () -> error ( 'Alternative login option {option} does not implement {interface} and is therefore ignored.' , [
2021-01-28 13:08:38 +00:00
'option' => $registration -> getService (),
2020-07-15 15:06:27 +00:00
'interface' => IAlternativeLogin :: class ,
2021-01-28 13:08:38 +00:00
'app' => $registration -> getAppId (),
2020-07-15 15:06:27 +00:00
]);
continue ;
}
try {
/** @var IAlternativeLogin $provider */
2023-06-06 09:09:24 +00:00
$provider = \OCP\Server :: get ( $registration -> getService ());
} catch ( ContainerExceptionInterface $e ) {
2020-07-15 15:06:27 +00:00
\OC :: $server -> getLogger () -> logException ( $e , [
'message' => 'Alternative login option {option} can not be initialised.' ,
2021-02-10 14:41:25 +00:00
'option' => $registration -> getService (),
'app' => $registration -> getAppId (),
2020-07-15 15:06:27 +00:00
]);
}
try {
$provider -> load ();
self :: $altLogin [] = [
'name' => $provider -> getLabel (),
'href' => $provider -> getLink (),
2022-10-20 04:32:13 +00:00
'class' => $provider -> getClass (),
2020-07-15 15:06:27 +00:00
];
} catch ( Throwable $e ) {
\OC :: $server -> getLogger () -> logException ( $e , [
'message' => 'Alternative login option {option} had an error while loading.' ,
2021-02-10 14:41:25 +00:00
'option' => $registration -> getService (),
'app' => $registration -> getAppId (),
2020-07-15 15:06:27 +00:00
]);
}
}
2013-01-29 16:28:08 +00:00
return self :: $altLogin ;
}
2011-08-10 10:20:43 +00:00
/**
2014-05-19 15:50:53 +00:00
* get a list of all apps in the apps folder
2015-02-02 13:47:38 +00:00
*
2020-05-28 18:37:24 +00:00
* @ return string [] an array of app names ( string IDs )
2012-09-18 13:35:27 +00:00
* @ todo : change the name of this method to getInstalledApps , which is more accurate
2011-08-10 10:20:43 +00:00
*/
2018-02-17 14:37:57 +00:00
public static function getAllApps () : array {
2018-02-17 14:18:34 +00:00
$apps = [];
2012-10-14 19:04:08 +00:00
2014-04-17 13:30:27 +00:00
foreach ( OC :: $APPSROOTS as $apps_dir ) {
if ( ! is_readable ( $apps_dir [ 'path' ])) {
2023-09-21 15:25:52 +00:00
\OCP\Server :: get ( LoggerInterface :: class ) -> warning ( 'unable to read app folder : ' . $apps_dir [ 'path' ], [ 'app' => 'core' ]);
2012-09-19 19:26:57 +00:00
continue ;
}
2014-04-17 13:30:27 +00:00
$dh = opendir ( $apps_dir [ 'path' ]);
2012-10-14 19:04:08 +00:00
2014-04-17 13:30:27 +00:00
if ( is_resource ( $dh )) {
2013-09-04 11:06:04 +00:00
while (( $file = readdir ( $dh )) !== false ) {
2015-07-08 08:25:39 +00:00
if ( $file [ 0 ] != '.' and is_dir ( $apps_dir [ 'path' ] . '/' . $file ) and is_file ( $apps_dir [ 'path' ] . '/' . $file . '/appinfo/info.xml' )) {
2013-09-04 11:06:04 +00:00
$apps [] = $file ;
}
}
2011-08-10 10:20:43 +00:00
}
}
2012-10-14 19:04:08 +00:00
2017-10-03 13:03:11 +00:00
$apps = array_unique ( $apps );
2011-08-10 10:20:43 +00:00
return $apps ;
}
2012-10-14 19:04:08 +00:00
2021-09-08 21:43:17 +00:00
/**
* List all supported apps
*
* @ return array
*/
public function getSupportedApps () : array {
/** @var \OCP\Support\Subscription\IRegistry $subscriptionRegistry */
2023-06-06 09:09:24 +00:00
$subscriptionRegistry = \OCP\Server :: get ( \OCP\Support\Subscription\IRegistry :: class );
2021-09-08 21:43:17 +00:00
$supportedApps = $subscriptionRegistry -> delegateGetSupportedApps ();
return $supportedApps ;
}
2013-01-21 21:18:11 +00:00
/**
2015-03-30 13:58:20 +00:00
* List all apps , this is used in apps . php
2015-02-02 13:47:38 +00:00
*
2013-01-21 21:18:11 +00:00
* @ return array
*/
2018-02-17 14:37:57 +00:00
public function listAllApps () : array {
2013-01-21 21:18:11 +00:00
$installedApps = OC_App :: getAllApps ();
2017-08-01 16:57:00 +00:00
$appManager = \OC :: $server -> getAppManager ();
2015-10-16 14:38:43 +00:00
//we don't want to show configuration for these
2017-08-01 16:57:00 +00:00
$blacklist = $appManager -> getAlwaysEnabledApps ();
2018-02-17 14:18:34 +00:00
$appList = [];
2016-09-30 09:00:58 +00:00
$langCode = \OC :: $server -> getL10N ( 'core' ) -> getLanguageCode ();
2016-09-23 19:47:47 +00:00
$urlGenerator = \OC :: $server -> getURLGenerator ();
2021-09-08 21:43:17 +00:00
$supportedApps = $this -> getSupportedApps ();
2013-01-21 21:18:11 +00:00
2014-04-17 13:30:27 +00:00
foreach ( $installedApps as $app ) {
if ( array_search ( $app , $blacklist ) === false ) {
2023-05-31 19:15:51 +00:00
$info = $appManager -> getAppInfo ( $app , false , $langCode );
2016-03-30 21:29:26 +00:00
if ( ! is_array ( $info )) {
2023-09-21 15:25:52 +00:00
\OCP\Server :: get ( LoggerInterface :: class ) -> error ( 'Could not read app info file for app "' . $app . '"' , [ 'app' => 'core' ]);
2016-03-30 21:29:26 +00:00
continue ;
}
2013-01-21 21:18:11 +00:00
if ( ! isset ( $info [ 'name' ])) {
2023-09-21 15:25:52 +00:00
\OCP\Server :: get ( LoggerInterface :: class ) -> error ( 'App id "' . $app . '" has no name in appinfo' , [ 'app' => 'core' ]);
2013-01-21 21:18:11 +00:00
continue ;
}
2018-01-17 20:10:40 +00:00
$enabled = \OC :: $server -> getConfig () -> getAppValue ( $app , 'enabled' , 'no' );
2014-04-18 12:29:45 +00:00
$info [ 'groups' ] = null ;
if ( $enabled === 'yes' ) {
2013-01-21 21:18:11 +00:00
$active = true ;
2020-04-10 08:35:09 +00:00
} elseif ( $enabled === 'no' ) {
2013-01-21 21:18:11 +00:00
$active = false ;
2014-04-18 12:29:45 +00:00
} else {
$active = true ;
$info [ 'groups' ] = $enabled ;
2013-01-21 21:18:11 +00:00
}
$info [ 'active' ] = $active ;
2017-08-01 16:57:00 +00:00
if ( $appManager -> isShipped ( $app )) {
2014-04-17 13:30:27 +00:00
$info [ 'internal' ] = true ;
2015-03-30 13:58:20 +00:00
$info [ 'level' ] = self :: officialApp ;
2014-05-31 15:50:39 +00:00
$info [ 'removable' ] = false ;
2013-01-21 21:18:11 +00:00
} else {
2014-04-17 13:30:27 +00:00
$info [ 'internal' ] = false ;
2014-05-31 15:50:39 +00:00
$info [ 'removable' ] = true ;
2013-01-21 21:18:11 +00:00
}
2019-05-10 12:50:24 +00:00
if ( in_array ( $app , $supportedApps )) {
$info [ 'level' ] = self :: supportedApp ;
}
2016-02-14 19:57:09 +00:00
$appPath = self :: getAppPath ( $app );
2020-04-10 12:19:56 +00:00
if ( $appPath !== false ) {
2016-02-14 19:57:09 +00:00
$appIcon = $appPath . '/img/' . $app . '.svg' ;
2014-08-14 13:48:38 +00:00
if ( file_exists ( $appIcon )) {
2017-08-01 16:57:00 +00:00
$info [ 'preview' ] = $urlGenerator -> imagePath ( $app , $app . '.svg' );
2014-08-14 13:48:38 +00:00
$info [ 'previewAsIcon' ] = true ;
2016-02-14 19:57:09 +00:00
} else {
$appIcon = $appPath . '/img/app.svg' ;
if ( file_exists ( $appIcon )) {
2017-08-01 16:57:00 +00:00
$info [ 'preview' ] = $urlGenerator -> imagePath ( $app , 'app.svg' );
2016-02-14 19:57:09 +00:00
$info [ 'previewAsIcon' ] = true ;
}
2014-08-14 13:48:38 +00:00
}
}
2016-09-23 19:47:47 +00: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 19:13:58 +00:00
$info [ 'version' ] = $appManager -> getAppVersion ( $app );
2013-01-21 21:18:11 +00:00
$appList [] = $info ;
}
}
2013-10-14 08:54:38 +00:00
2016-10-27 15:41:15 +00:00
return $appList ;
2013-10-14 08:54:38 +00:00
}
2018-02-17 14:37:57 +00:00
public static function shouldUpgrade ( string $app ) : bool {
2014-06-04 14:40:53 +00:00
$versions = self :: getAppVersions ();
2023-05-31 19:13:58 +00:00
$currentVersion = \OCP\Server :: get ( \OCP\App\IAppManager :: class ) -> getAppVersion ( $app );
2014-10-30 16:24:25 +00:00
if ( $currentVersion && isset ( $versions [ $app ])) {
2014-06-04 14:40:53 +00:00
$installedVersion = $versions [ $app ];
2016-07-22 12:44:00 +00:00
if ( ! version_compare ( $currentVersion , $installedVersion , '=' )) {
2014-06-04 14:40:53 +00:00
return true ;
}
}
return false ;
}
2014-05-27 09:54:12 +00:00
/**
2014-07-09 08:20:17 +00:00
* Adjust the number of version parts of $version1 to match
2014-05-27 09:54:12 +00: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 14:37:57 +00:00
private static function adjustVersionParts ( string $version1 , string $version2 ) : string {
2014-05-27 09:54:12 +00: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 11:38:00 +00:00
/**
2014-05-27 09:54:12 +00: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 13:47:38 +00:00
* @ param array $appInfo app info ( from xml )
2014-05-27 09:54:12 +00:00
*
2013-02-25 11:38:00 +00:00
* @ return boolean true if compatible , otherwise false
*/
2019-03-06 18:59:15 +00:00
public static function isAppCompatible ( string $ocVersion , array $appInfo , bool $ignoreMax = false ) : bool {
2014-05-27 09:54:12 +00:00
$requireMin = '' ;
$requireMax = '' ;
2016-10-31 10:07:54 +00: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 11:48:59 +00:00
$requireMin = $appInfo [ 'dependencies' ][ 'owncloud' ][ '@attributes' ][ 'min-version' ];
2020-04-10 08:35:09 +00:00
} elseif ( isset ( $appInfo [ 'requiremin' ])) {
2014-05-27 09:54:12 +00:00
$requireMin = $appInfo [ 'requiremin' ];
2020-04-10 08:35:09 +00:00
} elseif ( isset ( $appInfo [ 'require' ])) {
2014-05-27 09:54:12 +00:00
$requireMin = $appInfo [ 'require' ];
}
2013-02-25 11:38:00 +00:00
2016-10-31 10:07:54 +00: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 11:48:59 +00:00
$requireMax = $appInfo [ 'dependencies' ][ 'owncloud' ][ '@attributes' ][ 'max-version' ];
2020-04-10 08:35:09 +00:00
} elseif ( isset ( $appInfo [ 'requiremax' ])) {
2014-05-27 09:54:12 +00:00
$requireMax = $appInfo [ 'requiremax' ];
}
2013-02-25 11:38:00 +00:00
2014-05-27 09:54:12 +00:00
if ( ! empty ( $requireMin )
&& version_compare ( self :: adjustVersionParts ( $ocVersion , $requireMin ), $requireMin , '<' )
) {
return false ;
}
2019-03-06 18:59:15 +00:00
if ( ! $ignoreMax && ! empty ( $requireMax )
2014-05-27 09:54:12 +00:00
&& version_compare ( self :: adjustVersionParts ( $ocVersion , $requireMax ), $requireMax , '>' )
) {
return false ;
2013-02-25 11:38:00 +00:00
}
return true ;
}
2012-03-30 11:48:44 +00:00
/**
2012-06-28 20:01:46 +00:00
* get the installed version of all apps
2012-03-30 11:48:44 +00:00
*/
2012-09-07 13:22:01 +00:00
public static function getAppVersions () {
2012-06-26 18:53:28 +00:00
static $versions ;
2016-01-03 15:53:30 +00:00
2020-04-10 12:19:56 +00:00
if ( ! $versions ) {
2016-01-03 15:53:30 +00:00
$appConfig = \OC :: $server -> getAppConfig ();
$versions = $appConfig -> getValues ( false , 'installed_version' );
2012-03-30 11:48:44 +00:00
}
2016-01-03 15:53:30 +00:00
return $versions ;
2012-03-30 11:48:44 +00:00
}
2011-12-11 21:08:01 +00:00
/**
* update the database for the app and call the update script
2014-04-17 13:30:27 +00:00
*
2014-07-09 08:20:17 +00:00
* @ param string $appId
2014-05-21 10:14:10 +00:00
* @ return bool
2011-12-11 21:08:01 +00:00
*/
2018-02-19 09:28:41 +00:00
public static function updateApp ( string $appId ) : bool {
2023-01-26 11:38:20 +00: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 );
2020-04-10 12:19:56 +00:00
if ( $appPath === false ) {
2016-02-14 19:57:09 +00:00
return false ;
}
2017-06-09 12:49:40 +00:00
2020-06-30 19:47:31 +00:00
if ( is_file ( $appPath . '/appinfo/database.xml' )) {
\OC :: $server -> getLogger () -> error ( 'The appinfo/database.xml file is not longer supported. Used in ' . $appId );
return false ;
}
2018-05-30 14:06:18 +00:00
\OC :: $server -> getAppManager () -> clearAppsCache ();
2021-09-30 07:08:17 +00:00
$l = \OC :: $server -> getL10N ( 'core' );
2023-05-31 19:15:51 +00:00
$appData = \OCP\Server :: get ( \OCP\App\IAppManager :: class ) -> getAppInfo ( $appId , false , $l -> getLanguageCode ());
2020-01-13 14:12:04 +00:00
2020-11-26 15:44:20 +00:00
$ignoreMaxApps = \OC :: $server -> getConfig () -> getSystemValue ( 'app_install_overwrite' , []);
$ignoreMax = in_array ( $appId , $ignoreMaxApps , true );
\OC_App :: checkAppDependencies (
\OC :: $server -> getConfig (),
2021-09-30 07:08:17 +00:00
$l ,
2020-11-26 15:44:20 +00:00
$appData ,
$ignoreMax
);
2020-01-13 14:14:56 +00:00
self :: registerAutoloading ( $appId , $appPath , true );
2016-04-19 13:36:11 +00:00
self :: executeRepairSteps ( $appId , $appData [ 'repair-steps' ][ 'pre-migration' ]);
2017-06-01 14:56:34 +00:00
2020-06-30 19:47:31 +00:00
$ms = new MigrationService ( $appId , \OC :: $server -> get ( \OC\DB\Connection :: class ));
$ms -> migrate ();
2017-06-01 14:56:34 +00:00
2016-04-19 13:36:11 +00:00
self :: executeRepairSteps ( $appId , $appData [ 'repair-steps' ][ 'post-migration' ]);
2016-04-26 09:56:56 +00:00
self :: setupLiveMigrations ( $appId , $appData [ 'repair-steps' ][ 'live-migration' ]);
2018-01-29 12:09:32 +00:00
// update appversion in app manager
2018-06-02 06:48:33 +00:00
\OC :: $server -> getAppManager () -> clearAppsCache ();
2018-01-29 12:09:32 +00:00
\OC :: $server -> getAppManager () -> getAppVersion ( $appId , false );
2017-06-01 14:56:34 +00:00
2016-05-02 13:26:12 +00:00
self :: setupBackgroundJobs ( $appData [ 'background-jobs' ]);
2012-05-11 18:32:37 +00:00
2012-09-23 00:39:11 +00:00
//set remote/public handlers
2014-07-07 14:57:50 +00:00
if ( array_key_exists ( 'ocsid' , $appData )) {
2015-07-09 10:37:57 +00:00
\OC :: $server -> getConfig () -> setAppValue ( $appId , 'ocsid' , $appData [ 'ocsid' ]);
2020-04-10 12:19:56 +00:00
} elseif ( \OC :: $server -> getConfig () -> getAppValue ( $appId , 'ocsid' , null ) !== null ) {
2015-07-09 10:37:57 +00:00
\OC :: $server -> getConfig () -> deleteAppValue ( $appId , 'ocsid' );
2014-07-07 14:57:50 +00:00
}
2014-04-17 13:30:27 +00:00
foreach ( $appData [ 'remote' ] as $name => $path ) {
2015-07-09 10:37:57 +00:00
\OC :: $server -> getConfig () -> setAppValue ( 'core' , 'remote_' . $name , $appId . '/' . $path );
2012-05-11 18:32:37 +00:00
}
2014-04-17 13:30:27 +00:00
foreach ( $appData [ 'public' ] as $name => $path ) {
2015-07-09 10:37:57 +00:00
\OC :: $server -> getConfig () -> setAppValue ( 'core' , 'public_' . $name , $appId . '/' . $path );
2012-05-11 18:32:37 +00:00
}
2012-05-14 20:49:20 +00:00
2014-07-09 08:20:17 +00:00
self :: setAppTypes ( $appId );
2014-05-21 10:14:10 +00:00
2023-05-31 19:13:58 +00:00
$version = \OCP\Server :: get ( \OCP\App\IAppManager :: class ) -> getAppVersion ( $appId );
2018-01-17 20:14:09 +00:00
\OC :: $server -> getConfig () -> setAppValue ( $appId , 'installed_version' , $version );
2014-07-25 11:38:44 +00:00
2022-12-08 09:55:19 +00:00
\OC :: $server -> get ( IEventDispatcher :: class ) -> dispatchTyped ( new AppUpdateEvent ( $appId ));
2023-07-28 12:10:27 +00:00
\OC :: $server -> get ( IEventDispatcher :: class ) -> dispatch ( ManagerEvent :: EVENT_APP_UPDATE , new ManagerEvent (
2016-08-15 22:52:41 +00:00
ManagerEvent :: EVENT_APP_UPDATE , $appId
));
2014-05-21 10:14:10 +00:00
return true ;
2011-12-11 21:08:01 +00:00
}
2012-02-08 20:01:09 +00:00
2016-04-19 13:36:11 +00:00
/**
* @ param string $appId
* @ param string [] $steps
* @ throws \OC\NeedsUpdateException
*/
2018-02-17 14:37:57 +00:00
public static function executeRepairSteps ( string $appId , array $steps ) {
2016-04-19 13:36:11 +00:00
if ( empty ( $steps )) {
return ;
}
// load the app
2017-03-14 00:07:41 +00:00
self :: loadApp ( $appId );
2016-04-19 13:36:11 +00:00
2022-12-08 09:55:19 +00:00
$dispatcher = \OC :: $server -> get ( IEventDispatcher :: class );
2016-04-19 13:36:11 +00:00
// load the steps
2021-02-01 13:56:56 +00:00
$r = new Repair ([], $dispatcher , \OC :: $server -> get ( LoggerInterface :: class ));
2016-04-19 13:36:11 +00:00
foreach ( $steps as $step ) {
try {
$r -> addStep ( $step );
} catch ( Exception $ex ) {
2022-08-22 15:59:26 +00:00
$dispatcher -> dispatchTyped ( new RepairErrorEvent ( $ex -> getMessage ()));
2016-04-19 13:36:11 +00:00
\OC :: $server -> getLogger () -> logException ( $ex );
}
}
// run the steps
$r -> run ();
}
2016-05-02 13:26:12 +00:00
public static function setupBackgroundJobs ( array $jobs ) {
$queue = \OC :: $server -> getJobList ();
foreach ( $jobs as $job ) {
$queue -> add ( $job );
}
}
2016-04-26 09:56:56 +00:00
/**
* @ param string $appId
* @ param string [] $steps
*/
2018-02-17 14:37:57 +00:00
private static function setupLiveMigrations ( string $appId , array $steps ) {
2016-04-26 09:56:56 +00:00
$queue = \OC :: $server -> getJobList ();
foreach ( $steps as $step ) {
$queue -> add ( 'OC\Migration\BackgroundRepair' , [
'app' => $appId ,
'step' => $step ]);
}
}
2012-02-08 20:01:09 +00:00
/**
2014-07-09 08:20:17 +00:00
* @ param string $appId
2015-01-16 18:31:15 +00:00
* @ return \OC\Files\View | false
2012-02-08 20:01:09 +00:00
*/
2018-02-17 14:37:57 +00:00
public static function getStorage ( string $appId ) {
2017-10-23 21:31:17 +00:00
if ( \OC :: $server -> getAppManager () -> isEnabledForUser ( $appId )) { //sanity check
2017-03-02 15:52:05 +00:00
if ( \OC :: $server -> getUserSession () -> isLoggedIn ()) {
2014-04-17 13:30:27 +00:00
$view = new \OC\Files\View ( '/' . OC_User :: getUser ());
2014-07-09 08:20:17 +00:00
if ( ! $view -> file_exists ( $appId )) {
$view -> mkdir ( $appId );
2012-04-23 22:26:33 +00:00
}
2014-07-09 08:20:17 +00:00
return new \OC\Files\View ( '/' . OC_User :: getUser () . '/' . $appId );
2014-04-17 13:30:27 +00:00
} else {
2023-09-21 15:25:52 +00:00
\OCP\Server :: get ( LoggerInterface :: class ) -> error ( 'Can\'t get app storage, app ' . $appId . ', user not logged in' , [ 'app' => 'core' ]);
2012-02-08 20:01:09 +00:00
return false ;
}
2014-04-17 13:30:27 +00:00
} else {
2023-09-21 15:25:52 +00:00
\OCP\Server :: get ( LoggerInterface :: class ) -> error ( 'Can\'t get app storage, app ' . $appId . ' not enabled' , [ 'app' => 'core' ]);
2012-09-18 13:35:27 +00:00
return false ;
2012-02-08 20:01:09 +00:00
}
}
2015-01-13 13:48:30 +00:00
2018-02-17 14:37:57 +00:00
protected static function findBestL10NOption ( array $options , string $lang ) : string {
2018-04-12 10:28:25 +00:00
// only a single option
if ( isset ( $options [ '@value' ])) {
return $options [ '@value' ];
}
2016-10-04 11:29:54 +00: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 09:00:58 +00:00
foreach ( $options as $option ) {
if ( is_array ( $option )) {
if ( $fallback === false ) {
$fallback = $option [ '@value' ];
}
2016-10-04 11:29:54 +00:00
if ( ! isset ( $option [ '@attributes' ][ 'lang' ])) {
continue ;
}
$attributeLang = strtolower ( $option [ '@attributes' ][ 'lang' ]);
if ( $attributeLang === $lang ) {
2016-09-30 09:00:58 +00:00
return $option [ '@value' ];
}
2016-10-04 11:29:54 +00:00
if ( $attributeLang === $similarLang ) {
$similarLangFallback = $option [ '@value' ];
2023-05-15 11:47:19 +00:00
} elseif ( str_starts_with ( $attributeLang , $similarLang . '_' )) {
2016-10-04 11:29:54 +00:00
if ( $similarLangFallback === false ) {
2020-10-05 13:12:57 +00:00
$similarLangFallback = $option [ '@value' ];
2016-10-04 11:29:54 +00:00
}
}
2016-09-30 09:00:58 +00:00
} else {
$englishFallback = $option ;
}
}
2016-10-04 11:29:54 +00:00
if ( $similarLangFallback !== false ) {
return $similarLangFallback ;
2020-04-10 08:35:09 +00:00
} elseif ( $englishFallback !== false ) {
2016-10-04 11:29:54 +00:00
return $englishFallback ;
}
return ( string ) $fallback ;
2016-09-30 09:00:58 +00:00
}
2015-01-13 13:48:30 +00:00
/**
* parses the app data array and enhanced the 'description' value
*
* @ param array $data the app data
2016-09-30 09:00:58 +00:00
* @ param string $lang
2015-01-13 13:48:30 +00:00
* @ return array improved app data
*/
2018-02-17 14:37:57 +00:00
public static function parseAppInfo ( array $data , $lang = null ) : array {
2016-09-30 09:00:58 +00: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 09:57:26 +00:00
$data [ 'description' ] = trim ( self :: findBestL10NOption ( $data [ 'description' ], $lang ));
2020-04-10 08:35:09 +00:00
} elseif ( isset ( $data [ 'description' ]) && is_string ( $data [ 'description' ])) {
2017-01-11 09:57:26 +00:00
$data [ 'description' ] = trim ( $data [ 'description' ]);
2020-04-10 12:19:56 +00:00
} else {
2016-09-30 12:41:37 +00:00
$data [ 'description' ] = '' ;
2015-01-13 13:48:30 +00:00
}
return $data ;
}
2016-10-07 09:27:33 +00:00
/**
2017-01-11 09:57:26 +00:00
* @ param \OCP\IConfig $config
* @ param \OCP\IL10N $l
* @ param array $info
* @ throws \Exception
2016-10-07 09:27:33 +00:00
*/
2019-03-06 18:59:15 +00:00
public static function checkAppDependencies ( \OCP\IConfig $config , \OCP\IL10N $l , array $info , bool $ignoreMax ) {
2016-10-07 09:27:33 +00:00
$dependencyAnalyzer = new DependencyAnalyzer ( new Platform ( $config ), $l );
2019-03-06 18:59:15 +00:00
$missing = $dependencyAnalyzer -> analyze ( $info , $ignoreMax );
2016-10-07 09:27:33 +00:00
if ( ! empty ( $missing )) {
2017-07-23 19:03:26 +00:00
$missingMsg = implode ( PHP_EOL , $missing );
2016-10-07 09:27:33 +00:00
throw new \Exception (
2018-10-09 12:32:14 +00:00
$l -> t ( 'App "%1$s" cannot be installed because the following dependencies are not fulfilled: %2$s' ,
2016-10-07 09:27:33 +00:00
[ $info [ 'name' ], $missingMsg ]
)
);
}
}
2011-03-03 20:55:32 +00:00
}