mirror of
https://github.com/immich-app/immich.git
synced 2025-12-20 09:15:35 +03:00
feat: download backups from list
This commit is contained in:
@@ -26,7 +26,7 @@ import {
|
||||
SetMaintenanceModeDto,
|
||||
} from 'src/dtos/maintenance.dto';
|
||||
import { ApiTag, ImmichCookie, MaintenanceAction, Permission } from 'src/enum';
|
||||
import { Auth, Authenticated, GetLoginDetails } from 'src/middleware/auth.guard';
|
||||
import { Auth, Authenticated, FileResponse, GetLoginDetails } from 'src/middleware/auth.guard';
|
||||
import { LoginDetails } from 'src/services/auth.service';
|
||||
import { MaintenanceService } from 'src/services/maintenance.service';
|
||||
import { respondWithCookie } from 'src/utils/response';
|
||||
@@ -92,6 +92,19 @@ export class MaintenanceController {
|
||||
return this.service.listBackups();
|
||||
}
|
||||
|
||||
@Get('backups/:filename')
|
||||
@FileResponse()
|
||||
@Endpoint({
|
||||
summary: 'Download backup',
|
||||
description: 'Downloads the database backup file',
|
||||
history: new HistoryBuilder().added('v9.9.9').alpha('v9.9.9'),
|
||||
})
|
||||
@Authenticated({ permission: Permission.Maintenance, admin: true })
|
||||
async downloadBackup(@Param() { filename }: FilenameParamDto, @Res() res: Response) {
|
||||
res.header('Content-Disposition', 'attachment');
|
||||
res.sendFile(this.service.getBackupPath(filename));
|
||||
}
|
||||
|
||||
@Delete('backups/:filename')
|
||||
@Endpoint({
|
||||
summary: 'Delete backup',
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { BadRequestException, Injectable } from '@nestjs/common';
|
||||
import { join } from 'node:path';
|
||||
import { StorageCore } from 'src/cores/storage.core';
|
||||
import { OnEvent } from 'src/decorators';
|
||||
import { MaintenanceAuthDto, SetMaintenanceModeDto } from 'src/dtos/maintenance.dto';
|
||||
import { MaintenanceAction, SystemMetadataKey } from 'src/enum';
|
||||
import { MaintenanceAction, StorageFolder, SystemMetadataKey } from 'src/enum';
|
||||
import { BaseService } from 'src/services/base.service';
|
||||
import { MaintenanceModeState } from 'src/types';
|
||||
import { deleteBackup, listBackups, uploadBackup } from 'src/utils/backups';
|
||||
import { deleteBackup, isValidBackupName, listBackups, uploadBackup } from 'src/utils/backups';
|
||||
import { createMaintenanceLoginUrl, generateMaintenanceSecret, signMaintenanceJwt } from 'src/utils/maintenance';
|
||||
import { getExternalDomain } from 'src/utils/misc';
|
||||
|
||||
@@ -87,6 +89,14 @@ export class MaintenanceService extends BaseService {
|
||||
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,
|
||||
|
||||
Reference in New Issue
Block a user