]> err.no Git - scalable-opengroupware.org/blob - UI/Scheduler/UIxCalListingActions.m
git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1087 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
29 #import <NGObjWeb/WOContext.h>
30 #import <NGObjWeb/WOContext+SoObjects.h>
31 #import <NGObjWeb/WORequest.h>
32 #import <NGObjWeb/WOResponse.h>
33 #import <NGExtensions/NSCalendarDate+misc.h>
34
35 #import <SoObjects/SOGo/SOGoUser.h>
36 #import <SoObjects/SOGo/SOGoDateFormatter.h>
37 #import <SoObjects/SOGo/NSCalendarDate+SOGo.h>
38 #import <SoObjects/SOGo/NSArray+Utilities.h>
39 #import <SoObjects/SOGo/NSObject+Utilities.h>
40 #import <SoObjects/Appointments/SOGoAppointmentFolder.h>
41
42 #import "NSArray+Scheduler.h"
43
44 #import "UIxCalListingActions.h"
45
46 @implementation UIxCalListingActions
47
48 - (id) initWithRequest: (WORequest *) newRequest
49 {
50   SOGoUser *user;
51
52   if ((self = [super initWithRequest: newRequest]))
53     {
54       componentsData = [NSMutableDictionary new];
55       startDate = nil;
56       endDate = nil;
57       ASSIGN (request, newRequest);
58       user = [[self context] activeUser];
59       dateFormatter = [user dateFormatterInContext: context];
60       ASSIGN (userTimeZone, [user timeZone]);
61     }
62
63   return self;
64 }
65
66 - (void) dealloc
67 {
68   [dateFormatter release];
69   [request release];
70   [componentsData release];
71   [startDate release];
72   [endDate release];
73   [userTimeZone release];
74   [super dealloc];
75 }
76
77 - (void) _setupDatesWithPopup: (NSString *) popupValue
78                     andUserTZ: (NSTimeZone *) userTZ
79 {
80   NSCalendarDate *newDate;
81   NSString *param;
82
83   if ([popupValue isEqualToString: @"view_today"])
84     {
85       newDate = [NSCalendarDate calendarDate];
86       [newDate setTimeZone: userTZ];
87       startDate = [newDate beginOfDay];
88       endDate = [newDate endOfDay];
89     }
90   else if ([popupValue isEqualToString: @"view_all"])
91     {
92       startDate = nil;
93       endDate = nil;
94     }
95   else if ([popupValue isEqualToString: @"view_next7"])
96     {
97       newDate = [NSCalendarDate calendarDate];
98       [newDate setTimeZone: userTZ];
99       startDate = [newDate beginOfDay];
100       endDate = [[startDate dateByAddingYears: 0 months: 0 days: 6] endOfDay];
101     }
102   else if ([popupValue isEqualToString: @"view_next14"])
103     {
104       newDate = [NSCalendarDate calendarDate];
105       [newDate setTimeZone: userTZ];
106       startDate = [newDate beginOfDay];
107       endDate = [[startDate dateByAddingYears: 0 months: 0 days: 13] endOfDay];
108     }
109   else if ([popupValue isEqualToString: @"view_next31"])
110     {
111       newDate = [NSCalendarDate calendarDate];
112       [newDate setTimeZone: userTZ];
113       startDate = [newDate beginOfDay];
114       endDate = [[startDate dateByAddingYears: 0 months: 0 days: 30] endOfDay];
115     }
116   else if ([popupValue isEqualToString: @"view_thismonth"])
117     {
118       newDate = [NSCalendarDate calendarDate];
119       [newDate setTimeZone: userTZ];
120       startDate = [[newDate firstDayOfMonth] beginOfDay];
121       endDate = [[newDate lastDayOfMonth] endOfDay];
122     }
123   else if ([popupValue isEqualToString: @"view_future"])
124     {
125       newDate = [NSCalendarDate calendarDate];
126       [newDate setTimeZone: userTZ];
127       startDate = [newDate beginOfDay];
128       endDate = [NSCalendarDate distantFuture];
129     }
130   else if ([popupValue isEqualToString: @"view_selectedday"])
131     {
132       param = [request formValueForKey: @"day"];
133       if ([param length] > 0)
134         startDate = [[NSCalendarDate dateFromShortDateString: param
135                                      andShortTimeString: nil
136                                      inTimeZone: userTZ] beginOfDay];
137       else
138         {
139           newDate = [NSCalendarDate calendarDate];
140           [newDate setTimeZone: userTZ];
141           startDate = [newDate beginOfDay];
142         }
143       endDate = [startDate endOfDay];
144     }
145 }
146
147 - (void) _setupContext
148 {
149   SOGoUser *user;
150   NSTimeZone *userTZ;
151   NSString *param;
152
153   user = [context activeUser];
154   userLogin = [user login];
155   userTZ = [user timeZone];
156
157   param = [request formValueForKey: @"filterpopup"];
158   if ([param length] > 0)
159     [self _setupDatesWithPopup: param andUserTZ: userTZ];
160   else
161     {
162       param = [request formValueForKey: @"sd"];
163       if ([param length] > 0)
164         startDate = [[NSCalendarDate dateFromShortDateString: param
165                                      andShortTimeString: nil
166                                      inTimeZone: userTZ] beginOfDay];
167       else
168         startDate = nil;
169       
170       param = [request formValueForKey: @"ed"];
171       if ([param length] > 0)
172         endDate = [[NSCalendarDate dateFromShortDateString: param
173                                    andShortTimeString: nil
174                                    inTimeZone: userTZ] endOfDay];
175       else
176         endDate = nil;
177     }
178 }
179
180 - (void) _updatePrivacyInComponent: (NSMutableDictionary *) component
181                         fromFolder: (SOGoAppointmentFolder *) folder
182 {
183   int privacyFlag;
184   NSString *roleString;
185
186   privacyFlag = [[component objectForKey: @"classification"] intValue];
187   roleString = [folder roleForComponentsWithAccessClass: privacyFlag
188                        forUser: userLogin];
189   if ([roleString isEqualToString: @"ComponentDAndTViewer"])
190     {
191       [component setObject: @"" forKey: @"title"];
192       [component setObject: @"" forKey: @"location"];
193     }
194 }
195
196 - (SOGoAppointmentFolder *) _aptFolder: (NSString *) folder
197                       withClientObject: (SOGoAppointmentFolder *) clientObject
198 {
199   SOGoAppointmentFolder *aptFolder;
200   NSArray *folderParts;
201
202   if ([folder isEqualToString: @"/"])
203     aptFolder = clientObject;
204   else
205     {
206       folderParts = [folder componentsSeparatedByString: @":"];
207       aptFolder
208         = [clientObject lookupCalendarFolderForUID:
209                           [folderParts objectAtIndex: 0]];
210     }
211
212   return aptFolder;
213 }
214
215 - (NSArray *) _activeCalendarFolders
216 {
217   NSMutableArray *activeFolders;
218   NSEnumerator *folders;
219   NSDictionary *currentFolderDict;
220   SOGoAppointmentFolder *currentFolder, *clientObject;
221
222   activeFolders = [NSMutableArray new];
223   [activeFolders autorelease];
224
225   clientObject = [self clientObject];
226
227   folders = [[clientObject calendarFolders] objectEnumerator];
228   currentFolderDict = [folders nextObject];
229   while (currentFolderDict)
230     {
231       if ([[currentFolderDict objectForKey: @"active"] boolValue])
232         {
233           currentFolder
234             = [self _aptFolder: [currentFolderDict objectForKey: @"folder"]
235                     withClientObject: clientObject];
236           [activeFolders addObject: currentFolder];
237         }
238
239       currentFolderDict = [folders nextObject];
240     }
241
242   return activeFolders;
243 }
244
245 - (NSArray *) _fetchFields: (NSArray *) fields
246         forComponentOfType: (NSString *) component
247 {
248   NSEnumerator *folders, *currentInfos;
249   SOGoAppointmentFolder *currentFolder;
250   NSMutableDictionary *infos, *currentInfo, *newInfo;
251   NSString *owner, *uid;
252   NSNull *marker;
253
254   marker = [NSNull null];
255
256   infos = [NSMutableDictionary dictionary];
257   folders = [[self _activeCalendarFolders] objectEnumerator];
258   currentFolder = [folders nextObject];
259   while (currentFolder)
260     {
261       owner = [currentFolder ownerInContext: context];
262       currentInfos = [[currentFolder fetchCoreInfosFrom: startDate
263                                      to: endDate
264                                      component: component] objectEnumerator];
265       newInfo = [currentInfos nextObject];
266       while (newInfo)
267         {
268           uid = [newInfo objectForKey: @"uid"];
269           currentInfo = [infos objectForKey: uid];
270           if (!currentInfo
271               || [owner isEqualToString: userLogin])
272             {
273               [self _updatePrivacyInComponent: newInfo
274                     fromFolder: currentFolder];
275               [newInfo setObject: owner forKey: @"owner"];
276               [infos setObject: [newInfo objectsForKeys: fields
277                                          notFoundMarker: marker]
278                      forKey: uid];
279             }
280           newInfo = [currentInfos nextObject];
281         }
282       currentFolder = [folders nextObject];
283     }
284
285   return [infos allValues];
286 }
287
288 - (WOResponse *) _responseWithData: (NSArray *) data
289 {
290   WOResponse *response;
291
292   response = [context response];
293   [response setHeader: @"text/plain; charset=utf-8"
294             forKey: @"content-type"];
295   [response setStatus: 200];
296   [response appendContentString: [data jsonRepresentation]];
297
298   return response;
299 }
300
301 - (NSString *) _formattedDateForSeconds: (unsigned int) seconds
302                               forAllDay: (BOOL) forAllDay
303 {
304   NSCalendarDate *date;
305   NSString *formattedDate;
306
307   date = [NSCalendarDate dateWithTimeIntervalSince1970: seconds];
308   [date setTimeZone: userTimeZone];
309   if (forAllDay)
310     formattedDate = [dateFormatter formattedDate: date];
311   else
312     formattedDate = [dateFormatter formattedDateAndTime: date];
313
314   return formattedDate;    
315 }
316
317 - (WOResponse *) eventsListAction
318 {
319   NSArray *fields, *oldEvent;
320   NSEnumerator *events;
321   NSMutableArray *newEvents, *newEvent;
322   unsigned int interval;
323   BOOL isAllDay;
324
325   [self _setupContext];
326
327   newEvents = [NSMutableArray array];
328   fields = [NSArray arrayWithObjects: @"c_name", @"owner", @"status",
329                     @"title", @"startdate", @"enddate", @"location",
330                     @"isallday", nil];
331   events = [[self _fetchFields: fields
332                   forComponentOfType: @"vevent"] objectEnumerator];
333   oldEvent = [events nextObject];
334   while (oldEvent)
335     {
336       newEvent = [NSMutableArray arrayWithArray: oldEvent];
337       isAllDay = [[oldEvent objectAtIndex: 7] boolValue];
338       interval = [[oldEvent objectAtIndex: 4] intValue];
339       [newEvent addObject: [self _formattedDateForSeconds: interval
340                                  forAllDay: isAllDay]];
341       interval = [[oldEvent objectAtIndex: 5] intValue];
342       [newEvent addObject: [self _formattedDateForSeconds: interval
343                                  forAllDay: isAllDay]];
344       [newEvents addObject: newEvent];
345
346       oldEvent = [events nextObject];
347     }
348   [newEvents sortUsingSelector: @selector (compareEventsAscending:)];
349
350   return [self _responseWithData: newEvents];
351 }
352
353 - (NSString *) _getStatusClassForStatusCode: (int) statusCode
354                             andEndDateStamp: (unsigned int) endDateStamp
355 {
356   NSCalendarDate *taskDate, *now;
357   NSString *statusClass;
358
359   if (statusCode == 1)
360     statusClass = @"completed";
361   else
362     {
363       if (endDateStamp)
364         {
365           now = [NSCalendarDate calendarDate];
366           taskDate
367             = [NSCalendarDate dateWithTimeIntervalSince1970: endDateStamp];
368           if ([taskDate earlierDate: now] == taskDate)
369             statusClass = @"overdue";
370           else
371             {
372               if ([taskDate isToday])
373                 statusClass = @"duetoday";
374               else
375                 statusClass = @"duelater";
376             }
377         }
378       else
379         statusClass = @"duelater";
380     }
381
382   return statusClass;
383 }
384
385 - (WOResponse *) tasksListAction
386 {
387   NSEnumerator *tasks;
388   NSMutableArray *filteredTasks, *filteredTask;
389   BOOL showCompleted;
390   NSArray *fields, *task;
391   int statusCode;
392   unsigned int endDateStamp;
393   NSString *statusFlag;
394
395   filteredTasks = [NSMutableArray array];
396
397   [self _setupContext];
398
399   fields = [NSArray arrayWithObjects: @"c_name", @"owner", @"status",
400                     @"title", @"enddate", nil];
401
402   tasks = [[self _fetchFields: fields
403                  forComponentOfType: @"vtodo"] objectEnumerator];
404   showCompleted = [[request formValueForKey: @"show-completed"] intValue];
405
406   task = [tasks nextObject];
407   while (task)
408     {
409       statusCode = [[task objectAtIndex: 2] intValue];
410       if (statusCode != 1 || showCompleted)
411         {
412           filteredTask = [NSMutableArray arrayWithArray: task];
413           endDateStamp = [[task objectAtIndex: 4] intValue];
414           statusFlag = [self _getStatusClassForStatusCode: statusCode
415                              andEndDateStamp: endDateStamp];
416           [filteredTask addObject: statusFlag];
417           [filteredTasks addObject: filteredTask];
418         }
419       task = [tasks nextObject];
420     }
421   [filteredTasks sortUsingSelector: @selector (compareTasksAscending:)];
422
423   return [self _responseWithData: filteredTasks];
424 }
425
426 // - (BOOL) shouldDisplayCurrentTask
427 // {
428 //   if (!knowsToShow)
429 //     {
430 //       showCompleted
431 //         = [[self queryParameterForKey: @"show-completed"] intValue];
432 //       knowsToShow = YES;
433 //     }
434
435 //   return ([[currentTask objectForKey: @"status"] intValue] != 1
436 //         || showCompleted);
437 // }
438
439 // - (BOOL) shouldShowCompletedTasks
440 // {
441 //   if (!knowsToShow)
442 //     {
443 //       showCompleted
444 //         = [[self queryParameterForKey: @"show-completed"] intValue];
445 //       knowsToShow = YES;
446 //     }
447
448 //   return showCompleted;
449 // }
450
451 @end