From 894769ef6f609cfb48bc5a993dcef58ae6337a03 Mon Sep 17 00:00:00 2001 From: Francis Lachapelle Date: Fri, 27 Jul 2018 15:21:35 -0400 Subject: [PATCH] (web) New menu option to move mailboxes Fixes #644 Fixes #3511 Fixes #4479 --- NEWS | 3 + UI/MailerUI/UIxMailFolderActions.m | 106 +++++++++++++++++- UI/Templates/MailerUI/UIxMailMainFrame.wox | 22 ++++ .../js/Mailer/Mailbox.service.js | 17 ++- .../js/Mailer/sgMailboxListItem.directive.js | 31 +++++ 5 files changed, 177 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index ff8e29b339..7892f25580 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,9 @@ 4.x.x (2018-xx-xx) ------------------ +New features + - [web] move mailboxes (#644, #3511, #4479) + Bug fixes - [core] handle multi-valued mozillasecondemail attribute mapping diff --git a/UI/MailerUI/UIxMailFolderActions.m b/UI/MailerUI/UIxMailFolderActions.m index 17c4b140d5..bf2d26a090 100644 --- a/UI/MailerUI/UIxMailFolderActions.m +++ b/UI/MailerUI/UIxMailFolderActions.m @@ -1,6 +1,6 @@ /* UIxMailFolderActions.m - this file is part of SOGo * - * Copyright (C) 2007-2017 Inverse inc. + * Copyright (C) 2007-2018 Inverse inc. * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,6 +32,7 @@ #import #import +#import #import #import #import @@ -183,6 +184,109 @@ - (WOResponse *) renameFolderAction return response; } +/** + * @api {post} /so/:username/Mail/:accountId/:mailboxPath/renameFolder Rename mailbox + * @apiVersion 1.0.0 + * @apiName PostRenameFolder + * @apiGroup Mail + * + * @apiParam {String} parent Name of the new parent mailbox + * + * @apiSuccess (Success 200) {String} path New mailbox path relative to account + * @apiSuccess (Success 200) {String} sievePath New mailbox path relative to account for Sieve script usage + * @apiError (Error 500) {Object} error The error message + */ +- (WOResponse *) moveFolderAction +{ + SOGoMailFolder *co; + SOGoUserSettings *us; + WORequest *request; + WOResponse *response; + NSException *error; + NSString *newParentPath, *newFolderPath, *sievePath, *currentMailbox, *currentAccount, + *keyForMsgUIDs, *newKeyForMsgUIDs; + NSMutableDictionary *params, *moduleSettings, *threadsCollapsed, *message; + NSArray *currentComponents, *newComponents, *values; + int count; + + co = [self clientObject]; + + // Prepare the variables need to verify if the current folder have any collapsed threads saved in userSettings + us = [[context activeUser] userSettings]; + moduleSettings = [us objectForKey: @"Mail"]; + threadsCollapsed = [moduleSettings objectForKey:@"threadsCollapsed"]; + + // Retrieve new folder name from JSON payload + request = [context request]; + params = [[request contentAsString] objectFromJSONString]; + newParentPath = [params objectForKey: @"parent"]; // encoded parent path (ex: "Travail/Employ&AOk-s") + + if (!newParentPath || [newParentPath length] == 0) + { + message = [NSDictionary dictionaryWithObject: [self labelForKey: @"Missing parent parameter" inContext: context] + forKey: @"message"]; + response = [self responseWithStatus: 500 andJSONRepresentation: message]; + } + else + { + newFolderPath = [NSString stringWithFormat:@"/%@/%@", + newParentPath, + [[co imap4URL] lastPathComponent]]; + error = [co renameTo: newFolderPath]; + if (error) + { + message = [NSDictionary dictionaryWithObject: [self labelForKey: @"Unable to move folder." inContext: context] + forKey: @"message"]; + response = [self responseWithStatus: 500 andJSONRepresentation: message]; + } + else + { + // Build lookup key for current mailbox path + currentComponents = [[co imap4URL] pathComponents]; + count = [currentComponents count]; + currentComponents = [[currentComponents subarrayWithRange: NSMakeRange(1,count-1)] + resultsOfSelector: @selector (asCSSIdentifier)]; + currentComponents = [currentComponents stringsWithFormat: @"folder%@"]; + currentAccount = [[co mailAccountFolder] nameInContainer]; // integer (ex: 0) + keyForMsgUIDs = [NSString stringWithFormat:@"/%@/%@", currentAccount, + [currentComponents componentsJoinedByString: @"/"]]; + + // Build lookup key for new mailbox path + newComponents = [newParentPath pathComponents]; + newComponents = [newComponents resultsOfSelector: @selector (asCSSIdentifier)]; + newComponents = [newComponents stringsWithFormat: @"folder%@"]; + currentMailbox = [NSString stringWithFormat: @"folder%@", [[[co imap4URL] lastPathComponent] asCSSIdentifier]]; + newKeyForMsgUIDs = [NSString stringWithFormat:@"/%@/%@/%@", currentAccount, + [newComponents componentsJoinedByString: @"/"], currentMailbox]; + + // Verify if the current folder have any collapsed threads save under it old name and adjust the folderName + if (threadsCollapsed) + { + if ([threadsCollapsed objectForKey: keyForMsgUIDs]) + { + values = [NSArray arrayWithArray:[threadsCollapsed objectForKey:keyForMsgUIDs]]; + [threadsCollapsed setObject:values forKey:newKeyForMsgUIDs]; + [threadsCollapsed removeObjectForKey:keyForMsgUIDs]; + [us synchronize]; + } + } + newFolderPath = [newFolderPath substringFromIndex: 1]; // remove slash at beginning of path + + NSString *sieveFolderEncoding = [[SOGoSystemDefaults sharedSystemDefaults] sieveFolderEncoding]; + if ([sieveFolderEncoding isEqualToString: @"UTF-8"]) + sievePath = [newFolderPath stringByDecodingImap4FolderName]; + else + sievePath = newFolderPath; + + message = [NSDictionary dictionaryWithObjectsAndKeys: + newFolderPath, @"path", sievePath, @"sievePath", nil]; + response = [self responseWithStatus: 200 andJSONRepresentation: message]; + } + } + + return response; +} + - (NSURL *) _trashedURLOfFolder: (NSURL *) srcURL withObject: (SOGoMailFolder *) co { diff --git a/UI/Templates/MailerUI/UIxMailMainFrame.wox b/UI/Templates/MailerUI/UIxMailMainFrame.wox index 6fb53aabc6..1f4c2b4238 100644 --- a/UI/Templates/MailerUI/UIxMailMainFrame.wox +++ b/UI/Templates/MailerUI/UIxMailMainFrame.wox @@ -201,6 +201,28 @@ + + + + + + +
+ + + + + +
+
+
+
diff --git a/UI/WebServerResources/js/Mailer/Mailbox.service.js b/UI/WebServerResources/js/Mailer/Mailbox.service.js index 099df4986a..517c237a35 100644 --- a/UI/WebServerResources/js/Mailer/Mailbox.service.js +++ b/UI/WebServerResources/js/Mailer/Mailbox.service.js @@ -485,7 +485,7 @@ /** * @function $rename * @memberof AddressBook.prototype - * @desc Rename the addressbook and keep the list sorted + * @desc Rename the mailbox and keep the list sorted * @param {string} name - the new name * @returns a promise of the HTTP operation */ @@ -827,6 +827,21 @@ this.$shadowData = this.$omit(); }; + /** + * @function $move + * @memberof Mailbox.prototype + * @desc Move the mailbox to a different parent. Will reload the mailboxes list. + * @returns a promise of the HTTP operation + */ + Mailbox.prototype.$move = function(parentPath) { + var _this = this; + + return Mailbox.$$resource.post(this.id, 'move', {parent: parentPath}).finally(function() { + _this.$account.$getMailboxes({reload: true}); + return true; + }); + }; + /** * @function $save * @memberof Mailbox.prototype diff --git a/UI/WebServerResources/js/Mailer/sgMailboxListItem.directive.js b/UI/WebServerResources/js/Mailer/sgMailboxListItem.directive.js index 64db4a89ed..e29d374a20 100644 --- a/UI/WebServerResources/js/Mailer/sgMailboxListItem.directive.js +++ b/UI/WebServerResources/js/Mailer/sgMailboxListItem.directive.js @@ -296,6 +296,37 @@ }); }; + this.isParentOf = function(path) { + var findChildren; + + // Local recursive function + findChildren = function(parent) { + if (parent.children && parent.children.length > 0) { + for (var i = 0, found = false; !found && i < parent.children.length; i++) { + var o = parent.children[i]; + if (o.children && o.children.length > 0) { + if (findChildren(o)) { + return true; + } + } + else if (o.path == path) { + return true; + } + } + } + else { + return (parent.path == path); + } + }; + + return findChildren(this.folder); + }; + + this.moveFolder = function(path) { + this.folder.$move(path); + mdPanelRef.close(); + }; + } // MenuController