Monotone-Parent: 467dc56666485b20c968357bff135be6a192df0c

Monotone-Revision: 81ebf97febc5675193974e8834acc35e001494f1

Monotone-Author: wsourdeau@inverse.ca
Monotone-Date: 2007-03-18T15:20:38
Monotone-Branch: ca.inverse.sogo
maint-2.0.2
Wolfgang Sourdeau 2007-03-18 15:20:38 +00:00
parent 84bba82435
commit d26f7a625a
7 changed files with 982 additions and 1239 deletions

View File

@ -1,5 +1,14 @@
2007-03-18 Wolfgang Sourdeau <wsourdeau@inverse.ca> 2007-03-18 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* UI/Scheduler/UIxComponentEditor.m: no longer a superclass for
the task and appointment editors. Now a container component
handling the common elements of tasks and events.
* UI/Scheduler/UIxTaskEditor.m: same as below.
* UI/Scheduler/UIxAppointmentEditor.m: rewrote template. No longer
a subclass of UIxComponentEditor but a subcomponent of it.
* UI/Common/UIxToolbar.m ([UIxToolbar -toolbarConfig]): the * UI/Common/UIxToolbar.m ([UIxToolbar -toolbarConfig]): the
toolbar can have the special value "none" to indicate there is toolbar can have the special value "none" to indicate there is
none attached to the window. none attached to the window.

View File

@ -1,6 +1,6 @@
/* UIxAppointmentEditor.h - this file is part of SOGo /* UIxAppointmentEditor.h - this file is part of SOGo
* *
* Copyright (C) 2006 Inverse groupe conseil * Copyright (C) 2007 Inverse groupe conseil
* *
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca> * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* *
@ -23,50 +23,38 @@
#ifndef UIXAPPOINTMENTEDITOR_H #ifndef UIXAPPOINTMENTEDITOR_H
#define UIXAPPOINTMENTEDITOR_H #define UIXAPPOINTMENTEDITOR_H
#import <UIxComponentEditor.h> #import <SOGoUI/UIxComponent.h>
@class iCalEvent;
@class NSString; @class NSString;
@class iCalPerson;
@class iCalRecurrenceRule;
@interface UIxAppointmentEditor : UIxComponentEditor @interface UIxAppointmentEditor : UIxComponent
{ {
NSCalendarDate *endDate; iCalEvent *event;
NSCalendarDate *aptStartDate;
NSCalendarDate *aptEndDate;
NSString *item;
} }
/* template values */
- (NSString *) saveURL;
- (iCalEvent *) event;
/* icalendar values */
- (BOOL) isAllDay;
- (void) setIsAllDay: (BOOL) newIsAllDay;
- (void) setAptStartDate: (NSCalendarDate *) _date; - (void) setAptStartDate: (NSCalendarDate *) _date;
- (NSCalendarDate *) aptStartDate; - (NSCalendarDate *) aptStartDate;
- (void) setAptEndDate: (NSCalendarDate *) _date; - (void) setAptEndDate: (NSCalendarDate *) _date;
- (NSCalendarDate *) aptEndDate; - (NSCalendarDate *) aptEndDate;
/* iCal */ - (NSString *) repeat;
- (void) setRepeat: (NSString *) newRepeat;
- (NSString *) iCalStringTemplate; - (NSString *) reminder;
- (void) setReminder: (NSString *) newReminder;
/* new */
- (id) newAction;
/* save */
- (void) loadValuesFromAppointment: (iCalEvent *) _apt;
- (void) saveValuesIntoAppointment: (iCalEvent *) _apt;
- (iCalEvent *) appointmentFromString: (NSString *) _iCalString;
/* conflict management */
- (BOOL) containsConflict: (id) _apt;
- (id <WOActionResults>) defaultAction;
- (id <WOActionResults>) saveAction;
- (id) acceptAction;
- (id) declineAction;
- (NSString *) saveUrl;
// TODO: add tentatively
- (id) acceptOrDeclineAction: (BOOL) _accept;
@end @end

View File

@ -1,458 +1,366 @@
/* /* UIxAppointmentEditor.m - this file is part of SOGo
Copyright (C) 2004-2005 SKYRIX Software AG *
* Copyright (C) 2007 Inverse groupe conseil
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* 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
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
This file is part of OpenGroupware.org. #import <NGObjWeb/SoObject.h>
#import <NGObjWeb/WORequest.h>
#import <NGObjWeb/NSException+HTTP.h>
#import <NGExtensions/NSCalendarDate+misc.h>
OGo is free software; you can redistribute it and/or modify it under #import <NGCards/iCalEvent.h>
the terms of the GNU Lesser General Public License as published by the #import <NGCards/iCalPerson.h>
Free Software Foundation; either version 2, or (at your option) any
later version.
OGo is distributed in the hope that it will be useful, but WITHOUT ANY #import <SoObjects/SOGo/AgenorUserManager.h>
WARRANTY; without even the implied warranty of MERCHANTABILITY or #import <SoObjects/SOGo/SOGoUser.h>
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public #import <SoObjects/SOGo/SOGoContentObject.h>
License for more details. #import <SoObjects/Appointments/SOGoAppointmentFolder.h>
#import <SoObjects/Appointments/SOGoAppointmentObject.h>
You should have received a copy of the GNU Lesser General Public
License along with OGo; see the file COPYING. If not, write to the
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
#import <NGCards/NSString+NGCards.h>
#import <NGCards/NSCalendarDate+NGCards.h>
#import <SOGo/AgenorUserManager.h>
#import <SOGo/NSCalendarDate+SOGo.h>
#import "common.h"
#import <NGCards/NGCards.h>
#import <NGExtensions/NGCalendarDateRange.h>
#import <SOGoUI/SOGoDateFormatter.h>
#import <Appointments/SOGoAppointmentFolder.h>
#import <Appointments/SOGoAppointmentObject.h>
#import "UIxComponent+Agenor.h"
#import "UIxComponentEditor.h"
#import "UIxAppointmentEditor.h" #import "UIxAppointmentEditor.h"
/* TODO: CLEAN UP */
@implementation UIxAppointmentEditor @implementation UIxAppointmentEditor
+ (int)version { - (id) init
return [super version] + 0 /* v2 */;
}
+ (void)initialize {
NSAssert2([super version] == 2,
@"invalid superclass (%@) version %i !",
NSStringFromClass([self superclass]), [super version]);
}
- (void) dealloc
{ {
[endDate release]; if ((self = [super init]))
[super dealloc]; {
} aptStartDate = nil;
aptEndDate = nil;
/* accessors */ item = nil;
event = nil;
- (void) setAptStartDate: (NSCalendarDate *)_date
{
[self setStartDate: _date];
}
- (NSCalendarDate *) aptStartDate
{
return [self startDate];
}
- (void) setAptEndDate: (NSCalendarDate *) _date
{
ASSIGN(endDate, _date);
}
- (NSCalendarDate *) aptEndDate
{
return endDate;
}
/* transparency */
- (NSString *) transparency
{
return @"OPAQUE";
}
/* iCal */
- (NSString *)iCalStringTemplate {
static NSString *iCalStringTemplate = \
@"BEGIN:VCALENDAR\r\n"
@"METHOD:REQUEST\r\n"
@"PRODID://Inverse groupe conseil/SOGo 0.9\r\n"
@"VERSION:2.0\r\n"
@"BEGIN:VEVENT\r\n"
@"UID:%@\r\n"
@"CLASS:PUBLIC\r\n"
@"STATUS:CONFIRMED\r\n" /* confirmed by default */
@"DTSTAMP:%@Z\r\n"
@"DTSTART:%@Z\r\n"
@"DTEND:%@Z\r\n"
@"TRANSP:%@\r\n"
@"SEQUENCE:1\r\n"
@"PRIORITY:5\r\n"
@"%@" /* organizer */
@"%@" /* participants and resources */
@"END:VEVENT\r\n"
@"END:VCALENDAR";
NSTimeZone *utc;
NSCalendarDate *lStartDate, *lEndDate, *stamp;
NSString *template, *s;
unsigned minutes;
s = [self queryParameterForKey:@"dur"];
if ([s length] > 0)
minutes = [s intValue];
else
minutes = 60;
utc = [NSTimeZone timeZoneWithName: @"GMT"];
lStartDate = [self newStartDate];
[lStartDate setTimeZone: utc];
lEndDate = [lStartDate dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: minutes seconds: 0];
stamp = [NSCalendarDate calendarDate];
[stamp setTimeZone: utc];
s = [self iCalParticipantsAndResourcesStringFromQueryParameters];
template = [NSString stringWithFormat: iCalStringTemplate,
[[self clientObject] nameInContainer],
[stamp iCalFormattedDateTimeString],
[lStartDate iCalFormattedDateTimeString],
[lEndDate iCalFormattedDateTimeString],
[self transparency],
[self iCalOrganizerString],
s];
return template;
}
/* new */
- (id) newAction
{
/*
This method creates a unique ID and redirects to the "edit" method on the
new ID.
It is actually a folder method and should be defined on the folder.
Note: 'clientObject' is the SOGoAppointmentFolder!
Update: remember that there are group folders as well.
*/
NSString *uri, *objectId, *method, *ps;
objectId = [NSClassFromString(@"SOGoAppointmentFolder")
globallyUniqueObjectId];
if ([objectId length] == 0) {
return [NSException exceptionWithHTTPStatus:500 /* Internal Error */
reason:@"could not create a unique ID"];
}
method = [NSString stringWithFormat:@"Calendar/%@/editAsAppointment", objectId];
method = [[self userFolderPath] stringByAppendingPathComponent:method];
/* check if participants have already been provided */
ps = [self queryParameterForKey:@"ps"];
// if (ps) {
// [self setQueryParameter:ps forKey:@"ps"];
// }
if (!ps
&& [[self clientObject] respondsToSelector:@selector(calendarUIDs)]) {
AgenorUserManager *um;
NSArray *uids;
NSMutableArray *emails;
unsigned i, count;
/* add all current calendarUIDs as default participants */
um = [AgenorUserManager sharedUserManager];
uids = [[self clientObject] calendarUIDs];
count = [uids count];
emails = [NSMutableArray arrayWithCapacity:count];
for (i = 0; i < count; i++) {
NSString *email;
email = [um getEmailForUID:[uids objectAtIndex:i]];
if (email)
[emails addObject:email];
} }
ps = [emails componentsJoinedByString:@","];
[self setQueryParameter:ps forKey:@"ps"];
}
uri = [self completeHrefForMethod:method];
return [self redirectToLocation:uri];
}
/* save */
- (void) loadValuesFromAppointment: (iCalEvent *) appointment
{
NSTimeZone *uTZ;
[self loadValuesFromComponent: appointment];
uTZ = [[self clientObject] userTimeZone];
endDate = [appointment endDate];
if (!endDate)
endDate = [[self startDate] dateByAddingYears: 0 months: 0 days: 0
hours: 1 minutes: 0 seconds: 0];
[endDate setTimeZone: uTZ];
[endDate retain];
}
- (void) saveValuesIntoAppointment: (iCalEvent *) _appointment
{
/* merge in form values */
NSArray *attendees, *lResources;
iCalRecurrenceRule *rrule;
[_appointment setStartDate:[self aptStartDate]];
[_appointment setEndDate:[self aptEndDate]];
[_appointment setSummary: [self title]];
[_appointment setUrl: [self url]];
[_appointment setLocation: [self location]];
[_appointment setComment: [self comment]];
[_appointment setPriority:[self priority]];
[_appointment setAccessClass: [self privacy]];
[_appointment setStatus: [self status]];
// [_appointment setCategories: [[self categories] componentsJoinedByString: @","]];
[_appointment setTransparency: [self transparency]];
#if 0
/*
Note: bad, bad, bad!
Organizer is no form value, thus we MUST NOT change it
*/
[_appointment setOrganizer:organizer];
#endif
attendees = [self participants];
lResources = [self resources];
if ([lResources count] > 0) {
attendees = ([attendees count] > 0)
? [attendees arrayByAddingObjectsFromArray: lResources]
: lResources;
}
[attendees makeObjectsPerformSelector: @selector (setTag:)
withObject: @"attendee"];
[_appointment setAttendees: attendees];
/* cycles */
[_appointment removeAllRecurrenceRules];
rrule = [self rrule];
if (rrule)
[_appointment addToRecurrenceRules: rrule];
}
- (iCalEvent *) appointmentFromString: (NSString *) _iCalString
{
iCalCalendar *calendar;
iCalEvent *appointment;
calendar = [iCalCalendar parseSingleFromSource: _iCalString];
appointment = (iCalEvent *) [calendar firstChildWithTag: @"vevent"];
return appointment;
}
/* conflict management */
- (BOOL) containsConflict: (id) _apt
{
NSArray *attendees, *uids;
SOGoAppointmentFolder *groupCalendar;
NSArray *infos;
NSArray *ranges;
id folder;
[self logWithFormat:@"search from %@ to %@",
[_apt startDate], [_apt endDate]];
folder = [[self clientObject] container];
attendees = [_apt attendees];
uids = [folder uidsFromICalPersons:attendees];
if ([uids count] == 0) {
[self logWithFormat:@"Note: no UIDs selected."];
return NO;
}
groupCalendar = [folder lookupGroupCalendarFolderForUIDs:uids
inContext:[self context]];
[self debugWithFormat:@"group calendar: %@", groupCalendar];
if (![groupCalendar respondsToSelector:@selector(fetchFreeBusyInfosFrom:to:)]) {
[self errorWithFormat:@"invalid folder to run freebusy query on!"];
return NO;
}
infos = [groupCalendar fetchFreeBusyInfosFrom:[_apt startDate]
to:[_apt endDate]];
[self debugWithFormat:@" process: %d events", [infos count]];
ranges = [infos arrayByCreatingDateRangesFromObjectsWithStartDateKey: @"startDate"
andEndDateKey: @"endDate"];
ranges = [ranges arrayByCompactingContainedDateRanges];
[self debugWithFormat:@" blocked ranges: %@", ranges];
return [ranges count] != 0 ? YES : NO;
}
/* actions */
- (id) testAction
{
/* for testing only */
WORequest *req;
iCalEvent *apt;
NSString *content;
req = [[self context] request];
apt = [self appointmentFromString: [self iCalString]];
[self saveValuesIntoAppointment:apt];
content = [[apt parent] versitString];
[self logWithFormat:@"%s -- iCal:\n%@",
__PRETTY_FUNCTION__,
content];
return self; return self;
} }
- (id<WOActionResults>) defaultAction /* template values */
- (iCalEvent *) event
{ {
NSString *ical; return event;
/* load iCalendar file */
// TODO: can't we use [clientObject contentAsString]?
// ical = [[self clientObject] valueForKey:@"iCalString"];
ical = [[self clientObject] contentAsString];
if ([ical length] == 0) /* a new appointment */
ical = [self iCalStringTemplate];
[self setICalString:ical];
[self loadValuesFromAppointment: [self appointmentFromString: ical]];
// if (![self canEditComponent]) {
// /* TODO: we need proper ACLs */
// return [self redirectToLocation: [self completeURIForMethod: @"../view"]];
// }
return self;
} }
- (id <WOActionResults>) saveAction - (NSString *) saveURL
{
iCalEvent *apt;
iCalPerson *p;
id <WOActionResults> result;
NSString *content;
NSException *ex;
if (![self isWriteableClientObject]) {
/* return 400 == Bad Request */
return [NSException exceptionWithHTTPStatus:400
reason:@"method cannot be invoked on "
@"the specified object"];
}
apt = [self appointmentFromString: [self iCalString]];
if (apt == nil) {
NSString *s;
s = [self labelForKey:@"Invalid iCal data!"];
[self setErrorText:s];
return self;
}
[self saveValuesIntoAppointment:apt];
p = [apt findParticipantWithEmail:[self emailForUser]];
if (p) {
[p setParticipationStatus:iCalPersonPartStatAccepted];
}
if ([self checkForConflicts]) {
if ([self containsConflict:apt]) {
NSString *s;
s = [self labelForKey:@"Conflicts found!"];
[self setErrorText:s];
return self;
}
}
content = [[apt parent] versitString];
// [apt release]; apt = nil;
if (content == nil) {
NSString *s;
s = [self labelForKey:@"Could not create iCal data!"];
[self setErrorText:s];
return self;
}
ex = [[self clientObject] saveContentString:content];
if (ex != nil) {
[self setErrorText:[ex reason]];
return self;
}
if ([[[[self context] request] formValueForKey: @"nojs"] intValue])
result = [self redirectToLocation: [self applicationPath]];
else
result = [self jsCloseWithRefreshMethod: @"refreshAppointmentsAndDisplay()"];
return result;
}
- (NSString *) saveUrl
{ {
return [NSString stringWithFormat: @"%@/saveAsAppointment", return [NSString stringWithFormat: @"%@/saveAsAppointment",
[[self clientObject] baseURL]]; [[self clientObject] baseURL]];
} }
- (id) acceptAction - (NSString *) _toolbarForCalObject
{ {
return [self acceptOrDeclineAction:YES]; SOGoUser *currentUser;
SOGoAppointmentObject *clientObject;
NSString *filename, *email;
iCalPerson *person;
iCalPersonPartStat participationStatus;
clientObject = [self clientObject];
currentUser = [[self context] activeUser];
email = [currentUser email];
if ([clientObject isOrganizer: email
orOwner: [currentUser login]])
filename = @"SOGoAppointmentObject.toolbar";
else
{
if ([clientObject isParticipant: email])
{
person = [[clientObject component: NO] findParticipantWithEmail: email];
participationStatus = [person participationStatus];
if (participationStatus == iCalPersonPartStatAccepted)
filename = @"SOGoAppointmentObjectDecline.toolbar";
else if (participationStatus == iCalPersonPartStatDeclined)
filename = @"SOGoAppointmentObjectAccept.toolbar";
else
filename = @"SOGoAppointmentObjectAcceptOrDecline.toolbar";
}
else
filename = @"";
}
return filename;
} }
- (id) declineAction - (NSString *) toolbar
{ {
return [self acceptOrDeclineAction:NO]; return ([self _toolbarForCalObject]);
} }
// TODO: add tentatively /* icalendar values */
- (BOOL) isAllDay
- (id) acceptOrDeclineAction: (BOOL) _accept
{ {
// TODO: this should live in the SoObjects return NO;
NSException *ex;
if ((ex = [self validateObjectForStatusChange]) != nil)
return ex;
ex = [[self clientObject] changeParticipationStatus:
_accept ? @"ACCEPTED" : @"DECLINED"
inContext:[self context]];
if (ex != nil) return ex;
return self;
// return [self redirectToLocation: [self completeURIForMethod: @"../view"]];
} }
@end /* UIxAppointmentEditor */ - (void) setIsAllDay: (BOOL) newIsAllDay
{
}
- (void) setAptStartDate: (NSCalendarDate *) newAptStartDate
{
ASSIGN (aptStartDate, newAptStartDate);
}
- (NSCalendarDate *) aptStartDate
{
return aptStartDate;
}
- (void) setAptEndDate: (NSCalendarDate *) newAptEndDate
{
ASSIGN (aptEndDate, newAptEndDate);
}
- (NSCalendarDate *) aptEndDate
{
return aptEndDate;
}
- (NSArray *) repeatList
{
static NSArray *repeatItems = nil;
if (!repeatItems)
{
repeatItems = [NSArray arrayWithObjects: @"DAILY",
@"WEEKLY",
@"BI-WEEKLY",
@"EVERY WEEKDAY",
@"MONTHLY",
@"YEARLY",
@"-",
@"CUSTOM",
nil];
[repeatItems retain];
}
return repeatItems;
}
- (NSString *) itemRepeatText
{
NSString *text;
if ([item isEqualToString: @"-"])
text = item;
else
text = [self labelForKey: [NSString stringWithFormat: @"repeat_%@", item]];
return text;
}
- (void) setItem: (NSString *) newItem
{
item = newItem;
}
- (NSString *) item
{
return item;
}
- (NSArray *) reminderList
{
static NSArray *reminderItems = nil;
if (!reminderItems)
{
reminderItems = [NSArray arrayWithObjects: @"5_MINUTES_BEFORE",
@"10_MINUTES_BEFORE",
@"15_MINUTES_BEFORE",
@"30_MINUTES_BEFORE",
@"45_MINUTES_BEFORE",
@"-",
@"1_HOUR_BEFORE",
@"2_HOURS_BEFORE",
@"5_HOURS_BEFORE",
@"15_HOURS_BEFORE",
@"-",
@"1_DAY_BEFORE",
@"2_DAYS_BEFORE",
@"1_WEEK_BEFORE",
@"-",
@"CUSTOM",
nil];
[reminderItems retain];
}
return reminderItems;
}
// - (void) setReminder: (NSString *) reminder
// {
// ASSIGN(reminder, _reminder);
// }
// - (NSString *) reminder
// {
// return reminder;
// }
- (NSString *) itemReminderText
{
NSString *text;
if ([item isEqualToString: @"-"])
text = item;
else
text = [self labelForKey: [NSString stringWithFormat: @"reminder_%@", item]];
return text;
}
- (NSString *) repeat
{
return @"";
}
- (void) setRepeat: (NSString *) newRepeat
{
}
- (NSString *) reminder
{
return @"";
}
- (void) setReminder: (NSString *) newReminder
{
}
/* actions */
- (NSCalendarDate *) newStartDate
{
NSCalendarDate *newStartDate, *now;
int hour;
newStartDate = [self selectedDate];
if ([[self queryParameterForKey: @"hm"] length] == 0)
{
now = [NSCalendarDate calendarDate];
[now setTimeZone: [[self clientObject] userTimeZone]];
if ([now isDateOnSameDay: newStartDate])
{
hour = [now hourOfDay];
if (hour < 8)
newStartDate = [now hour: 8 minute: 0];
else if (hour > 18)
newStartDate = [[now tomorrow] hour: 8 minute: 0];
else
newStartDate = now;
}
else
newStartDate = [newStartDate hour: 8 minute: 0];
}
return newStartDate;
}
- (id <WOActionResults>) defaultAction
{
NSCalendarDate *startDate, *endDate;
NSString *duration;
unsigned int minutes;
event = (iCalEvent *) [[self clientObject] component: NO];
if (event)
{
startDate = [event startDate];
endDate = [event endDate];
}
else
{
startDate = [self newStartDate];
duration = [self queryParameterForKey:@"dur"];
if ([duration length] > 0)
minutes = [duration intValue];
else
minutes = 60;
endDate
= [startDate dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: minutes seconds: 0];
}
ASSIGN (aptStartDate, startDate);
ASSIGN (aptEndDate, endDate);
/* here comes the code for initializing repeat, reminder and isAllDay... */
return self;
}
- (id <WOActionResults>) newAction
{
NSString *objectId, *method, *uri;
id <WOActionResults> result;
Class clientKlazz;
clientKlazz = [[self clientObject] class];
objectId = [clientKlazz globallyUniqueObjectId];
if ([objectId length] > 0)
{
method = [NSString stringWithFormat:@"%@/Calendar/%@/editAsAppointment",
[self userFolderPath], objectId];
uri = [self completeHrefForMethod: method];
result = [self redirectToLocation: uri];
}
else
result = [NSException exceptionWithHTTPStatus: 500 /* Internal Error */
reason: @"could not create a unique ID"];
return result;
}
- (id <WOActionResults>) saveAction
{
SOGoAppointmentObject *clientObject;
NSString *iCalString;
clientObject = [self clientObject];
iCalString = [[clientObject calendar: NO] versitString];
[clientObject saveContentString: iCalString];
return [self jsCloseWithRefreshMethod: @"refreshAppointmentsAndDisplay()"];
}
- (BOOL) shouldTakeValuesFromRequest: (WORequest *) request
inContext: (WOContext*) context
{
return ([[self clientObject] isKindOfClass: [SOGoAppointmentObject class]]
&& [[request method] isEqualToString: @"POST"]);
}
- (void) takeValuesFromRequest: (WORequest *) _rq
inContext: (WOContext *) _ctx
{
SOGoAppointmentObject *clientObject;
clientObject = [self clientObject];
event = (iCalEvent *) [clientObject component: YES];
[super takeValuesFromRequest: _rq inContext: _ctx];
[event setStartDate: aptStartDate];
[event setEndDate: aptEndDate];
if ([clientObject isNew])
[event setTransparency: @"OPAQUE"];
}
@end

View File

@ -37,33 +37,36 @@
@interface UIxComponentEditor : UIxComponent @interface UIxComponentEditor : UIxComponent
{ {
NSString *iCalString; iCalRepeatableEntityObject *component;
NSString *errorText;
id item; id item;
NSString *saveURL;
/* individual values */ /* individual values */
NSCalendarDate *startDate;
NSCalendarDate *cycleUntilDate; NSCalendarDate *cycleUntilDate;
NSString *title; NSString *title;
NSString *location; NSString *location;
NSString *comment; NSString *comment;
NSString *url; NSString *url;
iCalPerson *organizer; iCalPerson *organizer;
NSArray *participants; /* array of iCalPerson's */
NSArray *resources; /* array of iCalPerson's */
NSString *priority; NSString *priority;
NSString *privacy; NSString *privacy;
NSString *status; NSString *status;
NSArray *categories; NSArray *categories;
BOOL checkForConflicts; /* default: NO */
NSDictionary *cycle; NSDictionary *cycle;
NSString *cycleEnd; NSString *cycleEnd;
NSString *componentOwner; NSString *componentOwner;
BOOL componentLoaded; NSString *attendeesNames;
NSString *attendeesEmails;
} }
- (NSArray *) categoryItems; - (void) setComponent: (iCalRepeatableEntityObject *) newComponent;
- (void) setSaveURL: (NSString *) newSaveURL;
- (NSString *) saveURL;
- (NSArray *) categoryList;
- (void) setCategories: (NSArray *) _categories; - (void) setCategories: (NSArray *) _categories;
- (NSArray *) categories; - (NSArray *) categories;
- (NSString *) itemCategoryText; - (NSString *) itemCategoryText;
@ -87,18 +90,6 @@
- (id) item; - (id) item;
- (NSString *) itemPriorityText; - (NSString *) itemPriorityText;
- (void) setErrorText: (NSString *) _txt;
- (NSString *) errorText;
- (BOOL) hasErrorText;
- (void) setICalString: (NSString *) _s;
- (NSString *) iCalString;
- (NSCalendarDate *) newStartDate;
- (void) setStartDate: (NSCalendarDate *) _date;
- (NSCalendarDate *) startDate;
- (void) setTitle: (NSString *) _value; - (void) setTitle: (NSString *) _value;
- (NSString *) title; - (NSString *) title;
@ -111,14 +102,11 @@
- (void) setUrl: (NSString *) _url; - (void) setUrl: (NSString *) _url;
- (NSString *) url; - (NSString *) url;
- (void) setParticipants: (NSArray *) _parts; - (void) setAttendeesNames: (NSString *) newAttendeesNames;
- (NSArray *) participants; - (NSString *) attendeesNames;
- (void) setResources: (NSArray *) _res; - (void) setAttendeesEmails: (NSString *) newAttendeesEmails;
- (NSArray *) resources; - (NSString *) attendeesEmails;
- (void) setCheckForConflicts: (BOOL) _checkForConflicts;
- (BOOL) checkForConflicts;
- (NSArray *) cycles; - (NSArray *) cycles;
- (void) setCycle: (NSDictionary *) _cycle; - (void) setCycle: (NSDictionary *) _cycle;
@ -150,17 +138,12 @@
- (BOOL) isWriteableClientObject; - (BOOL) isWriteableClientObject;
- (NSException *) validateObjectForStatusChange; - (NSException *) validateObjectForStatusChange;
/* subclasses */
- (void) loadValuesFromComponent: (iCalRepeatableEntityObject *) component;
- (NSString *) iCalStringTemplate;
- (NSString *) iCalParticipantsAndResourcesStringFromQueryParameters; - (NSString *) iCalParticipantsAndResourcesStringFromQueryParameters;
- (NSString *) iCalParticipantsStringFromQueryParameters; - (NSString *) iCalParticipantsStringFromQueryParameters;
- (NSString *) iCalResourcesStringFromQueryParameters; - (NSString *) iCalResourcesStringFromQueryParameters;
- (NSString *) iCalStringFromQueryParameter: (NSString *) _qp - (NSString *) iCalStringFromQueryParameter: (NSString *) _qp
format: (NSString *) _format; format: (NSString *) _format;
- (NSString *) iCalOrganizerString; - (NSString *) iCalOrganizerString;
- (NSString *) toolbar;
@end @end

View File

@ -55,11 +55,12 @@
{ {
if ((self = [super init])) if ((self = [super init]))
{ {
component = nil;
[self setPrivacy: @"PUBLIC"]; [self setPrivacy: @"PUBLIC"];
[self setCheckForConflicts: NO];
[self setIsCycleEndNever]; [self setIsCycleEndNever];
componentOwner = @""; componentOwner = @"";
componentLoaded = NO; attendeesNames = nil;
attendeesEmails = nil;
} }
return self; return self;
@ -67,31 +68,102 @@
- (void) dealloc - (void) dealloc
{ {
[iCalString release];
[errorText release];
[item release]; [item release];
[startDate release];
[cycleUntilDate release]; [cycleUntilDate release];
[title release]; [title release];
[location release]; [location release];
[organizer release]; [organizer release];
[comment release]; [comment release];
[participants release];
[resources release];
[priority release]; [priority release];
[categories release]; [categories release];
[cycle release]; [cycle release];
[cycleEnd release]; [cycleEnd release];
[url release]; [url release];
[attendeesNames release];
[attendeesEmails release];
[super dealloc]; [super dealloc];
} }
- (void) _loadAttendees
{
NSEnumerator *attendees;
iCalPerson *currentAttendee;
NSMutableString *names, *emails;
names = [NSMutableString new];
emails = [NSMutableString new];
attendees = [[component attendees] objectEnumerator];
currentAttendee = [attendees nextObject];
while (currentAttendee)
{
NSLog (@"currentCN: %@", [currentAttendee cn]);
[names appendFormat: @"%@,", [currentAttendee cn]];
[emails appendFormat: @"%@,", [currentAttendee rfc822Email]];
currentAttendee = [attendees nextObject];
}
if ([names length] > 0)
{
ASSIGN (attendeesNames, [names substringToIndex: [names length] - 1]);
ASSIGN (attendeesEmails,
[emails substringToIndex: [emails length] - 1]);
}
[names release];
[emails release];
}
/* warning: we use this method which will be triggered by the template system
when the page is instantiated, but we should find another and cleaner way of
doing this... for example, when the clientObject is set */
- (void) setComponent: (iCalRepeatableEntityObject *) newComponent
{
// iCalRecurrenceRule *rrule;
SOGoObject *co;
if (!component)
{
component = newComponent;
co = [self clientObject];
componentOwner = [co ownerInContext: nil];
ASSIGN (title, [component summary]);
ASSIGN (location, [component location]);
ASSIGN (comment, [component comment]);
ASSIGN (url, [[component url] absoluteString]);
ASSIGN (privacy, [component accessClass]);
ASSIGN (priority, [component priority]);
ASSIGN (status, [component status]);
ASSIGN (categories, [[component categories] commaSeparatedValues]);
ASSIGN (organizer, [component organizer]);
[self _loadAttendees];
}
// /* cycles */
// if ([component isRecurrent])
// {
// rrule = [[component recurrenceRules] objectAtIndex: 0];
// [self adjustCycleControlsForRRule: rrule];
// }
}
- (void) setSaveURL: (NSString *) newSaveURL
{
saveURL = newSaveURL;
}
- (NSString *) saveURL
{
return saveURL;
}
/* accessors */ /* accessors */
- (void) setItem: (id) _item - (void) setItem: (id) _item
{ {
ASSIGN(item, _item); ASSIGN (item, _item);
} }
- (id) item - (id) item
@ -114,34 +186,9 @@
return [self labelForKey: [NSString stringWithFormat: @"status_%@", item]]; return [self labelForKey: [NSString stringWithFormat: @"status_%@", item]];
} }
- (void) setErrorText: (NSString *) _txt
{
ASSIGNCOPY(errorText, _txt);
}
- (NSString *) errorText
{
return errorText;
}
- (BOOL) hasErrorText
{
return [errorText length] > 0 ? YES : NO;
}
- (void) setStartDate: (NSCalendarDate *) _date
{
ASSIGN(startDate, _date);
}
- (NSCalendarDate *) startDate
{
return startDate;
}
- (void) setTitle: (NSString *) _value - (void) setTitle: (NSString *) _value
{ {
ASSIGNCOPY(title, _value); ASSIGN (title, _value);
} }
- (NSString *) title - (NSString *) title
@ -151,7 +198,7 @@
- (void) setUrl: (NSString *) _url - (void) setUrl: (NSString *) _url
{ {
ASSIGNCOPY(url, _url); ASSIGN (url, _url);
} }
- (NSString *) url - (NSString *) url
@ -159,9 +206,29 @@
return url; return url;
} }
- (void) setAttendeesNames: (NSString *) newAttendeesNames
{
ASSIGN (attendeesNames, newAttendeesNames);
}
- (NSString *) attendeesNames
{
return attendeesNames;
}
- (void) setAttendeesEmails: (NSString *) newAttendeesEmails
{
ASSIGN (attendeesEmails, newAttendeesEmails);
}
- (NSString *) attendeesEmails
{
return attendeesEmails;
}
- (void) setLocation: (NSString *) _value - (void) setLocation: (NSString *) _value
{ {
ASSIGNCOPY(location, _value); ASSIGN (location, _value);
} }
- (NSString *) location - (NSString *) location
@ -171,7 +238,7 @@
- (void) setComment: (NSString *) _value - (void) setComment: (NSString *) _value
{ {
ASSIGNCOPY(comment, _value); ASSIGN (comment, _value);
} }
- (NSString *) comment - (NSString *) comment
@ -179,28 +246,34 @@
return comment; return comment;
} }
- (NSArray *) categoryItems - (NSArray *) categoryList
{ {
// TODO: make this configurable?
/*
Tasks categories will be modified as follow :
by default (a simple logo or no logo at all),
task,
outside,
meeting,
holidays,
phone.
*/
static NSArray *categoryItems = nil; static NSArray *categoryItems = nil;
if (!categoryItems) if (!categoryItems)
{ {
categoryItems = [NSArray arrayWithObjects: @"APPOINTMENT", categoryItems = [NSArray arrayWithObjects: @"ANNIVERSARY",
@"NOT IN OFFICE", @"BIRTHDAY",
@"MEETING", @"BUSINESS",
@"HOLIDAY", @"CALLS",
@"PHONE CALL", @"CLIENTS",
nil]; @"COMPETITION",
@"CUSTOMER",
@"FAVORITES",
@"FOLLOW UP",
@"GIFTS",
@"HOLIDAYS",
@"IDEAS",
@"ISSUES",
@"MISCELLANEOUS",
@"PERSONAL",
@"PROJECTS",
@"PUBLIC HOLIDAY",
@"STATUS",
@"SUPPLIERS",
@"TRAVEL",
@"VACATION",
nil];
[categoryItems retain]; [categoryItems retain];
} }
@ -209,7 +282,7 @@
- (void) setCategories: (NSArray *) _categories - (void) setCategories: (NSArray *) _categories
{ {
ASSIGN(categories, _categories); ASSIGN (categories, _categories);
} }
- (NSArray *) categories - (NSArray *) categories
@ -219,7 +292,7 @@
- (NSString *) itemCategoryText - (NSString *) itemCategoryText
{ {
return [[self labelForKey: item] stringByEscapingHTMLString]; return [self labelForKey: [NSString stringWithFormat: @"category_%@", item]];
} }
/* priorities */ /* priorities */
@ -234,7 +307,7 @@
if (!priorities) if (!priorities)
{ {
priorities = [NSArray arrayWithObjects:@"0", @"5", @"1", nil]; priorities = [NSArray arrayWithObjects: @"0", @"5", @"1", nil];
[priorities retain]; [priorities retain];
} }
@ -243,7 +316,7 @@
- (void) setPriority: (NSString *) _priority - (void) setPriority: (NSString *) _priority
{ {
ASSIGN(priority, _priority); ASSIGN (priority, _priority);
} }
- (NSString *) priority - (NSString *) priority
@ -267,7 +340,7 @@
- (void) setPrivacy: (NSString *) _privacy - (void) setPrivacy: (NSString *) _privacy
{ {
ASSIGN(privacy, _privacy); ASSIGN (privacy, _privacy);
} }
- (NSString *) privacy - (NSString *) privacy
@ -290,7 +363,7 @@
- (void) setStatus: (NSString *) _status - (void) setStatus: (NSString *) _status
{ {
ASSIGN(status, _status); ASSIGN (status, _status);
} }
- (NSString *) status - (NSString *) status
@ -298,36 +371,6 @@
return status; return status;
} }
- (void) setParticipants: (NSArray *) _parts
{
ASSIGN(participants, _parts);
}
- (NSArray *) participants
{
return participants;
}
- (void) setResources: (NSArray *) _res
{
ASSIGN(resources, _res);
}
- (NSArray *) resources
{
return resources;
}
- (void) setCheckForConflicts: (BOOL) _checkForConflicts
{
checkForConflicts = _checkForConflicts;
}
- (BOOL) checkForConflicts
{
return checkForConflicts;
}
- (NSArray *) cycles - (NSArray *) cycles
{ {
NSBundle *bundle; NSBundle *bundle;
@ -337,7 +380,7 @@
if (!cycles) if (!cycles)
{ {
bundle = [NSBundle bundleForClass:[self class]]; bundle = [NSBundle bundleForClass:[self class]];
path = [bundle pathForResource:@"cycles" ofType:@"plist"]; path = [bundle pathForResource: @"cycles" ofType: @"plist"];
NSAssert(path != nil, @"Cannot find cycles.plist!"); NSAssert(path != nil, @"Cannot find cycles.plist!");
cycles = [[NSArray arrayWithContentsOfFile:path] retain]; cycles = [[NSArray arrayWithContentsOfFile:path] retain];
NSAssert(cycles != nil, @"Cannot instantiate cycles from cycles.plist!"); NSAssert(cycles != nil, @"Cannot instantiate cycles from cycles.plist!");
@ -348,7 +391,7 @@
- (void) setCycle: (NSDictionary *) _cycle - (void) setCycle: (NSDictionary *) _cycle
{ {
ASSIGN(cycle, _cycle); ASSIGN (cycle, _cycle);
} }
- (NSDictionary *) cycle - (NSDictionary *) cycle
@ -365,21 +408,21 @@
{ {
NSString *key; NSString *key;
key = [(NSDictionary *)item objectForKey:@"label"]; key = [(NSDictionary *)item objectForKey: @"label"];
return [self labelForKey:key]; return [self labelForKey:key];
} }
- (void) setCycleUntilDate: (NSCalendarDate *) _cycleUntilDate - (void) setCycleUntilDate: (NSCalendarDate *) _cycleUntilDate
{ {
NSCalendarDate *until; // NSCalendarDate *until;
/* copy hour/minute/second from startDate */ // /* copy hour/minute/second from startDate */
until = [_cycleUntilDate hour: [startDate hourOfDay] // until = [_cycleUntilDate hour: [startDate hourOfDay]
minute: [startDate minuteOfHour] // minute: [startDate minuteOfHour]
second: [startDate secondOfMinute]]; // second: [startDate secondOfMinute]];
[until setTimeZone: [startDate timeZone]]; // [until setTimeZone: [startDate timeZone]];
ASSIGN(cycleUntilDate, until); // ASSIGN (cycleUntilDate, until);
} }
- (NSCalendarDate *) cycleUntilDate - (NSCalendarDate *) cycleUntilDate
@ -394,7 +437,7 @@
if (![self hasCycle]) if (![self hasCycle])
return nil; return nil;
ruleRep = [cycle objectForKey:@"rule"]; ruleRep = [cycle objectForKey: @"rule"];
rule = [iCalRecurrenceRule recurrenceRuleWithICalRepresentation:ruleRep]; rule = [iCalRecurrenceRule recurrenceRuleWithICalRepresentation:ruleRep];
if (cycleUntilDate && [self isCycleEndUntil]) if (cycleUntilDate && [self isCycleEndUntil])
@ -405,20 +448,20 @@
- (void) adjustCycleControlsForRRule: (iCalRecurrenceRule *) _rrule - (void) adjustCycleControlsForRRule: (iCalRecurrenceRule *) _rrule
{ {
NSDictionary *c; // NSDictionary *c;
NSCalendarDate *until; // NSCalendarDate *until;
c = [self cycleMatchingRRule:_rrule]; // c = [self cycleMatchingRRule:_rrule];
[self setCycle:c]; // [self setCycle:c];
until = [[[_rrule untilDate] copy] autorelease]; // until = [[[_rrule untilDate] copy] autorelease];
if (!until) // if (!until)
until = startDate; // until = startDate;
else // else
[self setIsCycleEndUntil]; // [self setIsCycleEndUntil];
[until setTimeZone:[[self clientObject] userTimeZone]]; // [until setTimeZone:[[self clientObject] userTimeZone]];
[self setCycleUntilDate:until]; // [self setCycleUntilDate:until];
} }
/* /*
@ -448,11 +491,11 @@
NSString *cr; NSString *cr;
c = [cycles objectAtIndex:i]; c = [cycles objectAtIndex:i];
cr = [c objectForKey:@"rule"]; cr = [c objectForKey: @"rule"];
if ([cr isEqualToString:cycleRep]) if ([cr isEqualToString:cycleRep])
return c; return c;
} }
[self warnWithFormat:@"No default cycle for rrule found! -> %@", _rrule]; [self warnWithFormat: @"No default cycle for rrule found! -> %@", _rrule];
return nil; return nil;
} }
@ -473,7 +516,7 @@
- (void) setCycleEnd: (NSString *) _cycleEnd - (void) setCycleEnd: (NSString *) _cycleEnd
{ {
ASSIGNCOPY(cycleEnd, _cycleEnd); ASSIGN (cycleEnd, _cycleEnd);
} }
- (NSString *) cycleEnd - (NSString *) cycleEnd
@ -483,18 +526,17 @@
- (BOOL) isCycleEndUntil - (BOOL) isCycleEndUntil
{ {
return (cycleEnd && return (cycleEnd && [cycleEnd isEqualToString: @"cycle_end_until"]);
[cycleEnd isEqualToString:@"cycle_end_until"]);
} }
- (void) setIsCycleEndUntil - (void) setIsCycleEndUntil
{ {
[self setCycleEnd:@"cycle_end_until"]; [self setCycleEnd: @"cycle_end_until"];
} }
- (void) setIsCycleEndNever - (void) setIsCycleEndNever
{ {
[self setCycleEnd:@"cycle_end_never"]; [self setCycleEnd: @"cycle_end_never"];
} }
/* helpers */ /* helpers */
@ -517,13 +559,13 @@
uri = [[[self context] request] uri]; uri = [[[self context] request] uri];
/* first: identify query parameters */ /* first: identify query parameters */
r = [uri rangeOfString:@"?" options:NSBackwardsSearch]; r = [uri rangeOfString: @"?" options:NSBackwardsSearch];
if (r.length > 0) if (r.length > 0)
uri = [uri substringToIndex:r.location]; uri = [uri substringToIndex:r.location];
/* next: append trailing slash */ /* next: append trailing slash */
if (![uri hasSuffix:@"/"]) if (![uri hasSuffix: @"/"])
uri = [uri stringByAppendingString:@"/"]; uri = [uri stringByAppendingString: @"/"];
/* next: append method */ /* next: append method */
uri = [uri stringByAppendingString:_method]; uri = [uri stringByAppendingString:_method];
@ -535,13 +577,7 @@
- (BOOL) isWriteableClientObject - (BOOL) isWriteableClientObject
{ {
return [[self clientObject] return [[self clientObject]
respondsToSelector:@selector(saveContentString:)]; respondsToSelector: @selector(saveContentString:)];
}
- (BOOL) shouldTakeValuesFromRequest: (WORequest *) _rq
inContext: (WOContext*) _c
{
return YES;
} }
- (BOOL) containsConflict: (id) _component - (BOOL) containsConflict: (id) _component
@ -593,81 +629,6 @@
: @"visibility: hidden;"); : @"visibility: hidden;");
} }
/* subclasses */
- (NSCalendarDate *) newStartDate
{
NSCalendarDate *newStartDate, *now;
int hour;
newStartDate = [self selectedDate];
if ([[self queryParameterForKey: @"hm"] length] == 0)
{
now = [NSCalendarDate calendarDate];
[now setTimeZone: [[self clientObject] userTimeZone]];
if ([now isDateOnSameDay: newStartDate])
{
hour = [now hourOfDay];
if (hour < 8)
newStartDate = [now hour: 8 minute: 0];
else if (hour > 18)
newStartDate = [[now tomorrow] hour: 8 minute: 0];
else
newStartDate = now;
}
else
newStartDate = [newStartDate hour: 8 minute: 0];
}
return newStartDate;
}
- (void) loadValuesFromComponent: (iCalRepeatableEntityObject *) component
{
iCalRecurrenceRule *rrule;
NSTimeZone *uTZ;
SOGoObject *co;
co = [self clientObject];
componentOwner = [co ownerInContext: nil];
componentLoaded = YES;
startDate = [component startDate];
// if ((startDate = [component startDate]) == nil)
// startDate = [[NSCalendarDate date] hour:11 minute:0];
uTZ = [co userTimeZone];
if (startDate)
{
[startDate setTimeZone: uTZ];
[startDate retain];
}
title = [[component summary] copy];
location = [[component location] copy];
comment = [[component comment] copy];
url = [[[component url] absoluteString] copy];
privacy = [[component accessClass] copy];
priority = [[component priority] copy];
status = [[component status] copy];
categories = [[[component categories] commaSeparatedValues] retain];
organizer = [[component organizer] retain];
participants = [[component participants] retain];
resources = [[component resources] retain];
/* cycles */
if ([component isRecurrent])
{
rrule = [[component recurrenceRules] objectAtIndex: 0];
[self adjustCycleControlsForRRule: rrule];
}
}
- (NSString *) iCalStringTemplate
{
[self subclassResponsibility: _cmd];
return @"";
}
- (NSString *) iCalParticipantsAndResourcesStringFromQueryParameters - (NSString *) iCalParticipantsAndResourcesStringFromQueryParameters
{ {
NSString *s; NSString *s;
@ -709,7 +670,7 @@
NSArray *es; NSArray *es;
unsigned i, count; unsigned i, count;
es = [s componentsSeparatedByString:@","]; es = [s componentsSeparatedByString: @","];
count = [es count]; count = [es count];
for(i = 0; i < count; i++) { for(i = 0; i < count; i++) {
NSString *email, *cn; NSString *email, *cn;
@ -728,13 +689,6 @@
[self cnForUser], [self emailForUser]]; [self cnForUser], [self emailForUser]];
} }
- (NSString *) saveUrl
{
[self subclassResponsibility: _cmd];
return @"";
}
- (NSException *) validateObjectForStatusChange - (NSException *) validateObjectForStatusChange
{ {
id co; id co;
@ -751,16 +705,6 @@
/* contact editor compatibility */ /* contact editor compatibility */
- (void) setICalString: (NSString *) _s
{
ASSIGNCOPY(iCalString, _s);
}
- (NSString *) iCalString
{
return iCalString;
}
- (NSArray *) availableCalendars - (NSArray *) availableCalendars
{ {
NSEnumerator *rawContacts; NSEnumerator *rawContacts;
@ -807,58 +751,58 @@
return classes; return classes;
} }
- (NSString *) _toolbarForCalObject: (iCalEntityObject *) calObject - (void) _handleAttendeesEdition
{ {
NSString *filename, *myEmail; NSArray *names, *emails;
iCalPerson *person; NSMutableArray *newAttendees;
NSEnumerator *persons; unsigned int count, max;
iCalPersonPartStat myParticipationStatus; NSString *currentEmail;
BOOL found; iCalPerson *currentAttendee;
myEmail = [[[self context] activeUser] email]; newAttendees = [NSMutableArray new];
if ([[organizer rfc822Email] isEqualToString: myEmail]) names = [attendeesNames componentsSeparatedByString: @","];
filename = @"SOGoAppointmentObject.toolbar"; emails = [attendeesEmails componentsSeparatedByString: @","];
else max = [emails count];
for (count = 0; count < max; count++)
{ {
filename = @""; currentEmail = [emails objectAtIndex: count];
found = NO; currentAttendee = [component findParticipantWithEmail: currentEmail];
persons = [participants objectEnumerator]; if (!currentAttendee)
person = [persons nextObject]; {
while (person && !found) currentAttendee = [iCalPerson elementWithTag: @"attendee"];
if ([[person rfc822Email] isEqualToString: myEmail]) [currentAttendee setCn: [names objectAtIndex: count]];
{ [currentAttendee setEmail: currentEmail];
found = YES; [currentAttendee setRole: @"REQ-PARTICIPANT"];
myParticipationStatus = [person participationStatus]; [currentAttendee
if (myParticipationStatus == iCalPersonPartStatAccepted) setParticipationStatus: iCalPersonPartStatNeedsAction];
filename = @"SOGoAppointmentObjectDecline.toolbar"; }
else if (myParticipationStatus == iCalPersonPartStatDeclined) [newAttendees addObject: currentAttendee];
filename = @"SOGoAppointmentObjectAccept.toolbar";
else
filename = @"SOGoAppointmentObjectAcceptOrDecline.toolbar";
}
else
person = [persons nextObject];
} }
return filename; [component setAttendees: newAttendees];
[newAttendees release];
} }
- (NSString *) toolbar - (void) takeValuesFromRequest: (WORequest *) _rq
inContext: (WOContext *) _ctx
{ {
NSString *filename; NSCalendarDate *now;
iCalEntityObject *calObject;
SOGoCalendarComponent *co;
if (componentLoaded) [super takeValuesFromRequest: _rq inContext: _ctx];
now = [NSCalendarDate calendarDate];
[component setSummary: title];
[component setLocation: location];
[component setComment: comment];
[component setUrl: url];
if ([[self clientObject] isNew])
{ {
co = [self clientObject]; [component setCreated: now];
calObject = [co component]; [component setTimeStampAsDate: now];
filename = [self _toolbarForCalObject: calObject]; [component setPriority: @"0"];
} }
else [component setLastModified: now];
filename = @""; [self _handleAttendeesEdition];
return filename;
} }
@end @end

View File

@ -1,6 +1,6 @@
/* UIxTaskEditor.h - this file is part of SOGo /* UIxTaskEditor.h - this file is part of SOGo
* *
* Copyright (C) 2006 Inverse groupe conseil * Copyright (C) 2007 Inverse groupe conseil
* *
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca> * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* *
@ -20,59 +20,41 @@
* Boston, MA 02111-1307, USA. * Boston, MA 02111-1307, USA.
*/ */
#ifndef UIXTASKEDITOR_H #ifndef UIXAPPOINTMENTEDITOR_H
#define UIXTASKEDITOR_H #define UIXAPPOINTMENTEDITOR_H
#import "UIxComponentEditor.h" #import <SOGoUI/UIxComponent.h>
@class NSString;
@class iCalPerson;
@class iCalRecurrenceRule;
@class iCalToDo; @class iCalToDo;
@class NSString;
@interface UIxTaskEditor : UIxComponentEditor @interface UIxTaskEditor : UIxComponent
{ {
NSCalendarDate *dueDate; iCalToDo *todo;
NSCalendarDate *taskStartDate;
NSCalendarDate *taskDueDate;
NSCalendarDate *statusDate;
NSString *status;
NSString *statusPercent;
BOOL hasStartDate; BOOL hasStartDate;
BOOL hasDueDate; BOOL hasDueDate;
BOOL newTask; NSString *item;
} }
/* template values */
- (NSString *) saveURL;
- (iCalToDo *) todo;
/* icalendar values */
- (void) setTaskStartDate: (NSCalendarDate *) _date; - (void) setTaskStartDate: (NSCalendarDate *) _date;
- (NSCalendarDate *) taskStartDate; - (NSCalendarDate *) taskStartDate;
- (void) setTaskDueDate: (NSCalendarDate *) _date; - (void) setTaskDueDate: (NSCalendarDate *) _date;
- (NSCalendarDate *) taskDueDate; - (NSCalendarDate *) taskDueDate;
/* iCal */ - (NSString *) repeat;
- (void) setRepeat: (NSString *) newRepeat;
- (NSString *) iCalStringTemplate;
/* new */
- (id) newAction;
/* save */
- (void) loadValuesFromTask: (iCalToDo *) _task;
- (void) saveValuesIntoTask: (iCalToDo *) _task;
- (iCalToDo *) taskFromString: (NSString *) _iCalString;
/* conflict management */
- (BOOL) containsConflict: (id) _task;
- (id <WOActionResults>) defaultAction;
- (id <WOActionResults>) saveAction;
- (id) changeStatusAction;
- (id) acceptAction;
- (id) declineAction;
- (NSString *) saveUrl;
// TODO: add tentatively
- (id) acceptOrDeclineAction: (BOOL) _accept;
@end @end
#endif /* UIXTASKEDITOR_H */ #endif /* UIXAPPOINTMENTEDITOR_H */

View File

@ -1,503 +1,432 @@
/* /* UIxTaskEditor.m - this file is part of SOGo
Copyright (C) 2004-2005 SKYRIX Software AG *
* Copyright (C) 2007 Inverse groupe conseil
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* 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
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
This file is part of OpenGroupware.org. #import <NGObjWeb/SoObject.h>
#import <NGObjWeb/WORequest.h>
#import <NGObjWeb/NSException+HTTP.h>
#import <NGExtensions/NSCalendarDate+misc.h>
OGo is free software; you can redistribute it and/or modify it under #import <NGCards/iCalToDo.h>
the terms of the GNU Lesser General Public License as published by the #import <NGCards/iCalPerson.h>
Free Software Foundation; either version 2, or (at your option) any
later version.
OGo is distributed in the hope that it will be useful, but WITHOUT ANY #import <SoObjects/SOGo/AgenorUserManager.h>
WARRANTY; without even the implied warranty of MERCHANTABILITY or #import <SoObjects/SOGo/SOGoUser.h>
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public #import <SoObjects/SOGo/SOGoContentObject.h>
License for more details. #import <SoObjects/Appointments/SOGoAppointmentFolder.h>
#import <SoObjects/Appointments/SOGoTaskObject.h>
You should have received a copy of the GNU Lesser General Public
License along with OGo; see the file COPYING. If not, write to the
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
#import <SOGo/NSCalendarDate+SOGo.h>
#import "UIxComponentEditor.h"
#import "UIxTaskEditor.h" #import "UIxTaskEditor.h"
/* TODO: CLEAN UP */
#import "common.h"
#import <NGCards/NGCards.h>
#import <NGExtensions/NGCalendarDateRange.h>
#import <SOGoUI/SOGoDateFormatter.h>
#import <SOGo/AgenorUserManager.h>
#import <Appointments/SOGoAppointmentFolder.h>
#import <Appointments/SOGoTaskObject.h>
#import "UIxComponent+Agenor.h"
@implementation UIxTaskEditor @implementation UIxTaskEditor
- (void) dealloc - (id) init
{ {
[dueDate release]; if ((self = [super init]))
[super dealloc];
}
- (void) setTaskStartDate: (NSCalendarDate *) _date
{
[self setStartDate: _date];
}
- (NSCalendarDate *) taskStartDate
{
return [self startDate];
}
- (void) setTaskDueDate: (NSCalendarDate *) _date
{
ASSIGN(dueDate, _date);
}
- (NSCalendarDate *) taskDueDate
{
return dueDate;
}
/* iCal */
- (NSString *) iCalStringTemplate
{
static NSString *iCalStringTemplate = \
@"BEGIN:VCALENDAR\r\n"
@"METHOD:REQUEST\r\n"
@"PRODID://Inverse groupe conseil/SOGo 0.9\r\n"
@"VERSION:2.0\r\n"
@"BEGIN:VTODO\r\n"
@"UID:%@\r\n"
@"CLASS:PUBLIC\r\n"
@"STATUS:NEEDS-ACTION\r\n" /* confirmed by default */
@"PERCENT-COMPLETE:0\r\n"
@"DTSTART:%@Z\r\n"
@"DUE:%@Z\r\n"
@"DTSTAMP:%@Z\r\n"
@"SEQUENCE:1\r\n"
@"PRIORITY:5\r\n"
@"%@" /* organizer */
@"%@" /* participants and resources */
@"END:VTODO\r\n"
@"END:VCALENDAR";
NSCalendarDate *stamp, *lStartDate, *lDueDate;
NSString *template, *s;
NSTimeZone *utc;
unsigned minutes;
s = [self queryParameterForKey:@"dur"];
if ([s length] > 0)
minutes = [s intValue];
else
minutes = 60;
utc = [NSTimeZone timeZoneWithName: @"GMT"];
lStartDate = [self newStartDate];
[lStartDate setTimeZone: utc];
lDueDate = [lStartDate dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: minutes seconds: 0];
stamp = [NSCalendarDate calendarDate];
[stamp setTimeZone: utc];
s = [self iCalParticipantsAndResourcesStringFromQueryParameters];
template = [NSString stringWithFormat:iCalStringTemplate,
[[self clientObject] nameInContainer],
[lStartDate iCalFormattedDateTimeString],
[lDueDate iCalFormattedDateTimeString],
[stamp iCalFormattedDateTimeString],
[self iCalOrganizerString],
s];
return template;
}
/* new */
- (id) newAction
{
/*
This method creates a unique ID and redirects to the "edit" method on the
new ID.
It is actually a folder method and should be defined on the folder.
Note: 'clientObject' is the SOGoAppointmentFolder!
Update: remember that there are group folders as well.
*/
NSString *uri, *objectId, *method, *ps;
objectId = [NSClassFromString(@"SOGoAppointmentFolder")
globallyUniqueObjectId];
if ([objectId length] == 0) {
return [NSException exceptionWithHTTPStatus:500 /* Internal Error */
reason:@"could not create a unique ID"];
}
method = [NSString stringWithFormat:@"Calendar/%@/editAsTask", objectId];
method = [[self userFolderPath] stringByAppendingPathComponent:method];
/* check if participants have already been provided */
ps = [self queryParameterForKey:@"ps"];
// if (ps) {
// [self setQueryParameter:ps forKey:@"ps"];
// }
if (!ps
&& [[self clientObject] respondsToSelector:@selector(calendarUIDs)]) {
AgenorUserManager *um;
NSArray *uids;
NSMutableArray *emails;
unsigned i, count;
/* add all current calendarUIDs as default participants */
um = [AgenorUserManager sharedUserManager];
uids = [[self clientObject] calendarUIDs];
count = [uids count];
emails = [NSMutableArray arrayWithCapacity:count];
for (i = 0; i < count; i++) {
NSString *email;
email = [um getEmailForUID:[uids objectAtIndex:i]];
if (email)
[emails addObject:email];
}
ps = [emails componentsJoinedByString:@","];
[self setQueryParameter:ps forKey:@"ps"];
}
uri = [self completeHrefForMethod:method];
return [self redirectToLocation:uri];
}
/* save */
- (void) loadValuesFromTask: (iCalToDo *) _task
{
NSTimeZone *uTZ;
[self loadValuesFromComponent: _task];
uTZ = [[self clientObject] userTimeZone];
dueDate = [_task due];
// if (!dueDate)
// dueDate = [[self startDate] dateByAddingYears: 0 months: 0 days: 0
// hours: 1 minutes: 0 seconds: 0];
if (dueDate)
{ {
[dueDate setTimeZone: uTZ]; taskStartDate = nil;
[dueDate retain]; taskDueDate = nil;
statusDate = nil;
hasStartDate = NO;
hasDueDate = NO;
status = nil;
statusPercent = nil;
item = nil;
todo = nil;
} }
}
- (void) saveValuesIntoTask: (iCalToDo *) _task
{
/* merge in form values */
NSArray *attendees, *lResources;
iCalRecurrenceRule *rrule;
NSCalendarDate *dateTime;
if (hasStartDate)
dateTime = [self taskStartDate];
else
dateTime = nil;
[_task setStartDate: dateTime];
if (hasDueDate)
dateTime = [self taskDueDate];
else
dateTime = nil;
[_task setDue: dateTime];
[_task setSummary: [self title]];
[_task setUrl: [self url]];
[_task setLocation: [self location]];
[_task setComment: [self comment]];
[_task setPriority:[self priority]];
[_task setAccessClass: [self privacy]];
[_task setStatus: [self status]];
// [_task setCategories: [[self categories] componentsJoinedByString: @","]];
#if 0
/*
Note: bad, bad, bad!
Organizer is no form value, thus we MUST NOT change it
*/
[_task setOrganizer:organizer];
#endif
attendees = [self participants];
lResources = [self resources];
if ([lResources count] > 0) {
attendees = ([attendees count] > 0)
? [attendees arrayByAddingObjectsFromArray:lResources]
: lResources;
}
[attendees makeObjectsPerformSelector: @selector (setTag:)
withObject: @"attendee"];
[_task setAttendees:attendees];
/* cycles */
[_task removeAllRecurrenceRules];
rrule = [self rrule];
if (rrule)
[_task addToRecurrenceRules: rrule];
}
- (iCalToDo *) taskFromString: (NSString *) _iCalString
{
iCalCalendar *calendar;
iCalToDo *task;
calendar = [iCalCalendar parseSingleFromSource: _iCalString];
task = (iCalToDo *) [calendar firstChildWithTag: @"vtodo"];
return task;
}
/* conflict management */
- (BOOL) containsConflict: (id) _task
{
NSArray *attendees, *uids;
SOGoAppointmentFolder *groupCalendar;
NSArray *infos;
NSArray *ranges;
id folder;
[self logWithFormat:@"search from %@ to %@",
[_task startDate], [_task due]];
folder = [[self clientObject] container];
attendees = [_task attendees];
uids = [folder uidsFromICalPersons:attendees];
if ([uids count] == 0) {
[self logWithFormat:@"Note: no UIDs selected."];
return NO;
}
groupCalendar = [folder lookupGroupCalendarFolderForUIDs:uids
inContext:[self context]];
[self debugWithFormat:@"group calendar: %@", groupCalendar];
if (![groupCalendar respondsToSelector:@selector(fetchFreeBusyInfosFrom:to:)]) {
[self errorWithFormat:@"invalid folder to run freebusy query on!"];
return NO;
}
infos = [groupCalendar fetchFreeBusyInfosFrom:[_task startDate]
to:[_task due]];
[self debugWithFormat:@" process: %d tasks", [infos count]];
ranges = [infos arrayByCreatingDateRangesFromObjectsWithStartDateKey:@"startDate"
andEndDateKey:@"dueDate"];
ranges = [ranges arrayByCompactingContainedDateRanges];
[self debugWithFormat:@" blocked ranges: %@", ranges];
return [ranges count] != 0 ? YES : NO;
}
- (id <WOActionResults>) defaultAction
{
NSString *ical;
/* load iCalendar file */
// TODO: can't we use [clientObject contentAsString]?
// ical = [[self clientObject] valueForKey:@"iCalString"];
ical = [[self clientObject] contentAsString];
if ([ical length] == 0)
{
newTask = YES;
ical = [self iCalStringTemplate];
}
else
newTask = NO;
[self setICalString:ical];
[self loadValuesFromTask: [self taskFromString: ical]];
// if (![self canEditComponent]) {
// /* TODO: we need proper ACLs */
// return [self redirectToLocation: [self completeURIForMethod: @"../view"]];
// }
return self; return self;
} }
- (id <WOActionResults>) saveAction - (void) dealloc
{ {
iCalToDo *task; [taskStartDate release];
iCalPerson *p; [taskDueDate release];
id <WOActionResults> result; [statusDate release];
NSString *content; [status release];
NSException *ex; [statusPercent release];
[super dealloc];
if (![self isWriteableClientObject]) {
/* return 400 == Bad Request */
return [NSException exceptionWithHTTPStatus:400
reason: @"method cannot be invoked on "
@"the specified object"];
}
task = [self taskFromString: [self iCalString]];
if (task == nil) {
NSString *s;
s = [self labelForKey: @"Invalid iCal data!"];
[self setErrorText: s];
return self;
}
[self saveValuesIntoTask:task];
p = [task findParticipantWithEmail:[self emailForUser]];
if (p) {
[p setParticipationStatus:iCalPersonPartStatAccepted];
}
if ([self checkForConflicts]) {
if ([self containsConflict:task]) {
NSString *s;
s = [self labelForKey:@"Conflicts found!"];
[self setErrorText:s];
return self;
}
}
content = [[task parent] versitString];
// [task release]; task = nil;
if (content == nil) {
NSString *s;
s = [self labelForKey: @"Could not create iCal data!"];
[self setErrorText: s];
return self;
}
ex = [[self clientObject] saveContentString:content];
if (ex != nil) {
[self setErrorText:[ex reason]];
return self;
}
if ([[[[self context] request] formValueForKey: @"nojs"] intValue])
result = [self redirectToLocation: [self applicationPath]];
else
result = [self jsCloseWithRefreshMethod: @"refreshTasks()"];
return result;
} }
- (id) changeStatusAction /* template values */
- (iCalToDo *) todo
{ {
iCalToDo *task; return todo;
SOGoTaskObject *taskObject;
NSString *content;
id ex;
int newStatus;
newStatus = [[self queryParameterForKey: @"status"] intValue];
taskObject = [self clientObject];
task = (iCalToDo *) [taskObject component];
switch (newStatus)
{
case 1:
[task setCompleted: [NSCalendarDate calendarDate]];
break;
case 2:
[task setStatus: @"IN-PROCESS"];
break;
case 3:
[task setStatus: @"CANCELLED"];
break;
default:
[task setStatus: @"NEEDS-ACTION"];
}
content = [[task parent] versitString];
ex = [[self clientObject] saveContentString: content];
if (ex != nil) {
[self setErrorText:[ex reason]];
return self;
}
return [self redirectToLocation: [self completeURIForMethod: @".."]];
} }
- (id)acceptAction { - (NSString *) saveURL
return [self acceptOrDeclineAction:YES];
}
- (id)declineAction {
return [self acceptOrDeclineAction:NO];
}
- (NSString *) saveUrl
{ {
return [NSString stringWithFormat: @"%@/saveAsTask", return [NSString stringWithFormat: @"%@/saveAsTask",
[[self clientObject] baseURL]]; [[self clientObject] baseURL]];
} }
// TODO: add tentatively - (NSString *) _toolbarForCalObject
{
SOGoUser *currentUser;
SOGoTaskObject *clientObject;
NSString *filename, *email;
iCalPerson *person;
iCalPersonPartStat participationStatus;
- (id)acceptOrDeclineAction:(BOOL)_accept { clientObject = [self clientObject];
// TODO: this should live in the SoObjects currentUser = [[self context] activeUser];
NSException *ex; email = [currentUser email];
if ([clientObject isOrganizer: email
orOwner: [currentUser login]])
filename = @"SOGoTaskObject.toolbar";
else
{
if ([clientObject isParticipant: email])
{
person = [[clientObject component: NO] findParticipantWithEmail: email];
participationStatus = [person participationStatus];
if (participationStatus == iCalPersonPartStatAccepted)
filename = @"SOGoTaskObjectDecline.toolbar";
else if (participationStatus == iCalPersonPartStatDeclined)
filename = @"SOGoTaskObjectAccept.toolbar";
else
filename = @"SOGoTaskObjectAcceptOrDecline.toolbar";
}
else
filename = @"";
}
if ((ex = [self validateObjectForStatusChange]) != nil) return filename;
return ex;
ex = [[self clientObject] changeParticipationStatus:
_accept ? @"ACCEPTED" : @"DECLINED"
inContext:[self context]];
if (ex != nil) return ex;
return self;
// return [self redirectToLocation: [self completeURIForMethod:@"../view"]];
} }
- (void) setHasStartDate: (BOOL) aBool - (NSString *) toolbar
{ {
hasStartDate = aBool; return ([self _toolbarForCalObject]);
}
/* icalendar values */
- (void) setTaskStartDate: (NSCalendarDate *) newTaskStartDate
{
ASSIGN (taskStartDate, newTaskStartDate);
}
- (NSCalendarDate *) taskStartDate
{
return taskStartDate;
}
- (void) setHasStartDate: (BOOL) newHasStartDate
{
hasStartDate = newHasStartDate;
} }
- (BOOL) hasStartDate - (BOOL) hasStartDate
{ {
return (!newTask && [self taskStartDate] != nil); return hasStartDate;
} }
- (BOOL) startDateDisabled - (BOOL) startDateDisabled
{ {
return (![self hasStartDate]); return !hasStartDate;
} }
- (void) setHasDueDate: (BOOL) aBool - (void) setTaskDueDate: (NSCalendarDate *) newTaskDueDate
{ {
hasDueDate = aBool; ASSIGN (taskDueDate, newTaskDueDate);
}
- (NSCalendarDate *) taskDueDate
{
return taskDueDate;
}
- (void) setHasDueDate: (BOOL) newHasDueDate
{
hasDueDate = newHasDueDate;
} }
- (BOOL) hasDueDate - (BOOL) hasDueDate
{ {
return (!newTask && [self taskDueDate] != nil); return hasDueDate;
} }
- (BOOL) dueDateDisabled - (BOOL) dueDateDisabled
{ {
return (![self hasDueDate]); return !hasDueDate;
} }
- (void) setDueDateDisabled: (BOOL) aBool - (NSArray *) repeatList
{
static NSArray *repeatItems = nil;
if (!repeatItems)
{
repeatItems = [NSArray arrayWithObjects: @"DAILY",
@"WEEKLY",
@"BI-WEEKLY",
@"EVERY WEEKDAY",
@"MONTHLY",
@"YEARLY",
@"-",
@"CUSTOM",
nil];
[repeatItems retain];
}
return repeatItems;
}
- (NSString *) itemRepeatText
{
NSString *text;
if ([item isEqualToString: @"-"])
text = item;
else
text = [self labelForKey: [NSString stringWithFormat: @"repeat_%@", item]];
return text;
}
- (NSArray *) statusList
{
static NSArray *statusItems = nil;
if (!statusItems)
{
statusItems = [NSArray arrayWithObjects: @"NEEDS-ACTION",
@"IN-PROCESS",
@"COMPLETED",
@"CANCELLED",
nil];
[statusItems retain];
}
return statusItems;
}
- (NSString *) itemStatusText
{
return [self labelForKey: [NSString stringWithFormat: @"status_%@", item]];
}
- (void) setItem: (NSString *) newItem
{
item = newItem;
}
- (NSString *) item
{
return item;
}
- (NSString *) repeat
{
return @"";
}
- (void) setRepeat: (NSString *) newRepeat
{ {
} }
- (void) setStartDateDisabled: (BOOL) aBool - (NSString *) status
{ {
return status;
} }
@end /* UIxTaskEditor */ - (void) setStatus: (NSString *) newStatus
{
status = newStatus;
}
- (void) setStatusDate: (NSCalendarDate *) newStatusDate
{
ASSIGN (statusDate, newStatusDate);
}
- (NSCalendarDate *) statusDate
{
return statusDate;
}
- (BOOL) statusDateDisabled
{
return ![status isEqualToString: @"COMPLETED"];
}
- (BOOL) statusPercentDisabled
{
NSLog (@"status: '%@'", status);
return ([status length] == 0
|| [status isEqualToString: @"CANCELLED"]);
}
- (void) setStatusPercent: (NSString *) newStatusPercent
{
ASSIGN (statusPercent, newStatusPercent);
}
- (NSString *) statusPercent
{
return statusPercent;
}
/* actions */
- (NSCalendarDate *) newStartDate
{
NSCalendarDate *newStartDate, *now;
int hour;
newStartDate = [self selectedDate];
if ([[self queryParameterForKey: @"hm"] length] == 0)
{
now = [NSCalendarDate calendarDate];
[now setTimeZone: [[self clientObject] userTimeZone]];
if ([now isDateOnSameDay: newStartDate])
{
hour = [now hourOfDay];
if (hour < 8)
newStartDate = [now hour: 8 minute: 0];
else if (hour > 18)
newStartDate = [[now tomorrow] hour: 8 minute: 0];
else
newStartDate = now;
}
else
newStartDate = [newStartDate hour: 8 minute: 0];
}
return newStartDate;
}
- (id <WOActionResults>) defaultAction
{
NSCalendarDate *startDate, *dueDate;
NSString *duration;
unsigned int minutes;
todo = (iCalToDo *) [[self clientObject] component: NO];
if (todo)
{
startDate = [todo startDate];
dueDate = [todo due];
hasStartDate = (startDate != nil);
hasDueDate = (dueDate != nil);
ASSIGN (status, [todo status]);
if ([status isEqualToString: @"COMPLETED"])
ASSIGN (statusDate, [todo completed]);
else
ASSIGN (statusDate, [self newStartDate]);
ASSIGN (statusPercent, [todo percentComplete]);
}
else
{
startDate = [self newStartDate];
duration = [self queryParameterForKey:@"dur"];
if ([duration length] > 0)
minutes = [duration intValue];
else
minutes = 60;
dueDate = [startDate dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: minutes seconds: 0];
hasStartDate = NO;
hasDueDate = NO;
ASSIGN (statusDate, [self newStartDate]);
ASSIGN (status, @"");
ASSIGN (statusPercent, @"");
}
ASSIGN (taskStartDate, startDate);
ASSIGN (taskDueDate, dueDate);
/* here comes the code for initializing repeat, reminder and isAllDay... */
return self;
}
- (id <WOActionResults>) newAction
{
NSString *objectId, *method, *uri;
id <WOActionResults> result;
Class clientKlazz;
clientKlazz = [[self clientObject] class];
objectId = [clientKlazz globallyUniqueObjectId];
if ([objectId length] > 0)
{
method = [NSString stringWithFormat:@"%@/Calendar/%@/editAsTask",
[self userFolderPath], objectId];
uri = [self completeHrefForMethod: method];
result = [self redirectToLocation: uri];
}
else
result = [NSException exceptionWithHTTPStatus: 500 /* Internal Error */
reason: @"could not create a unique ID"];
return result;
}
- (id <WOActionResults>) saveAction
{
SOGoTaskObject *clientObject;
NSString *iCalString;
clientObject = [self clientObject];
iCalString = [[clientObject calendar: NO] versitString];
[clientObject saveContentString: iCalString];
return [self jsCloseWithRefreshMethod: @"refreshTasks()"];
}
- (BOOL) shouldTakeValuesFromRequest: (WORequest *) request
inContext: (WOContext*) context
{
return ([[self clientObject] isKindOfClass: [SOGoTaskObject class]]
&& [[request method] isEqualToString: @"POST"]);
}
- (void) takeValuesFromRequest: (WORequest *) _rq
inContext: (WOContext *) _ctx
{
SOGoTaskObject *clientObject;
clientObject = [self clientObject];
todo = (iCalToDo *) [clientObject component: YES];
[super takeValuesFromRequest: _rq inContext: _ctx];
if (hasStartDate)
[todo setStartDate: taskStartDate];
if (hasDueDate)
[todo setDue: taskDueDate];
if ([status isEqualToString: @"COMPLETED"])
[todo setCompleted: statusDate];
else
[todo setCompleted: nil];
if ([status length] > 0)
{
[todo setStatus: status];
[todo setPercentComplete: statusPercent];
}
else
{
[todo setStatus: @""];
[todo setPercentComplete: @""];
}
}
@end