(feat) warn when double-booking attendees and offer force save option

This commit is contained in:
Ludovic Marcotte
2016-02-11 10:54:07 -05:00
parent 9cc4bfd9be
commit d7b010526b
13 changed files with 218 additions and 192 deletions
+1
View File
@@ -13,6 +13,7 @@ Enhancements
- [web] now supports RFC6154 and NoInferiors IMAP flag
- [web] improved confirm dialogs for deletions
- [web] allow resources to prevent invitations (#3410)
- [web] warn when double-booking attendees and offer force save option
Bug fixes
- [web] handle birthday dates before 1970
@@ -1,5 +1,5 @@
/*
Copyright (C) 2007-2014 Inverse inc.
Copyright (C) 2007-2016 Inverse inc.
This file is part of SOGo
+168 -128
View File
@@ -1,6 +1,5 @@
/*
Copyright (C) 2007-2015 Inverse inc.
Copyright (C) 2004-2005 SKYRIX Software AG
Copyright (C) 2007-2016 Inverse inc.
This file is part of SOGo
@@ -55,6 +54,7 @@
#import <SOGo/NSDictionary+Utilities.h>
#import <SOGo/NSObject+DAV.h>
#import <SOGo/NSString+Utilities.h>
#import <SOGo/SOGoDateFormatter.h>
#import <SOGo/SOGoObject.h>
#import <SOGo/SOGoPermissions.h>
#import <SOGo/SOGoGroup.h>
@@ -415,8 +415,8 @@
}
// This method scans the list of attendees.
- (NSException *) _handleAttendeeAvailability: (NSArray *) theAttendees
forEvent: (iCalEvent *) theEvent
- (NSException *) _handleAttendeesAvailability: (NSArray *) theAttendees
forEvent: (iCalEvent *) theEvent
{
iCalPerson *currentAttendee;
SOGoUser *user;
@@ -496,20 +496,20 @@
//
// This methods scans the list of attendees. If they are
// considered as resource, it checks for conflicting
// dates for the event.
// dates for the event and potentially auto-accept/decline
// the invitation.
//
// For normal attendees, it'll return an exception with
// conflicting dates, unless we force the save.//
// We check for between startDate + 1 second and
// endDate - 1 second
//
//
// It also CHANGES the participation status of resources
// depending on constraints defined on them.
//
// Note that it doesn't matter if it changes the participation
// status since in case of an error, nothing will get saved.
//
- (NSException *) _handleResourcesConflicts: (NSArray *) theAttendees
- (NSException *) _handleAttendeesConflicts: (NSArray *) theAttendees
forEvent: (iCalEvent *) theEvent
force: (BOOL) forceSave
{
iCalPerson *currentAttendee;
NSMutableArray *attendees;
@@ -540,110 +540,115 @@
enumerator = [attendees objectEnumerator];
while ((currentUID = [enumerator nextObject]))
{
NSCalendarDate *start, *end, *rangeStartDate, *rangeEndDate;
SOGoAppointmentFolder *folder;
NGCalendarDateRange *range;
NSMutableArray *fbInfo;
NSArray *allOccurences;
BOOL must_delete;
int i, j, delta;
user = [SOGoUser userWithLogin: currentUID];
if ([user isResource])
// We get the start/end date for our conflict range. If the event to be added is recurring, we
// check for at least a year to start with.
start = [[theEvent startDate] dateByAddingYears: 0 months: 0 days: 0 hours: 0 minutes: 0 seconds: 1];
end = [[theEvent endDate] dateByAddingYears: ([theEvent isRecurrent] ? 1 : 0) months: 0 days: 0 hours: 0 minutes: 0 seconds: -1];
folder = [user personalCalendarFolderInContext: context];
// Deny access to the resource if the ACLs don't allow the user
if (![folder aclSQLListingFilter])
{
NSCalendarDate *start, *end, *rangeStartDate, *rangeEndDate;
SOGoAppointmentFolder *folder;
NGCalendarDateRange *range;
NSMutableArray *fbInfo;
NSArray *allOccurences;
BOOL must_delete;
int i, j, delta;
// We get the start/end date for our conflict range. If the event to be added is recurring, we
// check for at least a year to start with.
start = [[theEvent startDate] dateByAddingYears: 0 months: 0 days: 0 hours: 0 minutes: 0 seconds: 1];
end = [[theEvent endDate] dateByAddingYears: ([theEvent isRecurrent] ? 1 : 0) months: 0 days: 0 hours: 0 minutes: 0 seconds: -1];
folder = [user personalCalendarFolderInContext: context];
// Deny access to the resource if the ACLs don't allow the user
if (![folder aclSQLListingFilter])
{
NSDictionary *values;
NSString *reason;
NSDictionary *values;
NSString *reason;
values = [NSDictionary dictionaryWithObjectsAndKeys:
[user cn], @"Cn",
[user systemEmail], @"SystemEmail"];
reason = [values keysWithFormat: [self labelForKey: @"Cannot access resource: \"%{Cn} %{SystemEmail}\""]];
return [NSException exceptionWithHTTPStatus:403 reason: reason];
}
values = [NSDictionary dictionaryWithObjectsAndKeys:
[user cn], @"Cn",
[user systemEmail], @"SystemEmail"];
reason = [values keysWithFormat: [self labelForKey: @"Cannot access resource: \"%{Cn} %{SystemEmail}\""]];
return [NSException exceptionWithHTTPStatus:403 reason: reason];
}
fbInfo = [NSMutableArray arrayWithArray: [folder fetchFreeBusyInfosFrom: start
fbInfo = [NSMutableArray arrayWithArray: [folder fetchFreeBusyInfosFrom: start
to: end]];
// We first remove any occurences in the freebusy that corresponds to the
// current event. We do this to avoid raising a conflict if we move a 1 hour
// meeting from 12:00-13:00 to 12:15-13:15. We would overlap on ourself otherwise.
//
// We must also check here for repetitive events that don't overlap our event.
// We remove all events that don't overlap. The events here are already
// decomposed.
//
if ([theEvent isRecurrent])
allOccurences = [theEvent recurrenceRangesWithinCalendarDateRange: [NGCalendarDateRange calendarDateRangeWithStartDate: start
endDate: end]
firstInstanceCalendarDateRange: [NGCalendarDateRange calendarDateRangeWithStartDate: [theEvent startDate]
endDate: [theEvent endDate]]];
else
allOccurences = nil;
for (i = [fbInfo count]-1; i >= 0; i--)
// We first remove any occurences in the freebusy that corresponds to the
// current event. We do this to avoid raising a conflict if we move a 1 hour
// meeting from 12:00-13:00 to 12:15-13:15. We would overlap on ourself otherwise.
//
// We must also check here for repetitive events that don't overlap our event.
// We remove all events that don't overlap. The events here are already
// decomposed.
//
if ([theEvent isRecurrent])
allOccurences = [theEvent recurrenceRangesWithinCalendarDateRange: [NGCalendarDateRange calendarDateRangeWithStartDate: start
endDate: end]
firstInstanceCalendarDateRange: [NGCalendarDateRange calendarDateRangeWithStartDate: [theEvent startDate]
endDate: [theEvent endDate]]];
else
allOccurences = nil;
for (i = [fbInfo count]-1; i >= 0; i--)
{
// We MUST use the -uniqueChildWithTag method here because the event has been flattened, so its timezone has been
// modified in SOGoAppointmentFolder: -fixupCycleRecord: ....
rangeStartDate = [[fbInfo objectAtIndex: i] objectForKey: @"startDate"];
delta = [[rangeStartDate timeZoneDetail] timeZoneSecondsFromGMT] - [[[(iCalDateTime *)[theEvent uniqueChildWithTag: @"dtstart"] timeZone] periodForDate: [theEvent startDate]] secondsOffsetFromGMT];
rangeStartDate = [rangeStartDate dateByAddingYears: 0 months: 0 days: 0 hours: 0 minutes: 0 seconds: delta];
rangeEndDate = [[fbInfo objectAtIndex: i] objectForKey: @"endDate"];
delta = [[rangeEndDate timeZoneDetail] timeZoneSecondsFromGMT] - [[[(iCalDateTime *)[theEvent uniqueChildWithTag: @"dtend"] timeZone] periodForDate: [theEvent endDate]] secondsOffsetFromGMT];
rangeEndDate = [rangeEndDate dateByAddingYears: 0 months: 0 days: 0 hours: 0 minutes: 0 seconds: delta];
range = [NGCalendarDateRange calendarDateRangeWithStartDate: rangeStartDate
endDate: rangeEndDate];
// We remove the freebusy entries corresponding to the actual event being modified
if ([[[fbInfo objectAtIndex: i] objectForKey: @"c_uid"] compare: [theEvent uid]] == NSOrderedSame)
{
// We MUST use the -uniqueChildWithTag method here because the event has been flattened, so its timezone has been
// modified in SOGoAppointmentFolder: -fixupCycleRecord: ....
rangeStartDate = [[fbInfo objectAtIndex: i] objectForKey: @"startDate"];
delta = [[rangeStartDate timeZoneDetail] timeZoneSecondsFromGMT] - [[[(iCalDateTime *)[theEvent uniqueChildWithTag: @"dtstart"] timeZone] periodForDate: [theEvent startDate]] secondsOffsetFromGMT];
rangeStartDate = [rangeStartDate dateByAddingYears: 0 months: 0 days: 0 hours: 0 minutes: 0 seconds: delta];
rangeEndDate = [[fbInfo objectAtIndex: i] objectForKey: @"endDate"];
delta = [[rangeEndDate timeZoneDetail] timeZoneSecondsFromGMT] - [[[(iCalDateTime *)[theEvent uniqueChildWithTag: @"dtend"] timeZone] periodForDate: [theEvent endDate]] secondsOffsetFromGMT];
rangeEndDate = [rangeEndDate dateByAddingYears: 0 months: 0 days: 0 hours: 0 minutes: 0 seconds: delta];
range = [NGCalendarDateRange calendarDateRangeWithStartDate: rangeStartDate
endDate: rangeEndDate];
[fbInfo removeObjectAtIndex: i];
continue;
}
if ([[[fbInfo objectAtIndex: i] objectForKey: @"c_uid"] compare: [theEvent uid]] == NSOrderedSame)
// No need to check if the event isn't recurrent here as it's handled correctly
// when we compute the "end" date.
if ([allOccurences count])
{
must_delete = YES;
for (j = 0; j < [allOccurences count]; j++)
{
[fbInfo removeObjectAtIndex: i];
continue;
}
// No need to check if the event isn't recurrent here as it's handled correctly
// when we compute the "end" date.
if ([allOccurences count])
{
must_delete = YES;
for (j = 0; j < [allOccurences count]; j++)
if ([range doesIntersectWithDateRange: [allOccurences objectAtIndex: j]])
{
if ([range doesIntersectWithDateRange: [allOccurences objectAtIndex: j]])
{
must_delete = NO;
break;
}
must_delete = NO;
break;
}
if (must_delete)
[fbInfo removeObjectAtIndex: i];
}
if (must_delete)
[fbInfo removeObjectAtIndex: i];
}
}
// Find the attendee associated to the current UID
for (i = 0; i < [theAttendees count]; i++)
{
currentAttendee = [theAttendees objectAtIndex: i];
if ([[currentAttendee uidInContext: context] isEqualToString: currentUID])
break;
else
currentAttendee = nil;
}
if ([fbInfo count])
{
SOGoDateFormatter *formatter;
formatter = [[context activeUser] dateFormatterInContext: context];
// Find the attendee associated to the current UID
for (i = 0; i < [theAttendees count]; i++)
{
currentAttendee = [theAttendees objectAtIndex: i];
if ([[currentAttendee uidInContext: context] isEqualToString: currentUID])
break;
else
currentAttendee = nil;
}
if ([fbInfo count])
if ([user isResource])
{
// If we always force the auto-accept if numberOfSimultaneousBookings <= 0 (ie., no limit
// is imposed) or if numberOfSimultaneousBookings is greater than the number of
@@ -663,35 +668,63 @@
NSDictionary *values;
NSString *reason;
iCalEvent *event;
calendar = [iCalCalendar parseSingleFromSource: [[fbInfo objectAtIndex: 0] objectForKey: @"c_content"]];
event = [[calendar events] lastObject];
values = [NSDictionary dictionaryWithObjectsAndKeys:
[NSString stringWithFormat: @"%d", [user numberOfSimultaneousBookings]], @"NumberOfSimultaneousBookings",
[user cn], @"Cn",
[user systemEmail], @"SystemEmail",
([event summary] ? [event summary] : @""), @"EventTitle",
[[fbInfo objectAtIndex: 0] objectForKey: @"startDate"], @"StartDate",
nil];
[NSString stringWithFormat: @"%d", [user numberOfSimultaneousBookings]], @"NumberOfSimultaneousBookings",
[user cn], @"Cn",
[user systemEmail], @"SystemEmail",
([event summary] ? [event summary] : @""), @"EventTitle",
[formatter formattedDateAndTime: [[fbInfo objectAtIndex: 0] objectForKey: @"startDate"]], @"StartDate",
nil];
reason = [values keysWithFormat: [self labelForKey: @"Maximum number of simultaneous bookings (%{NumberOfSimultaneousBookings}) reached for resource \"%{Cn} %{SystemEmail}\". The conflicting event is \"%{EventTitle}\", and starts on %{StartDate}."]];
return [NSException exceptionWithHTTPStatus: 403
reason: reason];
}
}
else if (currentAttendee)
//
// We are dealing with a normal attendee. Lets check if we have conflicts, unless
// we are being asked to force the save anyway
//
else if (!forceSave)
{
// No conflict, we auto-accept. We do this for resources automatically if no
// double-booking is observed. If it's not the desired behavior, just don't
// set the resource as one!
[[currentAttendee attributes] removeObjectForKey: @"RSVP"];
[currentAttendee setParticipationStatus: iCalPersonPartStatAccepted];
NSMutableDictionary *info;
NSMutableArray *conflicts;
id o;
info = [NSMutableDictionary dictionary];
conflicts = [NSMutableArray array];
[info setObject: [currentAttendee cn] forKey: @"attendee_name"];
[info setObject: [currentAttendee rfc822Email] forKey: @"attendee_email"];
for (i = 0; i < [fbInfo count]; i++)
{
o = [fbInfo objectAtIndex: i];
[conflicts addObject: [NSDictionary dictionaryWithObjectsAndKeys: [formatter formattedDateAndTime: [o objectForKey: @"startDate"]], @"startDate",
[formatter formattedDateAndTime: [o objectForKey: @"endDate"]], @"endDate", nil]];
}
[info setObject: conflicts forKey: @"conflicts"];
return [NSException exceptionWithHTTPStatus: 403
reason: [info jsonRepresentation]];
}
} // if ([fbInfo count]) ...
else if (currentAttendee && [user isResource])
{
// No conflict, we auto-accept. We do this for resources automatically if no
// double-booking is observed. If it's not the desired behavior, just don't
// set the resource as one!
[[currentAttendee attributes] removeObjectForKey: @"RSVP"];
[currentAttendee setParticipationStatus: iCalPersonPartStatAccepted];
}
}
} // if ([user isResource]) ...
return nil;
}
@@ -700,6 +733,7 @@
//
- (NSException *) _handleAddedUsers: (NSArray *) attendees
fromEvent: (iCalEvent *) newEvent
force: (BOOL) forceSave
{
iCalPerson *currentAttendee;
NSEnumerator *enumerator;
@@ -707,9 +741,9 @@
NSException *e;
// We check for conflicts
if ((e = [self _handleResourcesConflicts: attendees forEvent: newEvent]))
if ((e = [self _handleAttendeesConflicts: attendees forEvent: newEvent force: forceSave]))
return e;
if ((e = [self _handleAttendeeAvailability: attendees forEvent: newEvent]))
if ((e = [self _handleAttendeesAvailability: attendees forEvent: newEvent]))
return e;
enumerator = [attendees objectEnumerator];
@@ -765,6 +799,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
//
- (NSException *) _handleUpdatedEvent: (iCalEvent *) newEvent
fromOldEvent: (iCalEvent *) oldEvent
force: (BOOL) forceSave
{
NSArray *addedAttendees, *deletedAttendees, *updatedAttendees;
iCalEventChanges *changes;
@@ -804,9 +839,9 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
withType: @"calendar:cancellation"];
}
if ((ex = [self _handleResourcesConflicts: [newEvent attendees] forEvent: newEvent]))
if ((ex = [self _handleAttendeesConflicts: [newEvent attendees] forEvent: newEvent force: forceSave]))
return ex;
if ((ex = [self _handleAttendeeAvailability: [newEvent attendees] forEvent: newEvent]))
if ((ex = [self _handleAttendeesAvailability: [newEvent attendees] forEvent: newEvent]))
return ex;
addedAttendees = [changes insertedAttendees];
@@ -855,7 +890,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
if ([addedAttendees count])
{
// Send an invitation to new attendees
if ((ex = [self _handleAddedUsers: addedAttendees fromEvent: newEvent]))
if ((ex = [self _handleAddedUsers: addedAttendees fromEvent: newEvent force: forceSave]))
return ex;
[self sendEMailUsingTemplateNamed: @"Invitation"
@@ -900,6 +935,12 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
//
//
- (NSException *) saveComponent: (iCalEvent *) newEvent
{
return [self saveComponent: newEvent force: NO];
}
- (NSException *) saveComponent: (iCalEvent *) newEvent
force: (BOOL) forceSave
{
iCalEvent *oldEvent, *oldMasterEvent;
NSCalendarDate *recurrenceId;
@@ -924,7 +965,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
// We catch conflicts and abort the save process immediately
// in case of one with resources
if ((ex = [self _handleAddedUsers: attendees fromEvent: newEvent]))
if ((ex = [self _handleAddedUsers: attendees fromEvent: newEvent force: forceSave]))
return ex;
if ([attendees count])
@@ -967,7 +1008,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
if (!hasOrganizer || [oldMasterEvent userIsOrganizer: ownerUser])
// The owner is the organizer of the event; handle the modifications. We aslo
// catch conflicts just like when the events are created
if ((ex = [self _handleUpdatedEvent: newEvent fromOldEvent: oldEvent]))
if ((ex = [self _handleUpdatedEvent: newEvent fromOldEvent: oldEvent force: forceSave]))
return ex;
}
@@ -1604,7 +1645,6 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
currentUser = [context activeUser];
attendees = [occurence attendeesWithoutUser: currentUser];
#warning Make sure this is correct ..
if (![attendees count] && event != occurence)
attendees = [event attendeesWithoutUser: currentUser];
@@ -2007,7 +2047,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
attendees = [event attendeesWithoutUser: ownerUser];
if ([attendees count])
{
if ((ex = [self _handleAddedUsers: attendees fromEvent: event]))
if ((ex = [self _handleAddedUsers: attendees fromEvent: event force: YES]))
return ex;
else
{
@@ -2159,7 +2199,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
if (!newEvent && oldEvent)
[self prepareDeleteOccurence: oldEvent];
// The master event was changed, A RECCURENCE-ID was added or modified
else if ((ex = [self _handleUpdatedEvent: newEvent fromOldEvent: oldEvent]))
else if ((ex = [self _handleUpdatedEvent: newEvent fromOldEvent: oldEvent force: YES]))
return ex;
}
//
@@ -61,7 +61,8 @@
- (void) updateComponent: (iCalRepeatableEntityObject *) newObject;
- (NSException *) saveCalendar: (iCalCalendar *) newCalendar;
- (NSException *) saveComponent: (iCalRepeatableEntityObject *) newObject;
- (NSException *) saveComponent: (iCalRepeatableEntityObject *) newEvent
force: (BOOL) forceSave;
/* mail notifications */
- (void) sendEMailUsingTemplateNamed: (NSString *) pageName
forObject: (iCalRepeatableEntityObject *) object
@@ -685,6 +685,12 @@
return [self saveCalendar: [newObject parent]];
}
- (NSException *) saveComponent: (iCalRepeatableEntityObject *) newEvent
force: (BOOL) forceSave
{
return [self saveComponent: newEvent];
}
/* raw saving */
/* EMail Notifications */
+1 -21
View File
@@ -1,7 +1,5 @@
/*
Copyright (C) 2006-2014 Inverse inc.
Copyright (C) 2004-2005 SKYRIX Software AG
Copyright (C) 2006-2014-2016 Inverse inc.
This file is part of SOGo.
@@ -26,24 +24,6 @@
#import "SOGoCalendarComponent.h"
/*
SOGoTaskObject
Represents a single task. This SOPE controller object manages all the
attendee storages (that is, it might store into multiple folders for meeting
tasks!).
Note: SOGoTaskObject do not need to exist yet. They can also be "new"
tasks with an externally generated unique key.
*/
@class NSArray;
@class NSException;
@class NSString;
@class iCalToDo;
@class iCalCalendar;
@interface SOGoTaskObject : SOGoCalendarComponent
@end
+1 -2
View File
@@ -1,6 +1,5 @@
/*
Copyright (C) 2006-2014 Inverse inc.
Copyright (C) 2004-2005 SKYRIX Software AG
Copyright (C) 2006-2014-2016 Inverse inc.
This file is part of SOGo.
+4 -19
View File
@@ -1,14 +1,14 @@
/*
Copyright (C) 2004 SKYRIX Software AG
Copyright (C) 2005-2016 Inverse inc.
This file is part of OpenGroupware.org.
This file is part of SOGo.
OGo is free software; you can redistribute it and/or modify it under
SOGo is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
OGo is distributed in the hope that it will be useful, but WITHOUT ANY
SOGo is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
@@ -48,21 +48,6 @@
- (NSString *) stringForObjectValue: (id) date;
// - (void) setFullWeekdayNameAndDetails;
// - (NSString *) date: (NSCalendarDate *) date
// withFormat: (unsigned int) format;
// - (NSString *) date: (NSCalendarDate *) date
// withNSFormat: (NSNumber *) format;
// - (NSString *) shortDayOfWeek: (int)_day;
// - (NSString *) fullDayOfWeek: (int)_day;
// - (NSString *) shortMonthOfYear: (int)_month;
// - (NSString *) fullMonthOfYear: (int)_month;
// - (NSString *) fullWeekdayNameAndDetailsForDate: (NSCalendarDate *)_date;
@end
#endif /* __SOGoDateFormatter_H_ */
+5 -5
View File
@@ -1,14 +1,14 @@
/*
Copyright (C) 2004 SKYRIX Software AG
Copyright (C) 2005-2016 Inverse inc.
This file is part of OpenGroupware.org.
This file is part of SOGo.
OGo is free software; you can redistribute it and/or modify it under
SOGo is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
OGo is distributed in the hope that it will be useful, but WITHOUT ANY
SOGo is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
@@ -21,7 +21,7 @@
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSUserDefaults.h> /* for NSXXXFormatString, ... */
#import <Foundation/NSUserDefaults.h>
#import "SOGoDateFormatter.h"
+1 -3
View File
@@ -1,8 +1,6 @@
/* UIxAppointmentActions.h - this file is part of SOGo
*
* Copyright (C) 2010 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Copyright (C) 2010-2016 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
+16 -6
View File
@@ -1,8 +1,6 @@
/* UIxAppointmentActions.m - this file is part of SOGo
*
* Copyright (C) 2011-2014 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Copyright (C) 2011-2016 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
@@ -69,6 +67,7 @@
NSException *ex;
SOGoAppointmentFolder *targetCalendar, *sourceCalendar;
SOGoAppointmentFolders *folders;
BOOL forceSave;
rq = [context request];
params = [[rq contentAsString] objectFromJSONString];
@@ -77,6 +76,7 @@
startDelta = [params objectForKey: @"start"];
durationDelta = [params objectForKey: @"duration"];
destionationCalendar = [params objectForKey: @"destination"];
forceSave = NO;
if (daysDelta || startDelta || durationDelta)
{
@@ -120,7 +120,8 @@
[event updateRecurrenceRulesUntilDate: end];
[event setLastModified: [NSCalendarDate calendarDate]];
ex = [co saveComponent: event];
ex = [co saveComponent: event force: forceSave];
// This condition will be executed only if the event is moved from a calendar to another. If destionationCalendar == 0; there is no calendar change
if ([destionationCalendar length] > 0)
{
@@ -139,12 +140,21 @@
ex = [co moveToFolder: targetCalendar];
}
}
if (ex)
{
unsigned int httpStatus;
httpStatus = 500;
if ([ex respondsToSelect: @selector(httpStatus)])
httpStatus = [ex httpStatus];
jsonResponse = [NSDictionary dictionaryWithObjectsAndKeys:
[ex reason], @"message",
[ex reason], @"message",
nil];
response = [self responseWithStatus: 403
response = [self responseWithStatus: httpStatus
andJSONRepresentation: jsonResponse];
}
else
+1 -1
View File
@@ -1,6 +1,6 @@
/* UIxAppointmentEditor.h - this file is part of SOGo
*
* Copyright (C) 2007-2015 Inverse inc.
* Copyright (C) 2007-2016 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
+11 -5
View File
@@ -1,6 +1,6 @@
/* UIxAppointmentEditor.m - this file is part of SOGo
*
* Copyright (C) 2007-2015 Inverse inc.
* Copyright (C) 2007-2016 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
@@ -467,7 +467,9 @@
SOGoAppointmentObject *co;
SoSecurityManager *sm;
WORequest *request;
unsigned int httpStatus;
BOOL forceSave;
event = [self event];
co = [self clientObject];
@@ -488,6 +490,7 @@
else
{
[self setAttributes: params];
forceSave = NO;
if ([event hasRecurrenceRules])
[self _adjustRecurrentRules];
@@ -511,12 +514,12 @@
}
// Save the event.
ex = [co saveComponent: event];
ex = [co saveComponent: event force: forceSave];
}
else
{
// The event was modified -- save it.
ex = [co saveComponent: event];
ex = [co saveComponent: event force: forceSave];
if (componentCalendar
&& ![[componentCalendar ocsPath]
@@ -539,9 +542,12 @@
if (ex)
{
httpStatus = 500;
if ([ex respondsToSelect: @selector(httpStatus)])
httpStatus = [ex httpStatus];
jsonResponse = [NSDictionary dictionaryWithObjectsAndKeys:
@"failure", @"status",
[ex reason], @"message",
[ex reason], @"message",
nil];
}
else