Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
194 changes: 129 additions & 65 deletions lib/base.php
Original file line number Diff line number Diff line change
Expand Up @@ -255,45 +255,20 @@
}
}

private const WEB_UPGRADE_USER_THRESHOLD = 50;
private const WEB_UPGRADE_USER_LOOKUP_LIMIT = 51;
private const WEB_UPGRADE_RETRY_AFTER_SECONDS = 120;
private const BIG_INSTANCE_OVERRIDE_PARAM = 'IKnowThatThisIsABigInstanceAndTheUpdateRequestCouldRunIntoATimeoutAndHowToRestoreABackup';
private const BIG_INSTANCE_OVERRIDE_VALUE = 'IAmSuperSureToDoThis';

/**
* Prints the upgrade page
*/
private static function printUpgradePage(\OC\SystemConfig $systemConfig): void {
$cliUpgradeLink = $systemConfig->getValue('upgrade.cli-upgrade-link', '');
$disableWebUpdater = $systemConfig->getValue('upgrade.disable-web', false);
$tooBig = false;
if (!$disableWebUpdater) {
$apps = Server::get(\OCP\App\IAppManager::class);
if ($apps->isEnabledForAnyone('user_ldap')) {
$qb = Server::get(\OCP\IDBConnection::class)->getQueryBuilder();

$result = $qb->select($qb->func()->count('*', 'user_count'))
->from('ldap_user_mapping')
->executeQuery();
$row = $result->fetch();
$result->closeCursor();

$tooBig = ($row['user_count'] > 50);
}
if (!$tooBig && $apps->isEnabledForAnyone('user_saml')) {
$qb = Server::get(\OCP\IDBConnection::class)->getQueryBuilder();

$result = $qb->select($qb->func()->count('*', 'user_count'))
->from('user_saml_users')
->executeQuery();
$row = $result->fetch();
$result->closeCursor();

$tooBig = ($row['user_count'] > 50);
}
if (!$tooBig) {
// count users
$totalUsers = Server::get(\OCP\IUserManager::class)->countUsersTotal(51);
$tooBig = ($totalUsers > 50);
}
}
$ignoreTooBigWarning = isset($_GET['IKnowThatThisIsABigInstanceAndTheUpdateRequestCouldRunIntoATimeoutAndHowToRestoreABackup'])
&& $_GET['IKnowThatThisIsABigInstanceAndTheUpdateRequestCouldRunIntoATimeoutAndHowToRestoreABackup'] === 'IAmSuperSureToDoThis';
$disableWebUpdater = (bool)$systemConfig->getValue('upgrade.disable-web', false);
$tooBig = !$disableWebUpdater && self::isInstanceTooBigForWebUpgrade();
$ignoreTooBigWarning = self::isBigInstanceOverrideRequested();

Util::addTranslations('core');
Util::addScript('core', 'common');
Expand All @@ -302,24 +277,14 @@

$initialState = Server::get(IInitialStateService::class);
$serverVersion = Server::get(\OCP\ServerVersion::class);
if ($disableWebUpdater || ($tooBig && !$ignoreTooBigWarning)) {
// send http status 503
http_response_code(503);
header('Retry-After: 120');

$urlGenerator = Server::get(IURLGenerator::class);
$initialState->provideInitialState('core', 'updaterView', 'adminCli');
$initialState->provideInitialState('core', 'updateInfo', [
'cliUpgradeLink' => $cliUpgradeLink ?: $urlGenerator->linkToDocs('admin-cli-upgrade'),
'productName' => self::getProductName(),
'version' => $serverVersion->getVersionString(),
'tooBig' => $tooBig,
]);

// render error page
Server::get(ITemplateManager::class)
->getTemplate('', 'update', 'guest')
->printPage();
if ($disableWebUpdater || ($tooBig && !$ignoreTooBigWarning)) {
self::renderCliUpgradeRequiredPage(
$initialState,
$serverVersion,
$cliUpgradeLink,
$tooBig,
);
die();
}

Expand All @@ -336,49 +301,148 @@
/** @var \OC\App\AppManager $appManager */
$appManager = Server::get(\OCP\App\IAppManager::class);

$appState = self::prepareUpgradeAppState($appManager, $systemConfig, $serverVersion);

$params = [
'appsToUpgrade' => $appState['appsToUpgrade'],
'incompatibleAppsList' => $appState['incompatibleAppsList'],
'isAppsOnlyUpgrade' => $isAppsOnlyUpgrade,
'oldTheme' => $oldTheme,
'productName' => self::getProductName(),
'version' => $serverVersion->getVersionString(),
];

$initialState->provideInitialState('core', 'updaterView', 'admin');
$initialState->provideInitialState('core', 'updateInfo', $params);

Server::get(ITemplateManager::class)
->getTemplate('', 'update', 'guest')
->printPage();
}

private static function prepareUpgradeAppState(
\OCP\App\IAppManager $appManager,
\OC\SystemConfig $systemConfig,
\OCP\ServerVersion $serverVersion,
): array {
// get third party apps
$ocVersion = $serverVersion->getVersion();
$ocVersion = implode('.', $ocVersion);
$ocVersion = implode('.', $serverVersion->getVersion());
$incompatibleApps = $appManager->getIncompatibleApps($ocVersion);

Check failure on line 330 in lib/base.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

UndefinedInterfaceMethod

lib/base.php:330:36: UndefinedInterfaceMethod: Method OCP\App\IAppManager::getIncompatibleApps does not exist (see https://psalm.dev/181)
$incompatibleOverwrites = $systemConfig->getValue('app_install_overwrite', []);

$incompatibleShippedApps = [];
$incompatibleDisabledApps = [];

foreach ($incompatibleApps as $appInfo) {
if ($appManager->isShipped($appInfo['id'])) {
$incompatibleShippedApps[] = $appInfo['name'] . ' (' . $appInfo['id'] . ')';
continue;
}
if (!in_array($appInfo['id'], $incompatibleOverwrites)) {

if (!in_array($appInfo['id'], $incompatibleOverwrites, true)) {
$incompatibleDisabledApps[] = $appInfo;
}
}

if (!empty($incompatibleShippedApps)) {
$l = Server::get(\OCP\L10N\IFactory::class)->get('core');
$hint = $l->t('Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory.', [implode(', ', $incompatibleShippedApps)]);
throw new \OCP\HintException('Application ' . implode(', ', $incompatibleShippedApps) . ' is not present or has a non-compatible version with this server. Please check the apps directory.', $hint);
if ($incompatibleShippedApps !== []) {
self::throwIncompatibleShippedAppsException($incompatibleShippedApps);
}

$appConfig = Server::get(IAppConfig::class);
$appsToUpgrade = array_map(function ($app) use (&$appConfig) {
$appsToUpgrade = array_map(function (array $app) use ($appConfig): array {
return [
'id' => $app['id'],
'name' => $app['name'],
'version' => $app['version'],
'oldVersion' => $appConfig->getValueString($app['id'], 'installed_version'),
];
}, $appManager->getAppsNeedingUpgrade($ocVersion));

Check failure on line 359 in lib/base.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

UndefinedInterfaceMethod

lib/base.php:359:19: UndefinedInterfaceMethod: Method OCP\App\IAppManager::getAppsNeedingUpgrade does not exist (see https://psalm.dev/181)

$params = [
return [
'appsToUpgrade' => $appsToUpgrade,
'incompatibleAppsList' => $incompatibleDisabledApps,
'isAppsOnlyUpgrade' => $isAppsOnlyUpgrade,
'oldTheme' => $oldTheme,
];
}

private static function throwIncompatibleShippedAppsException(array $incompatibleShippedApps): void {
$appList = implode(', ', $incompatibleShippedApps);

$message = sprintf(
'Application %s is not present or has a non-compatible version with this server. Please check the apps directory.',
$appList,
);

$l = Server::get(\OCP\L10N\IFactory::class)->get('core');
$hint = $l->t(
'Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory.',
[$appList],
);

throw new \OCP\HintException($message, $hint);
}

private static function isBigInstanceOverrideRequested(): bool {
return isset($_GET[self::BIG_INSTANCE_OVERRIDE_PARAM])
&& $_GET[self::BIG_INSTANCE_OVERRIDE_PARAM] === self::BIG_INSTANCE_OVERRIDE_VALUE;
}

private static function isInstanceTooBigForWebUpgrade(): bool {
/** @var \OCP\App\IAppManager $appManager */
$appManager = Server::get(\OCP\App\IAppManager::class);

if ($appManager->isEnabledForAnyone('user_ldap')
&& self::tableRowCountExceeds('ldap_user_mapping', self::WEB_UPGRADE_USER_THRESHOLD)) {
return true;
}

if ($appManager->isEnabledForAnyone('user_saml')
&& self::tableRowCountExceeds('user_saml_users', self::WEB_UPGRADE_USER_THRESHOLD)) {
return true;
}

$totalUsers = Server::get(\OCP\IUserManager::class)
->countUsersTotal(self::WEB_UPGRADE_USER_LOOKUP_LIMIT);

return $totalUsers > self::WEB_UPGRADE_USER_THRESHOLD;
}

private static function tableRowCountExceeds(string $table, int $threshold): bool {
$qb = Server::get(\OCP\IDBConnection::class)->getQueryBuilder();

$result = $qb->select($qb->func()->count('*', 'row_count'))
->from($table)
->executeQuery();

try {
$row = $result->fetch();
} finally {
$result->closeCursor();
}

$count = is_array($row) ? (int)($row['row_count'] ?? 0) : 0;

return $count > $threshold;
}

private static function renderCliUpgradeRequiredPage(
IInitialStateService $initialState,
\OCP\ServerVersion $serverVersion,
string $cliUpgradeLink,
bool $tooBig,
): void {
http_response_code(503);
header('Retry-After: ' . self::WEB_UPGRADE_RETRY_AFTER_SECONDS);

$urlGenerator = Server::get(IURLGenerator::class);

$initialState->provideInitialState('core', 'updaterView', 'adminCli');
$initialState->provideInitialState('core', 'updateInfo', [
'cliUpgradeLink' => $cliUpgradeLink ?: $urlGenerator->linkToDocs('admin-cli-upgrade'),
'productName' => self::getProductName(),
'version' => $serverVersion->getVersionString(),
];
'tooBig' => $tooBig,
]);

$initialState->provideInitialState('core', 'updaterView', 'admin');
$initialState->provideInitialState('core', 'updateInfo', $params);
Server::get(ITemplateManager::class)
->getTemplate('', 'update', 'guest')
->printPage();
Expand Down
Loading