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>
27 @class NSString, SOGoAppointment, iCalPerson;
29 @interface UIxAppointmentEditor : UIxComponent
36 - (SOGoAppointment *)appointment;
37 - (NSString *)iCalStringTemplate;
38 - (NSString *)iCalString;
40 - (NSString *)emailForUser;
41 - (NSString *)cnForUser;
43 - (NSString *)_completeURIForMethod:(NSString *)_method;
45 - (iCalPerson *)getOrganizer;
46 - (NSArray *)getICalPersonsFromFormValues:(NSArray *)_values
47 treatAsResource:(BOOL)_isResource;
51 #include <SOGoUI/SOGoDateFormatter.h>
52 #include <SOGoLogic/SOGoAppointment.h>
53 #include <Appointments/SOGoAppointmentFolder.h>
54 #include <Appointments/SOGoAppointmentObject.h>
55 #include <NGiCal/NGiCal.h>
56 #include <SOGoLogic/AgenorUserManager.h>
57 #include "iCalPerson+UIx.h"
59 @interface NSDate(UsedPrivates)
60 - (NSString *)icalString; // TODO: this is in NGiCal
63 @interface NSObject (AppointmentHack)
64 - (BOOL)isAppointment;
67 @implementation NSObject (AppointmentHack)
68 - (BOOL)isAppointment {
69 return [self isKindOfClass:NSClassFromString(@"SOGoAppointmentObject")];
73 @implementation UIxAppointmentEditor
76 [self->appointment release];
77 [self->participants release];
84 - (void)setItem:(id)_item {
85 ASSIGN(self->item, _item);
91 - (NSString *)formattedAptStartTime {
93 SOGoDateFormatter *fmt;
96 date = [[[[self appointment] startDate] copy] autorelease];
97 [date setTimeZone:[self viewTimeZone]];
98 fmt = [[SOGoDateFormatter alloc] initWithLocale:[self locale]];
99 [fmt setFullWeekdayNameAndDetails];
100 s = [fmt stringForObjectValue:date];
105 - (BOOL)isNewAppointment {
106 /* that doesn't work! */
107 return ![[self clientObject] isAppointment];
110 - (NSString *)iCalString {
111 // TODO: improve check for new appointment
114 ical = [[self clientObject] valueForKey:@"iCalString"];
115 if ([ical length] == 0) /* a new appointment */
116 ical = [self iCalStringTemplate];
121 - (NSString *)iCalStringTemplate {
122 static NSString *iCalStringTemplate = \
123 @"BEGIN:VCALENDAR\nMETHOD:REQUEST\nPRODID:OpenGroupware.org SOGo 0.9\n"
128 @"STATUS:CONFIRMED\n"
136 NSCalendarDate *startDate, *endDate;
139 startDate = [self selectedDate];
140 endDate = [startDate dateByAddingYears:0 months:0 days:0
141 hours:1 minutes:0 seconds:0];
143 template = [NSString stringWithFormat:iCalStringTemplate,
144 [[self clientObject] nameInContainer],
145 [[NSCalendarDate date] icalString],
146 [startDate icalString],
147 [endDate icalString]];
154 - (SOGoAppointment *)appointment {
155 if (self->appointment == nil) {
156 self->appointment = [[SOGoAppointment alloc]
157 initWithICalString:[self iCalString]];
159 return self->appointment;
164 - (NSString *)jsCode {
165 static NSString *script = \
166 @"function addToTable(tableId, type, cn, dn, email, uid, sn) {\n"
167 @" var test = document.getElementById(email);"
171 @" var table = document.getElementById(tableId);"
172 @" var tr = document.createElement('tr');"
173 @" var td, checkbox, text;"
175 @" td = document.createElement('td');"
176 @" checkbox = document.createElement('input');"
177 @" checkbox.setAttribute('type', 'checkbox');"
178 @" checkbox.setAttribute('checked', 'checked');"
179 @" checkbox.setAttribute('value', email + ';' + cn);"
180 @" checkbox.setAttribute('id', email);"
181 @" checkbox.setAttribute('name', tableId);"
182 @" td.appendChild(checkbox);"
183 @" tr.appendChild(td);"
184 @" td = document.createElement('td');"
185 @" text = document.createTextNode(cn);"
186 @" td.appendChild(text);"
187 @" tr.appendChild(td);"
188 @" table.appendChild(tr);"
190 @"function addParticipant(type, cn, dn, email, uid, sn) {\n"
191 @" addToTable('participants', type, cn, dn, email, uid, sn);\n"
193 @"function addResource(type, cn, dn, email, uid, sn) {\n"
194 @" addToTable('resources', type, cn, dn, email, uid, sn);\n"
202 - (NSString *)_completeURIForMethod:(NSString *)_method {
206 uri = [[[self context] request] uri];
208 /* first: identify query parameters */
209 r = [uri rangeOfString:@"?" options:NSBackwardsSearch];
211 uri = [uri substringToIndex:r.location];
213 /* next: append trailing slash */
214 if(![uri hasSuffix:@"/"])
215 uri = [uri stringByAppendingString:@"/"];
217 /* next: append method */
218 uri = [uri stringByAppendingString:_method];
220 /* next: append query parameters */
221 return [self completeHrefForMethod:uri];
227 - (NSString *)emailForUser {
230 uid = [[self user] login];
231 return [[AgenorUserManager sharedUserManager] getEmailForUID:uid];
234 - (NSString *)cnForUser {
237 uid = [[self user] login];
238 return [[AgenorUserManager sharedUserManager] getCNForUID:uid];
241 - (NSString *)combinedCNAndEmailForUser {
242 return [NSString stringWithFormat:@"%@;%@",
247 - (NSString *)combinedCNAndEmail {
248 return [NSString stringWithFormat:@"%@;%@",
249 [self->item rfc822Email],
250 [self->item cnForDisplay]];
258 This method creates a unique ID and redirects to the "edit" method on the
260 It is actually a folder method and should be defined on the folder.
262 Note: 'clientObject' is the SOGoAppointmentFolder!
264 NSString *uri, *objectId, *nextMethod;
266 objectId = [NSClassFromString(@"SOGoAppointmentFolder")
267 globallyUniqueObjectId];
269 nextMethod = [NSString stringWithFormat:@"../%@/edit", objectId];
270 uri = [self _completeURIForMethod:nextMethod];
271 return [self redirectToLocation:uri];
276 /* returned dates are in GMT */
277 - (NSCalendarDate *)_dateFromString:(NSString *)_str {
278 NSCalendarDate *date;
280 date = [NSCalendarDate dateWithString:_str
281 calendarFormat:@"%Y-%m-%d %H:%M %Z"];
282 [date setTimeZone:[self backendTimeZone]];
286 - (iCalPerson *)getOrganizer {
290 emailProp = [NSString stringWithFormat:@"mailto:%@",
291 [self emailForUser]];
292 p = [[iCalPerson alloc] init];
293 [p setEmail:emailProp];
294 [p setCn:[self cnForUser]];
295 return [p autorelease];
298 - (NSArray *)getICalPersonsFromFormValues:(NSArray *)_values
299 treatAsResource:(BOOL)_isResource
302 NSMutableArray *result;
304 count = [_values count];
305 result = [[NSMutableArray alloc] initWithCapacity:count];
306 for (i = 0; i < count; i++) {
307 NSString *pString, *email, *cn;
311 pString = [_values objectAtIndex:i];
312 if([pString length] == 0)
315 /* delimiter between email and cn */
316 r = [pString rangeOfString:@";"];
318 email = [pString substringToIndex:r.location];
319 if(r.location + 1 < [pString length]) {
320 cn = [pString substringFromIndex:r.location + 1];
332 AgenorUserManager *um = [AgenorUserManager sharedUserManager];
333 cn = [um getCNForUID:[um getUIDForEmail:email]];
335 p = [[iCalPerson alloc] init];
336 [p setEmail:[@"mailto:" stringByAppendingString:email]];
340 /* see RFC2445, sect. 4.2.16 for details */
342 [p setRole:@"X-OGo-RESOURCE"];
345 [p setRole:@"REQ-PARTICIPANT"];
347 [result addObject:p];
350 return [result autorelease];
353 /* for testing only */
357 NSLog(@"%s BEEN HERE!",
358 __PRETTY_FUNCTION__);
360 req = [[self context] request];
361 NSLog(@"%@", [req formValues]);
366 SOGoAppointment *apt;
367 NSString *iCalString;
368 NSString *summary, *location, *uri;
369 NSCalendarDate *sd, *ed;
374 if (![[self clientObject] respondsToSelector:@selector(saveContentString:)]){
375 /* return 400 == Bad Request */
376 return [NSException exceptionWithHTTPStatus:400
377 reason:@"method cannot be invoked on "
378 @"the specified object"];
381 req = [[self context] request];
383 /* get iCalString from hidden input */
384 iCalString = [req formValueForKey:@"ical"];
385 if ([iCalString length] == 0) {
386 // TODO: improve user experience ... (eg error panel like Zope)
387 /* return 400 == Bad Request */
388 return [NSException exceptionWithHTTPStatus:400
389 reason:@"missing iCalendar form data in request"];
392 apt = [[SOGoAppointment alloc] initWithICalString:iCalString];
394 /* merge in form values */
396 sd = [self _dateFromString:[req formValueForKey:@"startDate"]];
397 ed = [self _dateFromString:[req formValueForKey:@"endDate"]];
398 [apt setStartDate:sd];
401 summary = [req formValueForKey:@"summary"];
402 [apt setSummary:summary];
403 location = [req formValueForKey:@"location"];
404 [apt setLocation:location];
406 [apt removeAllAttendees]; /* clean up */
408 [self getICalPersonsFromFormValues:[req formValuesForKey:@"participants"]
410 [apt appendAttendees:attendees];
412 [self getICalPersonsFromFormValues:[req formValuesForKey:@"resources"]
413 treatAsResource:YES];
414 [apt appendAttendees:attendees];
415 [apt setOrganizer:[self getOrganizer]];
417 /* receive current representation for save operation */
418 iCalString = [apt iCalString];
419 [apt release]; apt = nil;
424 ex = [[self clientObject] saveContentString:iCalString];
426 // TODO: add some error handling in form! (eg like in Zope)
429 uri = [self _completeURIForMethod:@"view"];
430 return [self redirectToLocation:uri];
433 @end /* UIxAppointmentEditor */