refactor: instead of param, allow bulk backup deletion

This commit is contained in:
izzy
2025-12-03 11:55:15 +00:00
parent a63b418507
commit 207a8bc55a
14 changed files with 283 additions and 149 deletions

View File

@@ -1,9 +1,13 @@
import { Controller, Delete, Get, Next, Param, Post, Res, UploadedFile, UseInterceptors } from '@nestjs/common';
import { Body, Controller, Delete, Get, Next, Param, Post, Res, UploadedFile, UseInterceptors } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { ApiBody, ApiConsumes, ApiTags } from '@nestjs/swagger';
import { NextFunction, Response } from 'express';
import { Endpoint, HistoryBuilder } from 'src/decorators';
import { MaintenanceListBackupsResponseDto, MaintenanceUploadBackupDto } from 'src/dtos/maintenance.dto';
import {
DatabaseBackupDeleteDto,
DatabaseBackupListResponseDto,
DatabaseBackupUploadDto,
} from 'src/dtos/database-backup.dto';
import { ApiTag, ImmichCookie, Permission } from 'src/enum';
import { Authenticated, FileResponse, GetLoginDetails } from 'src/middleware/auth.guard';
import { LoggingRepository } from 'src/repositories/logging.repository';
@@ -30,7 +34,7 @@ export class DatabaseBackupController {
history: new HistoryBuilder().added('v2.4.0').alpha('v2.4.0'),
})
@Authenticated({ permission: Permission.Maintenance, admin: true })
listDatabaseBackups(): Promise<MaintenanceListBackupsResponseDto> {
listDatabaseBackups(): Promise<DatabaseBackupListResponseDto> {
return this.service.listBackups();
}
@@ -50,15 +54,15 @@ export class DatabaseBackupController {
await sendFile(res, next, () => this.service.downloadBackup(filename), this.logger);
}
@Delete(':filename')
@Delete()
@Endpoint({
summary: 'Delete database backup',
description: 'Delete a backup by its filename',
history: new HistoryBuilder().added('v2.4.0').alpha('v2.4.0'),
})
@Authenticated({ permission: Permission.BackupDelete, admin: true })
async deleteDatabaseBackup(@Param() { filename }: FilenameParamDto): Promise<void> {
return this.service.deleteBackup(filename);
async deleteDatabaseBackup(@Body() dto: DatabaseBackupDeleteDto): Promise<void> {
return this.service.deleteBackup(dto.backups);
}
@Post('start-restore')
@@ -81,7 +85,7 @@ export class DatabaseBackupController {
@Post('upload')
@Authenticated({ permission: Permission.BackupUpload, admin: true })
@ApiConsumes('multipart/form-data')
@ApiBody({ description: 'Backup Upload', type: MaintenanceUploadBackupDto })
@ApiBody({ description: 'Backup Upload', type: DatabaseBackupUploadDto })
@Endpoint({
summary: 'Upload database backup',
description: 'Uploads .sql/.sql.gz file to restore backup from',

View File

@@ -0,0 +1,16 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString } from 'class-validator';
export class DatabaseBackupListResponseDto {
backups!: string[];
}
export class DatabaseBackupUploadDto {
@ApiProperty({ type: 'string', format: 'binary', required: false })
file?: any;
}
export class DatabaseBackupDeleteDto {
@IsString({ each: true })
backups!: string[];
}

View File

@@ -1,4 +1,3 @@
import { ApiProperty } from '@nestjs/swagger';
import { MaintenanceAction, StorageFolder } from 'src/enum';
import { ValidateEnum, ValidateString } from 'src/validation';
@@ -41,12 +40,3 @@ export class MaintenanceDetectInstallStorageFolderDto {
export class MaintenanceDetectInstallResponseDto {
storage!: MaintenanceDetectInstallStorageFolderDto[];
}
export class MaintenanceListBackupsResponseDto {
backups!: string[];
}
export class MaintenanceUploadBackupDto {
@ApiProperty({ type: 'string', format: 'binary', required: false })
file?: any;
}

View File

@@ -16,7 +16,6 @@ import { NextFunction, Request, Response } from 'express';
import {
MaintenanceAuthDto,
MaintenanceDetectInstallResponseDto,
MaintenanceListBackupsResponseDto,
MaintenanceLoginDto,
MaintenanceStatusResponseDto,
SetMaintenanceModeDto,
@@ -34,6 +33,7 @@ import { FilenameParamDto } from 'src/validation';
import type { DatabaseBackupController as _DatabaseBackupController } from 'src/controllers/database-backup.controller';
import type { ServerController as _ServerController } from 'src/controllers/server.controller';
import { DatabaseBackupListResponseDto } from 'src/dtos/database-backup.dto';
@Controller()
export class MaintenanceWorkerController {
@@ -55,7 +55,7 @@ export class MaintenanceWorkerController {
*/
@Get('admin/database-backups')
@MaintenanceRoute()
listDatabaseBackups(): Promise<MaintenanceListBackupsResponseDto> {
listDatabaseBackups(): Promise<DatabaseBackupListResponseDto> {
return this.service.listBackups();
}

View File

@@ -15,8 +15,8 @@ export class DatabaseBackupService extends BaseService {
return { backups: await listBackups(this.backupRepos) };
}
async deleteBackup(filename: string): Promise<void> {
return deleteBackup(this.backupRepos, basename(filename));
async deleteBackup(files: string[]): Promise<void> {
await Promise.all(files.map((filename) => deleteBackup(this.backupRepos, basename(filename))));
}
async uploadBackup(file: Express.Multer.File): Promise<void> {