diff --git a/NEWS b/NEWS index 203d32a8b..02b8b52a0 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,7 @@ Enhancements - [web] add constraints to start/end dates of automatic responder (#3841) + - [web] allow a mailbox to be deleted immediately (#3875) - [web] updated Angular to version 1.5.8 - [eas] initial support for recurring tasks EAS - [eas] now support replied/forwarded flags using EAS (#3796) diff --git a/UI/MailerUI/English.lproj/Localizable.strings b/UI/MailerUI/English.lproj/Localizable.strings index 5f8a64a73..88f7070bd 100644 --- a/UI/MailerUI/English.lproj/Localizable.strings +++ b/UI/MailerUI/English.lproj/Localizable.strings @@ -269,6 +269,10 @@ "quotasFormat" = "%{0}% used on %{1} MB"; "Unable to move/delete folder." = "Unable to move/delete folder."; +/* Alternative operation when folder cannot be deleted */ +"The mailbox could not be moved to the trash folder. Would you like to delete it immediately?" += "The mailbox could not be moved to the trash folder. Would you like to delete it immediately?"; + /* Confirmation message when deleting multiple messages */ "Are you sure you want to delete the selected messages?" = "Are you sure you want to delete the selected messages?"; diff --git a/UI/MailerUI/UIxMailFolderActions.m b/UI/MailerUI/UIxMailFolderActions.m index 7435b5483..821458788 100644 --- a/UI/MailerUI/UIxMailFolderActions.m +++ b/UI/MailerUI/UIxMailFolderActions.m @@ -212,42 +212,106 @@ return destURL; } -- (WOResponse *) deleteAction +- (void) _removeFolder { - NSString *currentMailbox, *currentAccount, *keyForMsgUIDs; - NSMutableDictionary *moduleSettings, *threadsCollapsed; NGImap4Connection *connection; - SOGoMailFolder *co, *inbox; - NSDictionary *jsonResponse; - NSURL *srcURL, *destURL; + NSMutableDictionary *moduleSettings, *threadsCollapsed;; + NSString *keyForMsgUIDs, *currentMailbox, *currentAccount; + NSURL *srcURL; + SOGoMailFolder *co; SOGoUserSettings *us; - WOResponse *response; - NSException *error; - BOOL moved; co = [self clientObject]; + srcURL = [co imap4URL]; + connection = [co imap4Connection]; + + // Unsubscribe from mailbox + [[connection client] unsubscribe: [srcURL path]]; + + // Verify if the current folder have any collapsed threads save under it name and erase it + us = [[context activeUser] userSettings]; + moduleSettings = [us objectForKey: @"Mail"]; + threadsCollapsed = [moduleSettings objectForKey: @"threadsCollapsed"]; + + if (threadsCollapsed) + { + currentMailbox = [co nameInContainer]; + currentAccount = [[co container] nameInContainer]; + keyForMsgUIDs = [NSString stringWithFormat:@"/%@/%@", currentAccount, currentMailbox]; + if ([threadsCollapsed objectForKey: keyForMsgUIDs]) + { + [threadsCollapsed removeObjectForKey: keyForMsgUIDs]; + [us synchronize]; + } + } +} + +- (WOResponse *) deleteAction +{ + NSDictionary *jsonRequest, *jsonResponse; + NGImap4Connection *connection; + SOGoMailFolder *co, *inbox; + NSURL *srcURL, *destURL; + WORequest *request; + WOResponse *response; + NSException *error; + BOOL moved, withTrash; + + request = [context request]; + co = [self clientObject]; + srcURL = [co imap4URL]; + jsonRequest = [[request contentAsString] objectFromJSONString]; + withTrash = ![[jsonRequest objectForKey: @"withoutTrash"] boolValue]; moved = YES; - if ([co ensureTrashFolder]) + if (withTrash) { - connection = [co imap4Connection]; - srcURL = [co imap4URL]; - destURL = [self _trashedURLOfFolder: srcURL withObject: co]; - connection = [co imap4Connection]; - inbox = [[co mailAccountFolder] inboxFolderInContext: context]; - [[connection client] select: [inbox absoluteImap4Name]]; - - // If srcURL is a prefix of destURL, that means we are deleting - // the folder within the 'Trash' folder, as it's getting renamed - // over and over with an integer suffix (in trashedURLOfFolder:...) - // If that is the case, we simple delete the folder, instead of renaming it - if ([[destURL path] hasPrefix: [srcURL path]]) + if ([co ensureTrashFolder]) { - error = [connection deleteMailboxAtURL: srcURL]; - moved = NO; + connection = [co imap4Connection]; + destURL = [self _trashedURLOfFolder: srcURL withObject: co]; + connection = [co imap4Connection]; + inbox = [[co mailAccountFolder] inboxFolderInContext: context]; + [[connection client] select: [inbox absoluteImap4Name]]; + + // If srcURL is a prefix of destURL, that means we are deleting + // the folder within the 'Trash' folder, as it's getting renamed + // over and over with an integer suffix (in trashedURLOfFolder:...) + // If that is the case, we simple delete the folder, instead of renaming it + if ([[destURL path] hasPrefix: [srcURL path]]) + { + error = [connection deleteMailboxAtURL: srcURL]; + moved = NO; + } + else + error = [connection moveMailboxAtURL: srcURL toURL: destURL]; + if (error) + { + jsonResponse = [NSDictionary dictionaryWithObject: [self labelForKey: @"Unable to move/delete folder." inContext: context] + forKey: @"error"]; + response = [self responseWithStatus: 500 andJSONRepresentation: jsonResponse]; + } + else + { + // We unsubscribe to the old one, and subscribe back to the new one + if (moved) + [[connection client] subscribe: [destURL path]]; + [self _removeFolder]; + response = [self responseWith204]; + } } else - error = [connection moveMailboxAtURL: srcURL toURL: destURL]; + { + jsonResponse = [NSDictionary dictionaryWithObject: [self labelForKey: @"Unable to move/delete folder." inContext: context] + forKey: @"message"]; + response = [self responseWithStatus: 500 andJSONRepresentation: jsonResponse]; + } + } + else + { + // Immediately delete mailbox + connection = [co imap4Connection]; + error = [connection deleteMailboxAtURL: srcURL]; if (error) { jsonResponse = [NSDictionary dictionaryWithObject: [self labelForKey: @"Unable to move/delete folder." inContext: context] @@ -256,36 +320,10 @@ } else { - // We unsubscribe to the old one, and subscribe back to the new one - if (moved) - [[connection client] subscribe: [destURL path]]; - [[connection client] unsubscribe: [srcURL path]]; - - // Verify if the current folder have any collapsed threads save under it name and erase it - us = [[context activeUser] userSettings]; - moduleSettings = [us objectForKey: @"Mail"]; - threadsCollapsed = [moduleSettings objectForKey: @"threadsCollapsed"]; - currentMailbox = [co nameInContainer]; - currentAccount = [[co container] nameInContainer]; - keyForMsgUIDs = [NSString stringWithFormat:@"/%@/%@", currentAccount, currentMailbox]; - - if (threadsCollapsed) - { - if ([threadsCollapsed objectForKey: keyForMsgUIDs]) - { - [threadsCollapsed removeObjectForKey: keyForMsgUIDs]; - [us synchronize]; - } - } + [self _removeFolder]; response = [self responseWith204]; } } - else - { - jsonResponse = [NSDictionary dictionaryWithObject: [self labelForKey: @"Unable to move/delete folder." inContext: context] - forKey: @"message"]; - response = [self responseWithStatus: 500 andJSONRepresentation: jsonResponse]; - } return response; } @@ -773,7 +811,6 @@ - (WOResponse *) _subscribeOrUnsubscribeAction: (BOOL) subscribing { NGImap4Client *client; - WOResponse *response; SOGoMailFolder *co; NSDictionary *d; diff --git a/UI/WebServerResources/js/Mailer/Mailbox.service.js b/UI/WebServerResources/js/Mailer/Mailbox.service.js index 08ddd8b97..0d7efe827 100644 --- a/UI/WebServerResources/js/Mailer/Mailbox.service.js +++ b/UI/WebServerResources/js/Mailer/Mailbox.service.js @@ -620,12 +620,13 @@ * @function $delete * @memberof Mailbox.prototype * @desc Delete the mailbox from the server + * @param {object} [options] - additional options (use {withoutTrash: true} to delete immediately) * @returns a promise of the HTTP operation */ - Mailbox.prototype.$delete = function() { + Mailbox.prototype.$delete = function(options) { var _this = this; - return Mailbox.$$resource.remove(this.id) + return Mailbox.$$resource.post(this.id, 'delete', options) .then(function() { _this.$account.$getMailboxes({reload: true}); return true; @@ -674,6 +675,7 @@ * @function $deleteMessages * @memberof Mailbox.prototype * @desc Delete multiple messages from mailbox. + * @param {object} [options] - additional options (use {withoutTrash: true} to delete immediately) * @return a promise of the HTTP operation */ Mailbox.prototype.$deleteMessages = function(messages, options) { diff --git a/UI/WebServerResources/js/Mailer/MailboxController.js b/UI/WebServerResources/js/Mailer/MailboxController.js index b00ee33bb..1a7819514 100644 --- a/UI/WebServerResources/js/Mailer/MailboxController.js +++ b/UI/WebServerResources/js/Mailer/MailboxController.js @@ -311,7 +311,7 @@ var selectedMessages = vm.selectedFolder.$selectedMessages(); if (messageDialog === null && _.size(selectedMessages) > 0) - messageDialog = Dialog.confirm(l('Warning'), + messageDialog = Dialog.confirm(l('Confirmation'), l('Are you sure you want to delete the selected messages?'), { ok: l('Delete') }) .then(function() { diff --git a/UI/WebServerResources/js/Mailer/MailboxesController.js b/UI/WebServerResources/js/Mailer/MailboxesController.js index e2f2a2801..8ad7c5b98 100644 --- a/UI/WebServerResources/js/Mailer/MailboxesController.js +++ b/UI/WebServerResources/js/Mailer/MailboxesController.js @@ -344,14 +344,26 @@ } function confirmDelete(folder) { - Dialog.confirm(l('Confirmation'), l('Do you really want to move this folder into the trash ?')) + Dialog.confirm(l('Warning'), + l('Do you really want to move this folder into the trash ?'), + { ok: l('Delete') }) .then(function() { folder.$delete() .then(function() { $state.go('mail.account.inbox'); - }, function(data, status) { - Dialog.alert(l('An error occured while deleting the mailbox "%{0}".', folder.name), - l(data.error)); + }, function(response) { + Dialog.confirm(l('Warning'), + l('The mailbox could not be moved to the trash folder. Would you like to delete it immediately?'), + { ok: l('Delete') }) + .then(function() { + folder.$delete({ withoutTrash: true }) + .then(function() { + $state.go('mail.account.inbox'); + }, function(response) { + Dialog.alert(l('An error occured while deleting the mailbox "%{0}".', folder.name), + l(response.error)); + }); + }); }); }); }