diff options
Diffstat (limited to 'Duplicati/Server/webroot/ngax/scripts/controllers/EditBackupController.js')
-rw-r--r-- | Duplicati/Server/webroot/ngax/scripts/controllers/EditBackupController.js | 264 |
1 files changed, 231 insertions, 33 deletions
diff --git a/Duplicati/Server/webroot/ngax/scripts/controllers/EditBackupController.js b/Duplicati/Server/webroot/ngax/scripts/controllers/EditBackupController.js index 8e9f31e25..5ee523386 100644 --- a/Duplicati/Server/webroot/ngax/scripts/controllers/EditBackupController.js +++ b/Duplicati/Server/webroot/ngax/scripts/controllers/EditBackupController.js @@ -1,4 +1,4 @@ -backupApp.controller('EditBackupController', function ($scope, $routeParams, $location, $timeout, AppService, AppUtils, SystemInfo, DialogService, EditBackupService, gettext, gettextCatalog) { +backupApp.controller('EditBackupController', function ($rootScope, $scope, $routeParams, $location, $timeout, AppService, AppUtils, SystemInfo, DialogService, EditBackupService, gettext, gettextCatalog) { $scope.SystemInfo = SystemInfo.watch($scope); $scope.AppUtils = AppUtils; @@ -6,14 +6,22 @@ backupApp.controller('EditBackupController', function ($scope, $routeParams, $lo $scope.RepeatPasshrase = null; $scope.PasswordStrength = 'unknown'; $scope.CurrentStep = 0; - $scope.EditUriState = false; $scope.showhiddenfolders = false; $scope.EditSourceAdvanced = false; $scope.EditFilterAdvanced = false; + $scope.DefaultFilters = []; $scope.ExcludeAttributes = []; $scope.ExcludeLargeFiles = false; + $scope.defaultFilterSetAll = 'All'; + $scope.defaultFilterSets = [ + { 'name': gettextCatalog.getString('Windows'), 'value': 'Windows' }, + { 'name': gettextCatalog.getString('OSX'), 'value': 'OSX' }, + { 'name': gettextCatalog.getString('Linux'), 'value': 'Linux' }, + { 'name': gettextCatalog.getString('All'), 'value': $scope.defaultFilterSetAll }, + ]; + $scope.fileAttributes = [ {'name': gettextCatalog.getString('Hidden files'), 'value': 'hidden'}, {'name': gettextCatalog.getString('System files'), 'value': 'system'}, @@ -25,7 +33,6 @@ backupApp.controller('EditBackupController', function ($scope, $routeParams, $lo function computePassPhraseStrength() { var strengthMap = { - '': gettextCatalog.getString("Empty"), 'x': gettextCatalog.getString("Passwords do not match"), 0: gettextCatalog.getString("Useless"), 1: gettextCatalog.getString("Very weak"), @@ -43,7 +50,7 @@ backupApp.controller('EditBackupController', function ($scope, $routeParams, $lo else scope.PassphraseScore = (zxcvbn(passphrase) || {'score': -1}).score; - scope.PassphraseScoreString = strengthMap[scope.PassphraseScore] || gettextCatalog.getString('Unknown'); + scope.PassphraseScoreString = strengthMap[scope.PassphraseScore]; } $scope.$watch('Options["passphrase"]', computePassPhraseStrength); @@ -56,20 +63,32 @@ backupApp.controller('EditBackupController', function ($scope, $routeParams, $lo }; $scope.togglePassphraseVisibility = function() { - this.ShowPassphrase = !this.ShowPassphrase;; + this.ShowPassphrase = !this.ShowPassphrase; }; $scope.nextPage = function() { - $scope.CurrentStep = Math.min(3, $scope.CurrentStep + 1); + $scope.CurrentStep = Math.min(4, $scope.CurrentStep + 1); }; $scope.prevPage = function() { $scope.CurrentStep = Math.max(0, $scope.CurrentStep - 1); + }; + $scope.setBuilduriFn = function(builduriFn) { + $scope.builduri = builduriFn; }; - $scope.HideEditUri = function() { - scope.EditUriState = false; + $scope.importUrl = function () { + DialogService.textareaDialog('Import URL', 'Enter a Backup destination URL:', null, gettextCatalog.getString('Enter URL'), [gettextCatalog.getString('Cancel'), gettextCatalog.getString('OK')], null, function(btn, input) { + if (btn == 1) + scope.Backup.TargetURL = input; + }); + }; + + $scope.copyUrlToClipboard = function () { + $scope.builduri(function(res) { + DialogService.textareaDialog('Copy URL', null, null, res, [gettextCatalog.getString('OK')], 'templates/copy_clipboard_buttons.html'); + }); }; var oldSchedule = null; @@ -125,23 +144,19 @@ backupApp.controller('EditBackupController', function ($scope, $routeParams, $lo } }); }); - }; + } if (scope.manualSourcePath.substr(scope.manualSourcePath.length - 1, 1) != dirsep) { - DialogService.dialog(gettextCatalog.getString('Include a file?'), gettextCatalog.getString("The path does not end with a '{0}' character, which means that you include a file, not a folder.\n\nDo you want to include the specified file?", dirsep), [gettextCatalog.getString('No'), gettextCatalog.getString('Yes')], function(ix) { + DialogService.dialog(gettextCatalog.getString('Include a file?'), gettextCatalog.getString("The path does not end with a '{{dirsep}}' character, which means that you include a file, not a folder.\n\nDo you want to include the specified file?", {dirsep: dirsep}), [gettextCatalog.getString('No'), gettextCatalog.getString('Yes')], function(ix) { if (ix == 1) continuation(); }); } else { continuation(); } - - - - }; - $scope.toggleArraySelection = function (lst, value) { + function toggleArraySelection(lst, value) { var ix = lst.indexOf(value); if (ix > -1) @@ -150,6 +165,61 @@ backupApp.controller('EditBackupController', function ($scope, $routeParams, $lo lst.push(value); }; + $scope.toggleAllowedDays = function(value) { + if ($scope.Schedule.AllowedDays == null) + $scope.Schedule.AllowedDays = []; + toggleArraySelection($scope.Schedule.AllowedDays, value); + }; + + $scope.isDefaultFilterSetEnabled = function (value) { + if ($scope.DefaultFilters == null) + $scope.DefaultFilters = []; + if (value != $scope.defaultFilterSetAll && $scope.isDefaultFilterSetEnabled($scope.defaultFilterSetAll)) + { + return true; + } + + return $scope.DefaultFilters.indexOf(value) > -1; + }; + + $scope.toggleDefaultFilters = function (value) { + if ($scope.DefaultFilters == null) + $scope.DefaultFilters = []; + if (value == $scope.defaultFilterSetAll) + { + var wasAllEnabled = $scope.isDefaultFilterSetEnabled($scope.defaultFilterSetAll); + $scope.DefaultFilters = []; + if (!wasAllEnabled) + { + for (var index = 0; index < $scope.defaultFilterSets.length; index++) + { + $scope.DefaultFilters.push($scope.defaultFilterSets[index].value); + } + } + } + else + { + if ($scope.isDefaultFilterSetEnabled($scope.defaultFilterSetAll)) + { + toggleArraySelection($scope.DefaultFilters, $scope.defaultFilterSetAll); + } + + toggleArraySelection($scope.DefaultFilters, value); + + // If everything but the 'all' group is enabled, enable it + if ($scope.DefaultFilters.length >= $scope.defaultFilterSets.length - 1) + { + toggleArraySelection($scope.DefaultFilters, $scope.defaultFilterSetAll); + } + } + }; + + $scope.toggleExcludeAttributes = function(value) { + if ($scope.ExcludeAttributes == null) + $scope.ExcludeAttributes = []; + toggleArraySelection($scope.ExcludeAttributes, value); + }; + $scope.save = function() { if (!EditBackupService.preValidate($scope)) @@ -160,7 +230,7 @@ backupApp.controller('EditBackupController', function ($scope, $routeParams, $lo Schedule: angular.copy($scope.Schedule) }; - var opts = angular.copy($scope.Options); + var opts = angular.copy($scope.Options, opts); if (!$scope.ExcludeLargeFiles) delete opts['--skip-files-larger-than']; @@ -174,6 +244,30 @@ backupApp.controller('EditBackupController', function ($scope, $routeParams, $lo if (!AppUtils.parse_extra_options(scope.ExtendedOptions, opts)) return false; + for (var n in $scope.servermodulesettings) + opts['--' + n] = $scope.servermodulesettings[n]; + + var defaultFilters = ($scope.DefaultFilters || []).concat((opts['--default-filters'] || '').split(/[,;\|]+/)); + var filterMap = { '': true }; + + // Remove duplicates + for (var i = defaultFilters.length - 1; i >= 0; i--) { + defaultFilters[i] = (defaultFilters[i] || '').trim(); + var cmp = defaultFilters[i].toLowerCase(); + if (filterMap[cmp]) + defaultFilters.splice(i, 1); + else + filterMap[cmp] = true; + } + + if (defaultFilters.length == 0) + delete opts['--default-filters']; + else + if (filterMap[$scope.defaultFilterSetAll.toLowerCase()]) + opts['--default-filters'] = $scope.defaultFilterSetAll; + else + opts['--default-filters'] = defaultFilters.join(','); + var exclattr = ($scope.ExcludeAttributes || []).concat((opts['--exclude-files-attributes'] || '').split(',')); var exclmap = { '': true }; @@ -190,7 +284,7 @@ backupApp.controller('EditBackupController', function ($scope, $routeParams, $lo if (exclattr.length == 0) delete opts['--exclude-files-attributes']; else - opts['--exclude-files-attributes'] = exclattr.join(',') + opts['--exclude-files-attributes'] = exclattr.join(','); if (($scope.Backup.Name || '').trim().length == 0) { DialogService.dialog(gettextCatalog.getString('Missing name'), gettextCatalog.getString('You must enter a name for the backup')); @@ -213,15 +307,9 @@ backupApp.controller('EditBackupController', function ($scope, $routeParams, $lo } } - if (($scope.Backup.TargetURL || '').trim().length == 0) { - DialogService.dialog(gettextCatalog.getString('Missing destination'), gettextCatalog.getString('You must enter a destination where the backups are stored')); - $scope.CurrentStep = 0; - return; - } - if ($scope.Backup.Sources == null || $scope.Backup.Sources.length == 0) { DialogService.dialog(gettextCatalog.getString('Missing sources'), gettextCatalog.getString('You must choose at least one source folder')); - $scope.CurrentStep = 1; + $scope.CurrentStep = 2; return; } @@ -230,6 +318,21 @@ backupApp.controller('EditBackupController', function ($scope, $routeParams, $lo if ($scope.KeepType == 'versions' || $scope.KeepType == '') delete opts['keep-time']; + if ($scope.KeepType == 'time' && (opts['keep-time'] || '').trim().length == 0) + { + DialogService.dialog(gettextCatalog.getString('Invalid retention time'), gettextCatalog.getString('You must enter a valid duration for the time to keep backups')); + $scope.CurrentStep = 4; + return; + } + + if ($scope.KeepType == 'versions' && (parseInt(opts['keep-versions']) <= 0 || isNaN(parseInt(opts['keep-versions'])))) + { + DialogService.dialog(gettextCatalog.getString('Invalid retention time'), gettextCatalog.getString('You must enter a positive number of backups to keep')); + $scope.CurrentStep = 4; + return; + } + + result.Backup.Settings = []; for(var k in opts) { var origfilter = ""; @@ -328,6 +431,19 @@ backupApp.controller('EditBackupController', function ($scope, $routeParams, $lo }; + function checkForValidBackupDestination(continuation) { + var success = false; + $scope.builduri(function(res) { + result.Backup.TargetURL = res; + $scope.Backup.TargetURL = res; + success = true; + continuation(); + }); + + if (!success) + $scope.CurrentStep = 1; + } + function checkForDisabledEncryption(continuation) { if (encryptionEnabled || $scope.Backup.TargetURL.indexOf('file://') == 0 || $scope.SystemInfo.EncryptionModules.length == 0) continuation(); @@ -370,10 +486,12 @@ backupApp.controller('EditBackupController', function ($scope, $routeParams, $lo // Chain calls checkForGeneratedPassphrase(function() { - checkForDisabledEncryption(function() { - warnWeakPassphrase(function() { - checkForExistingDb(function() { - EditBackupService.postValidate($scope, postDb); + checkForValidBackupDestination(function() { + checkForDisabledEncryption(function() { + warnWeakPassphrase(function() { + checkForExistingDb(function () { + EditBackupService.postValidate($scope, postDb); + }); }); }); }); @@ -386,9 +504,11 @@ backupApp.controller('EditBackupController', function ($scope, $routeParams, $lo AppService.put('/backup/' + $routeParams.backupid, result, {'headers': {'Content-Type': 'application/json'}}).then(function() { $location.path('/'); }, AppUtils.connectionError); - }; + } - checkForChangedPassphrase(putDb); + checkForChangedPassphrase(function() { + checkForValidBackupDestination(putDb); + }); } }; @@ -420,6 +540,38 @@ backupApp.controller('EditBackupController', function ($scope, $routeParams, $lo if ($scope.ExcludeLargeFiles) $scope.Options['--skip-files-larger-than'] = extopts['--skip-files-larger-than']; + var defaultFilters = (extopts['--default-filters'] || '').split(/[,;\|]+/); + var defaultFiltersActive = []; + var filterMap = {}; + + for (var i = defaultFilters.length - 1; i >= 0; i--) { + var cmp = (defaultFilters[i] || '').trim().toLowerCase(); + + // Remove empty entries + if (cmp.length == 0) { + defaultFilters.splice(i, 1); + continue; + } + + for (var j = scope.defaultFilterSets.length - 1; j >= 0; j--) { + if (scope.defaultFilterSets[j].value.toLowerCase() == cmp) { + // Remote duplicates + if (filterMap[cmp] == null) { + defaultFiltersActive.push(scope.defaultFilterSets[j].value); + filterMap[cmp] = true; + } + defaultFilters.splice(i, 1); + break; + } + } + } + + $scope.DefaultFilters = defaultFiltersActive; + if (defaultFilters.length == 0) + delete extopts['--default-filters']; + else + extopts['--default-filters'] = defaultFilters.join(','); + var exclattr = (extopts['--exclude-files-attributes'] || '').split(','); var dispattr = []; var dispmap = {}; @@ -465,11 +617,16 @@ backupApp.controller('EditBackupController', function ($scope, $routeParams, $lo $scope.KeepType = 'versions'; } - var delopts = ['--skip-files-larger-than', '--no-encryption'] + var delopts = ['--skip-files-larger-than', '--no-encryption']; for(var n in delopts) delete extopts[delopts[n]]; $scope.ExtendedOptions = AppUtils.serializeAdvancedOptionsToArray(extopts); + + $scope.servermodulesettings = {}; + AppUtils.extractServerModuleOptions($scope.ExtendedOptions, $scope.ServerModules, $scope.servermodulesettings, 'SupportedLocalCommands'); + + $scope.showAdvanced = $scope.ExtendedOptions.length > 0; var now = new Date(); if ($scope.Schedule != null) { @@ -502,6 +659,20 @@ backupApp.controller('EditBackupController', function ($scope, $routeParams, $lo } } + function setupServerModules() + { + var mods = []; + if ($scope.SystemInfo.ServerModules != null) + for(var ix in $scope.SystemInfo.ServerModules) + { + var m = $scope.SystemInfo.ServerModules[ix]; + if (m.SupportedLocalCommands != null && m.SupportedLocalCommands.length > 0) + mods.push(m); + } + + $scope.ServerModules = mods; + }; + function reloadOptionsList() { if ($scope.Options == null) @@ -514,9 +685,32 @@ backupApp.controller('EditBackupController', function ($scope, $routeParams, $lo if (ix > 0) backmodule = backmodule.substr(0, ix); - $scope.ExtendedOptionList = AppUtils.buildOptionList($scope.SystemInfo, encmodule, compmodule, backmodule); + $scope.ExtendedOptionList = AppUtils.buildOptionList($scope.SystemInfo, encmodule, compmodule, backmodule); + setupServerModules(); + + AppUtils.extractServerModuleOptions($scope.ExtendedOptions, $scope.ServerModules, $scope.servermodulesettings, 'SupportedLocalCommands'); + }; + + function checkAllowedDaysConfig() + { + if ($scope.Schedule == null || $scope.Schedule.AllowedDays == null) + return; + + // Remove invalid values + var alldays = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']; + for (var i = $scope.Schedule.AllowedDays.length - 1; i >= 0; i--) + if (alldays.indexOf($scope.Schedule.AllowedDays[i]) < 0) + $scope.Schedule.AllowedDays.splice(i, 1); + + // Empty and all are the same, but the UI confuses if no days are selected + if ($scope.Schedule.AllowedDays.length == 0) + $timeout(function() { + $scope.Schedule.AllowedDays = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']; + }); }; + setupServerModules(); + $scope.$watch("Options['encryption-module']", reloadOptionsList); $scope.$watch("Options['compression-module']", reloadOptionsList); $scope.$watch("Options['--compression-module']", reloadOptionsList); @@ -526,19 +720,23 @@ backupApp.controller('EditBackupController', function ($scope, $routeParams, $lo if ($scope.Options != null && $scope.Options['--skip-files-larger-than'] == null) $scope.Options['--skip-files-larger-than'] = '100MB'; }); + $scope.$watch("Schedule.AllowedDays", checkAllowedDaysConfig, true); if ($routeParams.backupid == null) { AppService.get('/backupdefaults').then(function(data) { $scope.rawddata = data.data.data; + + if ($location.$$path.indexOf('/add-import') == 0 && $rootScope.importConfig != null) + angular.merge($scope.rawddata, $rootScope.importConfig); + setupScope($scope.rawddata); }, function(data) { AppUtils.connectionError(gettextCatalog.getString('Failed to read backup defaults:') + ' ', data); $location.path('/'); }); - } else { AppService.get('/backup/' + $routeParams.backupid).then(function(data) { |