Initial JSON actions to get/set an event

pull/91/head
Francis Lachapelle 2015-02-12 15:01:26 -05:00
parent f694f57638
commit f9271b747c
10 changed files with 1192 additions and 2643 deletions

View File

@ -35,7 +35,7 @@ extern NSNumber *iCalDistantFutureNumber;
+ (void) initializeSOGoExtensions;
- (NSDictionary *) attributes;
- (NSDictionary *) attributesInContext: (WOContext *) context;
- (void) setAttributes: (NSDictionary *) data
inContext: (WOContext *) context;
@ -44,7 +44,6 @@ extern NSNumber *iCalDistantFutureNumber;
- (iCalPerson *) userAsAttendee: (SOGoUser *) user;
- (NSArray *) attendeeUIDs;
- (BOOL) isStillRelevant;
- (id) itipEntryWithMethod: (NSString *) method;
@ -52,7 +51,7 @@ extern NSNumber *iCalDistantFutureNumber;
- (NSArray *) attendeesWithoutUser: (SOGoUser *) user;
- (int) priorityNumber;
- (NSString *) createdBy;
- (NSDictionary *) createdBy;
- (NSNumber *) quickRecordDateAsNumber: (NSCalendarDate *) _date
withOffset: (int) offset

View File

@ -44,11 +44,13 @@
#import <NGObjWeb/WOContext+SoObjects.h>
#import <SOGo/NSArray+Utilities.h>
#import <SOGo/SOGoSource.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoUserDefaults.h>
#import <SOGo/SOGoUserManager.h>
#import "iCalPerson+SOGo.h"
#import "iCalAlarm+SOGo.h"
#import "iCalCalendar+SOGo.h"
#import "iCalEntityObject+SOGo.h"
@ -70,18 +72,23 @@ NSNumber *iCalDistantFutureNumber = nil;
/**
* @see [UIxAppointmentEditor viewAction]
*/
- (NSDictionary *) attributes
- (NSDictionary *) attributesInContext: (WOContext *) context
{
NSArray *elements;
NSMutableArray *attendees;
NSDictionary *organizerData;
NSMutableDictionary *data, *attendeeData, *alarmData;
NSDictionary *contactData;
NSMutableDictionary *data, *organizerData, *attendeeData, *alarmData;
NSEnumerator *attendeesList;
NSString *uid, *domain, *sentBy;
NSObject <SOGoSource> *source;
SOGoUserManager *um;
iCalPerson *organizer, *currentAttendee;
iCalAlarm *alarm;
iCalTrigger *trigger;
id value;
um = [SOGoUserManager sharedUserManager];
data = [NSMutableDictionary dictionaryWithObjectsAndKeys:
[[self tag] lowercaseString], @"component",
[self summary], @"summary",
@ -90,33 +97,46 @@ NSNumber *iCalDistantFutureNumber = nil;
value = [self location];
if (value) [data setObject: value forKey: @"location"];
if ([self comment]) [data setObject: [self comment] forKey: @"comment"];
if ([self attach]) [data setObject: [[self attach] absoluteString] forKey: @"attachUrl"];
if ([self accessClass]) [data setObject: [[self accessClass] lowercaseString] forKey: @"classification"];
if ([self status]) [data setObject: [self status] forKey: @"status"];
if ([self createdBy]) [data setObject: [self createdBy] forKey: @"createdBy"];
value = [self comment];
if (value) [data setObject: value forKey: @"comment"];
value = [self attach];
if (value) [data setObject: [value absoluteString] forKey: @"attachUrl"];
value = [self accessClass];
if (value) [data setObject: [value lowercaseString] forKey: @"classification"];
value = [self status];
if (value) [data setObject: value forKey: @"status"];
value = [self createdBy];
if (value) [data setObject: value forKey: @"createdBy"];
// Categories
elements = [self categories];
if ([elements count])
[data setObject: elements forKey: @"categories"];
// Send appointment notifications
// Send appointment notifications when the custom tag is *not* set
value = [self firstChildWithTag: @"X-SOGo-Send-Appointment-Notifications"];
[data setObject: [NSNumber numberWithBool: (value? 1:0)] forKey: @"sendAppointmentNotifications"];
[data setObject: [NSNumber numberWithBool: (value? 0:1)] forKey: @"sendAppointmentNotifications"];
// Organizer
organizer = [self organizer];
if (organizer)
{
organizerData = [NSDictionary dictionaryWithObjectsAndKeys:
[organizer rfc822Email], @"email",
[organizer cnWithoutQuotes], @"name",
nil];
organizerData = [NSMutableDictionary dictionaryWithObjectsAndKeys:
[organizer rfc822Email], @"email",
[organizer cnWithoutQuotes], @"name",
nil];
uid = [organizer uid];
if ([uid length]) [organizerData setObject: uid forKey: @"uid"];
sentBy = [organizer sentBy];
if ([sentBy length]) [organizerData setObject: sentBy forKey: @"sentBy"];
[data setObject: organizerData forKey: @"organizer"];
}
// Attendees
attendees = [NSMutableArray array];
attendeesList = [[self attendees] objectEnumerator];
@ -126,29 +146,28 @@ NSNumber *iCalDistantFutureNumber = nil;
[currentAttendee rfc822Email], @"email",
[currentAttendee cnWithoutQuotes], @"name",
nil];
if ([currentAttendee uid]) [attendeeData setObject: [currentAttendee uid] forKey: @"uid"];
// TODO: restore support for MS Exchange
// uid = [um getUIDForEmail: [currentAttendee rfc822Email]];
// if (uid != nil)
// [currentAttendeeData setObject: uid
// forKey: @"uid"];
// else
// {
// domain = [[context activeUser] domain];
// contacts = [um fetchContactsMatching: [currentAttendee rfc822Email] inDomain: domain];
// if ([contacts count] == 1)
// {
// contact = [contacts lastObject];
// source = [contact objectForKey: @"source"];
// if ([source conformsToProtocol: @protocol (SOGoDNSource)] &&
// [[(NSObject <SOGoDNSource>*) source MSExchangeHostname] length])
// {
// uid = [NSString stringWithFormat: @"%@:%@", [[context activeUser] login],
// [contact valueForKey: @"c_uid"]];
// [currentAttendeeData setObject: uid forKey: @"uid"];
// }
// }
// }
if ((uid = [currentAttendee uid]))
{
[attendeeData setObject: uid forKey: @"uid"];
}
else
{
// Search for attendee in global contacts sources that are associated with a MS Exchange server
domain = [[context activeUser] domain];
elements = [um fetchContactsMatching: [currentAttendee rfc822Email] inDomain: domain];
if ([elements count] == 1)
{
contactData = [elements lastObject];
source = [contactData objectForKey: @"source"];
if ([source conformsToProtocol: @protocol (SOGoDNSource)] &&
[[(NSObject <SOGoDNSource>*) source MSExchangeHostname] length])
{
uid = [NSString stringWithFormat: @"%@:%@", [[context activeUser] login],
[contactData valueForKey: @"c_uid"]];
[attendeeData setObject: uid forKey: @"uid"];
}
}
}
[attendeeData setObject: [[currentAttendee partStat] lowercaseString] forKey: @"status"];
[attendeeData setObject: [[currentAttendee role] lowercaseString] forKey: @"role"];
if ([[currentAttendee delegatedTo] length])
@ -193,6 +212,177 @@ NSNumber *iCalDistantFutureNumber = nil;
return data;
}
- (void) _setAttendees: (NSArray *) attendees
{
NSMutableArray *newAttendees;
NSUInteger count, max;
NSString *currentEmail;
iCalPerson *currentAttendee;
NSString *role, *partstat;
NSDictionary *currentData;
if (attendees)
{
newAttendees = [NSMutableArray array];
max = [attendees count];
for (count = 0; count < max; count++)
{
currentData = [attendees objectAtIndex: count];
currentEmail = [currentData objectForKey: @"email"];
if ([currentEmail length] > 0)
{
role = [[currentData objectForKey: @"role"] uppercaseString];
if (!role)
role = @"REQ-PARTICIPANT";
if ([role isEqualToString: @"NON-PARTICIPANT"])
partstat = @"";
else
{
partstat = [[currentData objectForKey: @"partstat"] uppercaseString];
if (!partstat)
partstat = @"NEEDS-ACTION";
}
currentAttendee = [self findAttendeeWithEmail: currentEmail];
if (!currentAttendee)
{
currentAttendee = [iCalPerson elementWithTag: @"attendee"];
[currentAttendee setCn: [currentData objectForKey: @"name"]];
[currentAttendee setEmail: currentEmail];
}
[currentAttendee
setRsvp: ([role isEqualToString: @"NON-PARTICIPANT"]
? @"FALSE"
: @"TRUE")];
[currentAttendee setRole: role];
[currentAttendee setPartStat: partstat];
[newAttendees addObject: currentAttendee];
}
}
[self setAttendees: newAttendees];
}
}
- (void) _appendAttendeesToEmailAlarm: (iCalAlarm *) alarm
{
NSArray *attendees;
NSMutableArray *aAttendees;
int count, max;
iCalPerson *currentAttendee, *aAttendee;
attendees = [self attendees];
max = [attendees count];
aAttendees = [NSMutableArray arrayWithCapacity: max];
for (count = 0; count < max; count++)
{
currentAttendee = [attendees objectAtIndex: count];
aAttendee = [iCalPerson elementWithTag: @"attendee"];
[aAttendee setCn: [currentAttendee cn]];
[aAttendee setEmail: [currentAttendee rfc822Email]];
[aAttendees addObject: aAttendee];
}
[alarm setAttendees: aAttendees];
}
- (void) _setAlarm: (NSDictionary *) alarm
forOwner: (NSString *) owner
{
iCalAlarm *anAlarm;
NSString *reminderAction, *reminderUnit, *reminderQuantity, *reminderReference, *reminderRelation;
BOOL reminderEmailAttendees, reminderEmailOrganizer;
reminderAction = [alarm objectForKey: @"action"];
reminderUnit = [alarm objectForKey: @"unit"];
reminderQuantity = [alarm objectForKey: @"quantity"];
reminderReference = [alarm objectForKey: @"reference"];
reminderRelation = [alarm objectForKey: @"relation"];
reminderEmailAttendees = [[alarm objectForKey: @"attendees"] boolValue];
reminderEmailOrganizer = [[alarm objectForKey: @"organizer"] boolValue];
anAlarm = [iCalAlarm alarmForEvent: self
owner: owner
action: reminderAction
unit: reminderUnit
quantity: reminderQuantity
reference: reminderReference
reminderRelation: reminderRelation
emailAttendees: reminderEmailAttendees
emailOrganizer: reminderEmailOrganizer];
// If there was an unsupported alarm defined in the event, it will be deleted.
[self removeAllAlarms];
if (anAlarm)
{
[self addToAlarms: anAlarm];
[anAlarm release];
}
}
/**
* @see [UIxAppointmentEditor saveAction]
*/
- (void) setAttributes: (NSDictionary *) data
inContext: (WOContext *) context
{
NSString *owner;
id o, sendAppointmentNotifications;
o = [data objectForKey: @"summary"];
if ([o isKindOfClass: [NSString class]])
[self setSummary: o];
o = [data objectForKey: @"priority"];
if ([o isKindOfClass: [NSNumber class]])
[self setPriority: [NSString stringWithFormat: @"%d", [o intValue]]];
o = [data objectForKey: @"location"];
if ([o isKindOfClass: [NSString class]])
[self setLocation: o];
o = [data objectForKey: @"comment"];
if ([o isKindOfClass: [NSString class]])
[self setComment: [o stringByReplacingString: @"\r\n" withString: @"\n"]];
o = [data objectForKey: @"attachUrl"];
if ([o isKindOfClass: [NSString class]])
[self setAttach: o];
o = [data objectForKey: @"classification"];
if ([o isKindOfClass: [NSString class]])
[self setAccessClass: [o uppercaseString]];
o = [data objectForKey: @"status"];
if ([o isKindOfClass: [NSString class]])
[self setStatus: o];
o = [data objectForKey: @"categories"];
if ([o isKindOfClass: [NSArray class]])
[self setCategories: o];
o = [data objectForKey: @"sendAppointmentNotifications"];
if ([o isKindOfClass: [NSNumber class]])
{
sendAppointmentNotifications = [self firstChildWithTag: @"X-SOGo-Send-Appointment-Notifications"];
if (!sendAppointmentNotifications && ![o boolValue])
[self addChild: [CardElement simpleElementWithTag: @"X-SOGo-Send-Appointment-Notifications" value: @"NO"]];
else if (sendAppointmentNotifications && [o boolValue])
[self removeChild: sendAppointmentNotifications];
}
o = [data objectForKey: @"attendees"];
if ([o isKindOfClass: [NSArray class]])
[self _setAttendees: o];
o = [data objectForKey: @"alarm"];
if ([o isKindOfClass: [NSDictionary class]])
{
owner = [data objectForKey: @"owner"];
[self _setAlarm: o forOwner: owner];
}
// Other attributes depend on the client object and therefore are set in [UIxComponentEditor setAttributes:]:
// - organizer & "created-by"
// - timestamps (creation/modification)
}
- (BOOL) userIsAttendee: (SOGoUser *) user
{
NSEnumerator *attendees;
@ -243,10 +433,11 @@ NSNumber *iCalDistantFutureNumber = nil;
if ([mail length])
return [user hasEmail: mail];
return NO;
}
/*
- (NSArray *) attendeeUIDs
{
NSEnumerator *attendees;
@ -266,6 +457,7 @@ NSNumber *iCalDistantFutureNumber = nil;
return uids;
}
*/
#warning this method should be implemented in a category of iCalToDo
- (BOOL) isStillRelevant
@ -282,11 +474,11 @@ NSNumber *iCalDistantFutureNumber = nil;
NSArray *events;
int i, count;
newCalendar = [parent mutableCopy];
[newCalendar autorelease];
[newCalendar setMethod: method];
events = [newCalendar childrenWithTag: tag];
count = [events count];
if (count > 1)
@ -379,19 +571,39 @@ NSNumber *iCalDistantFutureNumber = nil;
return priorityNumber;
}
- (NSString *) createdBy
- (NSDictionary *) createdBy
{
NSString *created_by;
NSString *created_by, *created_by_name, *login;
NSDictionary *createdByData;
SOGoUser *user;
created_by_name = nil;
createdByData = nil;
created_by = [[self firstChildWithTag: @"X-SOGo-Component-Created-By"] flattenedValuesForKey: @""];
// We consider "SENT-BY" in case our custom header isn't found
if (![created_by length])
{
// We consider "SENT-BY" in case our custom header isn't found
created_by = [[self organizer] sentBy];
}
return created_by;
if ([created_by length])
{
login = [[SOGoUserManager sharedUserManager] getUIDForEmail: created_by];
if (login)
{
user = [SOGoUser userWithLogin: login];
if (user)
created_by_name = [user cn];
}
createdByData = [NSDictionary dictionaryWithObjectsAndKeys: created_by, @"email",
created_by_name, @"name",
nil];
}
return createdByData;
;
}
//
@ -478,20 +690,20 @@ NSNumber *iCalDistantFutureNumber = nil;
NSCalendarDate *start, *end;
NGCalendarDateRange *range;
NSMutableArray *alarms;
alarms = [NSMutableArray array];
start = [NSCalendarDate date];
end = [start addYear:1 month:0 day:0 hour:0 minute:0 second:0];
range = [NGCalendarDateRange calendarDateRangeWithStartDate: start
endDate: end];
// Always check if container is defined. If not, that means this method
// call was reentrant.
if (theContainer)
{
NSTimeInterval now;
int i, v, delta, c_startdate, c_nextalarm;
//
// Here is the logic:
//
@ -506,12 +718,12 @@ NSNumber *iCalDistantFutureNumber = nil;
// If we don't have a match, we pick the event for which its trigger is the closest to the c_nextalarm.
//
nextAlarmDate = nil;
[theContainer flattenCycleRecord: (id)row
forRange: range
intoArray: alarms
withCalendar: [self parent]];
// We pickup the closest one from now. We remove the actual reminder (ie., 15 mins before - plus 1 minute for roundups)
// so we don't pickup the same alarm over and over. This could happen if our alarm popups and the user clicks on "Cancel".
// In case of a repetitive event, we want to pickup the next one (next day for example), and not the one that has just
@ -523,11 +735,11 @@ NSNumber *iCalDistantFutureNumber = nil;
c_startdate = [[[alarms objectAtIndex: i] objectForKey: @"c_startdate"] intValue];
c_nextalarm = [[[alarms objectAtIndex: i] objectForKey: @"c_nextalarm"] intValue];
delta = (c_startdate - now - (c_startdate - c_nextalarm)) - 60;
// If value is not initialized, we grab it right away
if (!v && delta > 0)
v = delta;
// If we found a smaller delta than before, use it.
if (v > 0 && delta > 0 && delta <= v)
{
@ -538,10 +750,10 @@ NSNumber *iCalDistantFutureNumber = nil;
o = [[self parent] eventWithRecurrenceID: [[alarms objectAtIndex: i] objectForKey: @"c_recurrence_id"]];
else
o = [[self parent] todoWithRecurrenceID: [[alarms objectAtIndex: i] objectForKey: @"c_recurrence_id"]];
if (!o)
o = self;
if ([[o alarms] count])
{
anAlarm = [self firstDisplayOrAudioAlarm];
@ -551,7 +763,7 @@ NSNumber *iCalDistantFutureNumber = nil;
if (!webstatus
|| ([webstatus caseInsensitiveCompare: @"TRIGGERED"]
!= NSOrderedSame))
v = delta;
nextAlarmDate = [NSDate dateWithTimeIntervalSince1970: [[[alarms objectAtIndex: i] objectForKey: @"c_nextalarm"] intValue]];
}
@ -565,7 +777,7 @@ NSNumber *iCalDistantFutureNumber = nil;
} // if (theContainer)
}
}
if ([nextAlarmDate isNotNull])
[row setObject: [NSNumber numberWithInt: [nextAlarmDate timeIntervalSince1970]]
forKey: @"c_nextalarm"];

View File

@ -1,6 +1,6 @@
/* iCalEvent+SOGo.h - this file is part of SOGo
*
* Copyright (C) 2007-2014 Inverse inc.
* Copyright (C) 2007-2015 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
@ -28,7 +28,7 @@
@interface iCalEvent (SOGoExtensions)
- (BOOL) isStillRelevant;
- (unsigned int) occurenceInterval;
- (NSTimeInterval) occurenceInterval;
- (void) updateRecurrenceRulesUntilDate: (NSCalendarDate *) previousEndDate;
@end

View File

@ -1,6 +1,6 @@
/* iCalEvent+SOGo.m - this file is part of SOGo
*
* Copyright (C) 2007-2014 Inverse inc.
* Copyright (C) 2007-2015 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
@ -22,12 +22,14 @@
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSEnumerator.h>
#import <Foundation/NSTimeZone.h>
#import <Foundation/NSValue.h>
#import <NGExtensions/NGCalendarDateRange.h>
#import <NGExtensions/NSNull+misc.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGCards/iCalCalendar.h>
#import <NGCards/iCalDateTime.h>
#import <NGCards/iCalTimeZone.h>
#import <NGCards/iCalEvent.h>
@ -36,6 +38,10 @@
#import <NGCards/iCalTrigger.h>
#import <NGCards/NSString+NGCards.h>
#import <SoObjects/SOGo/SOGoUser.h>
#import <SoObjects/SOGo/SOGoUserDefaults.h>
#import <SoObjects/SOGo/WOContext+SOGo.h>
#import "SOGoAppointmentFolder.h"
#import "iCalRepeatableEntityObject+SOGo.h"
@ -47,7 +53,7 @@
{
NSCalendarDate *now, *lastRecurrence;
BOOL isStillRelevent;
now = [NSCalendarDate calendarDate];
if ([self isRecurrent])
@ -57,7 +63,7 @@
}
else
isStillRelevent = ([[self endDate] earlierDate: now] == now);
return isStillRelevent;
}
@ -114,8 +120,8 @@
row = [NSMutableDictionary dictionaryWithCapacity:8];
[row setObject: @"vevent" forKey: @"c_component"];
if ([uid isNotNull])
if ([uid isNotNull])
[row setObject:uid forKey: @"c_uid"];
else
[self logWithFormat: @"WARNING: could not extract a uid from event!"];
@ -168,11 +174,11 @@
forAllDay: isAllDay]
forKey: @"c_enddate"];
}
if ([self isRecurrent])
{
NSCalendarDate *date;
date = [self lastPossibleRecurrenceStartDate];
if (!date)
{
@ -194,7 +200,7 @@
if ([status isNotNull])
{
int code = 1;
if ([status isEqualToString: @"TENTATIVE"])
code = 2;
else if ([status isEqualToString: @"CANCELLED"])
@ -214,12 +220,12 @@
if (organizer)
{
NSString *email;
email = [organizer valueForKey: @"rfc822Email"];
if (email)
[row setObject:email forKey: @"c_orgmail"];
}
/* construct partstates */
count = [attendees count];
partstates = [[NSMutableString alloc] initWithCapacity:count * 2];
@ -227,7 +233,7 @@
{
iCalPerson *p;
iCalPersonPartStat stat;
p = [attendees objectAtIndex:i];
stat = [p participationStatus];
if (i)
@ -263,7 +269,7 @@
}
/**
* Shift the "until dates" of the recurrence rules of the event
* Shift the "until dates" of the recurrence rules of the event
* with respect to the previous end date of the event.
* @param previousEndDate the previous end date of the event
*/
@ -312,12 +318,65 @@
}
}
}
// From [UIxDatePicker takeValuesFromRequest:inContext:]
- (NSCalendarDate *) _dateFromString: (NSString *) dateString
inContext: (WOContext *) context
{
NSInteger dateTZOffset, userTZOffset;
NSTimeZone *systemTZ, *userTZ;
SOGoUserDefaults *ud;
NSCalendarDate *date;
date = [NSCalendarDate dateWithString: dateString
calendarFormat: @"%Y-%m-%d"];
if (!date)
[self warnWithFormat: @"Could not parse dateString: '%@'", dateString];
// We must adjust the date timezone because "dateWithString:..." uses the
// system timezone, which can be different from the user's. */
ud = [[context activeUser] userDefaults];
systemTZ = [date timeZone];
dateTZOffset = [systemTZ secondsFromGMTForDate: date];
userTZ = [ud timeZone];
userTZOffset = [userTZ secondsFromGMTForDate: date];
if (dateTZOffset != userTZOffset)
date = [date dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: (dateTZOffset - userTZOffset)];
[date setTimeZone: userTZ];
return date;
}
// From [UIxTimeDatePicker takeValuesFromRequest:inContext:]
- (void) _adjustDate: (NSCalendarDate **) date
withTimeString: (NSString *) timeString
inContext: (WOContext *) context
{
unsigned _year, _month, _day, _hour, _minute;
SOGoUserDefaults *ud;
NSArray *_time;
_year = [*date yearOfCommonEra];
_month = [*date monthOfYear];
_day = [*date dayOfMonth];
_time = [timeString componentsSeparatedByString: @":"];
_hour = [[_time objectAtIndex: 0] intValue];
_minute = [[_time objectAtIndex: 1] intValue];
ud = [[context activeUser] userDefaults];
*date = [NSCalendarDate dateWithYear: _year month: _month day: _day
hour: _hour minute: _minute second: 0
timeZone: [ud timeZone]];
}
/**
* @see [iCalRepeatableEntityObject+SOGo attributes]
* @see [iCalEntityObject+SOGo attributes]
* @see [UIxAppointmentEditor viewAction]
*/
- (NSDictionary *) attributes
- (NSDictionary *) attributesInContext: (WOContext *) context
{
NSMutableDictionary *data;
@ -329,4 +388,100 @@
return data;
}
/**
* @see [iCalRepeatableEntityObject+SOGo setAttributes:inContext:]
* @see [iCalEntityObject+SOGo setAttributes:inContext:]
* @see [UIxAppointmentEditor saveAction]
*/
- (void) setAttributes: (NSDictionary *) data
inContext: (WOContext *) context
{
NSCalendarDate *aptStartDate, *aptEndDate, *allDayStartDate;
NSTimeZone *timeZone;
NSInteger offset, nbrDays;
iCalDateTime *startDate;
iCalTimeZone *tz;
SOGoUserDefaults *ud;
BOOL isAllDay;
id o;
[super setAttributes: data inContext: context];
aptStartDate = aptEndDate = nil;
// Handle start/end dates
o = [data objectForKey: @"startDate"];
if ([o isKindOfClass: [NSString class]] && [o length])
aptStartDate = [self _dateFromString: o inContext: context];
o = [data objectForKey: @"startTime"];
if ([o isKindOfClass: [NSString class]] && [o length])
[self _adjustDate: &aptStartDate withTimeString: o inContext: context];
o = [data objectForKey: @"endDate"];
if ([o isKindOfClass: [NSString class]] && [o length])
aptEndDate = [self _dateFromString: o inContext: context];
o = [data objectForKey: @"endTime"];
if ([o isKindOfClass: [NSString class]] && [o length])
[self _adjustDate: &aptEndDate withTimeString: o inContext: context];
o = [data objectForKey: @"isTransparent"];
if ([o isKindOfClass: [NSNumber class]])
[self setTransparency: ([o boolValue]? @"TRANSPARENT" : @"OPAQUE")];
isAllDay = [[data objectForKey: @"isAllDay"] boolValue];
if (aptStartDate && aptEndDate)
{
if (isAllDay)
{
nbrDays = ((float) abs ([aptEndDate timeIntervalSinceDate: aptStartDate]) / 86400) + 1;
// Convert all-day start date to GMT (floating date)
ud = [[context activeUser] userDefaults];
timeZone = [ud timeZone];
offset = [timeZone secondsFromGMTForDate: aptStartDate];
allDayStartDate = [aptStartDate dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: offset];
[self setAllDayWithStartDate: allDayStartDate
duration: nbrDays];
}
else
{
[self setStartDate: aptStartDate];
[self setEndDate: aptEndDate];
}
}
if (!isAllDay)
{
// Make sure there's a vTimeZone associated to the event unless it
// is an all-day event.
startDate = (iCalDateTime *)[self uniqueChildWithTag: @"dtstart"];
if (![startDate timeZone])
{
ud = [[context activeUser] userDefaults];
tz = [iCalTimeZone timeZoneForName: [ud timeZoneName]];
if ([[self parent] addTimeZone: tz])
{
[startDate setTimeZone: tz];
[(iCalDateTime *)[self uniqueChildWithTag: @"dtend"] setTimeZone: tz];
}
}
}
else // if (![[self clientObject] isNew])
{
// Remove the vTimeZone when dealing with an all-day event.
startDate = (iCalDateTime *)[self uniqueChildWithTag: @"dtstart"];
tz = [startDate timeZone];
if (tz)
{
[startDate setTimeZone: nil];
[(iCalDateTime *)[self uniqueChildWithTag: @"dtend"] setTimeZone: nil];
[[self parent] removeChild: tz];
}
}
}
@end

View File

@ -37,6 +37,10 @@
#import <NGExtensions/NGCalendarDateRange.h>
#import <SoObjects/SOGo/SOGoUser.h>
#import <SoObjects/SOGo/SOGoUserDefaults.h>
#import <SoObjects/SOGo/WOContext+SOGo.h>
#import "iCalRepeatableEntityObject+SOGo.h"
@implementation iCalRepeatableEntityObject (SOGoExtensions)
@ -76,7 +80,7 @@
* @see [iCalEvent+SOGo attributes]
* @see [UIxAppointmentEditor viewAction]
*/
- (NSDictionary *) attributes
- (NSDictionary *) attributesInContext: (WOContext *) context
{
NSMutableDictionary *data, *repeat;
NSArray *rules;
@ -110,6 +114,103 @@
return data;
}
/**
* @see [iCalEntityObject+SOGo setAttributes:inContext:]
* @see [UIxAppointmentEditor saveAction]
*/
- (void) setAttributes: (NSDictionary *) data
inContext: (WOContext *) context
{
iCalRecurrenceRule *rule;
iCalRecurrenceFrequency frequency;
NSCalendarDate *date;
SOGoUserDefaults *ud;
id repeat, o;
[super setAttributes: data inContext: context];
if ([self recurrenceId])
// Occurrence of a recurrent object can't have a recurrence rule
return;
repeat = [data objectForKey: @"repeat"];
if ([repeat isKindOfClass: [NSDictionary class]])
{
rule = [iCalRecurrenceRule new];
[rule setInterval: @"1"];
frequency = NSNotFound;
o = [repeat objectForKey: @"frequency"];
if ([o isKindOfClass: [NSString class]])
{
frequency = [rule valueForFrequency: o];
if ((NSUInteger) frequency == NSNotFound)
{
if ([o caseInsensitiveCompare: @"BI-WEEKLY"] == NSOrderedSame)
{
frequency = iCalRecurrenceFrequenceWeekly;
[rule setInterval: @"2"];
}
else if ([o caseInsensitiveCompare: @"EVERY WEEKDAY"] == NSOrderedSame)
{
frequency = iCalRecurrenceFrequenceDaily;
[rule setByDayMask: [iCalByDayMask byDayMaskWithWeekDays]];
}
}
else
{
o = [repeat objectForKey: @"interval"];
if ([o isKindOfClass: [NSNumber class]])
[rule setInterval: [NSString stringWithFormat: @"%i", [o intValue]]];
o = [repeat objectForKey: @"count"];
if ([o isKindOfClass: [NSNumber class]])
[rule setRepeatCount: [o intValue]];
o = [repeat objectForKey: @"until"];
if ([o isKindOfClass: [NSString class]])
{
date = [NSCalendarDate dateWithString: o
calendarFormat: @"%Y-%m-%d"];
if (date)
{
// Adjust timezone
ud = [[context activeUser] userDefaults];
date = [NSCalendarDate dateWithYear: [date yearOfCommonEra]
month: [date monthOfYear]
day: [date dayOfMonth]
hour: 0 minute: 0 second: 0
timeZone: [ud timeZone]];
[rule setUntilDate: date];
}
}
o = [repeat objectForKey: @"days"];
if ([o isKindOfClass: [NSArray class]])
[rule setByDayMask: [iCalByDayMask byDayMaskWithDaysAndOccurences: o]];
o = [repeat objectForKey: @"monthdays"];
if ([o isKindOfClass: [NSArray class]])
[rule setValues: o atIndex: 0 forKey: @"bymonthday"];
o = [repeat objectForKey: @"months"];
if ([o isKindOfClass: [NSArray class]])
[rule setValues: o atIndex: 0 forKey: @"bymonth"];
}
if ((NSUInteger) frequency != NSNotFound)
[rule setFrequency: frequency];
[self setRecurrenceRules: [NSArray arrayWithObject: rule]];
[rule release];
}
}
else if ([self hasRecurrenceRules])
{
[self removeAllRecurrenceRules];
}
}
- (NSString *) cycleInfo
{
NSArray *rules;
@ -124,7 +225,7 @@
rules = [self _indexedRules: [self recurrenceRules]];
if (rules)
[cycleInfo setObject: rules forKey: @"rules"];
rules = [self _indexedRules: [self exceptionRules]];
if (rules)
[cycleInfo setObject: rules forKey: @"exRules"];
@ -163,7 +264,7 @@
firstRange = [NGCalendarDateRange calendarDateRangeWithStartDate: start
endDate: end];
}
return firstRange;
}

View File

@ -301,13 +301,6 @@
}
else
data = @"";
else if ([data isKindOfClass: [NSArray class]])
{
if ([data count] > 0)
data = [data objectAtIndex: 0];
else
data = @"";
}
[newRecord setObject: data forKey: @"c_telephonenumber"];
// Custom attribute for group-lookups. See LDAPSource.m where

View File

@ -1,6 +1,6 @@
/* UIxAppointmentEditor.h - this file is part of SOGo
*
* Copyright (C) 2007-2014 Inverse inc.
* Copyright (C) 2007-2015 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
@ -24,43 +24,14 @@
#import <SOGoUI/UIxComponent.h>
@class iCalEvent;
@class NSString;
@interface UIxAppointmentEditor : UIxComponent
@interface UIxAppointmentEditor : UIxComponentEditor
{
iCalEvent *event;
BOOL isAllDay, isTransparent, sendAppointmentNotifications;
NSCalendarDate *aptStartDate;
NSCalendarDate *aptEndDate;
NSString *item;
SOGoAppointmentFolder *componentCalendar;
SOGoDateFormatter *dateFormatter;
}
/* template values */
- (NSString *) saveURL;
- (iCalEvent *) event;
/* icalendar values */
- (void) setIsAllDay: (BOOL) newIsAllDay;
- (BOOL) isAllDay;
- (void) setIsTransparent: (BOOL) newIsOpaque;
- (BOOL) isTransparent;
- (void) setSendAppointmentNotifications: (BOOL) theBOOL;
- (BOOL) sendAppointmentNotifications;
- (void) setAptStartDate: (NSCalendarDate *) newAptStartDate;
- (NSCalendarDate *) aptStartDate;
- (void) setAptEndDate: (NSCalendarDate *) newAptEndDate;
- (NSCalendarDate *) aptEndDate;
- (NSString *) aptStartDateText;
- (NSString *) aptStartDateTimeText;
- (NSString *) aptEndDateTimeText;
@end
#endif /* UIXAPPOINTMENTEDITOR_H */

View File

@ -33,6 +33,7 @@
#import <NGObjWeb/NSException+HTTP.h>
#import <NGExtensions/NSCalendarDate+misc.h>
#import <NGExtensions/NGCalendarDateRange.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGExtensions/NSString+misc.h>
#import <NGCards/iCalAlarm.h>
@ -73,15 +74,6 @@
if ((self = [super init]))
{
aptStartDate = nil;
aptEndDate = nil;
item = nil;
event = nil;
isAllDay = NO;
isTransparent = NO;
sendAppointmentNotifications = YES;
componentCalendar = nil;
user = [[self context] activeUser];
ASSIGN (dateFormatter, [user dateFormatterInContext: context]);
}
@ -91,116 +83,16 @@
- (void) dealloc
{
[item release];
[[event parent] release];
[aptStartDate release];
[aptEndDate release];
[dateFormatter release];
[componentCalendar release];
[super dealloc];
}
/* template values */
- (iCalEvent *) event
{
if (!event)
{
event = (iCalEvent *) [[self clientObject] occurence];
[[event parent] retain];
}
return event;
return (iCalEvent *) component;
}
- (NSString *) rsvpURL
{
return [NSString stringWithFormat: @"%@/rsvpAppointment",
[[self clientObject] baseURL]];
}
- (NSString *) saveURL
{
return [NSString stringWithFormat: @"%@/saveAsAppointment",
[[self clientObject] baseURL]];
}
/* icalendar values */
- (BOOL) isAllDay
{
NSString *hm;
hm = [self queryParameterForKey: @"hm"];
return (isAllDay
|| [hm isEqualToString: @"allday"]);
}
- (void) setIsAllDay: (BOOL) newIsAllDay
{
isAllDay = newIsAllDay;
}
- (BOOL) isTransparent
{
return isTransparent;
}
- (void) setIsTransparent: (BOOL) newIsTransparent
{
isTransparent = newIsTransparent;
}
- (void) setSendAppointmentNotifications: (BOOL) theBOOL
{
sendAppointmentNotifications = theBOOL;
}
- (BOOL) sendAppointmentNotifications
{
return sendAppointmentNotifications;
}
- (void) setAptStartDate: (NSCalendarDate *) newAptStartDate
{
ASSIGN (aptStartDate, newAptStartDate);
}
- (NSCalendarDate *) aptStartDate
{
return aptStartDate;
}
- (void) setAptEndDate: (NSCalendarDate *) newAptEndDate
{
ASSIGN (aptEndDate, newAptEndDate);
}
- (NSCalendarDate *) aptEndDate
{
return aptEndDate;
}
- (void) setItem: (NSString *) newItem
{
ASSIGN (item, newItem);
}
- (NSString *) item
{
return item;
}
- (SOGoAppointmentFolder *) componentCalendar
{
return componentCalendar;
}
- (void) setComponentCalendar: (SOGoAppointmentFolder *) _componentCalendar
{
ASSIGN (componentCalendar, _componentCalendar);
}
- (NSString *) formattedDateString: (NSCalendarDate *) date
- (NSString *) _dateString: (NSCalendarDate *) date
{
char buf[22];
NSNumber *day, *month, *year;
@ -217,14 +109,7 @@
return [NSString stringWithCString:buf];
}
/* read-only event */
- (BOOL) startDateIsEqualToEndDate
{
return [aptStartDate isEqualToDate: aptEndDate];
}
/* actions */
/*
- (NSCalendarDate *) newStartDate
{
NSCalendarDate *newStartDate, *now;
@ -262,7 +147,9 @@
return newStartDate;
}
*/
/*
- (id <WOActionResults>) defaultAction
{
NSCalendarDate *startDate, *endDate;
@ -316,7 +203,7 @@
endDate = [endDate dateByAddingYears:0 months:0 days:0 hours:0 minutes:0
seconds:-offset];
}
isTransparent = ![event isOpaque];
isTransparent = ![event isOpaque];
sendAppointmentNotifications = ([event firstChildWithTag: @"X-SOGo-Send-Appointment-Notifications"] ? NO : YES);
}
@ -328,15 +215,18 @@
return self;
}
*/
- (void) _adjustRecurrentRules
{
iCalEvent *event;
iCalRecurrenceRule *rule;
NSEnumerator *rules;
NSCalendarDate *untilDate;
SOGoUserDefaults *ud;
NSTimeZone *timeZone;
event = [self event];
rules = [[event recurrenceRules] objectEnumerator];
ud = [[context activeUser] userDefaults];
timeZone = [ud timeZone];
@ -492,66 +382,151 @@
return response;
}
//
//
//
/**
* @api {post} /so/:username/Calendar/:calendarId/:appointmentId/save Save event
* @apiVersion 1.0.0
* @apiName PostEventSave
* @apiGroup Calendar
* @apiExample {curl} Example usage:
* curl -i http://localhost/SOGo/so/sogo1/Calendar/personal/71B6-54904400-1-7C308500.ics/save \
* -H 'Content-Type: application/json' \
* -d '{ "summary": "Meeting", "startDate": "2015-01-28", "startTime": "10:00", \
* "endDate": "2015-01-28", "endTime": "12:00" }'
*
* Save in [iCalEvent+SOGo setAttributes:inContext:]
*
* @apiParam {String} startDate Start date (YYYY-MM-DD)
* @apiParam {String} startTime Start time (HH:MM)
* @apiParam {String} endDate End date (YYYY-MM-DD)
* @apiParam {String} endTime End time (HH:MM)
* @apiParam {Number} [isAllDay] 1 if event is all-day
* @apiParam {Number} isTransparent 1 if the event is not opaque
*
* Save in [iCalEntityObject+SOGo setAttributes:inContext:]
*
* @apiParam {Number} [sendAppointmentNotifications] 0 if notifications must not be sent
* @apiParam {String} [summary] Summary
* @apiParam {String} [location] Location
* @apiParam {String} [comment] Comment
* @apiParam {String} [status] Status
* @apiParam {String} [attachUrl] Attached URL
* @apiParam {Number} [priority] Priority
* @apiParam {NSString} [classification] Either public, confidential or private
* @apiParam {String[]} [categories] Categories
* @apiParam {Object[]} [attendees] List of attendees
* @apiParam {String} [attendees.name] Attendee's name
* @apiParam {String} attendees.email Attendee's email address
* @apiParam {String} [attendees.uid] System user ID
* @apiParam {String} attendees.status Attendee's participation status
* @apiParam {String} [attendees.role] Either CHAIR, REQ-PARTICIPANT, OPT-PARTICIPANT, or NON-PARTICIPANT
* @apiParam {String} [attendees.delegatedTo] User that the original request was delegated to
* @apiParam {String} [attendees.delegatedFrom] User the request was delegated from
* @apiParam {Object[]} [alarm] Alarm definition
* @apiParam {String} alarm.action Either display or email
* @apiParam {Number} alarm.quantity Quantity of units
* @apiParam {String} alarm.unit Either MINUTES, HOURS, or DAYS
* @apiParam {String} alarm.reference Either BEFORE or AFTER
* @apiParam {String} alarm.relation Either START or END
* @apiParam {Boolean} [alarm.attendees] Alert attendees by email if true and action is email
* @apiParam {Object} [alarm.organizer] Alert organizer at this email address if action is email
* @apiParam {String} [alarm.organizer.name] Attendee's name
* @apiParam {String} alarm.organizer.email Attendee's email address
*
* Save in [iCalRepeatbleEntityObject+SOGo setAttributes:inContext:]
*
* @apiParam {Object} [repeat] Recurrence rule definition
* @apiParam {String} repeat.frequency Either daily, every weekday, weekly, bi-weekly, monthly, or yearly
* @apiParam {Number} repeat.interval Intervals the recurrence rule repeats
* @apiParam {String} [repeat.count] Number of occurrences at which to range-bound the recurrence
* @apiParam {String} [repeat.until] A date (YYYY-MM-DD) that bounds the recurrence rule in an inclusive manner
* @apiParam {Object[]} [repeat.days] List of days of the week (by day mask)
* @apiParam {String} [repeat.days.day] Day of the week (SU, MO, TU, WE, TH, FR, SA)
* @apiParam {Number} [repeat.days.occurence] Occurrence of a specific day within the monthly or yearly rule (values are -5 to 5)
* @apiParam {Number[]} [repeat.months] List of months of the year (values are 1 to 12)
* @apiParam {Number[]} [repeat.monthdays] Days of the month (values are 1 to 31)
*
* Save in [UIxComponentEditor setAttributes:]
*
* @apiParam {Object} [organizer] Appointment organizer
* @apiParam {String} organizer.name Organizer's name
* @apiParam {String} organizer.email Organizer's email address
*
* @apiError (Error 500) {Object} error The error message
*/
- (id <WOActionResults>) saveAction
{
NSDictionary *params;
NSString *jsonResponse;
NSException *ex;
iCalEvent *event;
SOGoAppointmentFolder *previousCalendar;
SOGoAppointmentObject *co;
NSString *jsonResponse;
SoSecurityManager *sm;
NSException *ex;
WORequest *request;
event = [self event];
co = [self clientObject];
if ([co isKindOfClass: [SOGoAppointmentOccurence class]])
co = [co container];
previousCalendar = [co container];
sm = [SoSecurityManager sharedSecurityManager];
ex = nil;
if ([event hasRecurrenceRules])
[self _adjustRecurrentRules];
if ([co isNew])
request = [context request];
params = [[request contentAsString] objectFromJSONString];
if (params == nil)
{
if (componentCalendar
&& ![[componentCalendar ocsPath]
isEqualToString: [previousCalendar ocsPath]])
{
// New event in a different calendar -- make sure the user can
// write to the selected calendar since the rights were verified
// on the calendar specified in the URL, not on the selected
// calendar of the popup menu.
if (![sm validatePermission: SoPerm_AddDocumentsImagesAndFiles
onObject: componentCalendar
inContext: context])
co = [componentCalendar lookupName: [co nameInContainer]
inContext: context
acquire: NO];
}
// Save the event.
ex = [co saveComponent: event];
ex = [NSException exceptionWithName: @"JSONParsingException"
reason: @"Can't parse JSON string"
userInfo: nil];
}
else
{
// The event was modified -- save it.
ex = [co saveComponent: event];
[self setAttributes: params];
if (componentCalendar
&& ![[componentCalendar ocsPath]
isEqualToString: [previousCalendar ocsPath]])
if ([event hasRecurrenceRules])
[self _adjustRecurrentRules];
if ([co isNew])
{
// The event was moved to a different calendar.
if (![sm validatePermission: SoPerm_DeleteObjects
onObject: previousCalendar
inContext: context])
if (componentCalendar
&& ![[componentCalendar ocsPath]
isEqualToString: [previousCalendar ocsPath]])
{
// New event in a different calendar -- make sure the user can
// write to the selected calendar since the rights were verified
// on the calendar specified in the URL, not on the selected
// calendar of the popup menu.
if (![sm validatePermission: SoPerm_AddDocumentsImagesAndFiles
onObject: componentCalendar
inContext: context])
ex = [co moveToFolder: componentCalendar];
onObject: componentCalendar
inContext: context])
co = [componentCalendar lookupName: [co nameInContainer]
inContext: context
acquire: NO];
}
// Save the event.
ex = [co saveComponent: event];
}
else
{
// The event was modified -- save it.
ex = [co saveComponent: event];
if (componentCalendar
&& ![[componentCalendar ocsPath]
isEqualToString: [previousCalendar ocsPath]])
{
// The event was moved to a different calendar.
if (![sm validatePermission: SoPerm_DeleteObjects
onObject: previousCalendar
inContext: context])
{
if (![sm validatePermission: SoPerm_AddDocumentsImagesAndFiles
onObject: componentCalendar
inContext: context])
ex = [co moveToFolder: componentCalendar];
}
}
}
}
@ -565,9 +540,9 @@
else
jsonResponse = [NSDictionary dictionaryWithObjectsAndKeys:
@"success", @"status", nil];
return [self responseWithStatus: 200
andString: [jsonResponse jsonRepresentation]];
andJSONRepresentation: jsonResponse];
}
/**
@ -590,35 +565,41 @@
* @apiSuccess (Success 200) {String} endDate End date (YYYY-MM-DD)
* @apiSuccess (Success 200) {String} localizedEndDate Formatted end date
* @apiSuccess (Success 200) {String} endTime Formatted end time
*
* From [iCalEvent+SOGo attributes]
*
* @apiSuccess (Success 200) {Number} isAllDay 1 if event is all-day
* @apiSuccess (Success 200) {Number} isTransparent 1 if the event is not opaque
* @apiSuccess (Success 200) {Number} sendAppointmentNotifications 1 if notifications must be sent
*
* From [iCalEntityObject+SOGo attributes]
*
* @apiSuccess (Success 200) {Number} sendAppointmentNotifications 1 if notifications must be sent
* @apiSuccess (Success 200) {String} component "vevent"
* @apiSuccess (Success 200) {String} summary Summary
* @apiSuccess (Success 200) {String} location Location
* @apiSuccess (Success 200) {String} comment Comment
* @apiSuccess (Success 200) {String} [location] Location
* @apiSuccess (Success 200) {String} [comment] Comment
* @apiSuccess (Success 200) {String} [status] Status
* @apiSuccess (Success 200) {String} [attachUrl] Attached URL
* @apiSuccess (Success 200) {String} createdBy Value of custom header X-SOGo-Component-Created-By or organizer's "SENT-BY"
* @apiSuccess (Success 200) {String} [createdBy] Value of custom header X-SOGo-Component-Created-By or organizer's "SENT-BY"
* @apiSuccess (Success 200) {Number} priority Priority
* @apiSuccess (Success 200) {NSString} classification Either public, confidential or private
* @apiSuccess (Success 200) {NSString} [classification] Either public, confidential or private
* @apiSuccess (Success 200) {String[]} [categories] Categories
* @apiSuccess (Success 200) {Object} [organizer] Appointment organizer
* @apiSuccess (Success 200) {String} organizer.name Organizer's name
* @apiSuccess (Success 200) {String} [organizer.name] Organizer's name
* @apiSuccess (Success 200) {String} organizer.email Organizer's email address
* @apiSuccess (Success 200) {String} [organizer.uid] Organizer's user ID
* @apiSuccess (Success 200) {String} [organizer.sentBy] Email address of user that is acting on behalf of the calendar owner
* @apiSuccess (Success 200) {Object[]} [attendees] List of attendees
* @apiSuccess (Success 200) {String} [attendees.name] Attendee's name
* @apiSuccess (Success 200) {String} attendees.email Attendee's email address
* @apiSuccess (Success 200) {String} [attendees.uid] System user ID
* @apiSuccess (Success 200) {String} attendees.status Attendee's participation status
* @apiSuccess (Success 200) {String} [attendees.role] Attendee's role
* @apiSuccess (Success 200) {String} [attendees.role] Either CHAIR, REQ-PARTICIPANT, OPT-PARTICIPANT, or NON-PARTICIPANT
* @apiSuccess (Success 200) {String} [attendees.delegatedTo] User that the original request was delegated to
* @apiSuccess (Success 200) {String} [attendees.delegatedFrom] User the request was delegated from
* @apiSuccess (Success 200) {Object[]} [alarm] Alarm definition
* @apiSuccess (Success 200) {String} alarm.action Either display or email
* @apiSuccess (Success 200) {String} alarm.quantity Quantity of units
* @apiSuccess (Success 200) {Number} alarm.quantity Quantity of units
* @apiSuccess (Success 200) {String} alarm.unit Either MINUTES, HOURS, or DAYS
* @apiSuccess (Success 200) {String} alarm.reference Either BEFORE or AFTER
* @apiSuccess (Success 200) {String} alarm.relation Either START or END
@ -634,9 +615,9 @@
* @apiSuccess (Success 200) {Number} repeat.interval Intervals the recurrence rule repeats
* @apiSuccess (Success 200) {String} [repeat.count] Number of occurrences at which to range-bound the recurrence
* @apiSuccess (Success 200) {String} [repeat.until] A Unix epoch value that bounds the recurrence rule in an inclusive manner
* @apiSuccess (Success 200) {Number[]} [repeat.days] List of days of the week
* @apiSuccess (Success 200) {Object[]} [repeat.days] List of days of the week (by day mask)
* @apiSuccess (Success 200) {String} repeat.days.day Day of the week (SU, MO, TU, WE, TH, FR, SA)
* @apiSuccess (Success 200) {Number} [repeat.days.occurence] Occurrence of a specific day within the monthly or yearly rule (valures are -5 to 5)
* @apiSuccess (Success 200) {Number} [repeat.days.occurence] Occurrence of a specific day within the monthly or yearly rule (values are -5 to 5)
* @apiSuccess (Success 200) {Number[]} [repeat.months] List of months of the year (values are 1 to 12)
* @apiSuccess (Success 200) {Number[]} [repeat.monthdays] Days of the month (values are 1 to 31)
*/
@ -648,11 +629,14 @@
SOGoUserDefaults *ud;
SOGoCalendarComponent *co;
iCalAlarm *anAlarm;
iCalEvent *event;
BOOL resetAlarm;
unsigned int snoozeAlarm;
[self event];
// [self component];
// [self componentCalendar];
event = [self event];
ud = [[context activeUser] userDefaults];
timeZone = [ud timeZone];
@ -661,14 +645,6 @@
[eventStartDate setTimeZone: timeZone];
[eventEndDate setTimeZone: timeZone];
co = [self clientObject];
if (!componentCalendar)
{
componentCalendar = [co container];
if ([componentCalendar isKindOfClass: [SOGoCalendarComponent class]])
componentCalendar = [componentCalendar container];
[componentCalendar retain];
}
// resetAlarm=yes is set only when we are about to show the alarm popup in the Web
// interface of SOGo. See generic.js for details. snoozeAlarm=X is called when the
@ -676,7 +652,7 @@
// If either is set, we must find the right alarm.
resetAlarm = [[[context request] formValueForKey: @"resetAlarm"] boolValue];
snoozeAlarm = [[[context request] formValueForKey: @"snoozeAlarm"] intValue];
if (resetAlarm || snoozeAlarm)
{
iCalEvent *master;
@ -686,7 +662,7 @@
timezone: timeZone
startDate: &eventStartDate
endDate: &eventEndDate];
anAlarm = [event firstDisplayOrAudioAlarm];
if (resetAlarm)
@ -694,7 +670,7 @@
iCalTrigger *aTrigger;
aTrigger = [anAlarm trigger];
[aTrigger setValue: 0 ofAttribute: @"x-webstatus" to: @"triggered"];
[aTrigger setValue: 0 ofAttribute: @"x-webstatus" to: @"triggered"];
[co saveComponent: master];
}
else if (snoozeAlarm)
@ -707,10 +683,10 @@
[co nameInContainer], @"id",
[componentCalendar nameInContainer], @"pid",
[componentCalendar displayName], @"calendar",
[self formattedDateString: eventStartDate], @"startDate",
[self _dateString: eventStartDate], @"startDate",
[dateFormatter formattedDate: eventStartDate], @"localizedStartDate",
[dateFormatter formattedTime: eventStartDate], @"startTime",
[self formattedDateString: eventEndDate], @"endDate",
[self _dateString: eventEndDate], @"endDate",
[dateFormatter formattedDate: eventEndDate], @"localizedEndDate",
[dateFormatter formattedTime: eventEndDate], @"endTime",
nil];
@ -722,78 +698,4 @@
return [self responseWithStatus: 200 andJSONRepresentation: data];
}
- (void) takeValuesFromRequest: (WORequest *) _rq
inContext: (WOContext *) _ctx
{
int nbrDays;
iCalDateTime *startDate;
iCalTimeZone *tz;
NSCalendarDate *allDayStartDate;
NSTimeZone *timeZone;
SOGoUserDefaults *ud;
signed int offset;
id o;
[self event];
[super takeValuesFromRequest: _rq inContext: _ctx];
if (isAllDay)
{
nbrDays = ((float) abs ([aptEndDate timeIntervalSinceDate: aptStartDate])
/ 86400) + 1;
// Convert all-day start date to GMT (floating date)
ud = [[context activeUser] userDefaults];
timeZone = [ud timeZone];
offset = [timeZone secondsFromGMTForDate: aptStartDate];
allDayStartDate = [aptStartDate dateByAddingYears:0 months:0 days:0 hours:0 minutes:0
seconds:offset];
[event setAllDayWithStartDate: allDayStartDate
duration: nbrDays];
}
else
{
[event setStartDate: aptStartDate];
[event setEndDate: aptEndDate];
}
if (!isAllDay)
{
// Make sure there's a vTimeZone associated to the event unless it
// is an all-day event.
startDate = (iCalDateTime *)[event uniqueChildWithTag: @"dtstart"];
if (![startDate timeZone])
{
ud = [[context activeUser] userDefaults];
tz = [iCalTimeZone timeZoneForName: [ud timeZoneName]];
if ([[event parent] addTimeZone: tz])
{
[startDate setTimeZone: tz];
[(iCalDateTime *)[event uniqueChildWithTag: @"dtend"] setTimeZone: tz];
}
}
}
else if (![[self clientObject] isNew])
{
// Remove the vTimeZone when dealing with an all-day event.
startDate = (iCalDateTime *)[event uniqueChildWithTag: @"dtstart"];
tz = [startDate timeZone];
if (tz)
{
[startDate setTimeZone: nil];
[(iCalDateTime *)[event uniqueChildWithTag: @"dtend"] setTimeZone: nil];
[[event parent] removeChild: tz];
}
}
[event setTransparency: (isTransparent? @"TRANSPARENT" : @"OPAQUE")];
o = [event firstChildWithTag: @"X-SOGo-Send-Appointment-Notifications"];
if (!sendAppointmentNotifications && !o)
[event addChild: [CardElement simpleElementWithTag: @"X-SOGo-Send-Appointment-Notifications" value: @"NO"]];
else if (sendAppointmentNotifications && o)
[event removeChild: o];
}
@end

View File

@ -23,167 +23,17 @@
#import <SOGoUI/UIxComponent.h>
@class NSArray;
@class NSCalendarDate;
@class NSDictionary;
@class NSString;
@class iCalPerson;
@class iCalRecurrenceRule;
@class iCalRepeatableEntityObject;
@interface UIxComponentEditor : UIxComponent
{
iCalRepeatableEntityObject *component;
id item;
id attendee;
NSString *rsvpURL;
NSString *saveURL;
NSMutableArray *calendarList;
NSDictionary *organizerProfile;
/* individual values */
NSCalendarDate *cycleUntilDate;
NSString *title;
NSString *location;
SOGoAppointmentFolder *componentCalendar;
NSString *comment;
NSString *attachUrl;
NSString *priority;
NSString *classification;
NSString *status;
NSString *category;
NSArray *categories;
NSDictionary *cycle;
NSString *cycleEnd;
iCalPerson *organizer;
iCalPerson *ownerAsAttendee;
NSString *componentOwner;
NSString *dateFormat;
NSMutableDictionary *jsonAttendees;
NSString *reminder;
NSString *reminderQuantity;
NSString *reminderUnit;
NSString *reminderRelation;
NSString *reminderReference;
NSString *reminderAction;
BOOL reminderEmailOrganizer;
BOOL reminderEmailAttendees;
/* ugly */
NSString *repeat;
NSString *repeatType;
NSString *repeat1;
NSString *repeat2;
NSString *repeat3;
NSString *repeat4;
NSString *repeat5;
NSString *repeat6;
NSString *repeat7;
NSString *range1;
NSString *range2;
}
- (NSString *) toolbar;
- (void) setComponent: (iCalRepeatableEntityObject *) newComponent;
- (void) setSaveURL: (NSString *) newSaveURL;
- (NSString *) saveURL;
- (void) setItem: (id) _item;
- (id) item;
- (SOGoAppointmentFolder *) componentCalendar;
- (NSArray *) calendarList;
- (NSString *) calendarsFoldersList;
- (NSString *) calendarDisplayName;
- (SOGoAppointmentFolder *) componentCalendar;
- (void) setComponentCalendar: (SOGoAppointmentFolder *) _componentCalendar;
- (NSArray *) categoryList;
- (void) setCategories: (NSArray *) _categories;
- (NSArray *) categories;
- (NSArray *) priorities;
- (void) setPriority: (NSString *) _priority;
- (NSString *) priority;
- (NSString *) itemPriorityText;
- (NSArray *) classificationClasses;
- (void) setClassification: (NSString *) _classification;
- (NSString *) classification;
- (NSString *) itemClassificationText;
- (void) setStatus: (NSString *) _status;
- (NSString *) status;
- (NSString *) itemStatusText;
- (void) setTitle: (NSString *) _value;
- (NSString *) title;
- (void) setLocation: (NSString *) _value;
- (NSString *) location;
- (NSString *) location;
- (void) setComment: (NSString *) _value;
- (NSString *) comment;
- (void) setAttach: (NSString *) _attachUrl;
- (NSString *) attach;
- (BOOL) hasAttendees;
- (BOOL) hasCreatedBy;
- (NSString *) createdBy;
- (NSString *) createdByLink;
- (NSString *) createdByName;
- (NSString *) jsonAttendees;
- (NSString *) repeat;
- (void) setRepeat: (NSString *) newRepeat;
- (NSString *) reminder;
- (void) setReminder: (NSString *) newReminder;
////////////////////////////////// JUNK ////////////////////////////////////////
////////////////////////////////// JUNK ////////////////////////////////////////
////////////////////////////////// JUNK ////////////////////////////////////////
- (NSArray *) cycles;
- (void) setCycle: (NSDictionary *) _cycle;
- (NSDictionary *) cycle;
- (BOOL) hasCycle;
- (NSString *) cycleLabel;
- (void) setCycleUntilDate: (NSCalendarDate *) _cycleUntilDate;
- (NSCalendarDate *) cycleUntilDate;
- (iCalRecurrenceRule *) rrule;
- (void) adjustCycleControlsForRRule: (iCalRecurrenceRule *) _rrule;
- (NSDictionary *) cycleMatchingRRule: (iCalRecurrenceRule *) _rrule;
- (NSArray *) cycleEnds;
- (void) setCycleEnd: (NSString *) _cycleEnd;
- (NSString *) cycleEnd;
- (BOOL) isCycleEndUntil;
- (void) setIsCycleEndUntil;
- (void) setIsCycleEndNever;
////////////////////////////////// JUNK ////////////////////////////////////////
////////////////////////////////// JUNK ////////////////////////////////////////
////////////////////////////////// JUNK ////////////////////////////////////////
/* access */
- (BOOL) canEditComponent;
- (unsigned int) firstDayOfWeek;
/* helpers */
- (NSString *) completeURIForMethod: (NSString *) _method;
- (BOOL) isWriteableClientObject;
- (NSException *) validateObjectForStatusChange;
- (void) setAttributes: (NSDictionary *) attributes;
+ (NSArray *) reminderValues;

File diff suppressed because it is too large Load Diff