2 Copyright (C) 2004 SKYRIX Software AG
4 This file is part of OpenGroupware.org.
6 OGo is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
23 #include <SOGoUI/UIxComponent.h>
29 @class SOGoAppointment;
31 @interface UIxAppointmentEditor : UIxComponent
37 /* individual values */
38 NSCalendarDate *startDate;
39 NSCalendarDate *endDate;
43 NSArray *participants;
47 - (SOGoAppointment *)appointment;
48 - (NSString *)iCalStringTemplate;
49 - (NSString *)iCalString;
51 - (NSString *)_completeURIForMethod:(NSString *)_method;
53 - (iCalPerson *)getOrganizer;
54 - (NSArray *)getICalPersonsFromFormValues:(NSArray *)_values
55 treatAsResource:(BOOL)_isResource;
60 #include <SOGoUI/SOGoDateFormatter.h>
61 #include <SOGoLogic/SOGoAppointment.h>
62 #include <Appointments/SOGoAppointmentFolder.h>
63 #include <Appointments/SOGoAppointmentObject.h>
64 #include <NGiCal/NGiCal.h>
65 #include <SOGoLogic/AgenorUserManager.h>
66 #include "iCalPerson+UIx.h"
67 #include "UIxComponent+Agenor.h"
69 @interface NSDate(UsedPrivates)
70 - (NSString *)icalString; // TODO: this is in NGiCal
73 @implementation UIxAppointmentEditor
76 [self->participants release];
77 [self->resources release];
78 [self->startDate release];
79 [self->endDate release];
80 [self->title release];
81 [self->location release];
82 [self->comment release];
83 [self->iCalString release];
84 [self->appointment release];
91 - (void)setItem:(id)_item {
92 ASSIGN(self->item, _item);
98 - (NSFormatter *)titleDateFormatter {
99 SOGoDateFormatter *fmt;
101 fmt = [[[SOGoDateFormatter alloc] initWithLocale:[self locale]] autorelease];
102 [fmt setFullWeekdayNameAndDetails];
106 - (void)setAptStartDate:(NSCalendarDate *)_date {
107 ASSIGN(self->startDate, _date);
109 - (NSCalendarDate *)aptStartDate {
110 return self->startDate;
112 - (void)setAptEndDate:(NSCalendarDate *)_date {
113 ASSIGN(self->endDate, _date);
115 - (NSCalendarDate *)aptEndDate {
116 return self->endDate;
119 - (void)setTitle:(NSString *)_value {
120 ASSIGNCOPY(self->title, _value);
122 - (NSString *)title {
125 - (void)setLocation:(NSString *)_value {
126 ASSIGNCOPY(self->location, _value);
128 - (NSString *)location {
129 return self->location;
131 - (void)setComment:(NSString *)_value {
132 ASSIGNCOPY(self->comment, _value);
134 - (NSString *)comment {
135 return self->comment;
138 - (void)setParticipants:(NSArray *)_parts {
139 ASSIGN(self->participants, _parts);
141 - (NSArray *)participants {
142 return self->participants;
144 - (void)setResources:(NSArray *)_res {
145 ASSIGN(self->resources, _res);
147 - (NSArray *)resources {
148 return self->resources;
153 - (void)setICalString:(NSString *)_s {
154 ASSIGNCOPY(self->iCalString, _s);
156 - (NSString *)iCalString {
157 return self->iCalString;
160 - (NSString *)iCalStringTemplate {
161 static NSString *iCalStringTemplate = \
162 @"BEGIN:VCALENDAR\nMETHOD:REQUEST\nPRODID:OpenGroupware.org SOGo 0.9\n"
167 @"STATUS:CONFIRMED\n"
175 NSCalendarDate *lStartDate, *lEndDate;
178 lStartDate = [self selectedDate];
179 lEndDate = [lStartDate dateByAddingYears:0 months:0 days:0
180 hours:1 minutes:0 seconds:0];
182 template = [NSString stringWithFormat:iCalStringTemplate,
183 [[self clientObject] nameInContainer],
184 [[NSCalendarDate date] icalString],
185 [lStartDate icalString],
186 [lEndDate icalString]];
190 - (SOGoAppointment *)appointment {
191 return self->appointment;
196 - (NSString *)_completeURIForMethod:(NSString *)_method {
200 uri = [[[self context] request] uri];
202 /* first: identify query parameters */
203 r = [uri rangeOfString:@"?" options:NSBackwardsSearch];
205 uri = [uri substringToIndex:r.location];
207 /* next: append trailing slash */
208 if (![uri hasSuffix:@"/"])
209 uri = [uri stringByAppendingString:@"/"];
211 /* next: append method */
212 uri = [uri stringByAppendingString:_method];
214 /* next: append query parameters */
215 return [self completeHrefForMethod:uri];
222 This method creates a unique ID and redirects to the "edit" method on the
224 It is actually a folder method and should be defined on the folder.
226 Note: 'clientObject' is the SOGoAppointmentFolder!
227 Update: remember that there are group folders as well.
229 NSString *uri, *objectId, *nextMethod;
231 objectId = [NSClassFromString(@"SOGoAppointmentFolder")
232 globallyUniqueObjectId];
233 if ([objectId length] == 0) {
234 return [NSException exceptionWithHTTPStatus:500 /* Internal Error */
235 reason:@"could not create a unique ID"];
238 nextMethod = [NSString stringWithFormat:@"../%@/edit", objectId];
239 uri = [self _completeURIForMethod:nextMethod];
240 return [self redirectToLocation:uri];
245 /* returned dates are in GMT */
246 - (NSCalendarDate *)_dateFromString:(NSString *)_str {
247 NSCalendarDate *date;
249 date = [NSCalendarDate dateWithString:_str
250 calendarFormat:@"%Y-%m-%d %H:%M %Z"];
251 [date setTimeZone:[self backendTimeZone]];
255 - (iCalPerson *)getOrganizer {
259 emailProp = [@"mailto:" stringByAppendingString:[self emailForUser]];
260 p = [[[iCalPerson alloc] init] autorelease];
261 [p setEmail:emailProp];
262 [p setCn:[self cnForUser]];
266 - (NSArray *)getICalPersonsFromFormValues:(NSArray *)_values
267 treatAsResource:(BOOL)_isResource
270 NSMutableArray *result;
272 count = [_values count];
273 result = [[NSMutableArray alloc] initWithCapacity:count];
274 for (i = 0; i < count; i++) {
275 NSString *pString, *email, *cn;
279 pString = [_values objectAtIndex:i];
280 if ([pString length] == 0)
283 /* delimiter between email and cn */
284 r = [pString rangeOfString:@";"];
286 email = [pString substringToIndex:r.location];
287 cn = (r.location + 1 < [pString length])
288 ? [pString substringFromIndex:r.location + 1]
297 AgenorUserManager *um = [AgenorUserManager sharedUserManager];
298 cn = [um getCNForUID:[um getUIDForEmail:email]];
301 p = [[iCalPerson alloc] init];
302 [p setEmail:[@"mailto:" stringByAppendingString:email]];
303 if ([cn isNotNull]) [p setCn:cn];
305 /* see RFC2445, sect. 4.2.16 for details */
306 [p setRole:_isResource ? @"NON-PARTICIPANT" : @"REQ-PARTICIPANT"];
307 [result addObject:p];
310 return [result autorelease];
313 - (BOOL)isWriteableClientObject {
314 return [[self clientObject]
315 respondsToSelector:@selector(saveContentString:)];
318 - (void)loadValuesFromAppointment:(SOGoAppointment *)_appointment {
319 self->startDate = [[_appointment startDate] copy];
320 self->endDate = [[_appointment endDate] copy];
321 [self->startDate setTimeZone:[self viewTimeZone]];
322 [self->endDate setTimeZone:[self viewTimeZone]];
324 self->title = [[_appointment summary] copy];
325 self->location = [[_appointment location] copy];
326 self->comment = [[_appointment comment] copy];
328 self->participants = [[_appointment participants] retain];
329 self->resources = [[_appointment resources] retain];
334 - (BOOL)shouldTakeValuesFromRequest:(WORequest *)_rq inContext:(WOContext*)_c{
339 /* for testing only */
342 NSLog(@"%s BEEN HERE!", __PRETTY_FUNCTION__);
344 req = [[self context] request];
345 NSLog(@"%@", [req formValues]);
349 - (id)defaultAction {
352 /* load iCalendar file */
354 ical = [[self clientObject] valueForKey:@"iCalString"];
355 if ([ical length] == 0) /* a new appointment */
356 ical = [self iCalStringTemplate];
358 [self setICalString:ical];
363 [[SOGoAppointment alloc] initWithICalString:[self iCalString]];
367 [self loadValuesFromAppointment:[self appointment]];
374 NSCalendarDate *sd, *ed;
375 NSArray *attendees, *lResources;
378 if (![self isWriteableClientObject]) {
379 /* return 400 == Bad Request */
380 return [NSException exceptionWithHTTPStatus:400
381 reason:@"method cannot be invoked on "
382 @"the specified object"];
385 req = [[self context] request];
387 /* get iCalString from hidden input */
388 [self setICalString:[req formValueForKey:@"ical"]];
391 [[SOGoAppointment alloc] initWithICalString:[self iCalString]];
393 if (self->appointment == nil) {
394 return [NSException exceptionWithHTTPStatus:400 /* Bad Request */
395 reason:@"invalid iCalendar form data in request"];
398 /* merge in form values */
400 sd = [self _dateFromString:[req formValueForKey:@"startDate"]];
401 ed = [self _dateFromString:[req formValueForKey:@"endDate"]];
402 [self->appointment setStartDate:sd];
403 [self->appointment setEndDate:ed];
405 [self->appointment setSummary:[req formValueForKey:@"summary"]];
406 [self->appointment setLocation:[req formValueForKey:@"location"]];
408 attendees = [self getICalPersonsFromFormValues:
409 [req formValuesForKey:@"participants"]
411 lResources = [self getICalPersonsFromFormValues:
412 [req formValuesForKey:@"resources"]
413 treatAsResource:YES];
414 if ([lResources count] > 0) {
415 attendees = ([attendees count] > 0)
416 ? [attendees arrayByAddingObjectsFromArray:lResources]
419 [self->appointment setAttendees:attendees];
421 [self->appointment setOrganizer:[self getOrganizer]];
423 /* receive current representation for save operation */
428 content = [self->appointment iCalString];
429 if (content == nil) {
430 return [NSException exceptionWithHTTPStatus:500 /* Internal Error */
431 reason:@"failed to create iCal content for apt"];
434 ex = [[self clientObject] saveContentString:content];
436 // TODO: add some error handling in form! (eg like in Zope)
439 uri = [self _completeURIForMethod:@".."];
440 return [self redirectToLocation:uri];
443 @end /* UIxAppointmentEditor */