mirror of
https://github.com/inverse-inc/sogo.git
synced 2026-08-28 17:57:38 +00:00
See ChangeLog
Monotone-Parent: be9e28d5d42ed05605b27d2127cf29b07678495b Monotone-Revision: 5de6a9584cf27a2c1dad8d1ab8b84fc9ddab2720 Monotone-Author: ludovic@Sophos.ca Monotone-Date: 2011-04-25T10:31:08 Monotone-Branch: ca.inverse.sogo
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
Copyright (C) 2007-2011 Inverse inc.
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
This file is part of SOGo
|
||||
|
||||
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
|
||||
@@ -42,6 +42,7 @@
|
||||
|
||||
#import <SOGo/SOGoUserManager.h>
|
||||
#import <SOGo/NSArray+Utilities.h>
|
||||
#import <SOGo/NSDictionary+Utilities.h>
|
||||
#import <SOGo/NSObject+DAV.h>
|
||||
#import <SOGo/SOGoObject.h>
|
||||
#import <SOGo/SOGoPermissions.h>
|
||||
@@ -198,7 +199,6 @@
|
||||
// We check if the attendee that was added to a single occurence is
|
||||
// present in the master component. If not, we add it with a participation
|
||||
// status set to "DECLINED".
|
||||
|
||||
user = [SOGoUser userWithLogin: theUID];
|
||||
person = [iCalPerson elementWithTag: @"attendee"];
|
||||
[person setCn: [user cn]];
|
||||
@@ -425,14 +425,117 @@
|
||||
}
|
||||
|
||||
//
|
||||
// This methods scans the list of attendees. If they are
|
||||
// considered as resource, it checks for conflicting
|
||||
// dates for the event.
|
||||
//
|
||||
// We check for between startDate + 1 second and
|
||||
// endDate - 1 second
|
||||
//
|
||||
//
|
||||
- (void) _handleAddedUsers: (NSArray *) attendees
|
||||
fromEvent: (iCalEvent *) newEvent
|
||||
// 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
|
||||
forEvent: (iCalEvent *) theEvent
|
||||
{
|
||||
NSEnumerator *enumerator;
|
||||
iCalPerson *currentAttendee;
|
||||
NSEnumerator *enumerator;
|
||||
NSString *currentUID;
|
||||
SOGoUser *user;
|
||||
|
||||
enumerator = [theAttendees objectEnumerator];
|
||||
|
||||
while ((currentAttendee = [enumerator nextObject]))
|
||||
{
|
||||
currentUID = [currentAttendee uid];
|
||||
|
||||
if (currentUID)
|
||||
{
|
||||
user = [SOGoUser userWithLogin: currentUID];
|
||||
|
||||
if ([user isResource])
|
||||
{
|
||||
SOGoAppointmentFolder *folder;
|
||||
NSCalendarDate *start, *end;
|
||||
NSMutableArray *fbInfo;
|
||||
int i;
|
||||
|
||||
start = [[theEvent startDate] dateByAddingYears: 0 months: 0 days: 0 hours: 0 minutes: 0 seconds: 1];
|
||||
end = [[theEvent endDate] dateByAddingYears: 0 months: 0 days: 0 hours: 0 minutes: 0 seconds: -1];
|
||||
|
||||
folder = [[SOGoUser userWithLogin: currentUID]
|
||||
personalCalendarFolderInContext: context];
|
||||
|
||||
|
||||
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.
|
||||
for (i = [fbInfo count]-1; i >= 0; i--)
|
||||
{
|
||||
if ([[[fbInfo objectAtIndex: i] objectForKey: @"c_uid"] compare: [theEvent uid]] == NSOrderedSame)
|
||||
[fbInfo removeObjectAtIndex: i];
|
||||
}
|
||||
|
||||
if ([fbInfo count])
|
||||
{
|
||||
// If we always force the auto-accept if numberOfSimultaneousBookings == 0 (ie., no limit
|
||||
// is imposed) or if numberOfSimultaneousBookings is greater than the number of
|
||||
// overlapping events
|
||||
if ([user numberOfSimultaneousBookings] == 0 ||
|
||||
[user numberOfSimultaneousBookings] > [fbInfo count])
|
||||
[currentAttendee setParticipationStatus: iCalPersonPartStatAccepted];
|
||||
else
|
||||
{
|
||||
NSDictionary *values;
|
||||
NSString *reason;
|
||||
|
||||
values = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
[NSString stringWithFormat: @"%d", [user numberOfSimultaneousBookings]], @"NumberOfSimultaneousBookings",
|
||||
[user cn], @"Cn",
|
||||
[user systemEmail], @"SystemEmail",
|
||||
nil];
|
||||
|
||||
reason = [values keysWithFormat: [self labelForKey: @"Maximum number of simultaneous bookings (%{NumberOfSimultaneousBookings}) reached for resource \"%{Cn} %{SystemEmail}\"."]];
|
||||
|
||||
return [NSException exceptionWithHTTPStatus:403
|
||||
reason: reason];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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 setParticipationStatus: iCalPersonPartStatAccepted];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
- (NSException *) _handleAddedUsers: (NSArray *) attendees
|
||||
fromEvent: (iCalEvent *) newEvent
|
||||
{
|
||||
iCalPerson *currentAttendee;
|
||||
NSEnumerator *enumerator;
|
||||
NSString *currentUID;
|
||||
NSException *e;
|
||||
|
||||
// We check for conflicts
|
||||
if ((e = [self _handleResourcesConflicts: attendees forEvent: newEvent]))
|
||||
return e;
|
||||
|
||||
enumerator = [attendees objectEnumerator];
|
||||
while ((currentAttendee = [enumerator nextObject]))
|
||||
@@ -443,25 +546,31 @@
|
||||
forUID: currentUID
|
||||
owner: owner];
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
- (void) _handleUpdatedEvent: (iCalEvent *) newEvent
|
||||
fromOldEvent: (iCalEvent *) oldEvent
|
||||
- (NSException *) _handleUpdatedEvent: (iCalEvent *) newEvent
|
||||
fromOldEvent: (iCalEvent *) oldEvent
|
||||
{
|
||||
NSArray *attendees;
|
||||
iCalEventChanges *changes;
|
||||
NSArray *attendees;
|
||||
NSException *ex;
|
||||
|
||||
changes = [newEvent getChangesRelativeToEvent: oldEvent];
|
||||
if ([changes sequenceShouldBeIncreased])
|
||||
{
|
||||
// Set new attendees status to "needs action" and recompute changes when
|
||||
// the list of attendees has changed.
|
||||
// the list of attendees has changed. The list might have changed since
|
||||
// by changing a major property of the event, we remove all the delegation
|
||||
// chains to "other" attendees
|
||||
if ([self _requireResponseFromAttendees: newEvent])
|
||||
changes = [newEvent getChangesRelativeToEvent: oldEvent];
|
||||
}
|
||||
|
||||
attendees = [changes deletedAttendees];
|
||||
if ([attendees count])
|
||||
{
|
||||
@@ -475,6 +584,10 @@
|
||||
forObject: newEvent to: attendees];
|
||||
}
|
||||
|
||||
if ((ex = [self _handleResourcesConflicts: [newEvent attendees]
|
||||
forEvent: newEvent]))
|
||||
return ex;
|
||||
|
||||
attendees = [changes insertedAttendees];
|
||||
if ([changes sequenceShouldBeIncreased])
|
||||
{
|
||||
@@ -516,7 +629,9 @@
|
||||
if ([attendees count])
|
||||
{
|
||||
// Send an invitation to new attendees
|
||||
[self _handleAddedUsers: attendees fromEvent: newEvent];
|
||||
if ((ex = [self _handleAddedUsers: attendees fromEvent: newEvent]))
|
||||
return ex;
|
||||
|
||||
[self sendEMailUsingTemplateNamed: @"Invitation"
|
||||
forObject: [newEvent itipEntryWithMethod: @"request"]
|
||||
previousObject: oldEvent
|
||||
@@ -524,6 +639,8 @@
|
||||
[self sendReceiptEmailUsingTemplateNamed: @"Invitation"
|
||||
forObject: newEvent to: attendees];
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -551,14 +668,15 @@
|
||||
// _updateAttendee:withDelegate:ownerUser:forEventUID:withRecurrenceId:withSequence:forUID:shouldAddSentBy:
|
||||
//
|
||||
//
|
||||
- (void) saveComponent: (iCalEvent *) newEvent
|
||||
- (NSException *) saveComponent: (iCalEvent *) newEvent
|
||||
{
|
||||
iCalEvent *oldEvent, *oldMasterEvent;
|
||||
NSArray *attendees;
|
||||
NSCalendarDate *recurrenceId;
|
||||
NSString *recurrenceTime;
|
||||
SOGoUser *ownerUser;
|
||||
|
||||
NSArray *attendees;
|
||||
NSException *ex;
|
||||
|
||||
[[newEvent parent] setMethod: @""];
|
||||
ownerUser = [SOGoUser userWithLogin: owner];
|
||||
|
||||
@@ -574,7 +692,11 @@
|
||||
attendees = [newEvent attendeesWithoutUser: ownerUser];
|
||||
if ([attendees count])
|
||||
{
|
||||
[self _handleAddedUsers: attendees fromEvent: newEvent];
|
||||
// We catch conflicts and abort the save process immediately
|
||||
// in case of one with resources
|
||||
if ((ex = [self _handleAddedUsers: attendees fromEvent: newEvent]))
|
||||
return ex;
|
||||
|
||||
[self sendEMailUsingTemplateNamed: @"Invitation"
|
||||
forObject: [newEvent itipEntryWithMethod: @"request"]
|
||||
previousObject: nil
|
||||
@@ -586,6 +708,7 @@
|
||||
else
|
||||
{
|
||||
BOOL hasOrganizer;
|
||||
|
||||
// Event is modified -- sent update status to all attendees
|
||||
// and modify their calendars.
|
||||
recurrenceId = [newEvent recurrenceId];
|
||||
@@ -606,8 +729,10 @@
|
||||
hasOrganizer = [[[oldMasterEvent organizer] email] length];
|
||||
|
||||
if (!hasOrganizer || [oldMasterEvent userIsOrganizer: ownerUser])
|
||||
// The owner is the organizer of the event; handle the modifications
|
||||
[self _handleUpdatedEvent: newEvent fromOldEvent: oldEvent];
|
||||
// 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]))
|
||||
return ex;
|
||||
}
|
||||
|
||||
[super saveComponent: newEvent];
|
||||
@@ -618,6 +743,8 @@
|
||||
safeCalendar = nil;
|
||||
[originalCalendar release];
|
||||
originalCalendar = nil;
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -1479,6 +1606,7 @@
|
||||
//
|
||||
- (id) PUTAction: (WOContext *) _ctx
|
||||
{
|
||||
NSException *ex;
|
||||
NSArray *roles;
|
||||
WORequest *rq;
|
||||
id response;
|
||||
@@ -1540,7 +1668,9 @@
|
||||
attendees = [event attendeesWithoutUser: ownerUser];
|
||||
if ([attendees count])
|
||||
{
|
||||
[self _handleAddedUsers: attendees fromEvent: event];
|
||||
if ((ex = [self _handleAddedUsers: attendees fromEvent: event]))
|
||||
return ex;
|
||||
|
||||
[self sendEMailUsingTemplateNamed: @"Invitation"
|
||||
forObject: [event itipEntryWithMethod: @"request"]
|
||||
previousObject: nil
|
||||
@@ -1680,8 +1810,9 @@
|
||||
|
||||
if ([uid caseInsensitiveCompare: owner] == NSOrderedSame)
|
||||
{
|
||||
[self _handleUpdatedEvent: newEvent fromOldEvent: oldEvent];
|
||||
|
||||
if ((ex = [self _handleUpdatedEvent: newEvent fromOldEvent: oldEvent]))
|
||||
return ex;
|
||||
|
||||
// A RECURRENCE-ID was removed so there has to be a change in the master event
|
||||
// We could also have an EXDATE added in the master component of the attendees
|
||||
// so we always compare the MASTER event.
|
||||
|
||||
Reference in New Issue
Block a user