feat: list and delete backup routes

This commit is contained in:
izzy
2025-11-20 15:31:35 +00:00
parent dd1cf12aaa
commit 53a74a7279
5 changed files with 170 additions and 2 deletions

View File

@@ -372,6 +372,103 @@
"x-immich-state": "Alpha" "x-immich-state": "Alpha"
} }
}, },
"/admin/maintenance/admin/maintenance/backups/list": {
"get": {
"description": "Get the list of the successful and failed backups",
"operationId": "listBackups",
"parameters": [],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MaintenanceListBackupsResponseDto"
}
}
},
"description": ""
}
},
"security": [
{
"bearer": []
},
{
"cookie": []
},
{
"api_key": []
}
],
"summary": "List backups",
"tags": [
"Maintenance (admin)"
],
"x-immich-admin-only": true,
"x-immich-history": [
{
"version": "v9.9.9",
"state": "Added"
},
{
"version": "v9.9.9",
"state": "Alpha"
}
],
"x-immich-permission": "maintenance",
"x-immich-state": "Alpha"
}
},
"/admin/maintenance/admin/maintenance/backups/{filename}": {
"delete": {
"description": "Delete a backup by its filename",
"operationId": "deleteBackup",
"parameters": [
{
"name": "filename",
"required": true,
"in": "path",
"schema": {
"format": "string",
"type": "string"
}
}
],
"responses": {
"200": {
"description": ""
}
},
"security": [
{
"bearer": []
},
{
"cookie": []
},
{
"api_key": []
}
],
"summary": "Delete backup",
"tags": [
"Maintenance (admin)"
],
"x-immich-admin-only": true,
"x-immich-history": [
{
"version": "v9.9.9",
"state": "Added"
},
{
"version": "v9.9.9",
"state": "Alpha"
}
],
"x-immich-permission": "maintenance",
"x-immich-state": "Alpha"
}
},
"/admin/maintenance/admin/maintenance/status": { "/admin/maintenance/admin/maintenance/status": {
"get": { "get": {
"description": "Fetch information about the currently running maintenance action.", "description": "Fetch information about the currently running maintenance action.",
@@ -16576,6 +16673,27 @@
], ],
"type": "object" "type": "object"
}, },
"MaintenanceListBackupsResponseDto": {
"properties": {
"backups": {
"items": {
"type": "string"
},
"type": "array"
},
"failedBackups": {
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"backups",
"failedBackups"
],
"type": "object"
},
"MaintenanceLoginDto": { "MaintenanceLoginDto": {
"properties": { "properties": {
"token": { "token": {

View File

@@ -1,10 +1,11 @@
import { BadRequestException, Body, Controller, Get, Post, Res } from '@nestjs/common'; import { BadRequestException, Body, Controller, Delete, Get, Param, Post, Res } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger'; import { ApiTags } from '@nestjs/swagger';
import { Response } from 'express'; import { Response } from 'express';
import { Endpoint, HistoryBuilder } from 'src/decorators'; import { Endpoint, HistoryBuilder } from 'src/decorators';
import { AuthDto } from 'src/dtos/auth.dto'; import { AuthDto } from 'src/dtos/auth.dto';
import { import {
MaintenanceAuthDto, MaintenanceAuthDto,
MaintenanceListBackupsResponseDto,
MaintenanceLoginDto, MaintenanceLoginDto,
MaintenanceStatusResponseDto, MaintenanceStatusResponseDto,
SetMaintenanceModeDto, SetMaintenanceModeDto,
@@ -14,6 +15,7 @@ import { Auth, Authenticated, GetLoginDetails } from 'src/middleware/auth.guard'
import { LoginDetails } from 'src/services/auth.service'; import { LoginDetails } from 'src/services/auth.service';
import { MaintenanceService } from 'src/services/maintenance.service'; import { MaintenanceService } from 'src/services/maintenance.service';
import { respondWithCookie } from 'src/utils/response'; import { respondWithCookie } from 'src/utils/response';
import { FilenameParamDto } from 'src/validation';
@ApiTags(ApiTag.Maintenance) @ApiTags(ApiTag.Maintenance)
@Controller('admin/maintenance') @Controller('admin/maintenance')
@@ -63,4 +65,26 @@ export class MaintenanceController {
}); });
} }
} }
@Get('admin/maintenance/backups/list')
@Endpoint({
summary: 'List backups',
description: 'Get the list of the successful and failed backups',
history: new HistoryBuilder().added('v9.9.9').alpha('v9.9.9'),
})
@Authenticated({ permission: Permission.Maintenance, admin: true })
listBackups(): Promise<MaintenanceListBackupsResponseDto> {
return this.service.listBackups();
}
@Delete('admin/maintenance/backups/:filename')
@Endpoint({
summary: 'Delete backup',
description: 'Delete a backup by its filename',
history: new HistoryBuilder().added('v9.9.9').alpha('v9.9.9'),
})
@Authenticated({ permission: Permission.Maintenance, admin: true })
async deleteBackup(@Param() { filename }: FilenameParamDto): Promise<void> {
return this.service.deleteBackup(filename);
}
} }

View File

@@ -25,3 +25,8 @@ export class MaintenanceStatusResponseDto {
task?: string; task?: string;
error?: string; error?: string;
} }
export class MaintenanceListBackupsResponseDto {
backups!: string[];
failedBackups!: string[];
}

View File

@@ -1,7 +1,8 @@
import { Body, Controller, Get, Post, Req, Res } from '@nestjs/common'; import { Body, Controller, Delete, Get, Param, Post, Req, Res } from '@nestjs/common';
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import { import {
MaintenanceAuthDto, MaintenanceAuthDto,
MaintenanceListBackupsResponseDto,
MaintenanceLoginDto, MaintenanceLoginDto,
MaintenanceStatusResponseDto, MaintenanceStatusResponseDto,
SetMaintenanceModeDto, SetMaintenanceModeDto,
@@ -13,6 +14,7 @@ import { MaintenanceWorkerService } from 'src/maintenance/maintenance-worker.ser
import { GetLoginDetails } from 'src/middleware/auth.guard'; import { GetLoginDetails } from 'src/middleware/auth.guard';
import { LoginDetails } from 'src/services/auth.service'; import { LoginDetails } from 'src/services/auth.service';
import { respondWithCookie } from 'src/utils/response'; import { respondWithCookie } from 'src/utils/response';
import { FilenameParamDto } from 'src/validation';
@Controller() @Controller()
export class MaintenanceWorkerController { export class MaintenanceWorkerController {
@@ -48,4 +50,16 @@ export class MaintenanceWorkerController {
async setMaintenanceMode(@Body() dto: SetMaintenanceModeDto): Promise<void> { async setMaintenanceMode(@Body() dto: SetMaintenanceModeDto): Promise<void> {
await this.service.runAction(dto); await this.service.runAction(dto);
} }
@Get('admin/maintenance/backups/list')
@MaintenanceRoute()
listBackups(): Promise<MaintenanceListBackupsResponseDto> {
return this.service.listBackups();
}
@Delete('admin/maintenance/backups/:filename')
@MaintenanceRoute()
async deleteBackup(@Param() { filename }: FilenameParamDto): Promise<void> {
return this.service.deleteBackup(filename);
}
} }

View File

@@ -96,6 +96,13 @@ export class UUIDAssetIDParamDto {
assetId!: string; assetId!: string;
} }
export class FilenameParamDto {
@IsNotEmpty()
@IsString()
@ApiProperty({ format: 'string' })
filename!: string;
}
type PinCodeOptions = { optional?: boolean } & OptionalOptions; type PinCodeOptions = { optional?: boolean } & OptionalOptions;
export const PinCode = (options?: PinCodeOptions & ApiPropertyOptions) => { export const PinCode = (options?: PinCodeOptions & ApiPropertyOptions) => {
const { optional, nullable, emptyToNull, ...apiPropertyOptions } = { const { optional, nullable, emptyToNull, ...apiPropertyOptions } = {