]> err.no Git - scalable-opengroupware.org/blob - SOGo/UI/Scheduler/UIxAppointmentEditor.m
git-svn-id: http://svn.opengroupware.org/SOGo/trunk@245 d1b88da0-ebda-0310-925b-ed51d...
[scalable-opengroupware.org] / SOGo / UI / Scheduler / UIxAppointmentEditor.m
1 /*
2   Copyright (C) 2004 SKYRIX Software AG
3
4   This file is part of OpenGroupware.org.
5
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
9   later version.
10
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.
15
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
19   02111-1307, USA.
20 */
21 // $Id$
22
23 #include <SOGoUI/UIxComponent.h>
24
25 /* TODO: CLEAN UP */
26
27 @class NSString;
28 @class iCalPerson;
29 @class SOGoAppointment;
30
31 @interface UIxAppointmentEditor : UIxComponent
32 {
33   NSString *iCalString;
34   NSString *errorText;
35   id item;
36   
37   /* individual values */
38   NSCalendarDate *startDate;
39   NSCalendarDate *endDate;
40   NSString       *title;
41   NSString       *location;
42   NSString       *comment;
43   NSArray        *participants; /* array of iCalPerson's */
44   NSArray        *resources;    /* array of iCalPerson's */
45 }
46
47 - (NSString *)iCalStringTemplate;
48 - (NSString *)iCalString;
49
50 - (NSString *)_completeURIForMethod:(NSString *)_method;
51
52 - (iCalPerson *)getOrganizer;
53 - (NSArray *)getICalPersonsFromFormValues:(NSArray *)_values
54   treatAsResource:(BOOL)_isResource;
55
56 @end
57
58 #include "common.h"
59 #include <SOGoUI/SOGoDateFormatter.h>
60 #include <SOGoLogic/SOGoAppointment.h>
61 #include <Appointments/SOGoAppointmentFolder.h>
62 #include <Appointments/SOGoAppointmentObject.h>
63 #include <NGiCal/NGiCal.h>
64 #include <SOGoLogic/AgenorUserManager.h>
65 #include "iCalPerson+UIx.h"
66 #include "UIxComponent+Agenor.h"
67
68 @interface NSDate(UsedPrivates)
69 - (NSString *)icalString; // TODO: this is in NGiCal
70 @end
71
72 @implementation UIxAppointmentEditor
73
74 - (void)dealloc {
75   [self->errorText    release];
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->item         release];
85   [super dealloc];
86 }
87
88 /* accessors */
89
90 - (void)setItem:(id)_item {
91   ASSIGN(self->item, _item);
92 }
93 - (id)item {
94   return self->item;
95 }
96
97 - (void)setErrorText:(NSString *)_txt {
98   ASSIGNCOPY(self->errorText, _txt);
99 }
100 - (NSString *)errorText {
101   return self->errorText;
102 }
103 - (BOOL)hasErrorText {
104   return [self->errorText length] > 0 ? YES : NO;
105 }
106
107 - (NSFormatter *)titleDateFormatter {
108   SOGoDateFormatter *fmt;
109   
110   fmt = [[[SOGoDateFormatter alloc] initWithLocale:[self locale]] autorelease];
111   [fmt setFullWeekdayNameAndDetails];
112   return fmt;
113 }
114
115 - (void)setAptStartDate:(NSCalendarDate *)_date {
116   ASSIGN(self->startDate, _date);
117 }
118 - (NSCalendarDate *)aptStartDate {
119   return self->startDate;
120 }
121 - (void)setAptEndDate:(NSCalendarDate *)_date {
122   ASSIGN(self->endDate, _date);
123 }
124 - (NSCalendarDate *)aptEndDate {
125   return self->endDate;
126 }
127
128 - (void)setTitle:(NSString *)_value {
129   ASSIGNCOPY(self->title, _value);
130 }
131 - (NSString *)title {
132   return self->title;
133 }
134 - (void)setLocation:(NSString *)_value {
135   ASSIGNCOPY(self->location, _value);
136 }
137 - (NSString *)location {
138   return self->location;
139 }
140 - (void)setComment:(NSString *)_value {
141   ASSIGNCOPY(self->comment, _value);
142 }
143 - (NSString *)comment {
144   return self->comment;
145 }
146
147 - (void)setParticipants:(NSArray *)_parts {
148   ASSIGN(self->participants, _parts);
149 }
150 - (NSArray *)participants {
151   return self->participants;
152 }
153 - (void)setResources:(NSArray *)_res {
154   ASSIGN(self->resources, _res);
155 }
156 - (NSArray *)resources {
157   return self->resources;
158 }
159
160 /* iCal */
161
162 - (void)setICalString:(NSString *)_s {
163   ASSIGNCOPY(self->iCalString, _s);
164 }
165 - (NSString *)iCalString {
166   return self->iCalString;
167 }
168
169 - (NSString *)iCalStringTemplate {
170   static NSString *iCalStringTemplate = \
171     @"BEGIN:VCALENDAR\nMETHOD:REQUEST\nPRODID:OpenGroupware.org SOGo 0.9\n"
172     @"VERSION:2.0\n"
173     @"BEGIN:VEVENT\n"
174     @"UID:%@\n"
175     @"CLASS:PRIVATE\n"
176     @"STATUS:CONFIRMED\n"
177     @"DTSTAMP:%@\n"
178     @"DTSTART:%@\n"
179     @"DTEND:%@\n"
180     @"TRANSP:OPAQUE\n"
181     @"SEQUENCE:1\n"
182     @"END:VEVENT\n"
183     @"END:VCALENDAR";
184   NSCalendarDate *lStartDate, *lEndDate;
185   NSString       *template;
186   
187   lStartDate = [self selectedDate];
188   lEndDate   = [lStartDate dateByAddingYears:0 months:0 days:0
189                          hours:1 minutes:0 seconds:0];
190   
191   template = [NSString stringWithFormat:iCalStringTemplate,
192                          [[self clientObject] nameInContainer],
193                          [[NSCalendarDate date] icalString],
194                          [lStartDate icalString],
195                          [lEndDate   icalString]];
196   return template;
197 }
198
199 /* helper */
200
201 - (NSString *)_completeURIForMethod:(NSString *)_method {
202   NSString *uri;
203   NSRange r;
204     
205   uri = [[[self context] request] uri];
206     
207   /* first: identify query parameters */
208   r = [uri rangeOfString:@"?" options:NSBackwardsSearch];
209   if (r.length > 0)
210     uri = [uri substringToIndex:r.location];
211     
212   /* next: append trailing slash */
213   if (![uri hasSuffix:@"/"])
214     uri = [uri stringByAppendingString:@"/"];
215   
216   /* next: append method */
217   uri = [uri stringByAppendingString:_method];
218     
219   /* next: append query parameters */
220   return [self completeHrefForMethod:uri];
221 }
222
223 /* new */
224
225 - (id)newAction {
226   /*
227     This method creates a unique ID and redirects to the "edit" method on the
228     new ID.
229     It is actually a folder method and should be defined on the folder.
230     
231     Note: 'clientObject' is the SOGoAppointmentFolder!
232           Update: remember that there are group folders as well.
233   */
234   NSString *uri, *objectId, *nextMethod;
235   
236   objectId = [NSClassFromString(@"SOGoAppointmentFolder")
237                                globallyUniqueObjectId];
238   if ([objectId length] == 0) {
239     return [NSException exceptionWithHTTPStatus:500 /* Internal Error */
240                         reason:@"could not create a unique ID"];
241   }
242   
243   nextMethod = [NSString stringWithFormat:@"../%@/edit", objectId];
244   uri = [self _completeURIForMethod:nextMethod];
245   return [self redirectToLocation:uri];
246 }
247
248 /* save */
249
250 /* returned dates are in GMT */
251 - (NSCalendarDate *)_dateFromString:(NSString *)_str {
252   NSCalendarDate *date;
253   
254   date = [NSCalendarDate dateWithString:_str 
255                          calendarFormat:@"%Y-%m-%d %H:%M %Z"];
256   [date setTimeZone:[self backendTimeZone]];
257   return date;
258 }
259
260 - (iCalPerson *)getOrganizer {
261   iCalPerson *p;
262   NSString   *emailProp;
263   
264   emailProp = [@"mailto:" stringByAppendingString:[self emailForUser]];
265   p = [[[iCalPerson alloc] init] autorelease];
266   [p setEmail:emailProp];
267   [p setCn:[self cnForUser]];
268   return p;
269 }
270
271 - (NSArray *)getICalPersonsFromFormValues:(NSArray *)_values
272   treatAsResource:(BOOL)_isResource
273 {
274   unsigned i, count;
275   NSMutableArray *result;
276
277   count = [_values count];
278   result = [[NSMutableArray alloc] initWithCapacity:count];
279   for (i = 0; i < count; i++) {
280     NSString   *pString, *email, *cn;
281     NSRange    r;
282     iCalPerson *p;
283     
284     pString = [_values objectAtIndex:i];
285     if ([pString length] == 0)
286       continue;
287     
288     /* delimiter between email and cn */
289     r = [pString rangeOfString:@";"];
290     if (r.length > 0) {
291       email = [pString substringToIndex:r.location];
292       cn = (r.location + 1 < [pString length])
293         ? [pString substringFromIndex:r.location + 1]
294         : nil;
295     }
296     else {
297       email = pString;
298       cn    = nil;
299     }
300     if (cn == nil) {
301       /* fallback */
302       AgenorUserManager *um = [AgenorUserManager sharedUserManager];
303       cn = [um getCNForUID:[um getUIDForEmail:email]];
304     }
305     
306     p = [[iCalPerson alloc] init];
307     [p setEmail:[@"mailto:" stringByAppendingString:email]];
308     if ([cn isNotNull]) [p setCn:cn];
309     
310     /* see RFC2445, sect. 4.2.16 for details */
311     [p setRole:_isResource ? @"NON-PARTICIPANT" : @"REQ-PARTICIPANT"];
312     [result addObject:p];
313     [p release];
314   }
315   return [result autorelease];
316 }
317
318 - (BOOL)isWriteableClientObject {
319   return [[self clientObject] 
320                 respondsToSelector:@selector(saveContentString:)];
321 }
322
323 - (void)loadValuesFromAppointment:(SOGoAppointment *)_appointment {
324   self->startDate = [[_appointment startDate] copy];
325   self->endDate   = [[_appointment endDate]   copy];
326   [self->startDate setTimeZone:[self viewTimeZone]];
327   [self->endDate   setTimeZone:[self viewTimeZone]];
328   
329   self->title    = [[_appointment summary]  copy];
330   self->location = [[_appointment location] copy];
331   self->comment  = [[_appointment comment]  copy];
332   
333   self->participants = [[_appointment participants] retain];
334   self->resources    = [[_appointment resources]    retain];
335 }
336
337 - (void)saveValuesIntoAppointment:(SOGoAppointment *)_appointment {
338   /* merge in form values */
339   NSArray *attendees, *lResources;
340   
341   [_appointment setStartDate:[self aptStartDate]];
342   [_appointment setEndDate:[self aptEndDate]];
343   
344   [_appointment setSummary:[self title]];
345   [_appointment setLocation:[self location]];
346   
347   attendees  = [self participants];
348   lResources = [self resources];
349   if ([lResources count] > 0) {
350     attendees = ([attendees count] > 0)
351       ? [attendees arrayByAddingObjectsFromArray:lResources]
352       : lResources;
353   }
354   [_appointment setAttendees:attendees];
355   
356   [_appointment setOrganizer:[self getOrganizer]];
357 }
358
359 - (void)loadValuesFromICalString:(NSString *)_ical {
360   SOGoAppointment *apt;
361
362   apt = [[SOGoAppointment alloc] initWithICalString:_ical];
363   [self loadValuesFromAppointment:apt];
364   [apt release];
365 }
366
367 /* actions */
368
369 - (BOOL)shouldTakeValuesFromRequest:(WORequest *)_rq inContext:(WOContext*)_c{
370   return YES;
371 }
372
373 - (id)testAction {
374   /* for testing only */
375   WORequest *req;
376     
377   NSLog(@"%s BEEN HERE!", __PRETTY_FUNCTION__);
378
379   req = [[self context] request];
380   NSLog(@"%@", [req formValues]);
381   return self;
382 }
383
384 - (id)defaultAction {
385   NSString *ical;
386   
387   /* load iCalendar file */
388   
389   ical = [[self clientObject] valueForKey:@"iCalString"];
390   if ([ical length] == 0) /* a new appointment */
391     ical = [self iCalStringTemplate];
392   
393   [self setICalString:ical];
394   [self loadValuesFromICalString:ical];
395   
396   return self;
397 }
398
399 - (id)saveAction {
400   SOGoAppointment *apt;
401   NSException     *ex;
402   NSString        *content;
403   
404   if (![self isWriteableClientObject]) {
405     /* return 400 == Bad Request */
406     return [NSException exceptionWithHTTPStatus:400
407                         reason:@"method cannot be invoked on "
408                                @"the specified object"];
409   }
410   
411   apt = [[SOGoAppointment alloc] initWithICalString:[self iCalString]];
412   if (apt == nil) {
413     [self setErrorText:@"Invalid iCalendar data ..."]; // localize
414     return self;
415   }
416   
417   [self saveValuesIntoAppointment:apt];
418   content = [apt iCalString];
419   [apt release]; apt = nil;
420   
421   if (content == nil) {
422     [self setErrorText:@"Could not create iCalendar data ..."]; // localize
423     return self;
424   }
425   
426   ex = [[self clientObject] saveContentString:content];
427   if (ex != nil) {
428     [self setErrorText:[ex reason]];
429     return self;
430   }
431   
432   return [self redirectToLocation:[self _completeURIForMethod:@".."]];
433 }
434
435 @end /* UIxAppointmentEditor */