diff --git a/server/src/controllers/maintenance.controller.ts b/server/src/controllers/maintenance.controller.ts index 83a79abc6b..1705169208 100644 --- a/server/src/controllers/maintenance.controller.ts +++ b/server/src/controllers/maintenance.controller.ts @@ -87,4 +87,21 @@ export class MaintenanceController { async deleteBackup(@Param() { filename }: FilenameParamDto): Promise { return this.service.deleteBackup(filename); } + + @Post('backups/restore') + @Endpoint({ + summary: 'Start backup restore flow', + description: 'Put Immich into maintenance mode to restore a backup (Immich must not be configured)', + history: new HistoryBuilder().added('v9.9.9').alpha('v9.9.9'), + }) + async startRestoreFlow( + @GetLoginDetails() loginDetails: LoginDetails, + @Res({ passthrough: true }) res: Response, + ): Promise { + const { jwt } = await this.service.startRestoreFlow(); + return respondWithCookie(res, undefined, { + isSecure: loginDetails.isSecure, + values: [{ key: ImmichCookie.MaintenanceToken, value: jwt }], + }); + } } diff --git a/server/src/services/maintenance.service.ts b/server/src/services/maintenance.service.ts index 57ad90a053..8764bb70d6 100644 --- a/server/src/services/maintenance.service.ts +++ b/server/src/services/maintenance.service.ts @@ -1,7 +1,7 @@ -import { Injectable } from '@nestjs/common'; +import { BadRequestException, Injectable } from '@nestjs/common'; import { OnEvent } from 'src/decorators'; import { MaintenanceAuthDto, SetMaintenanceModeDto } from 'src/dtos/maintenance.dto'; -import { SystemMetadataKey } from 'src/enum'; +import { MaintenanceAction, SystemMetadataKey } from 'src/enum'; import { BaseService } from 'src/services/base.service'; import { MaintenanceModeState } from 'src/types'; import { deleteBackup, listBackups } from 'src/utils/backups'; @@ -36,6 +36,20 @@ export class MaintenanceService extends BaseService { }; } + async startRestoreFlow(): Promise<{ jwt: string }> { + const adminUser = await this.userRepository.getAdmin(); + if (adminUser) { + throw new BadRequestException('The server already has an admin'); + } + + return this.startMaintenance( + { + action: MaintenanceAction.RestoreDatabase, + }, + 'admin', + ); + } + @OnEvent({ name: 'AppRestart', server: true }) onRestart(): void { this.appRepository.exitApp();