From 49168cad25f0bda75998db4e78032eb95c991313 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Sun, 26 Jan 2014 00:57:14 -0800 Subject: [PATCH] UI and opt-in for setting permissions --- .../Configuration/ConfigService.cs | 9 ++- .../Configuration/IConfigService.cs | 1 + .../MediaFiles/EpisodeFileMovingService.cs | 20 ++++++- .../MediaFiles/SetMediaFilePermissions.cs | 60 ------------------- src/NzbDrone.Core/NzbDrone.Core.csproj | 1 - src/NzbDrone.Mono/DiskProvider.cs | 7 +++ src/UI/Handlebars/Helpers/Os.js | 9 +++ .../backbone.marionette.templates.js | 1 + .../MediaManagement/MediaManagementLayout.js | 9 ++- .../MediaManagementLayoutTemplate.html | 1 + .../Permissions/PermissionsView.js | 39 ++++++++++++ .../Permissions/PermissionsViewTemplate.html | 48 +++++++++++++++ 12 files changed, 137 insertions(+), 68 deletions(-) delete mode 100644 src/NzbDrone.Core/MediaFiles/SetMediaFilePermissions.cs create mode 100644 src/UI/Handlebars/Helpers/Os.js create mode 100644 src/UI/Settings/MediaManagement/Permissions/PermissionsView.js create mode 100644 src/UI/Settings/MediaManagement/Permissions/PermissionsViewTemplate.html diff --git a/src/NzbDrone.Core/Configuration/ConfigService.cs b/src/NzbDrone.Core/Configuration/ConfigService.cs index 1427f998f..17b5eba03 100644 --- a/src/NzbDrone.Core/Configuration/ConfigService.cs +++ b/src/NzbDrone.Core/Configuration/ConfigService.cs @@ -284,9 +284,16 @@ namespace NzbDrone.Core.Configuration set { SetValue("DownloadClientWorkingFolders", value); } } + public Boolean SetPermissionsLinux + { + get { return GetValueBoolean("SetPermissionsLinux", false); } + + set { SetValue("SetPermissionsLinux", value); } + } + public String FileChmod { - get { return GetValue("FileChmod", "0755"); } + get { return GetValue("FileChmod", "0644"); } set { SetValue("FileChmod", value); } } diff --git a/src/NzbDrone.Core/Configuration/IConfigService.cs b/src/NzbDrone.Core/Configuration/IConfigService.cs index 70982dedd..d70d36def 100644 --- a/src/NzbDrone.Core/Configuration/IConfigService.cs +++ b/src/NzbDrone.Core/Configuration/IConfigService.cs @@ -42,6 +42,7 @@ namespace NzbDrone.Core.Configuration Boolean EnableFailedDownloadHandling { get; set; } Boolean CreateEmptySeriesFolders { get; set; } void SaveValues(Dictionary configValues); + Boolean SetPermissionsLinux { get; set; } String FileChmod { get; set; } String FolderChmod { get; set; } } diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeFileMovingService.cs b/src/NzbDrone.Core/MediaFiles/EpisodeFileMovingService.cs index 626cdb020..a7921453b 100644 --- a/src/NzbDrone.Core/MediaFiles/EpisodeFileMovingService.cs +++ b/src/NzbDrone.Core/MediaFiles/EpisodeFileMovingService.cs @@ -79,7 +79,18 @@ namespace NzbDrone.Core.MediaFiles throw new SameFilenameException("File not moved, source and destination are the same", episodeFile.Path); } - _diskProvider.CreateFolder(new FileInfo(destinationFilename).DirectoryName); + var directoryName = new FileInfo(destinationFilename).DirectoryName; + + if (_diskProvider.FolderExists(directoryName)) + { + _diskProvider.CreateFolder(directoryName); + SetFolderPermissions(directoryName); + + if (!directoryName.PathEquals(series.Path)) + { + SetFolderPermissions(series.Path); + } + } _logger.Debug("Moving [{0}] > [{1}]", episodeFile.Path, destinationFilename); _diskProvider.MoveFile(episodeFile.Path, destinationFilename); @@ -88,7 +99,6 @@ namespace NzbDrone.Core.MediaFiles { _logger.Trace("Setting last write time on series folder: {0}", series.Path); _diskProvider.SetFolderWriteTime(series.Path, episodeFile.DateAdded); - SetFolderPermissions(series.Path); if (series.SeasonFolder) { @@ -96,7 +106,6 @@ namespace NzbDrone.Core.MediaFiles _logger.Trace("Setting last write time on season folder: {0}", seasonFolder); _diskProvider.SetFolderWriteTime(seasonFolder, episodeFile.DateAdded); - SetFolderPermissions(seasonFolder); } } @@ -136,6 +145,11 @@ namespace NzbDrone.Core.MediaFiles private void SetPermissions(string path, string permissions) { + if (!_configService.SetPermissionsLinux) + { + return; + } + try { _diskProvider.SetPermissions(path, permissions); diff --git a/src/NzbDrone.Core/MediaFiles/SetMediaFilePermissions.cs b/src/NzbDrone.Core/MediaFiles/SetMediaFilePermissions.cs deleted file mode 100644 index 1b379db76..000000000 --- a/src/NzbDrone.Core/MediaFiles/SetMediaFilePermissions.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using NLog; -using NzbDrone.Common.Disk; -using NzbDrone.Common.EnvironmentInfo; -using NzbDrone.Core.Configuration; - -namespace NzbDrone.Core.MediaFiles -{ - public interface ISetMediaFilePermissions - { - void SetPermissions(string filename); - } - - public class SetMediaFilePermissions : ISetMediaFilePermissions - { - private readonly IDiskProvider _diskProvider; - private readonly IConfigService _configService; - private readonly Logger _logger; - - public SetMediaFilePermissions(IDiskProvider diskProvider, IConfigService configService, Logger logger) - { - _diskProvider = diskProvider; - _configService = configService; - _logger = logger; - } - - public void SetPermissions(string filename) - { - if (OsInfo.IsWindows) - { - //Wrapped in Try/Catch to prevent this from causing issues with remote NAS boxes, the move worked, which is more important. - try - { - _diskProvider.InheritFolderPermissions(filename); - } - catch (Exception ex) - { - if (ex is UnauthorizedAccessException || ex is InvalidOperationException) - { - _logger.Debug("Unable to apply folder permissions to: ", filename); - _logger.TraceException(ex.Message, ex); - } - - else - { - throw; - } - } - } - - else - { - _diskProvider.SetPermissions(filename, _configService.FileChmod); - } - } - } -} diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index 894868c1c..5dbf4fd48 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -290,7 +290,6 @@ - diff --git a/src/NzbDrone.Mono/DiskProvider.cs b/src/NzbDrone.Mono/DiskProvider.cs index dedfe57b3..7582eb7c9 100644 --- a/src/NzbDrone.Mono/DiskProvider.cs +++ b/src/NzbDrone.Mono/DiskProvider.cs @@ -61,6 +61,13 @@ namespace NzbDrone.Mono throw new Exception("Error setting file permissions: " + error); } + + if (Syscall.chown(path, Syscall.getuid(), Syscall.getgid()) < 0) + { + var error = Stdlib.GetLastError(); + + throw new Exception("Error setting file owner: " + error); + } } public override long? GetTotalSize(string path) diff --git a/src/UI/Handlebars/Helpers/Os.js b/src/UI/Handlebars/Helpers/Os.js new file mode 100644 index 000000000..0d46f7391 --- /dev/null +++ b/src/UI/Handlebars/Helpers/Os.js @@ -0,0 +1,9 @@ +'use strict'; +define( + [ + 'handlebars' + ], function (Handlebars) { + Handlebars.registerHelper('LinuxOnly', function () { + return new Handlebars.SafeString(''); + }); + }); diff --git a/src/UI/Handlebars/backbone.marionette.templates.js b/src/UI/Handlebars/backbone.marionette.templates.js index 2c589a5cb..f849da4f1 100644 --- a/src/UI/Handlebars/backbone.marionette.templates.js +++ b/src/UI/Handlebars/backbone.marionette.templates.js @@ -10,6 +10,7 @@ define( 'Handlebars/Helpers/Series', 'Handlebars/Helpers/Quality', 'Handlebars/Helpers/System', + 'Handlebars/Helpers/Os', 'Handlebars/Handlebars.Debug' ], function (Templates) { return function () { diff --git a/src/UI/Settings/MediaManagement/MediaManagementLayout.js b/src/UI/Settings/MediaManagement/MediaManagementLayout.js index 56b34c814..3b5ac123e 100644 --- a/src/UI/Settings/MediaManagement/MediaManagementLayout.js +++ b/src/UI/Settings/MediaManagement/MediaManagementLayout.js @@ -5,15 +5,17 @@ define( 'marionette', 'Settings/MediaManagement/Naming/NamingView', 'Settings/MediaManagement/Sorting/View', - 'Settings/MediaManagement/FileManagement/FileManagementView' - ], function (Marionette, NamingView, SortingView, FileManagementView) { + 'Settings/MediaManagement/FileManagement/FileManagementView', + 'Settings/MediaManagement/Permissions/PermissionsView' + ], function (Marionette, NamingView, SortingView, FileManagementView, PermissionsView) { return Marionette.Layout.extend({ template: 'Settings/MediaManagement/MediaManagementLayoutTemplate', regions: { episodeNaming : '#episode-naming', sorting : '#sorting', - fileManagement : '#file-management' + fileManagement : '#file-management', + permissions : '#permissions' }, initialize: function (options) { @@ -25,6 +27,7 @@ define( this.episodeNaming.show(new NamingView({ model: this.namingSettings })); this.sorting.show(new SortingView({ model: this.settings })); this.fileManagement.show(new FileManagementView({ model: this.settings })); + this.permissions.show(new PermissionsView({ model: this.settings })); } }); }); diff --git a/src/UI/Settings/MediaManagement/MediaManagementLayoutTemplate.html b/src/UI/Settings/MediaManagement/MediaManagementLayoutTemplate.html index 4720aa606..05a416998 100644 --- a/src/UI/Settings/MediaManagement/MediaManagementLayoutTemplate.html +++ b/src/UI/Settings/MediaManagement/MediaManagementLayoutTemplate.html @@ -2,4 +2,5 @@
+
\ No newline at end of file diff --git a/src/UI/Settings/MediaManagement/Permissions/PermissionsView.js b/src/UI/Settings/MediaManagement/Permissions/PermissionsView.js new file mode 100644 index 000000000..e1a098106 --- /dev/null +++ b/src/UI/Settings/MediaManagement/Permissions/PermissionsView.js @@ -0,0 +1,39 @@ +'use strict'; +define( + [ + 'marionette', + 'Mixins/AsModelBoundView', + 'Mixins/AutoComplete' + ], function (Marionette, AsModelBoundView) { + + var view = Marionette.ItemView.extend({ + template: 'Settings/MediaManagement/Permissions/PermissionsViewTemplate', + + ui: { + recyclingBin : '.x-path', + failedDownloadHandlingCheckbox: '.x-failed-download-handling', + failedDownloadOptions : '.x-failed-download-options' + }, + + events: { + 'change .x-failed-download-handling': '_setFailedDownloadOptionsVisibility' + }, + + onShow: function () { + this.ui.recyclingBin.autoComplete('/directories'); + }, + + _setFailedDownloadOptionsVisibility: function () { + var checked = this.ui.failedDownloadHandlingCheckbox.prop('checked'); + if (checked) { + this.ui.failedDownloadOptions.slideDown(); + } + + else { + this.ui.failedDownloadOptions.slideUp(); + } + } + }); + + return AsModelBoundView.call(view); + }); diff --git a/src/UI/Settings/MediaManagement/Permissions/PermissionsViewTemplate.html b/src/UI/Settings/MediaManagement/Permissions/PermissionsViewTemplate.html new file mode 100644 index 000000000..9528724e6 --- /dev/null +++ b/src/UI/Settings/MediaManagement/Permissions/PermissionsViewTemplate.html @@ -0,0 +1,48 @@ +
+ Permissions + +
+ + +
+
+ +
+ + +
+ + + {{LinuxOnly}} + + +
+
+ +
+ + +
+ + + {{LinuxOnly}} + + +
+
+
\ No newline at end of file