From 49f1c30e77c9c715aa82298f2028c1cb07c5dd5e Mon Sep 17 00:00:00 2001 From: Ludovic Marcotte Date: Thu, 24 Mar 2016 14:53:27 -0400 Subject: [PATCH] (feat) now able to copy/move events and also duplicate them (fixes #3196) --- .../Appointments/SOGoCalendarComponent.m | 53 ++++++---- UI/Scheduler/UIxAppointmentActions.m | 96 +++++++++++-------- UI/Scheduler/product.plist | 7 +- .../UIxAppointmentViewTemplate.wox | 35 +++++++ .../js/Scheduler/Component.service.js | 22 +++++ .../js/Scheduler/ComponentController.js | 17 ++++ 6 files changed, 174 insertions(+), 56 deletions(-) diff --git a/SoObjects/Appointments/SOGoCalendarComponent.m b/SoObjects/Appointments/SOGoCalendarComponent.m index 7478d1239..6d12c78d9 100644 --- a/SoObjects/Appointments/SOGoCalendarComponent.m +++ b/SoObjects/Appointments/SOGoCalendarComponent.m @@ -1235,6 +1235,36 @@ return uids; } +- (NSException *) _copyComponent: (iCalCalendar *) calendar + toFolder: (SOGoGCSFolder *) newFolder + updateUID: (BOOL) updateUID +{ + NSString *newUID; + SOGoCalendarComponent *newComponent; + + if (updateUID) + { + NSArray *elements; + unsigned int count, max; + + newUID = [self globallyUniqueObjectId]; + elements = [calendar allObjects]; + max = [elements count]; + for (count = 0; count < max; count++) + [[elements objectAtIndex: count] setUid: newUID]; + } + else + { + newUID = [[[calendar events] objectAtIndex: 0] uid]; + } + + newComponent = [[self class] objectWithName: + [NSString stringWithFormat: @"%@.ics", newUID] + inContainer: newFolder]; + + return [newComponent saveCalendar: calendar]; +} + - (NSException *) copyToFolder: (SOGoGCSFolder *) newFolder { return [self copyComponent: [self calendar: NO secure: NO] @@ -1244,29 +1274,18 @@ - (NSException *) copyComponent: (iCalCalendar *) calendar toFolder: (SOGoGCSFolder *) newFolder { - NSArray *elements; - NSString *newUID; - unsigned int count, max; - SOGoCalendarComponent *newComponent; - - newUID = [self globallyUniqueObjectId]; - elements = [calendar allObjects]; - max = [elements count]; - for (count = 0; count < max; count++) - [[elements objectAtIndex: count] setUid: newUID]; - - newComponent = [[self class] objectWithName: - [NSString stringWithFormat: @"%@.ics", newUID] - inContainer: newFolder]; - - return [newComponent saveCalendar: calendar]; + return [self _copyComponent: calendar + toFolder: newFolder + updateUID: YES]; } - (NSException *) moveToFolder: (SOGoGCSFolder *) newFolder { NSException *ex; - ex = [self copyToFolder: newFolder]; + ex = [self _copyComponent: [self calendar: NO secure: NO] + toFolder: newFolder + updateUID: NO]; if (!ex) ex = [self delete]; diff --git a/UI/Scheduler/UIxAppointmentActions.m b/UI/Scheduler/UIxAppointmentActions.m index b6791fac6..cd47098c7 100644 --- a/UI/Scheduler/UIxAppointmentActions.m +++ b/UI/Scheduler/UIxAppointmentActions.m @@ -172,21 +172,21 @@ return response; } -- (WOResponse *) copyAction +- (WOResponse *) _copyOrMoveAction: (BOOL) moving { - NSString *destination; - NSArray *events; - iCalCalendar *calendar; - iCalRepeatableEntityObject *masterOccurence; - SOGoAppointmentObject *thisEvent; SOGoAppointmentFolder *sourceCalendar, *destinationCalendar; + SOGoAppointmentObject *thisEvent; + iCalCalendar *calendar; + NSString *destination; SoSecurityManager *sm; + NSDictionary *params; WOResponse *response; WORequest *rq; rq = [context request]; + params = [[rq contentAsString] objectFromJSONString]; + destination = [params objectForKey: @"destination"]; - destination = [rq formValueForKey: @"destination"]; if (![destination length]) destination = @"personal"; @@ -206,40 +206,50 @@ response = [NSException exceptionWithHTTPStatus: 403 reason: @"Can't add event to destination calendar."]; } - // Verify that the destination calendar is not the source calendar - else if ([[destinationCalendar nameInContainer] isEqualToString: [sourceCalendar nameInContainer]]) - { - response = [NSException exceptionWithHTTPStatus: 400 - reason: @"Destination calendar is the source calendar."]; - } else { - // Remove attendees, recurrence exceptions and single occurences from the event - calendar = [thisEvent calendar: NO secure: NO]; - events = [calendar events]; - masterOccurence = [events objectAtIndex: 0]; - - if ([masterOccurence hasAlarms]) - [masterOccurence removeAllAlarms]; - if ([masterOccurence hasRecurrenceRules]) - { - [masterOccurence removeAllExceptionRules]; - [masterOccurence removeAllExceptionDates]; - } - if ([[masterOccurence attendees] count] > 0) - { - [masterOccurence setOrganizer: nil]; - [masterOccurence removeAllAttendees]; - } - [calendar setUniqueChild: masterOccurence]; + calendar = [thisEvent calendar: NO secure: NO]; - // Perform the copy - if ([thisEvent copyComponent: calendar - toFolder: (SOGoGCSFolder *) destinationCalendar]) - response = [NSException exceptionWithHTTPStatus: 500 - reason: @"Can't copy event to destination calendar."]; - else - response = [self responseWith204]; + if (moving) + { + // Perform the move + if ([thisEvent moveToFolder: (SOGoGCSFolder *) destinationCalendar]) + response = [NSException exceptionWithHTTPStatus: 500 + reason: @"Can't move event to destination calendar."]; + else + response = [self responseWith204]; + } + else + { + iCalRepeatableEntityObject *masterOccurence; + NSArray *events; + + // Remove attendees, recurrence exceptions and single occurences from the event + events = [calendar events]; + masterOccurence = [events objectAtIndex: 0]; + + if ([masterOccurence hasAlarms]) + [masterOccurence removeAllAlarms]; + if ([masterOccurence hasRecurrenceRules]) + { + [masterOccurence removeAllExceptionRules]; + [masterOccurence removeAllExceptionDates]; + } + if ([[masterOccurence attendees] count] > 0) + { + [masterOccurence setOrganizer: nil]; + [masterOccurence removeAllAttendees]; + } + [calendar setUniqueChild: masterOccurence]; + + // Perform the copy + if ([thisEvent copyComponent: calendar + toFolder: (SOGoGCSFolder *) destinationCalendar]) + response = [NSException exceptionWithHTTPStatus: 500 + reason: @"Can't copy event to destination calendar."]; + else + response = [self responseWith204]; + } } } else @@ -251,4 +261,14 @@ return response; } +- (WOResponse *) copyAction +{ + return [self _copyOrMoveAction: NO]; +} + +- (WOResponse *) moveAction +{ + return [self _copyOrMoveAction: YES]; +} + @end diff --git a/UI/Scheduler/product.plist b/UI/Scheduler/product.plist index 4a344f2e9..eed817146 100644 --- a/UI/Scheduler/product.plist +++ b/UI/Scheduler/product.plist @@ -269,9 +269,14 @@ }; copy = { protectedBy = "ViewAllComponent"; - actionClass = "UIxAppointmentActions"; + actionClass = "UIxAppointmentActions"; actionName = "copy"; }; + move = { + protectedBy = "ViewAllComponent"; + actionClass = "UIxAppointmentActions"; + actionName = "move"; + }; raw = { protectedBy = "ViewAllComponent"; actionClass = "UIxAppointmentEditor"; diff --git a/UI/Templates/SchedulerUI/UIxAppointmentViewTemplate.wox b/UI/Templates/SchedulerUI/UIxAppointmentViewTemplate.wox index 82e05b960..7ae62c4bd 100644 --- a/UI/Templates/SchedulerUI/UIxAppointmentViewTemplate.wox +++ b/UI/Templates/SchedulerUI/UIxAppointmentViewTemplate.wox @@ -28,6 +28,41 @@ + + + + + + +
+ + + {{calendar.name}} + + +
+
+
+
+ + + + + + +
+ + + {{calendar.name}} + + +
+
+
+
diff --git a/UI/WebServerResources/js/Scheduler/Component.service.js b/UI/WebServerResources/js/Scheduler/Component.service.js index 1f3669988..734cb3e36 100644 --- a/UI/WebServerResources/js/Scheduler/Component.service.js +++ b/UI/WebServerResources/js/Scheduler/Component.service.js @@ -1229,6 +1229,28 @@ return localizedString; }; + /** + * @function copyTo + * @memberof Component.prototype + * @desc Copy an event to a calendar + * @param {string} calendar - a target calendar UID + * @returns a promise of the HTTP operation + */ + Component.prototype.copyTo = function(calendar) { + return Component.$$resource.post(this.pid + '/' + this.id, 'copy', {destination: calendar}); + }; + + /** + * @function moveTo + * @memberof Component.prototype + * @desc Move an event to a calendar + * @param {string} calendar - a target calendar UID + * @returns a promise of the HTTP operation + */ + Component.prototype.moveTo = function(calendar) { + return Component.$$resource.post(this.pid + '/' + this.id, 'move', {destination: calendar}); + }; + Component.prototype.toString = function() { return '[Component ' + this.id + ']'; }; diff --git a/UI/WebServerResources/js/Scheduler/ComponentController.js b/UI/WebServerResources/js/Scheduler/ComponentController.js index d57443d54..022a7ef61 100644 --- a/UI/WebServerResources/js/Scheduler/ComponentController.js +++ b/UI/WebServerResources/js/Scheduler/ComponentController.js @@ -10,6 +10,7 @@ function ComponentController($rootScope, $mdDialog, Calendar, Component, AddressBook, Alarm, stateComponent) { var vm = this, component; + vm.calendarService = Calendar; vm.service = Component; vm.component = stateComponent; vm.close = close; @@ -21,6 +22,8 @@ vm.deleteOccurrence = deleteOccurrence; vm.deleteAllOccurrences = deleteAllOccurrences; vm.toggleRawSource = toggleRawSource; + vm.copySelectedComponent = copySelectedComponent; + vm.moveSelectedComponent = moveSelectedComponent; // Load all attributes of component if (angular.isUndefined(vm.component.$futureComponentData)) { @@ -141,6 +144,20 @@ } }); } + + function copySelectedComponent(calendar) { + vm.component.copyTo(calendar).then(function() { + $mdDialog.hide(); + $rootScope.$emit('calendars:list'); + }); + } + + function moveSelectedComponent(calendar) { + vm.component.moveTo(calendar).then(function() { + $mdDialog.hide(); + $rootScope.$emit('calendars:list'); + }); + } } /**