From 02806edc925b2666e5110607227be0f9b92e9734 Mon Sep 17 00:00:00 2001 From: helge Date: Fri, 2 Jul 2004 17:42:14 +0000 Subject: [PATCH] git-svn-id: http://svn.opengroupware.org/SOGo/trunk@137 d1b88da0-ebda-0310-925b-ed51d893ca5b --- SOGo/SoObjects/Appointments/ChangeLog | 5 + .../Appointments/SOGoAppointmentFolder.h | 7 +- .../Appointments/SOGoAppointmentFolder.m | 75 +++++--- SOGo/SoObjects/SOGo/ChangeLog | 4 + SOGo/SoObjects/SOGo/SOGoFolder.h | 1 + SOGo/SoObjects/SOGo/SOGoFolder.m | 6 +- SOGo/SoObjects/SOGo/SOGoObject.h | 6 +- SOGo/SoObjects/SOGo/SOGoObject.m | 11 ++ SOGo/UI/SOGoUI/ChangeLog | 5 + SOGo/UI/SOGoUI/UIxComponent.h | 5 +- SOGo/UI/SOGoUI/UIxComponent.m | 177 ++++++++++-------- SOGo/UI/Scheduler/ChangeLog | 4 + SOGo/UI/Scheduler/GNUmakefile | 2 +- SOGo/UI/Scheduler/UIxAppointmentEditor.m | 148 +++++++++------ SOGo/UI/Scheduler/UIxAppointmentEditor.wox | 16 +- SOGo/UI/Scheduler/UIxAppointmentView.h | 10 +- SOGo/UI/Scheduler/UIxAppointmentView.m | 19 +- SOGo/UI/Scheduler/UIxCalView.m | 126 ++++++++++--- SOGo/UI/Scheduler/UIxCalWeekOverview.wox | 6 +- 19 files changed, 424 insertions(+), 209 deletions(-) diff --git a/SOGo/SoObjects/Appointments/ChangeLog b/SOGo/SoObjects/Appointments/ChangeLog index b3888f90..cc4a7037 100644 --- a/SOGo/SoObjects/Appointments/ChangeLog +++ b/SOGo/SoObjects/Appointments/ChangeLog @@ -1,3 +1,8 @@ +2004-07-02 Helge Hess + + * SOGoAppointmentFolder.m: added method to fetch core info from other + OCS folders, correct timezone to MET after fetch core info + 2004-07-01 Helge Hess * redirect to weekoverview if GET is run on the folder itself diff --git a/SOGo/SoObjects/Appointments/SOGoAppointmentFolder.h b/SOGo/SoObjects/Appointments/SOGoAppointmentFolder.h index f143020f..243b2fcf 100644 --- a/SOGo/SoObjects/Appointments/SOGoAppointmentFolder.h +++ b/SOGo/SoObjects/Appointments/SOGoAppointmentFolder.h @@ -25,7 +25,8 @@ #include -@class NSString, NSArray, NSCalendarDate; +@class NSString, NSArray, NSCalendarDate, NSException; +@class OCSFolder; @interface SOGoAppointmentFolder : SOGoFolder { @@ -38,6 +39,10 @@ - (NSArray *)fetchCoreInfosFrom:(NSCalendarDate *)_startDate to:(NSCalendarDate *)_endDate; +- (NSArray *)fetchCoreInfosFromFolder:(OCSFolder *)_folder + from:(NSCalendarDate *)_startDate + to:(NSCalendarDate *)_endDate; + @end #endif /* __Appointments_SOGoAppointmentFolder_H__ */ diff --git a/SOGo/SoObjects/Appointments/SOGoAppointmentFolder.m b/SOGo/SoObjects/Appointments/SOGoAppointmentFolder.m index 6019eee5..15286918 100644 --- a/SOGo/SoObjects/Appointments/SOGoAppointmentFolder.m +++ b/SOGo/SoObjects/Appointments/SOGoAppointmentFolder.m @@ -29,30 +29,32 @@ @implementation SOGoAppointmentFolder -static BOOL debugOn = NO; +static BOOL debugOn = NO; +static NSTimeZone *MET = nil; + ++ (void)initialize { + if (MET == nil) MET = [[NSTimeZone timeZoneWithAbbreviation:@"MET"] retain]; +} + (NSString *)globallyUniqueObjectId { -/* -4C08AE1A-A808-11D8-AC5A-000393BBAFF6 - SOGo-Web-28273-18283-288182 -printf( "%x", *(int *) &f); - */ - static int pid = 0; - static int sequence = 0; - static float rndm = 0; - float f; - - if(pid == 0) { + /* + 4C08AE1A-A808-11D8-AC5A-000393BBAFF6 + SOGo-Web-28273-18283-288182 + printf( "%x", *(int *) &f); + */ + static int pid = 0; + static int sequence = 0; + static float rndm = 0; + float f; + + if (pid == 0) { /* break if we fork ;-) */ pid = getpid(); rndm = random(); - } - sequence++; - f = [[NSDate date] timeIntervalSince1970]; - return [NSString stringWithFormat:@"%0X-%0X-%0X-%0X", - pid, - *(int *)&f, - sequence++, - random]; + } + sequence++; + f = [[NSDate date] timeIntervalSince1970]; + return [NSString stringWithFormat:@"%0X-%0X-%0X-%0X", + pid, *(int *)&f, sequence++, random]; } - (void)dealloc { @@ -97,6 +99,13 @@ printf( "%x", *(int *) &f); return [NSException exceptionWithHTTPStatus:404 /* Not Found */]; } +/* timezone */ + +- (NSTimeZone *)viewTimeZone { + // TODO: should use a cookie for configuration? we default to MET + return MET; +} + /* fetching */ - (NSMutableDictionary *)fixupRecord:(NSDictionary *)_record { @@ -108,6 +117,7 @@ printf( "%x", *(int *) &f); if ((tmp = [_record objectForKey:@"startdate"])) { tmp = [[NSCalendarDate alloc] initWithTimeIntervalSince1970: (NSTimeInterval)[tmp unsignedIntValue]]; + [tmp setTimeZone:[self viewTimeZone]]; if (tmp) [md setObject:tmp forKey:@"startDate"]; [tmp release]; } @@ -117,6 +127,7 @@ printf( "%x", *(int *) &f); if ((tmp = [_record objectForKey:@"enddate"])) { tmp = [[NSCalendarDate alloc] initWithTimeIntervalSince1970: (NSTimeInterval)[tmp unsignedIntValue]]; + [tmp setTimeZone:[self viewTimeZone]]; if (tmp) [md setObject:tmp forKey:@"endDate"]; [tmp release]; } @@ -144,21 +155,22 @@ printf( "%x", *(int *) &f); return ma; } -- (NSArray *)fetchCoreInfosFrom:(NSCalendarDate *)_startDate +- (NSArray *)fetchCoreInfosFromFolder:(OCSFolder *)_folder + from:(NSCalendarDate *)_startDate to:(NSCalendarDate *)_endDate { - OCSFolder *folder; EOQualifier *qualifier; NSArray *fields, *records; NSString *sql; - if ((folder = [self ocsFolder]) == nil) { + if (_folder == nil) { [self logWithFormat:@"ERROR(%s): missing folder for fetch!", __PRETTY_FUNCTION__]; return nil; } - [self logWithFormat:@"should fetch (%@ => %@) ...", _startDate, _endDate]; + if (debugOn) + [self debugWithFormat:@"should fetch (%@=>%@) ...", _startDate, _endDate]; sql = [NSString stringWithFormat:@"(startdate < %d) AND (enddate > %d)", (unsigned int)[_endDate timeIntervalSince1970], @@ -169,7 +181,7 @@ printf( "%x", *(int *) &f); @"uid", @"startdate", @"enddate", @"title", @"participants", nil]; - records = [folder fetchFields:fields matchingQualifier:qualifier]; + records = [_folder fetchFields:fields matchingQualifier:qualifier]; if (records == nil) { [self logWithFormat:@"ERROR(%s): fetch failed!", __PRETTY_FUNCTION__]; return nil; @@ -181,6 +193,19 @@ printf( "%x", *(int *) &f); return records; } +- (NSArray *)fetchCoreInfosFrom:(NSCalendarDate *)_startDate + to:(NSCalendarDate *)_endDate +{ + OCSFolder *folder; + + if ((folder = [self ocsFolder]) == nil) { + [self logWithFormat:@"ERROR(%s): missing folder for fetch!", + __PRETTY_FUNCTION__]; + return nil; + } + return [self fetchCoreInfosFromFolder:folder from:_startDate to:_endDate]; +} + /* GET */ - (id)GETAction:(WOContext *)_ctx { diff --git a/SOGo/SoObjects/SOGo/ChangeLog b/SOGo/SoObjects/SOGo/ChangeLog index 3fc026fd..5bf70eeb 100644 --- a/SOGo/SoObjects/SOGo/ChangeLog +++ b/SOGo/SoObjects/SOGo/ChangeLog @@ -1,3 +1,7 @@ +2004-07-02 Helge Hess + + * SOGoObject.m: added -delete method (but not yet implemented) + 2004-06-30 Helge Hess * SOGoContentObject.m: added -contentAsString method diff --git a/SOGo/SoObjects/SOGo/SOGoFolder.h b/SOGo/SoObjects/SOGo/SOGoFolder.h index 2250a372..df3a3301 100644 --- a/SOGo/SoObjects/SOGo/SOGoFolder.h +++ b/SOGo/SoObjects/SOGo/SOGoFolder.h @@ -38,6 +38,7 @@ - (void)setOCSPath:(NSString *)_Path; - (NSString *)ocsPath; +- (OCSFolder *)ocsFolderForPath:(NSString *)_path; - (OCSFolder *)ocsFolder; @end diff --git a/SOGo/SoObjects/SOGo/SOGoFolder.m b/SOGo/SoObjects/SOGo/SOGoFolder.m index c40c45e8..c3fff2fa 100644 --- a/SOGo/SoObjects/SOGo/SOGoFolder.m +++ b/SOGo/SoObjects/SOGo/SOGoFolder.m @@ -55,12 +55,14 @@ - (OCSFolderManager *)folderManager { return [OCSFolderManager defaultFolderManager]; } +- (OCSFolder *)ocsFolderForPath:(NSString *)_path { + return [[self folderManager] folderAtPath:_path]; +} - (OCSFolder *)ocsFolder { if (self->ocsFolder != nil) return [self->ocsFolder isNotNull] ? self->ocsFolder : nil; - self->ocsFolder = - [[[self folderManager] folderAtPath:[self ocsPath]] retain]; + self->ocsFolder = [[self ocsFolderForPath:[self ocsPath]] retain]; return self->ocsFolder; } diff --git a/SOGo/SoObjects/SOGo/SOGoObject.h b/SOGo/SoObjects/SOGo/SOGoObject.h index fb90b6eb..22e28556 100644 --- a/SOGo/SoObjects/SOGo/SOGoObject.h +++ b/SOGo/SoObjects/SOGo/SOGoObject.h @@ -25,7 +25,7 @@ #import -@class NSString, NSMutableString; +@class NSString, NSMutableString, NSException; @class OCSFolderManager, OCSFolder; @class SOGoUserFolder; @@ -46,6 +46,10 @@ - (SOGoUserFolder *)lookupUserFolder; +/* operations */ + +- (NSException *)delete; + /* description */ - (void)appendAttributesToDescription:(NSMutableString *)_ms; diff --git a/SOGo/SoObjects/SOGo/SOGoObject.m b/SOGo/SoObjects/SOGo/SOGoObject.m index ad29501b..b558aba0 100644 --- a/SOGo/SoObjects/SOGo/SOGoObject.m +++ b/SOGo/SoObjects/SOGo/SOGoObject.m @@ -66,6 +66,13 @@ return [self->container lookupUserFolder]; } +/* operations */ + +- (NSException *)delete { + return [NSException exceptionWithHTTPStatus:500 /* not implemented */ + reason:@"delete not yet implemented, sorry ..."]; +} + /* KVC hacks */ - (id)valueForUndefinedKey:(NSString *)_key { @@ -78,6 +85,10 @@ return [self nameInContainer]; } +- (id)DELETEAction:(id)_ctx { + return [self delete]; +} + /* description */ - (void)appendAttributesToDescription:(NSMutableString *)_ms { diff --git a/SOGo/UI/SOGoUI/ChangeLog b/SOGo/UI/SOGoUI/ChangeLog index 50aaf591..c81828cf 100644 --- a/SOGo/UI/SOGoUI/ChangeLog +++ b/SOGo/UI/SOGoUI/ChangeLog @@ -1,3 +1,8 @@ +2004-07-02 Helge Hess + + * UIxComponent.m: introduced 'viewTimeZone' method and adds some + timezone correction to date methods + 2004-06-30 Helge Hess * product.plist: make categories on SOGoObject instead of SxFolder diff --git a/SOGo/UI/SOGoUI/UIxComponent.h b/SOGo/UI/SOGoUI/UIxComponent.h index d9a0c6ff..8e99aba9 100644 --- a/SOGo/UI/SOGoUI/UIxComponent.h +++ b/SOGo/UI/SOGoUI/UIxComponent.h @@ -26,12 +26,12 @@ #include -@class NSCalendarDate; +@class NSCalendarDate, NSTimeZone, NSMutableDictionary; @interface UIxComponent : SoComponent { - NSMutableDictionary *queryParameters; + NSMutableDictionary *queryParameters; } - (NSString *)queryParameterForKey:(NSString *)_key; @@ -46,6 +46,7 @@ - (NSString *)ownMethodName; /* date selection */ +- (NSTimeZone *)viewTimeZone; - (NSCalendarDate *)selectedDate; - (NSString *)dateStringForDate:(NSCalendarDate *)_date; - (NSCalendarDate *)dateForDateString:(NSString *)_dateString; diff --git a/SOGo/UI/SOGoUI/UIxComponent.m b/SOGo/UI/SOGoUI/UIxComponent.m index 280bcd71..c52f0b93 100644 --- a/SOGo/UI/SOGoUI/UIxComponent.m +++ b/SOGo/UI/SOGoUI/UIxComponent.m @@ -1,7 +1,7 @@ /* - Copyright (C) 2000-2004 SKYRIX Software AG + Copyright (C) 2004 SKYRIX Software AG - This file is part of OGo + This file is part of OpenGroupware.org. OGo is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the @@ -34,135 +34,156 @@ @implementation UIxComponent +static NSTimeZone *MET = nil; + ++ (void)initialize { + if (MET == nil) MET = [[NSTimeZone timeZoneWithAbbreviation:@"MET"] retain]; +} + - (id)init { - if ((self = [super init])) { - self->queryParameters = [[NSMutableDictionary alloc] init]; - } - return self; + if ((self = [super init])) { + self->queryParameters = [[NSMutableDictionary alloc] init]; + } + return self; } - (void)dealloc { - [self->queryParameters release]; - [super dealloc]; + [self->queryParameters release]; + [super dealloc]; } - (void)awake { - WORequest *req; - NSString *uri; - NSRange r; + WORequest *req; + NSString *uri; + NSRange r; - [super awake]; + [super awake]; - req = [[self context] request]; - uri = [req uri]; - r = [uri rangeOfString:@"?"]; - if(r.length > 0) { - NSString *qs; - - qs = [uri substringFromIndex:(r.location + r.length)]; - [self->queryParameters removeAllObjects]; - [self _parseQueryString:qs]; - } + req = [[self context] request]; + uri = [req uri]; + r = [uri rangeOfString:@"?"]; + if (r.length > 0) { + NSString *qs; + + qs = [uri substringFromIndex:(r.location + r.length)]; + [self->queryParameters removeAllObjects]; + [self _parseQueryString:qs]; + } } - (void)_parseQueryString:(NSString *)_s { - NSEnumerator *e; - NSString *part; + NSEnumerator *e; + NSString *part; - e = [[_s componentsSeparatedByString:@"&"] objectEnumerator]; - while ((part = [e nextObject])) { - NSRange r; - NSString *key, *value; + e = [[_s componentsSeparatedByString:@"&"] objectEnumerator]; + while ((part = [e nextObject])) { + NSRange r; + NSString *key, *value; - r = [part rangeOfString:@"="]; - if (r.length == 0) { - /* missing value of query parameter */ - key = [part stringByUnescapingURL]; - value = @"1"; - } - else { - key = [[part substringToIndex:r.location] stringByUnescapingURL]; - value = [[part substringFromIndex:(r.location + r.length)] + r = [part rangeOfString:@"="]; + if (r.length == 0) { + /* missing value of query parameter */ + key = [part stringByUnescapingURL]; + value = @"1"; + } + else { + key = [[part substringToIndex:r.location] stringByUnescapingURL]; + value = [[part substringFromIndex:(r.location + r.length)] stringByUnescapingURL]; - } - [self->queryParameters setObject:value forKey:key]; } + [self->queryParameters setObject:value forKey:key]; + } } - (NSString *)queryParameterForKey:(NSString *)_key { - return [self->queryParameters objectForKey:_key]; + return [self->queryParameters objectForKey:_key]; } - (void)setQueryParameter:(NSString *)_param forKey:(NSString *)_key { - if(_key == nil) - return; + if(_key == nil) + return; - if(_param != nil) - [self->queryParameters setObject:_param forKey:_key]; - else - [self->queryParameters removeObjectForKey:_key]; + if(_param != nil) + [self->queryParameters setObject:_param forKey:_key]; + else + [self->queryParameters removeObjectForKey:_key]; } - (NSDictionary *)queryParameters { - return self->queryParameters; + return self->queryParameters; } - (NSString *)completeHrefForMethod:(NSString *)_method { - NSDictionary *qp; - NSString *qs; + NSDictionary *qp; + NSString *qs; - qp = [self queryParameters]; - if([qp count] == 0) - return _method; + qp = [self queryParameters]; + if([qp count] == 0) + return _method; - qs = [[self context] queryStringFromDictionary:qp]; - return [_method stringByAppendingFormat:@"?%@", qs]; + qs = [[self context] queryStringFromDictionary:qp]; + return [_method stringByAppendingFormat:@"?%@", qs]; } - (NSString *)ownMethodName { - NSString *uri; - NSRange r; + NSString *uri; + NSRange r; - uri = [[[self context] request] uri]; + uri = [[[self context] request] uri]; - /* first: cut off query parameters */ + /* first: cut off query parameters */ - r = [uri rangeOfString:@"?" options:NSBackwardsSearch]; - if (r.length > 0) - uri = [uri substringToIndex:r.location]; + r = [uri rangeOfString:@"?" options:NSBackwardsSearch]; + if (r.length > 0) + uri = [uri substringToIndex:r.location]; - /* next: strip trailing slash */ + /* next: strip trailing slash */ - if ([uri hasSuffix:@"/"]) uri = [uri substringToIndex:([uri length] - 1)]; - r = [uri rangeOfString:@"/" options:NSBackwardsSearch]; + if ([uri hasSuffix:@"/"]) uri = [uri substringToIndex:([uri length] - 1)]; + r = [uri rangeOfString:@"/" options:NSBackwardsSearch]; - /* then: cut of last path component */ + /* then: cut of last path component */ - if (r.length == 0) // no slash? are we at root? - return @"/"; + if (r.length == 0) // no slash? are we at root? + return @"/"; - return [uri substringFromIndex:(r.location + 1)]; + return [uri substringFromIndex:(r.location + 1)]; } /* date */ +- (NSTimeZone *)viewTimeZone { + // Note: also in the folder, should be based on a cookie? + return MET; +} + - (NSCalendarDate *)selectedDate { - NSString *s; - - s = [self queryParameterForKey:@"day"]; - if(s) { - return [self dateForDateString:s]; - } - return [NSCalendarDate date]; + NSString *s; + NSCalendarDate *cdate; + + s = [self queryParameterForKey:@"day"]; + cdate = ([s length] > 0) + ? [self dateForDateString:s] + : [NSCalendarDate date]; + [cdate setTimeZone:[self viewTimeZone]]; + return cdate; } - (NSString *)dateStringForDate:(NSCalendarDate *)_date { - return [_date descriptionWithCalendarFormat:@"%Y%m%d"]; + [_date setTimeZone:[self viewTimeZone]]; + return [_date descriptionWithCalendarFormat:@"%Y%m%d"]; } - (NSCalendarDate *)dateForDateString:(NSString *)_dateString { - return [NSCalendarDate dateWithString:_dateString calendarFormat:@"%Y%m%d"]; + NSTimeZone *tz; + + tz = [self viewTimeZone]; + /* Note: we should give a time, best is noon to avoid edge conditions */ + _dateString = [_dateString stringByAppendingFormat:@"12:00:00 %@", + [tz abbreviation]]; + return [NSCalendarDate dateWithString:_dateString + calendarFormat:@"%Y%m%d %H:%M:%S %Z"]; } -@end +@end /* UIxComponent */ diff --git a/SOGo/UI/Scheduler/ChangeLog b/SOGo/UI/Scheduler/ChangeLog index a29b19b7..cc48c7ce 100644 --- a/SOGo/UI/Scheduler/ChangeLog +++ b/SOGo/UI/Scheduler/ChangeLog @@ -1,3 +1,7 @@ +2004-07-02 Helge Hess + + * UIxAppointmentView.m: fixup timezone of start/enddate + 2004-06-30 Helge Hess * UIxCalWeekOverview.wox, UIxCalMonthOverview.wox: some minor tweaks diff --git a/SOGo/UI/Scheduler/GNUmakefile b/SOGo/UI/Scheduler/GNUmakefile index a354a777..09d45692 100644 --- a/SOGo/UI/Scheduler/GNUmakefile +++ b/SOGo/UI/Scheduler/GNUmakefile @@ -47,7 +47,7 @@ SchedulerUI_RESOURCE_FILES += \ images/icon_apt_list_inactive.gif \ ADDITIONAL_INCLUDE_DIRS += \ - -I.. + -I.. -I../.. -I../../.. # make diff --git a/SOGo/UI/Scheduler/UIxAppointmentEditor.m b/SOGo/UI/Scheduler/UIxAppointmentEditor.m index 0a2bf309..2e6ed61d 100644 --- a/SOGo/UI/Scheduler/UIxAppointmentEditor.m +++ b/SOGo/UI/Scheduler/UIxAppointmentEditor.m @@ -92,37 +92,49 @@ } - (BOOL)isNewAppointment { - return ! [[self clientObject] isAppointment]; + /* that doesn't work! */ + return ![[self clientObject] isAppointment]; } - (NSString *)iCalString { - if([self isNewAppointment]) { - return [self iCalStringTemplate]; - } - else { - return [[self clientObject] valueForKey:@"iCalString"]; - } + // TODO: improve check for new appointment + NSString *ical; + + ical = [[self clientObject] valueForKey:@"iCalString"]; + if ([ical length] == 0) /* a new appointment */ + ical = [self iCalStringTemplate]; + + return ical; } - (NSString *)iCalStringTemplate { - static NSString *iCalStringTemplate = \ - @"BEGIN:VCALENDAR\nMETHOD:REQUEST\nPRODID:OpenGroupware.org SOGo 0.9\n" \ - @"VERSION:2.0\nBEGIN:VEVENT\nCLASS:PRIVATE\nSTATUS:CONFIRMED\n" \ - @"DTSTART:%@\nDTEND:%@\n" \ - @"TRANSP:OPAQUE\n" \ - @"END:VEVENT\nEND:VCALENDAR"; - NSCalendarDate *startDate, *endDate; - NSString *template; - - startDate = [self selectedDate]; - endDate = [startDate dateByAddingYears:0 months:0 days:0 + static NSString *iCalStringTemplate = \ + @"BEGIN:VCALENDAR\nMETHOD:REQUEST\nPRODID:OpenGroupware.org SOGo 0.9\n" + @"VERSION:2.0\n" + @"BEGIN:VEVENT\n" + @"UID:%@\n" + @"CLASS:PRIVATE\n" + @"STATUS:CONFIRMED\n" + @"DTSTAMP:%@\n" + @"DTSTART:%@\n" + @"DTEND:%@\n" + @"TRANSP:OPAQUE\n" + @"SEQUENCE:1\n" + @"END:VEVENT\n" + @"END:VCALENDAR"; + NSCalendarDate *startDate, *endDate; + NSString *template; + + startDate = [self selectedDate]; + endDate = [startDate dateByAddingYears:0 months:0 days:0 hours:1 minutes:0 seconds:0]; - - template = [NSString stringWithFormat:iCalStringTemplate, - [startDate icalString], - [endDate icalString]]; - - return template; + + template = [NSString stringWithFormat:iCalStringTemplate, + [[self clientObject] nameInContainer], + [[NSCalendarDate date] icalString], + [startDate icalString], + [endDate icalString]]; + return template; } @@ -130,34 +142,36 @@ - (SOGoAppointment *)appointment { - if(self->appointment == nil) { - self->appointment = [[SOGoAppointment alloc] - initWithICalString:[self iCalString]]; - } - return self->appointment; + if(self->appointment == nil) { + self->appointment = [[SOGoAppointment alloc] + initWithICalString:[self iCalString]]; + } + return self->appointment; } - (id)participants { - if(self->participants == nil) { - NSArray *attendees; - NSMutableArray *emailAddresses; - unsigned i, count; - - attendees = [self->appointment attendees]; - count = [attendees count]; - emailAddresses = [[NSMutableArray alloc] initWithCapacity:count]; - for(i = 0; i < count; i++) { - NSString *email; - - email = [[attendees objectAtIndex:i] rfc822Email]; - if(email) - [emailAddresses addObject:email]; - } - self->participants = [[emailAddresses componentsJoinedByString:@"\n"] - retain]; - [emailAddresses release]; - } + NSArray *attendees; + NSMutableArray *emailAddresses; + unsigned i, count; + + if (self->participants) return self->participants; + + attendees = [self->appointment attendees]; + count = [attendees count]; + emailAddresses = [[NSMutableArray alloc] initWithCapacity:count]; + for (i = 0; i < count; i++) { + NSString *email; + + email = [[attendees objectAtIndex:i] rfc822Email]; + if (email) + [emailAddresses addObject:email]; + } + + self->participants = + [[emailAddresses componentsJoinedByString:@"\n"] copy]; + [emailAddresses release]; + return self->participants; } @@ -201,31 +215,40 @@ - (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! + */ WORequest *req; WOResponse *r; NSString *uri, *uriFormat, *objectId, *nextMethod; - /* - clientObject *is* SOGoAppointmentFolder, so this should be an instance - method? - */ objectId = [NSClassFromString(@"SOGoAppointmentFolder") globallyUniqueObjectId]; nextMethod = [NSString stringWithFormat:@"%@/edit", objectId]; uriFormat = [self uriAsFormat]; - uri = [NSString stringWithFormat:uriFormat, nextMethod]; - + uri = [[NSString alloc] initWithFormat:uriFormat, nextMethod]; + req = [[self context] request]; r = [WOResponse responseWithRequest:req]; [r setStatus:302 /* moved */]; [r setHeader:uri forKey:@"location"]; + [uri release]; uri = nil; return r; } /* save */ +- (NSCalendarDate *)_dateFromString:(NSString *)_str { + _str = [_str stringByAppendingString:@" GMT"]; + return [NSCalendarDate dateWithString:_str + calendarFormat:@"%Y-%m-%d %H:%M %Z"]; +} - (id)saveAction { SOGoAppointment *apt; @@ -240,16 +263,23 @@ req = [[self context] request]; /* get iCalString from hidden input */ + iCalString = [req formValueForKey:@"ical"]; + if ([iCalString length] == 0) { + // TODO: improve user experience ... (eg error panel like Zope) + return [NSException exceptionWithHTTPStatus:400 /* bad request */ + reason:@"missing iCalendar form data in request"]; + } + apt = [[SOGoAppointment alloc] initWithICalString:iCalString]; - + /* merge in form values */ - sd = [NSCalendarDate dateWithString:[req formValueForKey:@"startDate"] - calendarFormat:@"%Y-%m-%d %H:%M"]; + + sd = [self _dateFromString:[req formValueForKey:@"startDate"]]; + ed = [self _dateFromString:[req formValueForKey:@"endDate"]]; [apt setStartDate:sd]; - ed = [NSCalendarDate dateWithString:[req formValueForKey:@"endDate"] - calendarFormat:@"%Y-%m-%d %H:%M"]; [apt setEndDate:ed]; + summary = [req formValueForKey:@"summary"]; [apt setSummary:summary]; location = [req formValueForKey:@"location"]; diff --git a/SOGo/UI/Scheduler/UIxAppointmentEditor.wox b/SOGo/UI/Scheduler/UIxAppointmentEditor.wox index ce2381aa..0aaaf19e 100644 --- a/SOGo/UI/Scheduler/UIxAppointmentEditor.wox +++ b/SOGo/UI/Scheduler/UIxAppointmentEditor.wox @@ -25,10 +25,12 @@ - +
@@ -37,7 +39,10 @@ @@ -47,7 +52,10 @@ diff --git a/SOGo/UI/Scheduler/UIxAppointmentView.h b/SOGo/UI/Scheduler/UIxAppointmentView.h index 22dce898..03b1ce3e 100644 --- a/SOGo/UI/Scheduler/UIxAppointmentView.h +++ b/SOGo/UI/Scheduler/UIxAppointmentView.h @@ -7,9 +7,9 @@ @interface UIxAppointmentView : UIxComponent { - NSString *tabSelection; - id appointment; - id attendee; + NSString *tabSelection; + id appointment; + id attendee; } - (id)appointment; @@ -18,8 +18,8 @@ - (NSString *)participantsTabLink; - (NSString *)completeHrefForMethod:(NSString *)_method - withParameter:(NSString *)_param - forKey:(NSString *)_key; + withParameter:(NSString *)_param + forKey:(NSString *)_key; @end diff --git a/SOGo/UI/Scheduler/UIxAppointmentView.m b/SOGo/UI/Scheduler/UIxAppointmentView.m index 62fd16a2..241fef8a 100644 --- a/SOGo/UI/Scheduler/UIxAppointmentView.m +++ b/SOGo/UI/Scheduler/UIxAppointmentView.m @@ -8,7 +8,7 @@ - (void)dealloc { [self->appointment release]; - [self->attendee release]; + [self->attendee release]; [super dealloc]; } @@ -30,7 +30,6 @@ return self->attendee; } - - (NSString *)attendeeEmail { NSString *s; @@ -48,6 +47,12 @@ return self->appointment; iCalString = [[self clientObject] valueForKey:@"iCalString"]; + if ([iCalString length] == 0) { + [self logWithFormat:@"ERROR(%s): missing iCal string!", + __PRETTY_FUNCTION__]; + return nil; + } + self->appointment = [[SOGoAppointment alloc] initWithICalString:iCalString]; return self->appointment; } @@ -56,15 +61,15 @@ NSCalendarDate *date; date = [[self appointment] startDate]; - /* TODO: convert this into display timeZone! */ + [date setTimeZone:[self viewTimeZone]]; return [date descriptionWithCalendarFormat:@"%A, %Y-%m-%d %H:%M %Z"]; } - (NSString *)formattedAptEndTime { NSCalendarDate *date; - + date = [[self appointment] endDate]; - /* TODO: convert this into display timeZone! */ + [date setTimeZone:[self viewTimeZone]]; return [date descriptionWithCalendarFormat:@"%A, %Y-%m-%d %H:%M %Z"]; } @@ -90,8 +95,8 @@ } - (NSString *)completeHrefForMethod:(NSString *)_method - withParameter:(NSString *)_param - forKey:(NSString *)_key + withParameter:(NSString *)_param + forKey:(NSString *)_key { NSString *href; diff --git a/SOGo/UI/Scheduler/UIxCalView.m b/SOGo/UI/Scheduler/UIxCalView.m index fe0b42a5..ec9baee4 100644 --- a/SOGo/UI/Scheduler/UIxCalView.m +++ b/SOGo/UI/Scheduler/UIxCalView.m @@ -3,6 +3,8 @@ #include "UIxCalView.h" #include "common.h" #include "UIxAppointmentFormatter.h" +#include +#include "SoObjects/Appointments/SOGoAppointmentFolder.h" @implementation UIxCalView @@ -46,6 +48,7 @@ NSString *ms; startDate = [[self appointment] valueForKey:@"startDate"]; + [startDate setTimeZone:[self viewTimeZone]]; ms = [NSString stringWithFormat:@"%02i:%02i %@", [startDate hourOfDay], [startDate minuteOfHour], @@ -57,29 +60,29 @@ NSString *title; title = [self->appointment valueForKey:@"title"]; - if([title length] > 12) { - title = [NSString stringWithFormat:@"%@...", - [title substringToIndex:11]]; - } + if ([title length] > 12) + title = [[title substringToIndex:11] stringByAppendingString:@"..."]; + return title; } - (NSCalendarDate *)referenceDateForFormatter { - return [self selectedDate]; + return [self selectedDate]; } /* current day related */ - (void)setCurrentDay:(NSCalendarDate *)_day { - ASSIGN(self->currentDay, _day); + ASSIGN(self->currentDay, _day); } - (NSCalendarDate *)currentDay { - return self->currentDay; + return self->currentDay; } - (NSString *)currentDayName { - // TODO: this is slow, use locale dictionary to speed this up - return [self->currentDay descriptionWithCalendarFormat:@"%A"]; + // TODO: this is slow, use locale dictionary to speed this up + [self->currentDay setTimeZone:[self viewTimeZone]]; + return [self->currentDay descriptionWithCalendarFormat:@"%A"]; } - (BOOL)hasDayInfo { @@ -161,13 +164,93 @@ return [[self startDate] tomorrow]; } +- (NSArray *)_fetchCoreInfosForUIDs:(NSArray *)_uids + uniqueWithSet:(NSMutableSet *)_uniquer +{ + NSMutableArray *ma; + unsigned i, count; + + count = [_uids count]; + ma = [NSMutableArray arrayWithCapacity:count * 10]; + + for (i = 0; i < count; i++) { + OCSFolder *folder; + NSString *path; + NSString *uid; + NSArray *res; + + uid = [_uids objectAtIndex:i]; + if ([uid length] == 0) continue; + + path = [[@"/Users/" stringByAppendingString:uid] + stringByAppendingString:@"/Calendar"]; + + if ((folder = [[self clientObject] ocsFolderForPath:path]) == nil) { + [self logWithFormat:@"ERROR: did not find user: %@", uid]; + continue; + } + + res = [[self clientObject] fetchCoreInfosFromFolder:folder + from:[self startDate] to:[self endDate]]; + if (res == nil) { + [self logWithFormat:@"ERROR: fetch failed for user: %@", uid]; + continue; + } + + /* perform uniquing */ + { + int j, rcount; + + for (j = 0, rcount = [res count]; j < rcount; j++) { + NSDictionary *record; + + record = [res objectAtIndex:j]; + + if ([_uniquer containsObject:[record valueForKey:@"uid"]]) + continue; + + [ma addObject:record]; + [_uniquer addObject:[record valueForKey:@"uid"]]; + } + } + } + return ma; +} + - (NSArray *)fetchCoreInfos { + id aptFolder; + NSArray *more; + id uids; + if (self->appointments) return self->appointments; - + + aptFolder = [self clientObject]; self->appointments = - [[[self clientObject] fetchCoreInfosFrom:[self startDate] - to:[self endDate]] retain]; + [[aptFolder fetchCoreInfosFrom:[self startDate] to:[self endDate]] retain]; + + uids = [[[[self context] request] formValueForKey:@"uids"] stringValue]; + uids = [uids length] > 0 ? [uids componentsSeparatedByString:@","] : nil; + if ([uids count] > 0) { + NSMutableSet *availUIDs; + id tmp; + + /* make appointments unique, prefer the own "versions" */ + tmp = [self->appointments valueForKey:@"uid"]; + availUIDs = [[NSMutableSet alloc] initWithArray:tmp]; + + more = [self _fetchCoreInfosForUIDs:uids uniqueWithSet:availUIDs]; + if (more > 0) { + NSArray *tmp; + + tmp = self->appointments; + self->appointments = [[tmp arrayByAddingObjectsFromArray:more] retain]; + [tmp release]; + } + + [availUIDs release]; + } + return self->appointments; } @@ -175,14 +258,14 @@ - (NSDictionary *)todayQueryParameters { - NSCalendarDate *date; + NSCalendarDate *date; - date = [NSCalendarDate date]; /* today */ - return [self queryParametersBySettingSelectedDate:date]; + date = [NSCalendarDate date]; /* today */ + return [self queryParametersBySettingSelectedDate:date]; } - (NSDictionary *)currentDayQueryParameters { - return [self queryParametersBySettingSelectedDate:self->currentDay]; + return [self queryParametersBySettingSelectedDate:self->currentDay]; } - (NSDictionary *)queryParametersBySettingSelectedDate:(NSCalendarDate *)_date { @@ -194,13 +277,12 @@ } - (void)setSelectedDateQueryParameter:(NSCalendarDate *)_newDate - inDictionary:(NSMutableDictionary *)_qp; + inDictionary:(NSMutableDictionary *)_qp; { - if(_newDate != nil) - [_qp setObject:[self dateStringForDate:_newDate] - forKey:@"day"]; - else - [_qp removeObjectForKey:@"day"]; + if(_newDate != nil) + [_qp setObject:[self dateStringForDate:_newDate] forKey:@"day"]; + else + [_qp removeObjectForKey:@"day"]; } @end /* UIxCalView */ diff --git a/SOGo/UI/Scheduler/UIxCalWeekOverview.wox b/SOGo/UI/Scheduler/UIxCalWeekOverview.wox index 53d61a90..e3cffd50 100644 --- a/SOGo/UI/Scheduler/UIxCalWeekOverview.wox +++ b/SOGo/UI/Scheduler/UIxCalWeekOverview.wox @@ -136,7 +136,7 @@ + >
@@ -144,7 +144,9 @@
- +
- Appointment on + Appointment on +
- +
- +
-- 2.39.5