See ChangeLog
Monotone-Parent: be9e28d5d42ed05605b27d2127cf29b07678495b Monotone-Revision: 5de6a9584cf27a2c1dad8d1ab8b84fc9ddab2720 Monotone-Author: ludovic@Sophos.ca Monotone-Date: 2011-04-25T10:31:08 Monotone-Branch: ca.inverse.sogomaint-2.0.2
parent
326d376e6d
commit
12856abe4d
|
@ -1,3 +1,10 @@
|
||||||
|
2011-04-25 Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||||
|
|
||||||
|
* Added the concept of "resources" in SOGo in order
|
||||||
|
to avoid double-bookings (if not more) and also, handle
|
||||||
|
auto-accepts. This works for the web interface and
|
||||||
|
over DAV - generating 403 errors in case of a conflict.
|
||||||
|
|
||||||
2011-04-21 Ludovic Marcotte <lmarcotte@inverse.ca>
|
2011-04-21 Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||||
|
|
||||||
* Added the possibility of translating IMAP namespaces
|
* Added the possibility of translating IMAP namespaces
|
||||||
|
|
|
@ -60,3 +60,6 @@ vtodo_class2 = "(Confidential task)";
|
||||||
= "%{Attendee} %{SentByText}has delegated the invitation to %{Delegate}.";
|
= "%{Attendee} %{SentByText}has delegated the invitation to %{Delegate}.";
|
||||||
"%{Attendee} %{SentByText}has not yet decided upon your event invitation."
|
"%{Attendee} %{SentByText}has not yet decided upon your event invitation."
|
||||||
= "%{Attendee} %{SentByText}has not yet decided upon your event invitation.";
|
= "%{Attendee} %{SentByText}has not yet decided upon your event invitation.";
|
||||||
|
|
||||||
|
/* Resources */
|
||||||
|
"Maximum number of simultaneous bookings (%{NumberOfSimultaneousBookings}) reached for resource \"%{Cn} %{SystemEmail}\"." = "Maximum number of simultaneous bookings (%{NumberOfSimultaneousBookings}) reached for resource \"%{Cn} %{SystemEmail}\".";
|
|
@ -60,3 +60,6 @@ vtodo_class2 = "(Tâche confidentielle)";
|
||||||
= "%{Attendee} %{SentByText}a délégué votre invitation à %{Delegate}.";
|
= "%{Attendee} %{SentByText}a délégué votre invitation à %{Delegate}.";
|
||||||
"%{Attendee} %{SentByText}has not yet decided upon your event invitation."
|
"%{Attendee} %{SentByText}has not yet decided upon your event invitation."
|
||||||
= "%{Attendee} %{SentByText}choisit de reporter sa décision par rapport à votre invitation.";
|
= "%{Attendee} %{SentByText}choisit de reporter sa décision par rapport à votre invitation.";
|
||||||
|
|
||||||
|
/* Resources */
|
||||||
|
"Maximum number of simultaneous bookings (%{NumberOfSimultaneousBookings}) reached for resource \"%{Cn} %{SystemEmail}\"." = "Le nombre maximum (%{NumberOfSimultaneousBookings}) de réservation(s) simultanée(s) a été atteint pour la ressource \"%{Cn} %{SystemEmail}\".";
|
|
@ -2,14 +2,14 @@
|
||||||
Copyright (C) 2007-2011 Inverse inc.
|
Copyright (C) 2007-2011 Inverse inc.
|
||||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||||
|
|
||||||
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
|
the terms of the GNU Lesser General Public License as published by the
|
||||||
Free Software Foundation; either version 2, or (at your option) any
|
Free Software Foundation; either version 2, or (at your option) any
|
||||||
later version.
|
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
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||||
License for more details.
|
License for more details.
|
||||||
|
@ -623,6 +623,9 @@ static NSNumber *sharedYes = nil;
|
||||||
return record;
|
return record;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
- (NSArray *) fixupRecords: (NSArray *) theRecords
|
- (NSArray *) fixupRecords: (NSArray *) theRecords
|
||||||
{
|
{
|
||||||
// TODO: is the result supposed to be sorted by date?
|
// TODO: is the result supposed to be sorted by date?
|
||||||
|
@ -802,6 +805,9 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
|
||||||
[self _fixExceptionRecord: newRecord fromRow: row];
|
[self _fixExceptionRecord: newRecord fromRow: row];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
- (void) _appendCycleExceptionsFromRow: (NSDictionary *) row
|
- (void) _appendCycleExceptionsFromRow: (NSDictionary *) row
|
||||||
firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
|
firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
|
||||||
forRange: (NGCalendarDateRange *) dateRange
|
forRange: (NGCalendarDateRange *) dateRange
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
Copyright (C) 2007-2011 Inverse inc.
|
||||||
Copyright (C) 2007-2010 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
|
the terms of the GNU Lesser General Public License as published by the
|
||||||
Free Software Foundation; either version 2, or (at your option) any
|
Free Software Foundation; either version 2, or (at your option) any
|
||||||
later version.
|
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
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||||
License for more details.
|
License for more details.
|
||||||
|
@ -25,17 +24,6 @@
|
||||||
|
|
||||||
#import <SOGo/SOGoContentObject.h>
|
#import <SOGo/SOGoContentObject.h>
|
||||||
|
|
||||||
/*
|
|
||||||
SOGoAppointmentObject
|
|
||||||
|
|
||||||
Represents a single appointment. This SOPE controller object manages all the
|
|
||||||
attendee storages (that is, it might store into multiple folders for meeting
|
|
||||||
appointments!).
|
|
||||||
|
|
||||||
Note: SOGoAppointmentObject do not need to exist yet. They can also be "new"
|
|
||||||
appointments with an externally generated unique key.
|
|
||||||
*/
|
|
||||||
|
|
||||||
@class NSArray;
|
@class NSArray;
|
||||||
@class NSException;
|
@class NSException;
|
||||||
@class NSString;
|
@class NSString;
|
||||||
|
@ -61,13 +49,6 @@
|
||||||
- (NSArray *) postCalDAVEventReplyTo: (NSArray *) recipients from: (NSString *) originator;
|
- (NSArray *) postCalDAVEventReplyTo: (NSArray *) recipients from: (NSString *) originator;
|
||||||
- (NSArray *) postCalDAVEventCancelTo: (NSArray *) recipients from: (NSString *) originator;
|
- (NSArray *) postCalDAVEventCancelTo: (NSArray *) recipients from: (NSString *) originator;
|
||||||
|
|
||||||
/* "iCal multifolder saves" */
|
|
||||||
|
|
||||||
// - (NSException *) saveContentString: (NSString *) _iCal
|
|
||||||
// baseSequence: (int) _v;
|
|
||||||
// - (NSException *) deleteWithBaseSequence: (int) _v;
|
|
||||||
// - (NSException *) saveContentString: (NSString *) _iCalString;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
#endif /* __Appointments_SOGoAppointmentObject_H__ */
|
#endif /* __Appointments_SOGoAppointmentObject_H__ */
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
Copyright (C) 2007-2011 Inverse inc.
|
Copyright (C) 2007-2011 Inverse inc.
|
||||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
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
|
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
|
the terms of the GNU Lesser General Public License as published by the
|
||||||
|
@ -42,6 +42,7 @@
|
||||||
|
|
||||||
#import <SOGo/SOGoUserManager.h>
|
#import <SOGo/SOGoUserManager.h>
|
||||||
#import <SOGo/NSArray+Utilities.h>
|
#import <SOGo/NSArray+Utilities.h>
|
||||||
|
#import <SOGo/NSDictionary+Utilities.h>
|
||||||
#import <SOGo/NSObject+DAV.h>
|
#import <SOGo/NSObject+DAV.h>
|
||||||
#import <SOGo/SOGoObject.h>
|
#import <SOGo/SOGoObject.h>
|
||||||
#import <SOGo/SOGoPermissions.h>
|
#import <SOGo/SOGoPermissions.h>
|
||||||
|
@ -198,7 +199,6 @@
|
||||||
// We check if the attendee that was added to a single occurence is
|
// 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
|
// present in the master component. If not, we add it with a participation
|
||||||
// status set to "DECLINED".
|
// status set to "DECLINED".
|
||||||
|
|
||||||
user = [SOGoUser userWithLogin: theUID];
|
user = [SOGoUser userWithLogin: theUID];
|
||||||
person = [iCalPerson elementWithTag: @"attendee"];
|
person = [iCalPerson elementWithTag: @"attendee"];
|
||||||
[person setCn: [user cn]];
|
[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
|
// It also CHANGES the participation status of resources
|
||||||
fromEvent: (iCalEvent *) newEvent
|
// 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;
|
iCalPerson *currentAttendee;
|
||||||
|
NSEnumerator *enumerator;
|
||||||
NSString *currentUID;
|
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];
|
enumerator = [attendees objectEnumerator];
|
||||||
while ((currentAttendee = [enumerator nextObject]))
|
while ((currentAttendee = [enumerator nextObject]))
|
||||||
|
@ -443,25 +546,31 @@
|
||||||
forUID: currentUID
|
forUID: currentUID
|
||||||
owner: owner];
|
owner: owner];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
- (void) _handleUpdatedEvent: (iCalEvent *) newEvent
|
- (NSException *) _handleUpdatedEvent: (iCalEvent *) newEvent
|
||||||
fromOldEvent: (iCalEvent *) oldEvent
|
fromOldEvent: (iCalEvent *) oldEvent
|
||||||
{
|
{
|
||||||
NSArray *attendees;
|
|
||||||
iCalEventChanges *changes;
|
iCalEventChanges *changes;
|
||||||
|
NSArray *attendees;
|
||||||
|
NSException *ex;
|
||||||
|
|
||||||
changes = [newEvent getChangesRelativeToEvent: oldEvent];
|
changes = [newEvent getChangesRelativeToEvent: oldEvent];
|
||||||
if ([changes sequenceShouldBeIncreased])
|
if ([changes sequenceShouldBeIncreased])
|
||||||
{
|
{
|
||||||
// Set new attendees status to "needs action" and recompute changes when
|
// 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])
|
if ([self _requireResponseFromAttendees: newEvent])
|
||||||
changes = [newEvent getChangesRelativeToEvent: oldEvent];
|
changes = [newEvent getChangesRelativeToEvent: oldEvent];
|
||||||
}
|
}
|
||||||
|
|
||||||
attendees = [changes deletedAttendees];
|
attendees = [changes deletedAttendees];
|
||||||
if ([attendees count])
|
if ([attendees count])
|
||||||
{
|
{
|
||||||
|
@ -475,6 +584,10 @@
|
||||||
forObject: newEvent to: attendees];
|
forObject: newEvent to: attendees];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((ex = [self _handleResourcesConflicts: [newEvent attendees]
|
||||||
|
forEvent: newEvent]))
|
||||||
|
return ex;
|
||||||
|
|
||||||
attendees = [changes insertedAttendees];
|
attendees = [changes insertedAttendees];
|
||||||
if ([changes sequenceShouldBeIncreased])
|
if ([changes sequenceShouldBeIncreased])
|
||||||
{
|
{
|
||||||
|
@ -516,7 +629,9 @@
|
||||||
if ([attendees count])
|
if ([attendees count])
|
||||||
{
|
{
|
||||||
// Send an invitation to new attendees
|
// Send an invitation to new attendees
|
||||||
[self _handleAddedUsers: attendees fromEvent: newEvent];
|
if ((ex = [self _handleAddedUsers: attendees fromEvent: newEvent]))
|
||||||
|
return ex;
|
||||||
|
|
||||||
[self sendEMailUsingTemplateNamed: @"Invitation"
|
[self sendEMailUsingTemplateNamed: @"Invitation"
|
||||||
forObject: [newEvent itipEntryWithMethod: @"request"]
|
forObject: [newEvent itipEntryWithMethod: @"request"]
|
||||||
previousObject: oldEvent
|
previousObject: oldEvent
|
||||||
|
@ -524,6 +639,8 @@
|
||||||
[self sendReceiptEmailUsingTemplateNamed: @"Invitation"
|
[self sendReceiptEmailUsingTemplateNamed: @"Invitation"
|
||||||
forObject: newEvent to: attendees];
|
forObject: newEvent to: attendees];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -551,14 +668,15 @@
|
||||||
// _updateAttendee:withDelegate:ownerUser:forEventUID:withRecurrenceId:withSequence:forUID:shouldAddSentBy:
|
// _updateAttendee:withDelegate:ownerUser:forEventUID:withRecurrenceId:withSequence:forUID:shouldAddSentBy:
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
- (void) saveComponent: (iCalEvent *) newEvent
|
- (NSException *) saveComponent: (iCalEvent *) newEvent
|
||||||
{
|
{
|
||||||
iCalEvent *oldEvent, *oldMasterEvent;
|
iCalEvent *oldEvent, *oldMasterEvent;
|
||||||
NSArray *attendees;
|
|
||||||
NSCalendarDate *recurrenceId;
|
NSCalendarDate *recurrenceId;
|
||||||
NSString *recurrenceTime;
|
NSString *recurrenceTime;
|
||||||
SOGoUser *ownerUser;
|
SOGoUser *ownerUser;
|
||||||
|
NSArray *attendees;
|
||||||
|
NSException *ex;
|
||||||
|
|
||||||
[[newEvent parent] setMethod: @""];
|
[[newEvent parent] setMethod: @""];
|
||||||
ownerUser = [SOGoUser userWithLogin: owner];
|
ownerUser = [SOGoUser userWithLogin: owner];
|
||||||
|
|
||||||
|
@ -574,7 +692,11 @@
|
||||||
attendees = [newEvent attendeesWithoutUser: ownerUser];
|
attendees = [newEvent attendeesWithoutUser: ownerUser];
|
||||||
if ([attendees count])
|
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"
|
[self sendEMailUsingTemplateNamed: @"Invitation"
|
||||||
forObject: [newEvent itipEntryWithMethod: @"request"]
|
forObject: [newEvent itipEntryWithMethod: @"request"]
|
||||||
previousObject: nil
|
previousObject: nil
|
||||||
|
@ -586,6 +708,7 @@
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
BOOL hasOrganizer;
|
BOOL hasOrganizer;
|
||||||
|
|
||||||
// Event is modified -- sent update status to all attendees
|
// Event is modified -- sent update status to all attendees
|
||||||
// and modify their calendars.
|
// and modify their calendars.
|
||||||
recurrenceId = [newEvent recurrenceId];
|
recurrenceId = [newEvent recurrenceId];
|
||||||
|
@ -606,8 +729,10 @@
|
||||||
hasOrganizer = [[[oldMasterEvent organizer] email] length];
|
hasOrganizer = [[[oldMasterEvent organizer] email] length];
|
||||||
|
|
||||||
if (!hasOrganizer || [oldMasterEvent userIsOrganizer: ownerUser])
|
if (!hasOrganizer || [oldMasterEvent userIsOrganizer: ownerUser])
|
||||||
// The owner is the organizer of the event; handle the modifications
|
// The owner is the organizer of the event; handle the modifications. We aslo
|
||||||
[self _handleUpdatedEvent: newEvent fromOldEvent: oldEvent];
|
// catch conflicts just like when the events are created
|
||||||
|
if ((ex = [self _handleUpdatedEvent: newEvent fromOldEvent: oldEvent]))
|
||||||
|
return ex;
|
||||||
}
|
}
|
||||||
|
|
||||||
[super saveComponent: newEvent];
|
[super saveComponent: newEvent];
|
||||||
|
@ -618,6 +743,8 @@
|
||||||
safeCalendar = nil;
|
safeCalendar = nil;
|
||||||
[originalCalendar release];
|
[originalCalendar release];
|
||||||
originalCalendar = nil;
|
originalCalendar = nil;
|
||||||
|
|
||||||
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -1479,6 +1606,7 @@
|
||||||
//
|
//
|
||||||
- (id) PUTAction: (WOContext *) _ctx
|
- (id) PUTAction: (WOContext *) _ctx
|
||||||
{
|
{
|
||||||
|
NSException *ex;
|
||||||
NSArray *roles;
|
NSArray *roles;
|
||||||
WORequest *rq;
|
WORequest *rq;
|
||||||
id response;
|
id response;
|
||||||
|
@ -1540,7 +1668,9 @@
|
||||||
attendees = [event attendeesWithoutUser: ownerUser];
|
attendees = [event attendeesWithoutUser: ownerUser];
|
||||||
if ([attendees count])
|
if ([attendees count])
|
||||||
{
|
{
|
||||||
[self _handleAddedUsers: attendees fromEvent: event];
|
if ((ex = [self _handleAddedUsers: attendees fromEvent: event]))
|
||||||
|
return ex;
|
||||||
|
|
||||||
[self sendEMailUsingTemplateNamed: @"Invitation"
|
[self sendEMailUsingTemplateNamed: @"Invitation"
|
||||||
forObject: [event itipEntryWithMethod: @"request"]
|
forObject: [event itipEntryWithMethod: @"request"]
|
||||||
previousObject: nil
|
previousObject: nil
|
||||||
|
@ -1680,8 +1810,9 @@
|
||||||
|
|
||||||
if ([uid caseInsensitiveCompare: owner] == NSOrderedSame)
|
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
|
// 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
|
// We could also have an EXDATE added in the master component of the attendees
|
||||||
// so we always compare the MASTER event.
|
// so we always compare the MASTER event.
|
||||||
|
|
|
@ -60,7 +60,7 @@
|
||||||
toFolder: (SOGoGCSFolder *) newFolder;
|
toFolder: (SOGoGCSFolder *) newFolder;
|
||||||
|
|
||||||
- (void) updateComponent: (iCalRepeatableEntityObject *) newObject;
|
- (void) updateComponent: (iCalRepeatableEntityObject *) newObject;
|
||||||
- (void) saveComponent: (iCalRepeatableEntityObject *) newObject;
|
- (NSException *) saveComponent: (iCalRepeatableEntityObject *) newObject;
|
||||||
|
|
||||||
/* mail notifications */
|
/* mail notifications */
|
||||||
- (void) sendEMailUsingTemplateNamed: (NSString *) pageName
|
- (void) sendEMailUsingTemplateNamed: (NSString *) pageName
|
||||||
|
|
|
@ -655,13 +655,15 @@ static inline BOOL _occurenceHasID (iCalRepeatableEntityObject *occurence,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) saveComponent: (iCalRepeatableEntityObject *) newObject
|
- (NSException *) saveComponent: (iCalRepeatableEntityObject *) newObject
|
||||||
{
|
{
|
||||||
NSString *newiCalString;
|
NSString *newiCalString;
|
||||||
|
|
||||||
newiCalString = [[newObject parent] versitString];
|
newiCalString = [[newObject parent] versitString];
|
||||||
|
|
||||||
[self saveContentString: newiCalString];
|
[self saveContentString: newiCalString];
|
||||||
|
|
||||||
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* raw saving */
|
/* raw saving */
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
/*
|
/*
|
||||||
|
Copyright (C) 2007-2011 Inverse inc.
|
||||||
Copyright (C) 2000-2004 SKYRIX Software AG
|
Copyright (C) 2000-2004 SKYRIX Software AG
|
||||||
|
|
||||||
This file is part of OGo
|
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
|
the terms of the GNU Lesser General Public License as published by the
|
||||||
Free Software Foundation; either version 2, or (at your option) any
|
Free Software Foundation; either version 2, or (at your option) any
|
||||||
later version.
|
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
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||||
License for more details.
|
License for more details.
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
/*
|
/*
|
||||||
|
Copyright (C) 2007-2011 Inverse inc.
|
||||||
Copyright (C) 2000-2004 SKYRIX Software AG
|
Copyright (C) 2000-2004 SKYRIX Software AG
|
||||||
|
|
||||||
This file is part of OGo
|
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
|
the terms of the GNU Lesser General Public License as published by the
|
||||||
Free Software Foundation; either version 2, or (at your option) any
|
Free Software Foundation; either version 2, or (at your option) any
|
||||||
later version.
|
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
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||||
License for more details.
|
License for more details.
|
||||||
|
|
|
@ -68,6 +68,10 @@
|
||||||
BOOL passwordPolicy;
|
BOOL passwordPolicy;
|
||||||
|
|
||||||
NSMutableDictionary *_dnCache;
|
NSMutableDictionary *_dnCache;
|
||||||
|
|
||||||
|
/* resources handling */
|
||||||
|
NSString *kindField;
|
||||||
|
NSString *multipleBookingsField;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) setBindDN: (NSString *) newBindDN
|
- (void) setBindDN: (NSString *) newBindDN
|
||||||
|
@ -85,7 +89,9 @@
|
||||||
searchFields: (NSArray *) newSearchFields
|
searchFields: (NSArray *) newSearchFields
|
||||||
IMAPHostField: (NSString *) newIMAPHostField
|
IMAPHostField: (NSString *) newIMAPHostField
|
||||||
IMAPLoginField: (NSString *) newIMAPLoginField
|
IMAPLoginField: (NSString *) newIMAPLoginField
|
||||||
andBindFields: (id) newBindFields;
|
bindFields: (id) newBindFields
|
||||||
|
kindField: (NSString *) newKindField
|
||||||
|
andMultipleBookingsField: (NSString *) newMultipleBookingsField;
|
||||||
|
|
||||||
- (NGLdapEntry *) lookupGroupEntryByUID: (NSString *) theUID;
|
- (NGLdapEntry *) lookupGroupEntryByUID: (NSString *) theUID;
|
||||||
- (NGLdapEntry *) lookupGroupEntryByEmail: (NSString *) theEmail;
|
- (NGLdapEntry *) lookupGroupEntryByEmail: (NSString *) theEmail;
|
||||||
|
|
|
@ -170,6 +170,9 @@ static NSArray *commonSearchFields;
|
||||||
searchAttributes = nil;
|
searchAttributes = nil;
|
||||||
passwordPolicy = NO;
|
passwordPolicy = NO;
|
||||||
|
|
||||||
|
kindField = nil;
|
||||||
|
multipleBookingsField = nil;
|
||||||
|
|
||||||
_dnCache = [[NSMutableDictionary alloc] init];
|
_dnCache = [[NSMutableDictionary alloc] init];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,6 +201,8 @@ static NSArray *commonSearchFields;
|
||||||
[searchAttributes release];
|
[searchAttributes release];
|
||||||
[domain release];
|
[domain release];
|
||||||
[_dnCache release];
|
[_dnCache release];
|
||||||
|
[kindField release];
|
||||||
|
[multipleBookingsField release];
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,7 +231,9 @@ static NSArray *commonSearchFields;
|
||||||
searchFields: [udSource objectForKey: @"SearchFieldNames"]
|
searchFields: [udSource objectForKey: @"SearchFieldNames"]
|
||||||
IMAPHostField: [udSource objectForKey: @"IMAPHostFieldName"]
|
IMAPHostField: [udSource objectForKey: @"IMAPHostFieldName"]
|
||||||
IMAPLoginField: [udSource objectForKey: @"IMAPLoginFieldName"]
|
IMAPLoginField: [udSource objectForKey: @"IMAPLoginFieldName"]
|
||||||
andBindFields: [udSource objectForKey: @"bindFields"]];
|
bindFields: [udSource objectForKey: @"bindFields"]
|
||||||
|
kindField: [udSource objectForKey: @"KindFieldName"]
|
||||||
|
andMultipleBookingsField: [udSource objectForKey: @"MultipleBookingsFieldName"]];
|
||||||
|
|
||||||
if ([sourceDomain length])
|
if ([sourceDomain length])
|
||||||
{
|
{
|
||||||
|
@ -309,7 +316,9 @@ static NSArray *commonSearchFields;
|
||||||
searchFields: (NSArray *) newSearchFields
|
searchFields: (NSArray *) newSearchFields
|
||||||
IMAPHostField: (NSString *) newIMAPHostField
|
IMAPHostField: (NSString *) newIMAPHostField
|
||||||
IMAPLoginField: (NSString *) newIMAPLoginField
|
IMAPLoginField: (NSString *) newIMAPLoginField
|
||||||
andBindFields: (id) newBindFields
|
bindFields: (id) newBindFields
|
||||||
|
kindField: (NSString *) newKindField
|
||||||
|
andMultipleBookingsField: (NSString *) newMultipleBookingsField
|
||||||
{
|
{
|
||||||
ASSIGN (baseDN, [newBaseDN lowercaseString]);
|
ASSIGN (baseDN, [newBaseDN lowercaseString]);
|
||||||
if (newIDField)
|
if (newIDField)
|
||||||
|
@ -349,6 +358,10 @@ static NSArray *commonSearchFields;
|
||||||
ASSIGN(bindFields, [newBindFields componentsSeparatedByString: @","]);
|
ASSIGN(bindFields, [newBindFields componentsSeparatedByString: @","]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (newKindField)
|
||||||
|
ASSIGN(kindField, newKindField);
|
||||||
|
if (newMultipleBookingsField)
|
||||||
|
ASSIGN(multipleBookingsField, newMultipleBookingsField);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL) _setupEncryption: (NGLdapConnection *) encryptedConn
|
- (BOOL) _setupEncryption: (NGLdapConnection *) encryptedConn
|
||||||
|
@ -704,6 +717,13 @@ static NSArray *commonSearchFields;
|
||||||
// Add IMAP login from user defaults
|
// Add IMAP login from user defaults
|
||||||
if ([IMAPLoginField length])
|
if ([IMAPLoginField length])
|
||||||
[searchAttributes addObjectUniquely: IMAPLoginField];
|
[searchAttributes addObjectUniquely: IMAPLoginField];
|
||||||
|
|
||||||
|
// Add the resources handling attributes
|
||||||
|
if ([kindField length])
|
||||||
|
[searchAttributes addObjectUniquely: kindField];
|
||||||
|
|
||||||
|
if ([multipleBookingsField length])
|
||||||
|
[searchAttributes addObjectUniquely: multipleBookingsField];
|
||||||
}
|
}
|
||||||
|
|
||||||
return searchAttributes;
|
return searchAttributes;
|
||||||
|
@ -855,6 +875,14 @@ static NSArray *commonSearchFields;
|
||||||
[contactEntry setObject: [NSNumber numberWithInt: 1]
|
[contactEntry setObject: [NSNumber numberWithInt: 1]
|
||||||
forKey: @"isGroup"];
|
forKey: @"isGroup"];
|
||||||
}
|
}
|
||||||
|
// We check if our entry is a resource. We also support
|
||||||
|
// determining resources based on the KindFieldName attribute
|
||||||
|
// value - see below.
|
||||||
|
else if ([classes containsObject: @"calendarresource"])
|
||||||
|
{
|
||||||
|
[contactEntry setObject: [NSNumber numberWithInt: 1]
|
||||||
|
forKey: @"isResource"];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((currentAttribute = [attributes nextObject]))
|
while ((currentAttribute = [attributes nextObject]))
|
||||||
|
@ -864,7 +892,37 @@ static NSArray *commonSearchFields;
|
||||||
|
|
||||||
// It's important here to set our attributes' key in lowercase.
|
// It's important here to set our attributes' key in lowercase.
|
||||||
if (value)
|
if (value)
|
||||||
[contactEntry setObject: value forKey: [currentAttribute lowercaseString]];
|
{
|
||||||
|
currentAttribute = [currentAttribute lowercaseString];
|
||||||
|
[contactEntry setObject: value forKey: currentAttribute];
|
||||||
|
|
||||||
|
// We check if that entry corresponds to a resource. For this,
|
||||||
|
// kindField must be defined and it must hold one of those values
|
||||||
|
//
|
||||||
|
// location
|
||||||
|
// thing
|
||||||
|
// group
|
||||||
|
//
|
||||||
|
if (kindField &&
|
||||||
|
[kindField caseInsensitiveCompare: currentAttribute] == NSOrderedSame)
|
||||||
|
{
|
||||||
|
if ([value caseInsensitiveCompare: @"location"] == NSOrderedSame ||
|
||||||
|
[value caseInsensitiveCompare: @"thing"] == NSOrderedSame ||
|
||||||
|
[value caseInsensitiveCompare: @"group"] == NSOrderedSame)
|
||||||
|
{
|
||||||
|
[contactEntry setObject: [NSNumber numberWithInt: 1]
|
||||||
|
forKey: @"isResource"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// We check for the number of simultanous bookings that is allowed.
|
||||||
|
// A value of 0 means that there's no limit.
|
||||||
|
if (multipleBookingsField &&
|
||||||
|
[multipleBookingsField caseInsensitiveCompare: currentAttribute] == NSOrderedSame)
|
||||||
|
{
|
||||||
|
[contactEntry setObject: [NSNumber numberWithInt: [value intValue]]
|
||||||
|
forKey: @"numberOfSimultaneousBookings"];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
value = [[ldapEntry attributeWithName: IDField] stringValueAtIndex: 0];
|
value = [[ldapEntry attributeWithName: IDField] stringValueAtIndex: 0];
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* SOGoGroup.m - this file is part of SOGo
|
/* SOGoGroup.m - this file is part of SOGo
|
||||||
*
|
*
|
||||||
* Copyright (C) 2009-2010 Inverse inc.
|
* Copyright (C) 2009-2011 Inverse inc.
|
||||||
*
|
*
|
||||||
* Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
* Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2006-2010 Inverse inc.
|
Copyright (C) 2006-2011 Inverse inc.
|
||||||
Copyright (C) 2005 SKYRIX Software AG
|
Copyright (C) 2005 SKYRIX Software AG
|
||||||
|
|
||||||
This file is part of SOGo.
|
This file is part of SOGo.
|
||||||
|
@ -114,16 +114,17 @@
|
||||||
- (BOOL) isSuperUser;
|
- (BOOL) isSuperUser;
|
||||||
- (BOOL) canAuthenticate;
|
- (BOOL) canAuthenticate;
|
||||||
|
|
||||||
|
/* resource */
|
||||||
|
- (BOOL) isResource;
|
||||||
|
- (int) numberOfSimultaneousBookings;
|
||||||
|
|
||||||
/* module access */
|
/* module access */
|
||||||
- (BOOL) canAccessModule: (NSString *) module;
|
- (BOOL) canAccessModule: (NSString *) module;
|
||||||
|
|
||||||
/* folders */
|
/* folders */
|
||||||
|
|
||||||
- (SOGoUserFolder *) homeFolderInContext: (id) context;
|
- (SOGoUserFolder *) homeFolderInContext: (id) context;
|
||||||
|
|
||||||
- (SOGoAppointmentFolders *) calendarsFolderInContext: (WOContext *) context;
|
- (SOGoAppointmentFolders *) calendarsFolderInContext: (WOContext *) context;
|
||||||
- (SOGoAppointmentFolder *)
|
- (SOGoAppointmentFolder *) personalCalendarFolderInContext: (WOContext *) context;
|
||||||
personalCalendarFolderInContext: (WOContext *) context;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
|
@ -766,6 +766,28 @@
|
||||||
return [authValue boolValue];
|
return [authValue boolValue];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* resource */
|
||||||
|
- (BOOL) isResource
|
||||||
|
{
|
||||||
|
NSNumber *v;
|
||||||
|
|
||||||
|
v = [self _fetchFieldForUser: @"isResource"];
|
||||||
|
|
||||||
|
return (v && [v intValue]);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (int) numberOfSimultaneousBookings
|
||||||
|
{
|
||||||
|
NSNumber *v;
|
||||||
|
|
||||||
|
v = [self _fetchFieldForUser: @"numberOfSimultaneousBookings"];
|
||||||
|
|
||||||
|
if (v)
|
||||||
|
return [v intValue];
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* module access */
|
/* module access */
|
||||||
- (BOOL) canAccessModule: (NSString *) module
|
- (BOOL) canAccessModule: (NSString *) module
|
||||||
{
|
{
|
||||||
|
|
|
@ -548,6 +548,9 @@
|
||||||
[contact setObject: [emails objectAtIndex: 0] forKey: @"c_email"];
|
[contact setObject: [emails objectAtIndex: 0] forKey: @"c_email"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
- (void) _fillContactInfosForUser: (NSMutableDictionary *) currentUser
|
- (void) _fillContactInfosForUser: (NSMutableDictionary *) currentUser
|
||||||
withUIDorEmail: (NSString *) uid
|
withUIDorEmail: (NSString *) uid
|
||||||
{
|
{
|
||||||
|
@ -600,6 +603,15 @@
|
||||||
if (!access)
|
if (!access)
|
||||||
[currentUser setObject: [NSNumber numberWithBool: NO]
|
[currentUser setObject: [NSNumber numberWithBool: NO]
|
||||||
forKey: @"MailAccess"];
|
forKey: @"MailAccess"];
|
||||||
|
|
||||||
|
// We also fill the resource attributes, if any
|
||||||
|
if ([userEntry objectForKey: @"isResource"])
|
||||||
|
[currentUser setObject: [userEntry objectForKey: @"isResource"]
|
||||||
|
forKey: @"isResource"];
|
||||||
|
if ([userEntry objectForKey: @"numberOfSimultaneousBookings"])
|
||||||
|
[currentUser setObject: [userEntry objectForKey: @"numberOfSimultaneousBookings"]
|
||||||
|
forKey: @"numberOfSimultaneousBookings"];
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -614,6 +626,7 @@
|
||||||
[currentUser setObject: c_imaphostname forKey: @"c_imaphostname"];
|
[currentUser setObject: c_imaphostname forKey: @"c_imaphostname"];
|
||||||
if (c_imaplogin)
|
if (c_imaplogin)
|
||||||
[currentUser setObject: c_imaplogin forKey: @"c_imaplogin"];
|
[currentUser setObject: c_imaplogin forKey: @"c_imaplogin"];
|
||||||
|
|
||||||
[currentUser setObject: emails forKey: @"emails"];
|
[currentUser setObject: emails forKey: @"emails"];
|
||||||
[currentUser setObject: cn forKey: @"cn"];
|
[currentUser setObject: cn forKey: @"cn"];
|
||||||
[currentUser setObject: c_uid forKey: @"c_uid"];
|
[currentUser setObject: c_uid forKey: @"c_uid"];
|
||||||
|
|
|
@ -165,8 +165,8 @@
|
||||||
"InboxFolderName" = "Posteingang";
|
"InboxFolderName" = "Posteingang";
|
||||||
"DraftsFolderName" = "Entwürfe";
|
"DraftsFolderName" = "Entwürfe";
|
||||||
"SieveFolderName" = "Filter";
|
"SieveFolderName" = "Filter";
|
||||||
"OtherUsersFolderName" = "Other Users";
|
"Other Users" = "Andere Benutzer";
|
||||||
"SharedFoldersName" = "Shared Folders";
|
"Shared Folders" = "Gemeinsame Ordner";
|
||||||
"Folders" = "Ordner"; /* title line */
|
"Folders" = "Ordner"; /* title line */
|
||||||
|
|
||||||
/* MailMoveToPopUp */
|
/* MailMoveToPopUp */
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
/*
|
/*
|
||||||
|
Copyright (C) 2007-2011 Inverse inc.
|
||||||
Copyright (C) 2004 SKYRIX Software AG
|
Copyright (C) 2004 SKYRIX Software AG
|
||||||
|
|
||||||
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
|
the terms of the GNU Lesser General Public License as published by the
|
||||||
Free Software Foundation; either version 2, or (at your option) any
|
Free Software Foundation; either version 2, or (at your option) any
|
||||||
later version.
|
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
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||||
License for more details.
|
License for more details.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* UIxJSClose.h - this file is part of SOGo
|
/* UIxJSClose.h - this file is part of SOGo
|
||||||
*
|
*
|
||||||
* Copyright (C) 2006 Inverse inc.
|
* Copyright (C) 2006-2011 Inverse inc.
|
||||||
*
|
*
|
||||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* UIxJSClose.m - this file is part of SOGo
|
/* UIxJSClose.m - this file is part of SOGo
|
||||||
*
|
*
|
||||||
* Copyright (C) 2006 Inverse inc.
|
* Copyright (C) 2006-2011 Inverse inc.
|
||||||
*
|
*
|
||||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||||
*
|
*
|
||||||
|
|
|
@ -378,6 +378,7 @@
|
||||||
{
|
{
|
||||||
SOGoAppointmentFolder *previousCalendar;
|
SOGoAppointmentFolder *previousCalendar;
|
||||||
SOGoAppointmentObject *co;
|
SOGoAppointmentObject *co;
|
||||||
|
NSString *jsonResponse;
|
||||||
SoSecurityManager *sm;
|
SoSecurityManager *sm;
|
||||||
NSException *ex;
|
NSException *ex;
|
||||||
|
|
||||||
|
@ -386,6 +387,7 @@
|
||||||
co = [co container];
|
co = [co container];
|
||||||
previousCalendar = [co container];
|
previousCalendar = [co container];
|
||||||
sm = [SoSecurityManager sharedSecurityManager];
|
sm = [SoSecurityManager sharedSecurityManager];
|
||||||
|
ex = nil;
|
||||||
|
|
||||||
if ([event hasRecurrenceRules])
|
if ([event hasRecurrenceRules])
|
||||||
[self _adjustRecurrentRules];
|
[self _adjustRecurrentRules];
|
||||||
|
@ -409,12 +411,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save the event.
|
// Save the event.
|
||||||
[co saveComponent: event];
|
ex = [co saveComponent: event];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// The event was modified -- save it.
|
// The event was modified -- save it.
|
||||||
[co saveComponent: event];
|
ex = [co saveComponent: event];
|
||||||
|
|
||||||
if (componentCalendar
|
if (componentCalendar
|
||||||
&& ![[componentCalendar ocsPath]
|
&& ![[componentCalendar ocsPath]
|
||||||
|
@ -432,8 +434,19 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ex)
|
||||||
|
jsonResponse = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
|
@"failure", @"status",
|
||||||
|
[ex reason],
|
||||||
|
@"message",
|
||||||
|
nil];
|
||||||
|
else
|
||||||
|
jsonResponse = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
|
@"success", @"status", nil];
|
||||||
|
|
||||||
return [self jsCloseWithRefreshMethod: @"refreshEventsAndDisplay()"];
|
return [self responseWithStatus: 200
|
||||||
|
andString: [jsonResponse jsonRepresentation]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id <WOActionResults>) viewAction
|
- (id <WOActionResults>) viewAction
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form var:href="saveURL" name="editform" onsubmit="return validateAptEditor();">
|
<form var:href="saveURL" name="editform">
|
||||||
<div id="eventView">
|
<div id="eventView">
|
||||||
<label><var:string label:value="Title:" /><span class="content"
|
<label><var:string label:value="Title:" /><span class="content"
|
||||||
><input type="text" name="summary" id="summary"
|
><input type="text" name="summary" id="summary"
|
||||||
|
|
|
@ -96,6 +96,8 @@ function validateAptEditor() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AIM.submit($(document.editform), {'onComplete' : onEventPostComplete});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,6 +178,21 @@ function addContact(tag, fullContactName, contactId, contactName, contactEmail)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onEventPostComplete(response) {
|
||||||
|
if (response && response.length > 0) {
|
||||||
|
var jsonResponse = response.evalJSON();
|
||||||
|
if (jsonResponse["status"] == "success") {
|
||||||
|
if (window.opener)
|
||||||
|
window.opener.refreshEventsAndDisplay();
|
||||||
|
window.close();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var message = jsonResponse["message"];
|
||||||
|
alert(jsonResponse["message"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function saveEvent(sender) {
|
function saveEvent(sender) {
|
||||||
if (validateAptEditor()) {
|
if (validateAptEditor()) {
|
||||||
document.forms['editform'].attendees.value = Object.toJSON($(attendees));
|
document.forms['editform'].attendees.value = Object.toJSON($(attendees));
|
||||||
|
|
Loading…
Reference in New Issue