Ajoute les mises à jour autonomes

Les installations hors YunoHost peuvent désormais vérifier et installer une release Forgejo avec sauvegarde et retour arrière complet.
This commit is contained in:
Alexandre NOEL 2026-09-08 20:13:55 +02:00
commit 53e79a72d7
25 changed files with 1146 additions and 61 deletions

View file

@ -1114,6 +1114,105 @@ final class SettingsController
}
exit();
}
public static function updates(): void
{
self::admin();
render('settings_updates.php', [
'title' => t('updates.title'),
'updateStatus' => UpdateService::cachedStatus(),
'checks' => UpdateService::preflight(),
'lastUpdate' => UpdateService::lastUpdate(),
'status' => (string) ($_GET['status'] ?? ''),
'error' => (string) ($_GET['error'] ?? ''),
]);
}
public static function checkUpdates(): void
{
self::admin();
self::postOnly();
try {
UpdateService::check();
header('Location: /settings/updates?status=checked');
} catch (Throwable $e) {
header('Location: /settings/updates?error=' . rawurlencode(SecurityService::publicError($e)));
}
exit();
}
public static function installUpdate(): void
{
self::admin();
self::postOnly();
if (!Auth::verifyCurrentPassword((string) ($_POST['password'] ?? ''))) {
header('Location: /settings/updates?error=' . rawurlencode(t('updates.password_invalid')));
exit();
}
try {
@set_time_limit(0);
$result = UpdateService::installFromRepository();
AuditService::log('application_updated', '/settings/updates/install', 'Globinours mis à jour vers ' . $result['to']);
header('Location: /settings/updates?status=installed&version=' . rawurlencode($result['to']));
} catch (Throwable $e) {
header('Location: /settings/updates?error=' . rawurlencode(SecurityService::publicError($e)));
}
exit();
}
public static function uploadUpdate(): void
{
self::admin();
self::postOnly();
$upload = $_FILES['release'] ?? null;
if (!Auth::verifyCurrentPassword((string) ($_POST['password'] ?? ''))) {
header('Location: /settings/updates?error=' . rawurlencode(t('updates.password_invalid')));
exit();
}
if (!is_array($upload) || ($upload['error'] ?? UPLOAD_ERR_NO_FILE) !== UPLOAD_ERR_OK || !is_uploaded_file((string) ($upload['tmp_name'] ?? ''))) {
header('Location: /settings/updates?error=' . rawurlencode(t('updates.archive_invalid')));
exit();
}
try {
@set_time_limit(0);
$result = UpdateService::install((string) $upload['tmp_name'], (string) ($_POST['sha256'] ?? ''), 'upload');
AuditService::log('application_updated', '/settings/updates/upload', 'Globinours mis à jour vers ' . $result['to']);
header('Location: /settings/updates?status=installed&version=' . rawurlencode($result['to']));
} catch (Throwable $e) {
header('Location: /settings/updates?error=' . rawurlencode(SecurityService::publicError($e)));
}
exit();
}
public static function rollbackUpdate(): void
{
self::admin();
self::postOnly();
if (!Auth::verifyCurrentPassword((string) ($_POST['password'] ?? ''))) {
header('Location: /settings/updates?error=' . rawurlencode(t('updates.password_invalid')));
exit();
}
try {
@set_time_limit(0);
$result = UpdateService::rollbackLast();
Auth::logout();
header('Location: /login?rollback=1&version=' . rawurlencode($result['version']));
} catch (Throwable $e) {
header('Location: /settings/updates?error=' . rawurlencode(SecurityService::publicError($e)));
}
exit();
}
public static function downloadUpdateLog(): void
{
self::admin();
$path = UpdateService::logPath();
if (!$path) {
http_response_code(404);
echo h(t('updates.log_missing'));
return;
}
header('Content-Type: text/plain; charset=utf-8');
header('Content-Disposition: attachment; filename="globinours-update.log"');
header('Content-Length: ' . filesize($path));
header('Cache-Control: private, no-store');
header('X-Content-Type-Options: nosniff');
readfile($path);
}
private static function postOnly(): void
{
if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {