feat: download backups from list

This commit is contained in:
izzy
2025-11-21 14:47:11 +00:00
parent a3c6d71a58
commit 174670a1b7
6 changed files with 154 additions and 24 deletions
@@ -71,6 +71,13 @@ export class MaintenanceWorkerController {
return this.service.listBackups();
}
@Get('admin/maintenance/backups/:filename')
@MaintenanceRoute()
async downloadBackup(@Param() { filename }: FilenameParamDto, @Res() res: Response) {
res.header('Content-Disposition', 'attachment');
res.sendFile(this.service.getBackupPath(filename));
}
@Delete('admin/maintenance/backups/:filename')
@MaintenanceRoute()
async deleteBackup(@Param() { filename }: FilenameParamDto): Promise<void> {
@@ -1,12 +1,14 @@
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { BadRequestException, Injectable, UnauthorizedException } from '@nestjs/common';
import { parse } from 'cookie';
import { NextFunction, Request, Response } from 'express';
import { jwtVerify } from 'jose';
import { readFileSync } from 'node:fs';
import { IncomingHttpHeaders } from 'node:http';
import { join } from 'node:path';
import { StorageCore } from 'src/cores/storage.core';
import { MaintenanceAuthDto, MaintenanceStatusResponseDto, SetMaintenanceModeDto } from 'src/dtos/maintenance.dto';
import { ServerConfigDto } from 'src/dtos/server.dto';
import { DatabaseLock, ImmichCookie, MaintenanceAction, SystemMetadataKey } from 'src/enum';
import { DatabaseLock, ImmichCookie, MaintenanceAction, StorageFolder, SystemMetadataKey } from 'src/enum';
import { MaintenanceEphemeralStateRepository } from 'src/maintenance/maintenance-ephemeral-state.repository';
import { MaintenanceWebsocketRepository } from 'src/maintenance/maintenance-websocket.repository';
import { AppRepository } from 'src/repositories/app.repository';
@@ -20,7 +22,7 @@ import { type ApiService as _ApiService } from 'src/services/api.service';
import { type BaseService as _BaseService } from 'src/services/base.service';
import { type ServerService as _ServerService } from 'src/services/server.service';
import { MaintenanceModeState } from 'src/types';
import { deleteBackup, listBackups, restoreBackup, uploadBackup } from 'src/utils/backups';
import { deleteBackup, isValidBackupName, listBackups, restoreBackup, uploadBackup } from 'src/utils/backups';
import { getConfig } from 'src/utils/config';
import { createMaintenanceLoginUrl } from 'src/utils/maintenance';
import { getExternalDomain } from 'src/utils/misc';
@@ -287,6 +289,14 @@ export class MaintenanceWorkerService {
return uploadBackup(file);
}
getBackupPath(filename: string): string {
if (!isValidBackupName(filename)) {
throw new BadRequestException('Invalid backup name!');
}
return join(StorageCore.getBaseFolder(StorageFolder.Backups), filename);
}
private get backupRepos() {
return {
logger: this.logger,