Don't allow duplicate GCS folder names
parent
18df3bafb5
commit
3bdd90e2be
|
@ -614,15 +614,17 @@ static NSArray *childRecordFields = nil;
|
||||||
NSURL *folderLocation;
|
NSURL *folderLocation;
|
||||||
NSString *sql;
|
NSString *sql;
|
||||||
|
|
||||||
|
if ([[self container] hasLocalSubFolderNamed: newName])
|
||||||
|
[NSException raise: NSInvalidArgumentException
|
||||||
|
format: @"That name already exists"];
|
||||||
|
|
||||||
cm = [GCSChannelManager defaultChannelManager];
|
cm = [GCSChannelManager defaultChannelManager];
|
||||||
folderLocation
|
folderLocation = [[GCSFolderManager defaultFolderManager] folderInfoLocation];
|
||||||
= [[GCSFolderManager defaultFolderManager] folderInfoLocation];
|
|
||||||
fc = [cm acquireOpenChannelForURL: folderLocation];
|
fc = [cm acquireOpenChannelForURL: folderLocation];
|
||||||
if (fc)
|
if (fc)
|
||||||
{
|
{
|
||||||
#warning GDLContentStore should provide methods for renaming folders
|
#warning GDLContentStore should provide methods for renaming folders
|
||||||
sql
|
sql = [NSString stringWithFormat: (@"UPDATE %@ SET c_foldername = '%@'"
|
||||||
= [NSString stringWithFormat: (@"UPDATE %@ SET c_foldername = '%@'"
|
|
||||||
@" WHERE c_path = '%@'"),
|
@" WHERE c_path = '%@'"),
|
||||||
[folderLocation gcsTableName],
|
[folderLocation gcsTableName],
|
||||||
[newName stringByReplacingString: @"'" withString: @"''"],
|
[newName stringByReplacingString: @"'" withString: @"''"],
|
||||||
|
|
|
@ -289,9 +289,19 @@
|
||||||
if ([folderName length] > 0)
|
if ([folderName length] > 0)
|
||||||
{
|
{
|
||||||
clientObject = [self clientObject];
|
clientObject = [self clientObject];
|
||||||
|
NS_DURING
|
||||||
|
{
|
||||||
[clientObject renameTo: folderName];
|
[clientObject renameTo: folderName];
|
||||||
response = [self responseWith204];
|
response = [self responseWith204];
|
||||||
}
|
}
|
||||||
|
NS_HANDLER
|
||||||
|
{
|
||||||
|
message = [NSDictionary dictionaryWithObject: [localException reason] forKey: @"message"];
|
||||||
|
response = [self responseWithStatus: 409 /* Conflict */
|
||||||
|
andString: [message jsonRepresentation]];
|
||||||
|
}
|
||||||
|
NS_ENDHANDLER;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
message = [NSDictionary dictionaryWithObject: @"Missing name parameter" forKey: @"message"];
|
message = [NSDictionary dictionaryWithObject: @"Missing name parameter" forKey: @"message"];
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* UIxContactFolderProperties.m - this file is part of SOGo
|
/* UIxContactFolderProperties.m - this file is part of SOGo
|
||||||
*
|
*
|
||||||
* Copyright (C) 2015 Inverse inc.
|
* Copyright (C) 2015-2018 Inverse inc.
|
||||||
*
|
*
|
||||||
* This file is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -21,8 +21,10 @@
|
||||||
#import <Foundation/NSDictionary.h>
|
#import <Foundation/NSDictionary.h>
|
||||||
#import <Foundation/NSValue.h>
|
#import <Foundation/NSValue.h>
|
||||||
|
|
||||||
|
#import <NGObjWeb/NSException+HTTP.h>
|
||||||
#import <NGObjWeb/WORequest.h>
|
#import <NGObjWeb/WORequest.h>
|
||||||
|
|
||||||
|
#import <SOGo/NSDictionary+Utilities.h>
|
||||||
#import <SOGo/NSString+Utilities.h>
|
#import <SOGo/NSString+Utilities.h>
|
||||||
|
|
||||||
#import <Contacts/SOGoContactGCSFolder.h>
|
#import <Contacts/SOGoContactGCSFolder.h>
|
||||||
|
@ -59,12 +61,16 @@
|
||||||
- (WOResponse *) savePropertiesAction
|
- (WOResponse *) savePropertiesAction
|
||||||
{
|
{
|
||||||
WORequest *request;
|
WORequest *request;
|
||||||
NSDictionary *params;
|
WOResponse *response;
|
||||||
|
NSDictionary *params, *message;
|
||||||
id o;
|
id o;
|
||||||
|
|
||||||
request = [context request];
|
request = [context request];
|
||||||
params = [[request contentAsString] objectFromJSONString];
|
params = [[request contentAsString] objectFromJSONString];
|
||||||
|
response = [self responseWith204];
|
||||||
|
|
||||||
|
NS_DURING
|
||||||
|
{
|
||||||
o = [params objectForKey: @"name"];
|
o = [params objectForKey: @"name"];
|
||||||
if ([o isKindOfClass: [NSString class]])
|
if ([o isKindOfClass: [NSString class]])
|
||||||
[addressbook renameTo: o];
|
[addressbook renameTo: o];
|
||||||
|
@ -72,8 +78,17 @@
|
||||||
o = [params objectForKey: @"synchronize"];
|
o = [params objectForKey: @"synchronize"];
|
||||||
if ([o isKindOfClass: [NSNumber class]])
|
if ([o isKindOfClass: [NSNumber class]])
|
||||||
[addressbook setSynchronize: [o boolValue]];
|
[addressbook setSynchronize: [o boolValue]];
|
||||||
|
}
|
||||||
|
NS_HANDLER
|
||||||
|
{
|
||||||
|
message = [NSDictionary dictionaryWithObject: [localException reason] forKey: @"message"];
|
||||||
|
response = [self responseWithStatus: 400 /* Bad Request */
|
||||||
|
andString: [message jsonRepresentation]];
|
||||||
|
|
||||||
return [self responseWith204];
|
}
|
||||||
|
NS_ENDHANDLER;
|
||||||
|
|
||||||
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -581,15 +581,16 @@
|
||||||
* @returns a promise of the HTTP operation
|
* @returns a promise of the HTTP operation
|
||||||
*/
|
*/
|
||||||
AddressBook.prototype.$rename = function(name) {
|
AddressBook.prototype.$rename = function(name) {
|
||||||
var i, list;
|
var _this = this, i, list;
|
||||||
|
|
||||||
list = this.isSubscription? AddressBook.$subscriptions : AddressBook.$addressbooks;
|
list = this.isSubscription? AddressBook.$subscriptions : AddressBook.$addressbooks;
|
||||||
i = _.indexOf(_.map(list, 'id'), this.id);
|
i = _.indexOf(_.map(list, 'id'), this.id);
|
||||||
this.name = name;
|
|
||||||
list.splice(i, 1);
|
|
||||||
AddressBook.$add(this);
|
|
||||||
|
|
||||||
return this.$save();
|
return this.$save().then(function() {
|
||||||
|
list.splice(i, 1);
|
||||||
|
_this.name = name;
|
||||||
|
AddressBook.$add(_this);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
vm.edit = edit;
|
vm.edit = edit;
|
||||||
vm.revertEditing = revertEditing;
|
vm.revertEditing = revertEditing;
|
||||||
vm.save = save;
|
vm.save = save;
|
||||||
|
vm.saving = false;
|
||||||
vm.confirmDelete = confirmDelete;
|
vm.confirmDelete = confirmDelete;
|
||||||
vm.importCards = importCards;
|
vm.importCards = importCards;
|
||||||
vm.showLinks = showLinks;
|
vm.showLinks = showLinks;
|
||||||
|
@ -98,13 +99,18 @@
|
||||||
|
|
||||||
function save(folder) {
|
function save(folder) {
|
||||||
var name = folder.name;
|
var name = folder.name;
|
||||||
if (name && name.length > 0) {
|
if (!vm.saving && name && name.length > 0) {
|
||||||
if (name != vm.originalAddressbook.name) {
|
if (name != vm.originalAddressbook.name) {
|
||||||
|
vm.saving = true;
|
||||||
folder.$rename(name)
|
folder.$rename(name)
|
||||||
.then(function(data) {
|
.then(function(data) {
|
||||||
vm.editMode = false;
|
vm.editMode = false;
|
||||||
}, function(data, status) {
|
}, function() {
|
||||||
Dialog.alert(l('Warning'), data);
|
revertEditing(folder);
|
||||||
|
vm.editMode = folder.id;
|
||||||
|
})
|
||||||
|
.finally(function() {
|
||||||
|
vm.saving = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -498,18 +498,20 @@
|
||||||
* @returns a promise of the HTTP operation
|
* @returns a promise of the HTTP operation
|
||||||
*/
|
*/
|
||||||
Calendar.prototype.$save = function() {
|
Calendar.prototype.$save = function() {
|
||||||
var _this = this;
|
var _this = this,
|
||||||
|
d = Calendar.$q.defer();
|
||||||
|
|
||||||
return Calendar.$$resource.save(this.id, this.$omit()).then(function(data) {
|
Calendar.$$resource.save(this.id, this.$omit()).then(function(data) {
|
||||||
// Make a copy of the data for an eventual reset
|
// Make a copy of the data for an eventual reset
|
||||||
_this.$shadowData = _this.$omit();
|
_this.$shadowData = _this.$omit();
|
||||||
return data;
|
return d.resolve(data);
|
||||||
}, function(data) {
|
}, function(data) {
|
||||||
Calendar.$log.error(JSON.stringify(data, undefined, 2));
|
|
||||||
// Restore previous version
|
// Restore previous version
|
||||||
_this.$reset();
|
_this.$reset();
|
||||||
return data;
|
return d.reject(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return d.promise;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -87,7 +87,7 @@
|
||||||
this.inputElement.value = this.calendar.name;
|
this.inputElement.value = this.calendar.name;
|
||||||
this.clickableElement.classList.add('ng-hide');
|
this.clickableElement.classList.add('ng-hide');
|
||||||
this.inputContainer.classList.remove('ng-hide');
|
this.inputContainer.classList.remove('ng-hide');
|
||||||
if ($event.srcEvent.type == 'touchend') {
|
if ($event.srcEvent && $event.srcEvent.type == 'touchend') {
|
||||||
$timeout(function() {
|
$timeout(function() {
|
||||||
$ctrl.inputElement.focus();
|
$ctrl.inputElement.focus();
|
||||||
$ctrl.inputElement.select();
|
$ctrl.inputElement.select();
|
||||||
|
@ -115,6 +115,12 @@
|
||||||
$ctrl.inputContainer.classList.add('ng-hide');
|
$ctrl.inputContainer.classList.add('ng-hide');
|
||||||
$ctrl.clickableElement.classList.remove('ng-hide');
|
$ctrl.clickableElement.classList.remove('ng-hide');
|
||||||
$ctrl.updateCalendarName();
|
$ctrl.updateCalendarName();
|
||||||
|
}, function() {
|
||||||
|
$ctrl.editMode = true;
|
||||||
|
$timeout(function() {
|
||||||
|
$ctrl.inputElement.focus();
|
||||||
|
$ctrl.inputElement.select();
|
||||||
|
}, 200); // delayed focus for iOS
|
||||||
})
|
})
|
||||||
.finally(function() {
|
.finally(function() {
|
||||||
$ctrl.inputElement.disabled = false;
|
$ctrl.inputElement.disabled = false;
|
||||||
|
|
Loading…
Reference in New Issue