(web) New menu option to move mailboxes

Fixes #644
Fixes #3511
Fixes #4479
pull/229/merge
Francis Lachapelle 2018-07-27 15:21:35 -04:00
parent 7e75c8be45
commit 894769ef6f
5 changed files with 177 additions and 2 deletions

3
NEWS
View File

@ -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

View File

@ -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 <Mailer/SOGoMailAccount.h>
#import <Mailer/SOGoTrashFolder.h>
#import <SOGo/NSArray+Utilities.h>
#import <SOGo/NSObject+Utilities.h>
#import <SOGo/NSString+Utilities.h>
#import <SOGo/SOGoDomainDefaults.h>
@ -183,6 +184,109 @@
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
{

View File

@ -201,6 +201,28 @@
<var:string label:value="Rename"/>
</md-button>
</md-menu-item>
<md-menu-item ng-show="::$menuCtrl.folder.$isEditable">
<md-menu md-position-mode="cascade target">
<md-button label:aria-label="Move To" ng-click="$mdMenu.open($event)">
<var:string label:value="Move To"/>
</md-button>
<md-menu-content class="md-dense" width="3">
<div ng-repeat="folder in
$menuCtrl.folder.$account.$flattenMailboxes({ all: true })
track by folder.path">
<md-menu-item>
<md-button class="sg-no-wrap"
aria-label="{{folder.$displayName}}"
ng-disabled="$menuCtrl.isParentOf(folder.path)"
ng-click="$menuCtrl.moveFolder(folder.path)">
<span ng-class="::('sg-child-level-' + folder.level)"
ng-bind="folder.$displayName"><!-- mailbox name --></span>
</md-button>
</md-menu-item>
</div>
</md-menu-content>
</md-menu>
</md-menu-item>
<md-menu-item>
<md-button type="button" ng-click="$menuCtrl.compactFolder()">
<var:string label:value="Compact"/>

View File

@ -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

View File

@ -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