From da59d63bd194e871ccc6894ec485ffe4eb2a4b6f Mon Sep 17 00:00:00 2001 From: Bogdan Date: Wed, 10 Apr 2024 01:09:57 +0300 Subject: [PATCH] New: Disable backup downloads --- frontend/src/System/Backup/BackupRow.js | 10 +------ frontend/src/System/Backup/Backups.js | 12 ++++++-- .../src/System/Backup/BackupsConnector.js | 7 +++-- src/NzbDrone.Core/Backup/BackupCommand.cs | 13 +------- src/NzbDrone.Core/Backup/BackupService.cs | 12 ++++---- src/NzbDrone.Core/Localization/Core/en.json | 19 ++++++------ .../System/Backup/BackupController.cs | 1 - .../System/Backup/BackupResource.cs | 1 - src/Sonarr.Api.V3/System/SystemController.cs | 7 ++++- src/Sonarr.Api.V3/System/SystemResource.cs | 1 + .../Frontend/Mappers/BackupFileMapper.cs | 30 ------------------- 11 files changed, 39 insertions(+), 74 deletions(-) delete mode 100644 src/Sonarr.Http/Frontend/Mappers/BackupFileMapper.cs diff --git a/frontend/src/System/Backup/BackupRow.js b/frontend/src/System/Backup/BackupRow.js index ad63544e3..dbc557c62 100644 --- a/frontend/src/System/Backup/BackupRow.js +++ b/frontend/src/System/Backup/BackupRow.js @@ -2,7 +2,6 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import Icon from 'Components/Icon'; import IconButton from 'Components/Link/IconButton'; -import Link from 'Components/Link/Link'; import ConfirmModal from 'Components/Modal/ConfirmModal'; import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellConnector'; import TableRowCell from 'Components/Table/Cells/TableRowCell'; @@ -65,7 +64,6 @@ class BackupRow extends Component { id, type, name, - path, size, time } = this.props; @@ -98,12 +96,7 @@ class BackupRow extends Component { - - {name} - + {name} @@ -155,7 +148,6 @@ BackupRow.propTypes = { id: PropTypes.number.isRequired, type: PropTypes.string.isRequired, name: PropTypes.string.isRequired, - path: PropTypes.string.isRequired, size: PropTypes.number.isRequired, time: PropTypes.string.isRequired, onDeleteBackupPress: PropTypes.func.isRequired diff --git a/frontend/src/System/Backup/Backups.js b/frontend/src/System/Backup/Backups.js index ede2f97f6..b1ba15082 100644 --- a/frontend/src/System/Backup/Backups.js +++ b/frontend/src/System/Backup/Backups.js @@ -73,6 +73,7 @@ class Backups extends Component { isPopulated, error, items, + location, backupExecuting, onBackupPress, onDeleteBackupPress @@ -101,6 +102,12 @@ class Backups extends Component { + + {translate('BackupFilesLocation', { + location + })} + + { isFetching && !isPopulated && @@ -115,7 +122,7 @@ class Backups extends Component { { noBackups && - + {translate('NoBackupsAreAvailable')} } @@ -132,7 +139,6 @@ class Backups extends Component { id, type, name, - path, size, time } = item; @@ -143,7 +149,6 @@ class Backups extends Component { id={id} type={type} name={name} - path={path} size={size} time={time} onDeleteBackupPress={onDeleteBackupPress} @@ -171,6 +176,7 @@ Backups.propTypes = { isPopulated: PropTypes.bool.isRequired, error: PropTypes.object, items: PropTypes.array.isRequired, + location: PropTypes.string.isRequired, backupExecuting: PropTypes.bool.isRequired, onBackupPress: PropTypes.func.isRequired, onDeleteBackupPress: PropTypes.func.isRequired diff --git a/frontend/src/System/Backup/BackupsConnector.js b/frontend/src/System/Backup/BackupsConnector.js index 1353b6196..3565f1fd0 100644 --- a/frontend/src/System/Backup/BackupsConnector.js +++ b/frontend/src/System/Backup/BackupsConnector.js @@ -11,21 +11,24 @@ import Backups from './Backups'; function createMapStateToProps() { return createSelector( (state) => state.system.backups, + (state) => state.system.status.item, createCommandExecutingSelector(commandNames.BACKUP), - (backups, backupExecuting) => { + (backups, status, backupExecuting) => { const { isFetching, isPopulated, error, items } = backups; + const { backupFolder } = status; return { isFetching, isPopulated, error, items, - backupExecuting + backupExecuting, + location: backupFolder }; } ); diff --git a/src/NzbDrone.Core/Backup/BackupCommand.cs b/src/NzbDrone.Core/Backup/BackupCommand.cs index 1f5550e59..83d3d0044 100644 --- a/src/NzbDrone.Core/Backup/BackupCommand.cs +++ b/src/NzbDrone.Core/Backup/BackupCommand.cs @@ -4,18 +4,7 @@ namespace NzbDrone.Core.Backup { public class BackupCommand : Command { - public BackupType Type - { - get - { - if (Trigger == CommandTrigger.Scheduled) - { - return BackupType.Scheduled; - } - - return BackupType.Manual; - } - } + public BackupType Type => Trigger == CommandTrigger.Scheduled ? BackupType.Scheduled : BackupType.Manual; public override bool SendUpdatesToClient => true; diff --git a/src/NzbDrone.Core/Backup/BackupService.cs b/src/NzbDrone.Core/Backup/BackupService.cs index e45370214..db463a1f9 100644 --- a/src/NzbDrone.Core/Backup/BackupService.cs +++ b/src/NzbDrone.Core/Backup/BackupService.cs @@ -105,12 +105,12 @@ namespace NzbDrone.Core.Backup if (_diskProvider.FolderExists(folder)) { backups.AddRange(GetBackupFiles(folder).Select(b => new Backup - { - Name = Path.GetFileName(b), - Type = backupType, - Size = _diskProvider.GetFileSize(b), - Time = _diskProvider.FileGetLastWrite(b) - })); + { + Name = Path.GetFileName(b), + Type = backupType, + Size = _diskProvider.GetFileSize(b), + Time = _diskProvider.FileGetLastWrite(b) + })); } } diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index f6b312928..321c8a5ba 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -142,6 +142,7 @@ "AutomaticSearch": "Automatic Search", "AutomaticUpdatesDisabledDocker": "Automatic updates are not directly supported when using the Docker update mechanism. You will need to update the container image outside of {appName} or use a script", "Backup": "Backup", + "BackupFilesLocation": "Backup files are located in: {location}", "BackupFolderHelpText": "Relative paths will be under {appName}'s AppData directory", "BackupIntervalHelpText": "Interval between automatic backups", "BackupNow": "Backup Now", @@ -248,8 +249,8 @@ "ConnectionLost": "Connection Lost", "ConnectionLostReconnect": "{appName} will try to connect automatically, or you can click reload below.", "ConnectionLostToBackend": "{appName} has lost its connection to the backend and will need to be reloaded to restore functionality.", - "Connections": "Connections", "ConnectionSettingsUrlBaseHelpText": "Adds a prefix to the {connectionName} url, such as {url}", + "Connections": "Connections", "Continuing": "Continuing", "ContinuingOnly": "Continuing Only", "ContinuingSeriesDescription": "More episodes/another season is expected", @@ -280,8 +281,8 @@ "CustomFormats": "Custom Formats", "CustomFormatsLoadError": "Unable to load Custom Formats", "CustomFormatsSettings": "Custom Formats Settings", - "CustomFormatsSettingsTriggerInfo": "A Custom Format will be applied to a release or file when it matches at least one of each of the different condition types chosen.", "CustomFormatsSettingsSummary": "Custom Formats and Settings", + "CustomFormatsSettingsTriggerInfo": "A Custom Format will be applied to a release or file when it matches at least one of each of the different condition types chosen.", "CustomFormatsSpecificationFlag": "Flag", "CustomFormatsSpecificationLanguage": "Language", "CustomFormatsSpecificationMaximumSize": "Maximum Size", @@ -410,16 +411,16 @@ "DownloadClientAriaSettingsDirectoryHelpText": "Optional location to put downloads in, leave blank to use the default Aria2 location", "DownloadClientCheckNoneAvailableHealthCheckMessage": "No download client is available", "DownloadClientCheckUnableToCommunicateWithHealthCheckMessage": "Unable to communicate with {downloadClientName}. {errorMessage}", + "DownloadClientDelugeSettingsDirectory": "Download Directory", + "DownloadClientDelugeSettingsDirectoryCompleted": "Move When Completed Directory", + "DownloadClientDelugeSettingsDirectoryCompletedHelpText": "Optional location to move completed downloads to, leave blank to use the default Deluge location", + "DownloadClientDelugeSettingsDirectoryHelpText": "Optional location to put downloads in, leave blank to use the default Deluge location", "DownloadClientDelugeSettingsUrlBaseHelpText": "Adds a prefix to the deluge json url, see {url}", "DownloadClientDelugeTorrentStateError": "Deluge is reporting an error", "DownloadClientDelugeValidationLabelPluginFailure": "Configuration of label failed", "DownloadClientDelugeValidationLabelPluginFailureDetail": "{appName} was unable to add the label to {clientName}.", "DownloadClientDelugeValidationLabelPluginInactive": "Label plugin not activated", "DownloadClientDelugeValidationLabelPluginInactiveDetail": "You must have the Label plugin enabled in {clientName} to use categories.", - "DownloadClientDelugeSettingsDirectory": "Download Directory", - "DownloadClientDelugeSettingsDirectoryHelpText": "Optional location to put downloads in, leave blank to use the default Deluge location", - "DownloadClientDelugeSettingsDirectoryCompleted": "Move When Completed Directory", - "DownloadClientDelugeSettingsDirectoryCompletedHelpText": "Optional location to move completed downloads to, leave blank to use the default Deluge location", "DownloadClientDownloadStationProviderMessage": "{appName} is unable to connect to Download Station if 2-Factor Authentication is enabled on your DSM account", "DownloadClientDownloadStationSettingsDirectoryHelpText": "Optional shared folder to put downloads into, leave blank to use the default Download Station location", "DownloadClientDownloadStationValidationApiVersion": "Download Station API version not supported, should be at least {requiredVersion}. It supports from {minVersion} to {maxVersion}", @@ -866,12 +867,12 @@ "ImportListsSimklSettingsUserListTypePlanToWatch": "Plan To Watch", "ImportListsSimklSettingsUserListTypeWatching": "Watching", "ImportListsSonarrSettingsApiKeyHelpText": "API Key of the {appName} instance to import from", - "ImportListsSonarrSettingsSyncSeasonMonitoring": "Sync Season Monitoring", - "ImportListsSonarrSettingsSyncSeasonMonitoringHelpText": "Sync season monitoring from {appName} instance, if enabled 'Monitor' will be ignored", "ImportListsSonarrSettingsFullUrl": "Full URL", "ImportListsSonarrSettingsFullUrlHelpText": "URL, including port, of the {appName} instance to import from", "ImportListsSonarrSettingsQualityProfilesHelpText": "Quality Profiles from the source instance to import from", "ImportListsSonarrSettingsRootFoldersHelpText": "Root Folders from the source instance to import from", + "ImportListsSonarrSettingsSyncSeasonMonitoring": "Sync Season Monitoring", + "ImportListsSonarrSettingsSyncSeasonMonitoringHelpText": "Sync season monitoring from {appName} instance, if enabled 'Monitor' will be ignored", "ImportListsSonarrSettingsTagsHelpText": "Tags from the source instance to import from", "ImportListsSonarrValidationInvalidUrl": "{appName} URL is invalid, are you missing a URL base?", "ImportListsTraktSettingsAdditionalParameters": "Additional Parameters", @@ -1787,7 +1788,6 @@ "SelectSeries": "Select Series", "SendAnonymousUsageData": "Send Anonymous Usage Data", "Series": "Series", - "SeriesFootNote": "Optionally control truncation to a maximum number of bytes including ellipsis (`...`). Truncating from the end (e.g. `{Series Title:30}`) or the beginning (e.g. `{Series Title:-30}`) are both supported.", "SeriesAndEpisodeInformationIsProvidedByTheTVDB": "Series and episode information is provided by TheTVDB.com. [Please consider supporting them]({url}) .", "SeriesCannotBeFound": "Sorry, that series cannot be found.", "SeriesDetailsCountEpisodeFiles": "{episodeFileCount} episode files", @@ -1801,6 +1801,7 @@ "SeriesFolderFormat": "Series Folder Format", "SeriesFolderFormatHelpText": "Used when adding a new series or moving series via the series editor", "SeriesFolderImportedTooltip": "Episode imported from series folder", + "SeriesFootNote": "Optionally control truncation to a maximum number of bytes including ellipsis (`...`). Truncating from the end (e.g. `{Series Title:30}`) or the beginning (e.g. `{Series Title:-30}`) are both supported.", "SeriesID": "Series ID", "SeriesIndexFooterContinuing": "Continuing (All episodes downloaded)", "SeriesIndexFooterDownloading": "Downloading (One or more episodes)", diff --git a/src/Sonarr.Api.V3/System/Backup/BackupController.cs b/src/Sonarr.Api.V3/System/Backup/BackupController.cs index bb2554c03..10f3bfeaa 100644 --- a/src/Sonarr.Api.V3/System/Backup/BackupController.cs +++ b/src/Sonarr.Api.V3/System/Backup/BackupController.cs @@ -40,7 +40,6 @@ namespace Sonarr.Api.V3.System.Backup { Id = GetBackupId(b), Name = b.Name, - Path = $"/backup/{b.Type.ToString().ToLower()}/{b.Name}", Size = b.Size, Type = b.Type, Time = b.Time diff --git a/src/Sonarr.Api.V3/System/Backup/BackupResource.cs b/src/Sonarr.Api.V3/System/Backup/BackupResource.cs index 25ff1f2bf..1838b1c2b 100644 --- a/src/Sonarr.Api.V3/System/Backup/BackupResource.cs +++ b/src/Sonarr.Api.V3/System/Backup/BackupResource.cs @@ -7,7 +7,6 @@ namespace Sonarr.Api.V3.System.Backup public class BackupResource : RestResource { public string Name { get; set; } - public string Path { get; set; } public BackupType Type { get; set; } public long Size { get; set; } public DateTime Time { get; set; } diff --git a/src/Sonarr.Api.V3/System/SystemController.cs b/src/Sonarr.Api.V3/System/SystemController.cs index 80d177cfb..7c2fa130a 100644 --- a/src/Sonarr.Api.V3/System/SystemController.cs +++ b/src/Sonarr.Api.V3/System/SystemController.cs @@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing.Internal; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Extensions; +using NzbDrone.Core.Backup; using NzbDrone.Core.Configuration; using NzbDrone.Core.Datastore; using NzbDrone.Core.Lifecycle; @@ -27,6 +28,7 @@ namespace Sonarr.Api.V3.System private readonly EndpointDataSource _endpointData; private readonly DfaGraphWriter _graphWriter; private readonly DuplicateEndpointDetector _detector; + private readonly IBackupService _backupService; public SystemController(IAppFolderInfo appFolderInfo, IRuntimeInfo runtimeInfo, @@ -38,7 +40,8 @@ namespace Sonarr.Api.V3.System IDeploymentInfoProvider deploymentInfoProvider, EndpointDataSource endpoints, DfaGraphWriter graphWriter, - DuplicateEndpointDetector detector) + DuplicateEndpointDetector detector, + IBackupService backupService) { _appFolderInfo = appFolderInfo; _runtimeInfo = runtimeInfo; @@ -51,6 +54,7 @@ namespace Sonarr.Api.V3.System _endpointData = endpoints; _graphWriter = graphWriter; _detector = detector; + _backupService = backupService; } [HttpGet("status")] @@ -69,6 +73,7 @@ namespace Sonarr.Api.V3.System IsUserInteractive = RuntimeInfo.IsUserInteractive, StartupPath = _appFolderInfo.StartUpFolder, AppData = _appFolderInfo.GetAppDataPath(), + BackupFolder = _backupService.GetBackupFolder(), OsName = _osInfo.Name, OsVersion = _osInfo.Version, IsNetCore = true, diff --git a/src/Sonarr.Api.V3/System/SystemResource.cs b/src/Sonarr.Api.V3/System/SystemResource.cs index 53f35921e..2210b9209 100644 --- a/src/Sonarr.Api.V3/System/SystemResource.cs +++ b/src/Sonarr.Api.V3/System/SystemResource.cs @@ -18,6 +18,7 @@ namespace Sonarr.Api.V3.System public bool IsUserInteractive { get; set; } public string StartupPath { get; set; } public string AppData { get; set; } + public string BackupFolder { get; set; } public string OsName { get; set; } public string OsVersion { get; set; } public bool IsNetCore { get; set; } diff --git a/src/Sonarr.Http/Frontend/Mappers/BackupFileMapper.cs b/src/Sonarr.Http/Frontend/Mappers/BackupFileMapper.cs deleted file mode 100644 index 17027aeab..000000000 --- a/src/Sonarr.Http/Frontend/Mappers/BackupFileMapper.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.IO; -using NLog; -using NzbDrone.Common.Disk; -using NzbDrone.Core.Backup; - -namespace Sonarr.Http.Frontend.Mappers -{ - public class BackupFileMapper : StaticResourceMapperBase - { - private readonly IBackupService _backupService; - - public BackupFileMapper(IBackupService backupService, IDiskProvider diskProvider, Logger logger) - : base(diskProvider, logger) - { - _backupService = backupService; - } - - public override string Map(string resourceUrl) - { - var path = resourceUrl.Replace("/backup/", "").Replace('/', Path.DirectorySeparatorChar); - - return Path.Combine(_backupService.GetBackupFolder(), path); - } - - public override bool CanHandle(string resourceUrl) - { - return resourceUrl.StartsWith("/backup/") && BackupService.BackupFileRegex.IsMatch(resourceUrl); - } - } -}