parent
7e75c8be45
commit
894769ef6f
3
NEWS
3
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
|
||||
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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"/>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue