]> err.no Git - scalable-opengroupware.org/blob - UI/Scheduler/UIxCalListingActions.m
git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1236 d1b88da0-ebda-0310...
[scalable-opengroupware.org] / UI / Scheduler / UIxCalListingActions.m
1 /* UIxCalListingActions.m - this file is part of SOGo
2  *
3  * Copyright (C) 2006 Inverse groupe conseil
4  *
5  * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
6  *
7  * This file is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2, or (at your option)
10  * any later version.
11  *
12  * This file is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; see the file COPYING.  If not, write to
19  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #import <Foundation/NSArray.h>
24 #import <Foundation/NSDictionary.h>
25 #import <Foundation/NSEnumerator.h>
26 #import <Foundation/NSNull.h>
27 #import <Foundation/NSString.h>
28 #import <Foundation/NSTimeZone.h>
29 #import <Foundation/NSValue.h>
30
31 #import <NGObjWeb/WOContext.h>
32 #import <NGObjWeb/WOContext+SoObjects.h>
33 #import <NGObjWeb/WORequest.h>
34 #import <NGObjWeb/WOResponse.h>
35 #import <NGExtensions/NSCalendarDate+misc.h>
36
37 #import <SoObjects/SOGo/SOGoUser.h>
38 #import <SoObjects/SOGo/SOGoDateFormatter.h>
39 #import <SoObjects/SOGo/NSCalendarDate+SOGo.h>
40 #import <SoObjects/SOGo/NSArray+Utilities.h>
41 #import <SoObjects/SOGo/NSObject+Utilities.h>
42 #import <SoObjects/Appointments/SOGoAppointmentFolder.h>
43 #import <SoObjects/Appointments/SOGoAppointmentFolders.h>
44
45 #import <UI/Common/WODirectAction+SOGo.h>
46
47 #import "NSArray+Scheduler.h"
48
49 #import "UIxCalListingActions.h"
50
51 @implementation UIxCalListingActions
52
53 - (id) initWithRequest: (WORequest *) newRequest
54 {
55   SOGoUser *user;
56
57   if ((self = [super initWithRequest: newRequest]))
58     {
59       componentsData = [NSMutableDictionary new];
60       startDate = nil;
61       endDate = nil;
62       ASSIGN (request, newRequest);
63       user = [[self context] activeUser];
64       dateFormatter = [user dateFormatterInContext: context];
65       ASSIGN (userTimeZone, [user timeZone]);
66     }
67
68   return self;
69 }
70
71 - (void) dealloc
72 {
73   [dateFormatter release];
74   [request release];
75   [componentsData release];
76   [startDate release];
77   [endDate release];
78   [userTimeZone release];
79   [super dealloc];
80 }
81
82 - (void) _setupDatesWithPopup: (NSString *) popupValue
83                     andUserTZ: (NSTimeZone *) userTZ
84 {
85   NSCalendarDate *newDate;
86   NSString *param;
87
88   if ([popupValue isEqualToString: @"view_today"])
89     {
90       newDate = [NSCalendarDate calendarDate];
91       [newDate setTimeZone: userTZ];
92       startDate = [newDate beginOfDay];
93       endDate = [newDate endOfDay];
94     }
95   else if ([popupValue isEqualToString: @"view_all"])
96     {
97       startDate = nil;
98       endDate = nil;
99     }
100   else if ([popupValue isEqualToString: @"view_next7"])
101     {
102       newDate = [NSCalendarDate calendarDate];
103       [newDate setTimeZone: userTZ];
104       startDate = [newDate beginOfDay];
105       endDate = [[startDate dateByAddingYears: 0 months: 0 days: 6] endOfDay];
106     }
107   else if ([popupValue isEqualToString: @"view_next14"])
108     {
109       newDate = [NSCalendarDate calendarDate];
110       [newDate setTimeZone: userTZ];
111       startDate = [newDate beginOfDay];
112       endDate = [[startDate dateByAddingYears: 0 months: 0 days: 13] endOfDay];
113     }
114   else if ([popupValue isEqualToString: @"view_next31"])
115     {
116       newDate = [NSCalendarDate calendarDate];
117       [newDate setTimeZone: userTZ];
118       startDate = [newDate beginOfDay];
119       endDate = [[startDate dateByAddingYears: 0 months: 0 days: 30] endOfDay];
120     }
121   else if ([popupValue isEqualToString: @"view_thismonth"])
122     {
123       newDate = [NSCalendarDate calendarDate];
124       [newDate setTimeZone: userTZ];
125       startDate = [[newDate firstDayOfMonth] beginOfDay];
126       endDate = [[newDate lastDayOfMonth] endOfDay];
127     }
128   else if ([popupValue isEqualToString: @"view_future"])
129     {
130       newDate = [NSCalendarDate calendarDate];
131       [newDate setTimeZone: userTZ];
132       startDate = [newDate beginOfDay];
133       endDate = [NSCalendarDate distantFuture];
134     }
135   else if ([popupValue isEqualToString: @"view_selectedday"])
136     {
137       param = [request formValueForKey: @"day"];
138       if ([param length] > 0)
139         startDate = [[NSCalendarDate dateFromShortDateString: param
140                                      andShortTimeString: nil
141                                      inTimeZone: userTZ] beginOfDay];
142       else
143         {
144           newDate = [NSCalendarDate calendarDate];
145           [newDate setTimeZone: userTZ];
146           startDate = [newDate beginOfDay];
147         }
148       endDate = [startDate endOfDay];
149     }
150 }
151
152 - (void) _setupContext
153 {
154   SOGoUser *user;
155   NSTimeZone *userTZ;
156   NSString *param;
157
158   user = [context activeUser];
159   userLogin = [user login];
160   userTZ = [user timeZone];
161
162   param = [request formValueForKey: @"filterpopup"];
163   if ([param length] > 0)
164     [self _setupDatesWithPopup: param andUserTZ: userTZ];
165   else
166     {
167       param = [request formValueForKey: @"sd"];
168       if ([param length] > 0)
169         startDate = [[NSCalendarDate dateFromShortDateString: param
170                                      andShortTimeString: nil
171                                      inTimeZone: userTZ] beginOfDay];
172       else
173         startDate = nil;
174       
175       param = [request formValueForKey: @"ed"];
176       if ([param length] > 0)
177         endDate = [[NSCalendarDate dateFromShortDateString: param
178                                    andShortTimeString: nil
179                                    inTimeZone: userTZ] endOfDay];
180       else
181         endDate = nil;
182     }
183 }
184
185 - (void) _updatePrivacyInComponent: (NSMutableDictionary *) component
186                         fromFolder: (SOGoAppointmentFolder *) folder
187 {
188   int privacyFlag;
189   NSString *roleString;
190
191   privacyFlag = [[component objectForKey: @"classification"] intValue];
192   roleString = [folder roleForComponentsWithAccessClass: privacyFlag
193                        forUser: userLogin];
194   if ([roleString isEqualToString: @"ComponentDAndTViewer"])
195     {
196       [component setObject: @"" forKey: @"c_title"];
197       [component setObject: @"" forKey: @"c_location"];
198     }
199 }
200
201 - (SOGoAppointmentFolder *) _aptFolder: (NSString *) folder
202                       withClientObject: (SOGoAppointmentFolder *) clientObject
203 {
204   SOGoAppointmentFolder *aptFolder;
205   NSArray *folderParts;
206
207   if ([folder isEqualToString: @"/"])
208     aptFolder = clientObject;
209   else
210     {
211       folderParts = [folder componentsSeparatedByString: @":"];
212       aptFolder
213         = [clientObject lookupCalendarFolderForUID:
214                           [folderParts objectAtIndex: 0]];
215     }
216
217   return aptFolder;
218 }
219
220 - (NSArray *) _fetchFields: (NSArray *) fields
221         forComponentOfType: (NSString *) component
222 {
223   NSEnumerator *folders, *currentInfos;
224   SOGoAppointmentFolder *currentFolder;
225   NSMutableDictionary *newInfo;
226   NSMutableArray *infos;
227   NSNull *marker;
228   SOGoAppointmentFolders *clientObject;
229
230   marker = [NSNull null];
231
232    clientObject = [self clientObject];
233
234   folders = [[clientObject subFolders] objectEnumerator];
235   currentFolder = [folders nextObject];
236
237   infos = [NSMutableArray array];
238   while (currentFolder)
239     {
240       if ([currentFolder isActive])
241         {
242           currentInfos = [[currentFolder fetchCoreInfosFrom: startDate
243                                          to: endDate
244                                          component: component] objectEnumerator];
245
246           while ((newInfo = [currentInfos nextObject]))
247             {
248               [self _updatePrivacyInComponent: newInfo
249                     fromFolder: currentFolder];
250               [newInfo setObject: [currentFolder nameInContainer]
251                        forKey: @"c_folder"];
252               
253               [infos addObject: [newInfo objectsForKeys: fields
254                                          notFoundMarker: marker]];
255             }
256         }
257       currentFolder = [folders nextObject];
258     }
259
260   return infos;
261 }
262
263 - (WOResponse *) _responseWithData: (NSArray *) data
264 {
265   WOResponse *response;
266
267   response = [self responseWithStatus: 200];
268   [response setHeader: @"text/plain; charset=utf-8"
269             forKey: @"content-type"];
270   [response appendContentString: [data jsonRepresentation]];
271
272   return response;
273 }
274
275 - (NSString *) _formattedDateForSeconds: (unsigned int) seconds
276                               forAllDay: (BOOL) forAllDay
277 {
278   NSCalendarDate *date;
279   NSString *formattedDate;
280
281   date = [NSCalendarDate dateWithTimeIntervalSince1970: seconds];
282   [date setTimeZone: userTimeZone];
283   if (forAllDay)
284     formattedDate = [dateFormatter formattedDate: date];
285   else
286     formattedDate = [dateFormatter formattedDateAndTime: date];
287
288   return formattedDate;    
289 }
290
291 - (NSString *) _adjustedDateForSeconds: (unsigned int) seconds
292                              forAllDay: (BOOL) forAllDay
293 {
294   NSCalendarDate *date;
295   unsigned int newSeconds, offset;
296
297   date = [NSCalendarDate dateWithTimeIntervalSince1970: seconds];
298   [date setTimeZone: userTimeZone];
299
300   offset = [userTimeZone secondsFromGMTForDate: date];
301   if (forAllDay)
302     newSeconds = seconds + [userTimeZone secondsFromGMT] - offset;
303   else
304     newSeconds = seconds + offset;
305
306   return [NSString stringWithFormat: @"%u", newSeconds];
307 }
308
309 - (WOResponse *) eventsListAction
310 {
311   NSArray *fields, *oldEvent;
312   NSEnumerator *events;
313   NSMutableArray *newEvents, *newEvent;
314   unsigned int interval;
315   BOOL isAllDay;
316
317   [self _setupContext];
318
319   newEvents = [NSMutableArray array];
320   fields = [NSArray arrayWithObjects: @"c_name", @"c_folder", @"c_status",
321                     @"c_title", @"c_startdate", @"c_enddate", @"c_location",
322                     @"c_isallday", nil];
323   events = [[self _fetchFields: fields
324                   forComponentOfType: @"vevent"] objectEnumerator];
325   oldEvent = [events nextObject];
326   while (oldEvent)
327     {
328       newEvent = [NSMutableArray arrayWithArray: oldEvent];
329       isAllDay = [[oldEvent objectAtIndex: 7] boolValue];
330       interval = [[oldEvent objectAtIndex: 4] intValue];
331       [newEvent replaceObjectAtIndex: 4
332                 withObject: [self _adjustedDateForSeconds: interval
333                                   forAllDay: isAllDay]];
334       [newEvent addObject: [self _formattedDateForSeconds: interval
335                                  forAllDay: isAllDay]];
336       interval = [[oldEvent objectAtIndex: 5] intValue];
337       [newEvent replaceObjectAtIndex: 5
338                 withObject: [self _adjustedDateForSeconds: interval
339                                   forAllDay: isAllDay]];
340       [newEvent addObject: [self _formattedDateForSeconds: interval
341                                  forAllDay: isAllDay]];
342       [newEvents addObject: newEvent];
343
344       oldEvent = [events nextObject];
345     }
346   [newEvents sortUsingSelector: @selector (compareEventsAscending:)];
347
348   return [self _responseWithData: newEvents];
349 }
350
351 - (NSString *) _getStatusClassForStatusCode: (int) statusCode
352                             andEndDateStamp: (unsigned int) endDateStamp
353 {
354   NSCalendarDate *taskDate, *now;
355   NSString *statusClass;
356
357   if (statusCode == 1)
358     statusClass = @"completed";
359   else
360     {
361       if (endDateStamp)
362         {
363           now = [NSCalendarDate calendarDate];
364           taskDate
365             = [NSCalendarDate dateWithTimeIntervalSince1970: endDateStamp];
366           if ([taskDate earlierDate: now] == taskDate)
367             statusClass = @"overdue";
368           else
369             {
370               if ([taskDate isToday])
371                 statusClass = @"duetoday";
372               else
373                 statusClass = @"duelater";
374             }
375         }
376       else
377         statusClass = @"duelater";
378     }
379
380   return statusClass;
381 }
382
383 - (WOResponse *) tasksListAction
384 {
385   NSEnumerator *tasks;
386   NSMutableArray *filteredTasks, *filteredTask;
387   BOOL showCompleted;
388   NSArray *fields, *task;
389   int statusCode;
390   unsigned int endDateStamp;
391   NSString *statusFlag;
392
393   filteredTasks = [NSMutableArray array];
394
395   [self _setupContext];
396
397   fields = [NSArray arrayWithObjects: @"c_name", @"c_folder", @"c_status",
398                     @"c_title", @"c_enddate", nil];
399
400   tasks = [[self _fetchFields: fields
401                  forComponentOfType: @"vtodo"] objectEnumerator];
402   showCompleted = [[request formValueForKey: @"show-completed"] intValue];
403
404   task = [tasks nextObject];
405   while (task)
406     {
407       statusCode = [[task objectAtIndex: 2] intValue];
408       if (statusCode != 1 || showCompleted)
409         {
410           filteredTask = [NSMutableArray arrayWithArray: task];
411           endDateStamp = [[task objectAtIndex: 4] intValue];
412           statusFlag = [self _getStatusClassForStatusCode: statusCode
413                              andEndDateStamp: endDateStamp];
414           [filteredTask addObject: statusFlag];
415           [filteredTasks addObject: filteredTask];
416         }
417       task = [tasks nextObject];
418     }
419   [filteredTasks sortUsingSelector: @selector (compareTasksAscending:)];
420
421   return [self _responseWithData: filteredTasks];
422 }
423
424 // - (BOOL) shouldDisplayCurrentTask
425 // {
426 //   if (!knowsToShow)
427 //     {
428 //       showCompleted
429 //         = [[self queryParameterForKey: @"show-completed"] intValue];
430 //       knowsToShow = YES;
431 //     }
432
433 //   return ([[currentTask objectForKey: @"status"] intValue] != 1
434 //         || showCompleted);
435 // }
436
437 // - (BOOL) shouldShowCompletedTasks
438 // {
439 //   if (!knowsToShow)
440 //     {
441 //       showCompleted
442 //         = [[self queryParameterForKey: @"show-completed"] intValue];
443 //       knowsToShow = YES;
444 //     }
445
446 //   return showCompleted;
447 // }
448
449 @end