using System.IO;
using System.Threading.Tasks;
using Jellyfin.Server.Implementations.SystemBackupService;
using MediaBrowser.Common.Api;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.SystemBackupService;
using Microsoft.AspNetCore.Authentication.OAuth.Claims;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
namespace Jellyfin.Api.Controllers;
///
/// The backup controller.
///
[Authorize(Policy = Policies.RequiresElevation)]
public class BackupController : BaseJellyfinApiController
{
private readonly IBackupService _backupService;
private readonly IApplicationPaths _applicationPaths;
///
/// Initializes a new instance of the class.
///
/// Instance of the interface.
/// Instance of the interface.
public BackupController(IBackupService backupService, IApplicationPaths applicationPaths)
{
_backupService = backupService;
_applicationPaths = applicationPaths;
}
///
/// Creates a new Backup.
///
/// The backup options.
/// Backup created.
/// User does not have permission to retrieve information.
/// The created backup manifest.
[HttpPost("Create")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
public async Task> CreateBackup([FromBody] BackupOptionsDto backupOptions)
{
return Ok(await _backupService.CreateBackupAsync(backupOptions ?? new()).ConfigureAwait(false));
}
///
/// Restores to a backup by restarting the server and applying the backup.
///
/// The data to start a restore process.
/// Backup restore started.
/// User does not have permission to retrieve information.
/// No-Content.
[HttpPost("Restore")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
public IActionResult StartRestoreBackup([FromBody, BindRequired] BackupRestoreRequestDto archiveRestoreDto)
{
var archivePath = SanitizePath(archiveRestoreDto.ArchiveFileName);
if (!System.IO.File.Exists(archivePath))
{
return NotFound();
}
_backupService.ScheduleRestoreAndRestartServer(archivePath);
return NoContent();
}
///
/// Gets a list of all currently present backups in the backup directory.
///
/// Backups available.
/// User does not have permission to retrieve information.
/// The list of backups.
[HttpGet]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
public async Task> ListBackups()
{
return Ok(await _backupService.EnumerateBackups().ConfigureAwait(false));
}
///
/// Gets the descriptor from an existing archive is present.
///
/// The data to start a restore process.
/// Backup archive manifest.
/// Not a valid jellyfin Archive.
/// Not a valid path.
/// User does not have permission to retrieve information.
/// The backup manifest.
[HttpGet("Manifest")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
public async Task> GetBackup([BindRequired] string path)
{
var backupPath = SanitizePath(path);
if (!System.IO.File.Exists(backupPath))
{
return NotFound();
}
var manifest = await _backupService.GetBackupManifest(backupPath).ConfigureAwait(false);
if (manifest is null)
{
return NoContent();
}
return Ok(manifest);
}
[NonAction]
private string SanitizePath(string path)
{
// sanitize path
var archiveRestorePath = Path.GetFileName(Path.GetFullPath(path));
var archivePath = Path.Combine(_applicationPaths.BackupPath, archiveRestorePath);
return archivePath;
}
}