diff --git a/SoObjects/SOGo/SOGoGCSFolder.m b/SoObjects/SOGo/SOGoGCSFolder.m index bd60c49b2..362b9d32c 100644 --- a/SoObjects/SOGo/SOGoGCSFolder.m +++ b/SoObjects/SOGo/SOGoGCSFolder.m @@ -614,19 +614,21 @@ static NSArray *childRecordFields = nil; NSURL *folderLocation; NSString *sql; + if ([[self container] hasLocalSubFolderNamed: newName]) + [NSException raise: NSInvalidArgumentException + format: @"That name already exists"]; + cm = [GCSChannelManager defaultChannelManager]; - folderLocation - = [[GCSFolderManager defaultFolderManager] folderInfoLocation]; + folderLocation = [[GCSFolderManager defaultFolderManager] folderInfoLocation]; fc = [cm acquireOpenChannelForURL: folderLocation]; if (fc) { #warning GDLContentStore should provide methods for renaming folders - sql - = [NSString stringWithFormat: (@"UPDATE %@ SET c_foldername = '%@'" - @" WHERE c_path = '%@'"), - [folderLocation gcsTableName], - [newName stringByReplacingString: @"'" withString: @"''"], - ocsPath]; + sql = [NSString stringWithFormat: (@"UPDATE %@ SET c_foldername = '%@'" + @" WHERE c_path = '%@'"), + [folderLocation gcsTableName], + [newName stringByReplacingString: @"'" withString: @"''"], + ocsPath]; [fc evaluateExpressionX: sql]; [cm releaseChannel: fc]; // sql = [sql stringByAppendingFormat:@" WHERE %@ = '%@'", diff --git a/UI/Common/UIxFolderActions.m b/UI/Common/UIxFolderActions.m index 034413c8d..3f3a23612 100644 --- a/UI/Common/UIxFolderActions.m +++ b/UI/Common/UIxFolderActions.m @@ -289,8 +289,18 @@ if ([folderName length] > 0) { clientObject = [self clientObject]; - [clientObject renameTo: folderName]; - response = [self responseWith204]; + NS_DURING + { + [clientObject renameTo: folderName]; + response = [self responseWith204]; + } + NS_HANDLER + { + message = [NSDictionary dictionaryWithObject: [localException reason] forKey: @"message"]; + response = [self responseWithStatus: 409 /* Conflict */ + andString: [message jsonRepresentation]]; + } + NS_ENDHANDLER; } else { diff --git a/UI/Contacts/UIxContactFolderProperties.m b/UI/Contacts/UIxContactFolderProperties.m index 2adcecb82..8d99ea2ca 100644 --- a/UI/Contacts/UIxContactFolderProperties.m +++ b/UI/Contacts/UIxContactFolderProperties.m @@ -1,6 +1,6 @@ /* 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 * it under the terms of the GNU General Public License as published by @@ -21,8 +21,10 @@ #import #import +#import #import +#import #import #import @@ -59,21 +61,34 @@ - (WOResponse *) savePropertiesAction { WORequest *request; - NSDictionary *params; + WOResponse *response; + NSDictionary *params, *message; id o; request = [context request]; params = [[request contentAsString] objectFromJSONString]; + response = [self responseWith204]; - o = [params objectForKey: @"name"]; - if ([o isKindOfClass: [NSString class]]) - [addressbook renameTo: o]; + NS_DURING + { + o = [params objectForKey: @"name"]; + if ([o isKindOfClass: [NSString class]]) + [addressbook renameTo: o]; - o = [params objectForKey: @"synchronize"]; - if ([o isKindOfClass: [NSNumber class]]) - [addressbook setSynchronize: [o boolValue]]; + o = [params objectForKey: @"synchronize"]; + if ([o isKindOfClass: [NSNumber class]]) + [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 diff --git a/UI/WebServerResources/js/Contacts/AddressBook.service.js b/UI/WebServerResources/js/Contacts/AddressBook.service.js index fe4578f32..e6ec70221 100644 --- a/UI/WebServerResources/js/Contacts/AddressBook.service.js +++ b/UI/WebServerResources/js/Contacts/AddressBook.service.js @@ -581,15 +581,16 @@ * @returns a promise of the HTTP operation */ AddressBook.prototype.$rename = function(name) { - var i, list; + var _this = this, i, list; list = this.isSubscription? AddressBook.$subscriptions : AddressBook.$addressbooks; 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); + }); }; /** diff --git a/UI/WebServerResources/js/Contacts/AddressBooksController.js b/UI/WebServerResources/js/Contacts/AddressBooksController.js index 959de1f1f..0cfaee4cb 100644 --- a/UI/WebServerResources/js/Contacts/AddressBooksController.js +++ b/UI/WebServerResources/js/Contacts/AddressBooksController.js @@ -17,6 +17,7 @@ vm.edit = edit; vm.revertEditing = revertEditing; vm.save = save; + vm.saving = false; vm.confirmDelete = confirmDelete; vm.importCards = importCards; vm.showLinks = showLinks; @@ -98,13 +99,18 @@ function save(folder) { var name = folder.name; - if (name && name.length > 0) { + if (!vm.saving && name && name.length > 0) { if (name != vm.originalAddressbook.name) { + vm.saving = true; folder.$rename(name) .then(function(data) { vm.editMode = false; - }, function(data, status) { - Dialog.alert(l('Warning'), data); + }, function() { + revertEditing(folder); + vm.editMode = folder.id; + }) + .finally(function() { + vm.saving = false; }); } else { diff --git a/UI/WebServerResources/js/Scheduler/Calendar.service.js b/UI/WebServerResources/js/Scheduler/Calendar.service.js index 5fc3c2313..e5b25f8b8 100644 --- a/UI/WebServerResources/js/Scheduler/Calendar.service.js +++ b/UI/WebServerResources/js/Scheduler/Calendar.service.js @@ -498,18 +498,20 @@ * @returns a promise of the HTTP operation */ 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 _this.$shadowData = _this.$omit(); - return data; + return d.resolve(data); }, function(data) { - Calendar.$log.error(JSON.stringify(data, undefined, 2)); // Restore previous version _this.$reset(); - return data; + return d.reject(data); }); + + return d.promise; }; /** diff --git a/UI/WebServerResources/js/Scheduler/sgCalendarListItem.directive.js b/UI/WebServerResources/js/Scheduler/sgCalendarListItem.directive.js index 25acf4c65..6f1f69531 100644 --- a/UI/WebServerResources/js/Scheduler/sgCalendarListItem.directive.js +++ b/UI/WebServerResources/js/Scheduler/sgCalendarListItem.directive.js @@ -87,7 +87,7 @@ this.inputElement.value = this.calendar.name; this.clickableElement.classList.add('ng-hide'); this.inputContainer.classList.remove('ng-hide'); - if ($event.srcEvent.type == 'touchend') { + if ($event.srcEvent && $event.srcEvent.type == 'touchend') { $timeout(function() { $ctrl.inputElement.focus(); $ctrl.inputElement.select(); @@ -115,6 +115,12 @@ $ctrl.inputContainer.classList.add('ng-hide'); $ctrl.clickableElement.classList.remove('ng-hide'); $ctrl.updateCalendarName(); + }, function() { + $ctrl.editMode = true; + $timeout(function() { + $ctrl.inputElement.focus(); + $ctrl.inputElement.select(); + }, 200); // delayed focus for iOS }) .finally(function() { $ctrl.inputElement.disabled = false;