mirror of
https://github.com/inverse-inc/sogo.git
synced 2026-03-31 11:02:44 +00:00
Monotone-Parent: 9004babc502ac0232d7659ba8ada6726ad286662
Monotone-Revision: fe15a52bbb65b7147dfd596fd4f0791b716d1b26 Monotone-Author: flachapelle@inverse.ca Monotone-Date: 2008-11-22T07:20:22 Monotone-Branch: ca.inverse.sogo
This commit is contained in:
@@ -47,6 +47,8 @@
|
||||
@interface SOGoAppointmentObject : SOGoCalendarComponent
|
||||
|
||||
- (NSException *) changeParticipationStatus: (NSString *) _status;
|
||||
- (NSException *) changeParticipationStatus: (NSString *) _status
|
||||
forRecurrenceId: (NSCalendarDate *) _recurrenceId;
|
||||
|
||||
- (void) takeAttendeeStatus: (iCalPerson *) attendee from: (NSString *) originator;
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
#import "NSArray+Appointments.h"
|
||||
#import "SOGoAppointmentFolder.h"
|
||||
#import "SOGoAppointmentOccurence.h"
|
||||
#import "SOGoCalendarComponent.h"
|
||||
|
||||
#import "SOGoAppointmentObject.h"
|
||||
|
||||
@@ -162,6 +163,7 @@
|
||||
NSString *possibleName;
|
||||
|
||||
folder = [container lookupCalendarFolderForUID: uid];
|
||||
// should call lookupCalendarFoldersForUIDs to search among all folders
|
||||
object = [folder lookupName: nameInContainer
|
||||
inContext: context acquire: NO];
|
||||
if ([object isKindOfClass: [NSException class]])
|
||||
@@ -324,7 +326,7 @@
|
||||
if ([attendees count])
|
||||
{
|
||||
[self _handleAddedUsers: attendees fromEvent: newEvent];
|
||||
[self sendEMailUsingTemplateNamed: @"Invitation"
|
||||
[self sendEMailUsingTemplateNamed: @"Update"
|
||||
forObject: [newEvent itipEntryWithMethod: @"request"]
|
||||
previousObject: oldEvent
|
||||
toAttendees: attendees];
|
||||
@@ -379,14 +381,18 @@
|
||||
- (NSException *) _updateAttendee: (iCalPerson *) attendee
|
||||
ownerUser: (SOGoUser *) theOwnerUser
|
||||
forEventUID: (NSString *) eventUID
|
||||
withRecurrenceId: (NSCalendarDate *) recurrenceId
|
||||
withSequence: (NSNumber *) sequence
|
||||
forUID: (NSString *) uid
|
||||
shouldAddSentBy: (BOOL) b
|
||||
{
|
||||
SOGoAppointmentObject *eventObject;
|
||||
iCalEvent *event;
|
||||
//iCalEvent *event;
|
||||
iCalCalendar *calendar;
|
||||
iCalEntityObject *event;
|
||||
iCalPerson *otherAttendee;
|
||||
NSString *iCalString;
|
||||
NSArray *events;
|
||||
NSString *iCalString, *recurrenceTime;
|
||||
NSException *error;
|
||||
|
||||
error = nil;
|
||||
@@ -394,32 +400,55 @@
|
||||
eventObject = [self _lookupEvent: eventUID forUID: uid];
|
||||
if (![eventObject isNew])
|
||||
{
|
||||
event = [eventObject component: NO secure: NO];
|
||||
if (recurrenceId == nil)
|
||||
{
|
||||
// We must update main event and all its occurences (if any).
|
||||
calendar = [eventObject calendar: NO secure: NO];
|
||||
event = [calendar firstChildWithTag: [self componentTag]];
|
||||
events = [calendar allObjects];
|
||||
}
|
||||
else
|
||||
{
|
||||
// If recurrenceId is defined, find the specified occurence
|
||||
// within the repeating vEvent.
|
||||
recurrenceTime = [NSString stringWithFormat: @"%f", [recurrenceId timeIntervalSince1970]];
|
||||
event = [eventObject lookupOccurence: recurrenceTime];
|
||||
|
||||
if (event == nil)
|
||||
event = [eventObject newOccurenceWithID: recurrenceTime];
|
||||
events = [NSArray arrayWithObject: event];
|
||||
}
|
||||
|
||||
if ([[event sequence] compare: sequence]
|
||||
== NSOrderedSame)
|
||||
{
|
||||
SOGoUser *currentUser;
|
||||
|
||||
//otherAttendee = [event findParticipant: [context activeUser]];
|
||||
otherAttendee = [event findParticipant: theOwnerUser];
|
||||
[otherAttendee setPartStat: [attendee partStat]];
|
||||
|
||||
// If one has accepted / declined an invitation on behalf of
|
||||
// the attendee, we add the user to the SENT-BY attribute.
|
||||
currentUser = [context activeUser];
|
||||
if (b && ![[currentUser login] isEqualToString: [theOwnerUser login]])
|
||||
int i;
|
||||
|
||||
for (i = 0; i < [events count]; i++)
|
||||
{
|
||||
NSString *currentEmail;
|
||||
currentEmail = [[currentUser allEmails] objectAtIndex: 0];
|
||||
[otherAttendee addAttribute: @"SENT-BY"
|
||||
value: [NSString stringWithFormat: @"\"MAILTO:%@\"", currentEmail]];
|
||||
}
|
||||
else
|
||||
{
|
||||
// We must REMOVE any SENT-BY here. This is important since if A accepted
|
||||
// the event for B and then, B changes by himself his participation status,
|
||||
// we don't want to keep the previous SENT-BY attribute there.
|
||||
[(NSMutableDictionary *)[otherAttendee attributes] removeObjectForKey: @"SENT-BY"];
|
||||
event = [events objectAtIndex: i];
|
||||
|
||||
otherAttendee = [event findParticipant: theOwnerUser];
|
||||
[otherAttendee setPartStat: [attendee partStat]];
|
||||
|
||||
// If one has accepted / declined an invitation on behalf of
|
||||
// the attendee, we add the user to the SENT-BY attribute.
|
||||
currentUser = [context activeUser];
|
||||
if (b && ![[currentUser login] isEqualToString: [theOwnerUser login]])
|
||||
{
|
||||
NSString *currentEmail;
|
||||
currentEmail = [[currentUser allEmails] objectAtIndex: 0];
|
||||
[otherAttendee addAttribute: @"SENT-BY"
|
||||
value: [NSString stringWithFormat: @"\"MAILTO:%@\"", currentEmail]];
|
||||
}
|
||||
else
|
||||
{
|
||||
// We must REMOVE any SENT-BY here. This is important since if A accepted
|
||||
// the event for B and then, B changes by himself his participation status,
|
||||
// we don't want to keep the previous SENT-BY attribute there.
|
||||
[(NSMutableDictionary *)[otherAttendee attributes] removeObjectForKey: @"SENT-BY"];
|
||||
}
|
||||
}
|
||||
|
||||
iCalString = [[event parent] versitString];
|
||||
@@ -489,10 +518,16 @@
|
||||
from: ownerUser];
|
||||
|
||||
organizerUID = [[event organizer] uid];
|
||||
|
||||
if (!organizerUID)
|
||||
// event is an recurrence; retrieve organizer from master event
|
||||
organizerUID = [[(iCalEntityObject*)[[event parent] firstChildWithTag: [self componentTag]] organizer] uid];
|
||||
|
||||
if (organizerUID)
|
||||
ex = [self _updateAttendee: attendee
|
||||
ownerUser: theOwnerUser
|
||||
forEventUID: [event uid]
|
||||
withRecurrenceId: [event recurrenceId]
|
||||
withSequence: [event sequence]
|
||||
forUID: organizerUID
|
||||
shouldAddSentBy: YES];
|
||||
@@ -523,6 +558,7 @@
|
||||
[self _updateAttendee: attendee
|
||||
ownerUser: theOwnerUser
|
||||
forEventUID: [event uid]
|
||||
withRecurrenceId: [event recurrenceId]
|
||||
withSequence: [event sequence]
|
||||
forUID: uid
|
||||
shouldAddSentBy: YES];
|
||||
@@ -687,6 +723,7 @@
|
||||
[self _updateAttendee: attendee
|
||||
ownerUser: ownerUser
|
||||
forEventUID: [event uid]
|
||||
withRecurrenceId: [event recurrenceId]
|
||||
withSequence: [event sequence]
|
||||
forUID: uid
|
||||
shouldAddSentBy: NO];
|
||||
@@ -713,6 +750,7 @@
|
||||
[self _updateAttendee: attendee
|
||||
ownerUser: ownerUser
|
||||
forEventUID: [event uid]
|
||||
withRecurrenceId: [event recurrenceId]
|
||||
withSequence: [event sequence]
|
||||
forUID: uid
|
||||
shouldAddSentBy: NO];
|
||||
@@ -778,14 +816,38 @@
|
||||
//
|
||||
- (NSException *) changeParticipationStatus: (NSString *) _status
|
||||
{
|
||||
return [self changeParticipationStatus: _status forRecurrenceId: nil];
|
||||
}
|
||||
|
||||
- (NSException *) changeParticipationStatus: (NSString *) _status forRecurrenceId: (NSCalendarDate *) _recurrenceId
|
||||
{
|
||||
iCalCalendar *calendar;
|
||||
iCalEvent *event;
|
||||
iCalPerson *attendee;
|
||||
NSException *ex;
|
||||
SOGoUser *ownerUser;
|
||||
NSString *recurrenceTime;
|
||||
|
||||
event = nil;
|
||||
ex = nil;
|
||||
|
||||
event = [self component: NO secure: NO];
|
||||
calendar = [self calendar: NO secure: NO];
|
||||
if (calendar)
|
||||
{
|
||||
if (_recurrenceId)
|
||||
{
|
||||
// If _recurrenceId is defined, find the specified occurence
|
||||
// within the repeating vEvent.
|
||||
recurrenceTime = [NSString stringWithFormat: @"%f", [_recurrenceId timeIntervalSince1970]];
|
||||
event = [self lookupOccurence: recurrenceTime];
|
||||
// If no occurence found, create one
|
||||
event = [self newOccurenceWithID: recurrenceTime];
|
||||
}
|
||||
else
|
||||
// No specific occurence specified; return the first vEvent of
|
||||
// the vCalendar.
|
||||
event = [calendar firstChildWithTag: [self componentTag]];
|
||||
}
|
||||
if (event)
|
||||
{
|
||||
// owerUser will actually be the owner of the calendar
|
||||
@@ -794,7 +856,7 @@
|
||||
// course be on the attendee that is the owner of the
|
||||
// calendar where the participation change has occured.
|
||||
ownerUser = [SOGoUser userWithLogin: owner roles: nil];
|
||||
|
||||
|
||||
attendee = [event findParticipant: ownerUser];
|
||||
if (attendee)
|
||||
ex = [self _handleAttendee: attendee
|
||||
@@ -802,14 +864,14 @@
|
||||
statusChange: _status
|
||||
inEvent: event];
|
||||
else
|
||||
ex = [NSException exceptionWithHTTPStatus: 404 /* Not Found */
|
||||
ex = [NSException exceptionWithHTTPStatus: 404 // Not Found
|
||||
reason: @"user does not participate in this "
|
||||
@"calendar event"];
|
||||
}
|
||||
else
|
||||
ex = [NSException exceptionWithHTTPStatus: 500 /* Server Error */
|
||||
ex = [NSException exceptionWithHTTPStatus: 500 // Server Error
|
||||
reason: @"unable to parse event record"];
|
||||
|
||||
|
||||
return ex;
|
||||
}
|
||||
|
||||
@@ -827,7 +889,7 @@
|
||||
occurence = event;
|
||||
if ([event userIsOrganizer: ownerUser])
|
||||
{
|
||||
currentUser = [context activeUser];
|
||||
currentUser = [context activeUser]; // is this correct?
|
||||
attendees = [occurence attendeesWithoutUser: currentUser];
|
||||
if (![attendees count] && event != occurence)
|
||||
attendees = [event attendeesWithoutUser: currentUser];
|
||||
|
||||
@@ -79,6 +79,7 @@
|
||||
- (NSArray *) getUIDsForICalPersons: (NSArray *) iCalPersons;
|
||||
|
||||
/* recurrences */
|
||||
- (iCalRepeatableEntityObject *) lookupOccurence: (NSString *) recID;
|
||||
- (SOGoComponentOccurence *)
|
||||
occurence: (iCalRepeatableEntityObject *) component;
|
||||
- (iCalRepeatableEntityObject *) newOccurenceWithID: (NSString *) recID;
|
||||
|
||||
@@ -532,6 +532,8 @@ _occurenceHasID (iCalRepeatableEntityObject *occurence, NSString *recID)
|
||||
|
||||
subject = [p getSubject];
|
||||
text = [p getBody];
|
||||
NSLog(@"Template: %@", pageName);
|
||||
NSLog(@"Email: %@ => %@ (%@)", senderEmail, recipient, subject);
|
||||
|
||||
/* construct message */
|
||||
headerMap = [NGMutableHashMap hashMapWithCapacity: 5];
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
- (iCalRepeatableEntityObject *) occurence;
|
||||
- (BOOL) isNew;
|
||||
- (NSException *) delete;
|
||||
- (NSException *) prepareDelete;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -27,9 +27,11 @@
|
||||
#import <NGCards/iCalCalendar.h>
|
||||
#import <NGCards/iCalRepeatableEntityObject.h>
|
||||
|
||||
#import "SOGoAppointmentObject.h"
|
||||
#import "SOGoCalendarComponent.h"
|
||||
|
||||
#import "SOGoComponentOccurence.h"
|
||||
|
||||
#import "SOGoCalendarComponent.h"
|
||||
@interface SOGoCalendarComponent (OccurenceExtensions)
|
||||
|
||||
- (void) prepareDeleteOccurence: (iCalRepeatableEntityObject *) component;
|
||||
@@ -135,7 +137,7 @@
|
||||
return component;
|
||||
}
|
||||
|
||||
- (NSException *) delete;
|
||||
- (NSException *) prepareDelete;
|
||||
{
|
||||
NSException *error;
|
||||
iCalCalendar *parent;
|
||||
@@ -149,7 +151,10 @@
|
||||
[master addToExceptionDates: [component startDate]];
|
||||
parent = [component parent];
|
||||
[[parent children] removeObject: component];
|
||||
|
||||
// changes participant status & send invitation email - as if it was a new event! :(
|
||||
[container saveComponent: master];
|
||||
|
||||
error = nil;
|
||||
}
|
||||
|
||||
@@ -163,9 +168,13 @@
|
||||
|
||||
#warning most of SOGoCalendarComponent and SOGoComponentOccurence share the same external interface... \
|
||||
they should be siblings or SOGoComponentOccurence the parent class of SOGoCalendarComponent...
|
||||
- (NSException *) changeParticipationStatus: (NSString *) newPartStat
|
||||
- (NSException *) changeParticipationStatus: (NSString *) newStatus
|
||||
{
|
||||
return [container changeParticipationStatus: newPartStat];
|
||||
NSCalendarDate *date;
|
||||
|
||||
date = [component recurrenceId];
|
||||
|
||||
return [container changeParticipationStatus: newStatus forRecurrenceId: date];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -116,11 +116,11 @@
|
||||
doesOccur = [self isRecurrent];
|
||||
if (doesOccur)
|
||||
{
|
||||
tz = [occurenceDate timeZone];
|
||||
if ([tz isDaylightSavingTimeForDate: occurenceDate] != [tz isDaylightSavingTimeForDate: [self startDate]]) {
|
||||
daylightOffset = [tz secondsFromGMTForDate: occurenceDate] - [tz secondsFromGMTForDate: [self startDate]];
|
||||
occurenceDate = [occurenceDate dateByAddingYears: 0 months: 0 days: 0 hours: 0 minutes: 0 seconds: daylightOffset];
|
||||
}
|
||||
// tz = [occurenceDate timeZone];
|
||||
// if ([tz isDaylightSavingTimeForDate: occurenceDate] != [tz isDaylightSavingTimeForDate: [self startDate]]) {
|
||||
// daylightOffset = [tz secondsFromGMTForDate: occurenceDate] - [tz secondsFromGMTForDate: [self startDate]];
|
||||
// occurenceDate = [occurenceDate dateByAddingYears: 0 months: 0 days: 0 hours: 0 minutes: 0 seconds: daylightOffset];
|
||||
// }
|
||||
|
||||
endDate = [occurenceDate addTimeInterval: [self occurenceInterval]];
|
||||
checkRange = [NGCalendarDateRange calendarDateRangeWithStartDate: occurenceDate
|
||||
|
||||
@@ -87,4 +87,17 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
- (WOResponse *) deleteAction
|
||||
{
|
||||
SOGoCalendarComponent *component;
|
||||
WOResponse *response;
|
||||
|
||||
component = [self clientObject];
|
||||
response = (WOResponse *) [component prepareDelete];
|
||||
if (!response)
|
||||
response = [self responseWithStatus: 204];
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -251,7 +251,7 @@
|
||||
confirmDeletion = {
|
||||
protectedBy = "ModifyComponent";
|
||||
pageName = "UIxOccurenceDialog";
|
||||
actionName = "confirmDeletion";
|
||||
actionName = "confirmDeletion";
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -273,6 +273,11 @@
|
||||
pageName = "UIxAppointmentEditor";
|
||||
actionName = "save";
|
||||
};
|
||||
delete = {
|
||||
protectedBy = "Delete Objects";
|
||||
pageName = "UIxOccurenceDialog";
|
||||
actionName = "delete";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -396,7 +396,7 @@ function onViewEventCallback(http) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
log("onViewEventCallback ajax error:" + http.url);
|
||||
log("onViewEventCallback ajax error: " + http.url);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -414,23 +414,29 @@ function performEventEdition(folder, event, recurrence) {
|
||||
}
|
||||
|
||||
function performEventDeletion(folder, event, recurrence) {
|
||||
if (calendarEvents) {
|
||||
var urlstr = ApplicationBaseURL + folder + "/" + event;
|
||||
var occurenceTime;
|
||||
if (calendarEvents) {
|
||||
if (recurrence) {
|
||||
urlstr += "/" + recurrence;
|
||||
occurenceTime = recurrence.substring(9);
|
||||
// Only one recurrence
|
||||
var occurenceTime = recurrence.substring(9);
|
||||
var nodes = _eventBlocksMatching(folder, event, occurenceTime);
|
||||
var urlstr = ApplicationBaseURL + folder + "/" + event + "/" + recurrence + "/delete";
|
||||
|
||||
if (nodes)
|
||||
document.deleteEventAjaxRequest = triggerAjaxRequest(urlstr,
|
||||
performDeleteEventCallback,
|
||||
{ nodes: nodes,
|
||||
occurence: occurenceTime });
|
||||
}
|
||||
else
|
||||
occurenceTime = null;
|
||||
|
||||
urlstr += "/delete";
|
||||
var nodes = _eventBlocksMatching(folder, event, occurenceTime);
|
||||
if (nodes)
|
||||
document.deleteEventAjaxRequest = triggerAjaxRequest(urlstr,
|
||||
performDeleteEventCallback,
|
||||
{ nodes: nodes,
|
||||
occurence: occurenceTime });
|
||||
else {
|
||||
// All recurrences
|
||||
if (document.deleteEventAjaxRequest) {
|
||||
document.deleteEventAjaxRequest.aborted = true;
|
||||
document.deleteEventAjaxRequest.abort();
|
||||
}
|
||||
eventsToDelete.push([event]);
|
||||
calendarsOfEventsToDelete.push(folder);
|
||||
_batchDeleteEvents();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -443,7 +449,6 @@ function performDeleteEventCallback(http) {
|
||||
var calendar = nodes[0].calendar;
|
||||
for (var i = 0; i < nodes.length; i++) {
|
||||
var node = nodes[i];
|
||||
// log("node: " + node);
|
||||
node.parentNode.removeChild(node);
|
||||
}
|
||||
var basename = calendar + "-" + cname;
|
||||
@@ -453,11 +458,12 @@ function performDeleteEventCallback(http) {
|
||||
if (row)
|
||||
row.parentNode.removeChild(row);
|
||||
|
||||
// Update calendar events cache
|
||||
var occurences = calendarEvents[calendar][cname];
|
||||
var newOccurences = [];
|
||||
for (var i = 0; i < occurences.length; i++) {
|
||||
var occurence = occurences[i];
|
||||
if (occurence[13] != recurrenceTime)
|
||||
if (occurence[13] != occurenceTime)
|
||||
newOccurences.push(occurence);
|
||||
}
|
||||
calendarEvents[calendar][cname] = newOccurences;
|
||||
|
||||
Reference in New Issue
Block a user