JSON-based getter operations for Calendar module

pull/91/head
Francis Lachapelle 2015-01-22 12:12:51 -05:00
parent cf8c4c482d
commit f2587aa385
4 changed files with 415 additions and 105 deletions

View File

@ -572,15 +572,79 @@
andString: [jsonResponse jsonRepresentation]];
}
/**
* @api {get} /so/:username/Calendar/:calendarId/:eventId/view Get event
* @apiVersion 1.0.0
* @apiName GetEventView
* @apiGroup Calendar
* @apiExample {curl} Example usage:
* curl -i http://localhost/SOGo/so/sogo1/Calendar/personal/71B6-54904400-1-7C308500.ics/view
*
* @apiParam {Number} [resetAlarm] Mark alarm as triggered if set to 1
* @apiParam {Number} [snoozeAlarm] Snooze the alarm for this number of minutes
*
* @apiSuccess (Success 200) {String} id Event ID
* @apiSuccess (Success 200) {String} pid Calendar ID (event's folder)
* @apiSuccess (Success 200) {String} calendar Human readable name of calendar
* @apiSuccess (Success 200) {String} startDate Formatted start date
* @apiSuccess (Success 200) {String} startTime Formatted start time
* @apiSuccess (Success 200) {String} endDate Formatted end date
* @apiSuccess (Success 200) {String} endTime Formatted end time
* @apiSuccess (Success 200) {Number} isAllDay 1 if event is all-day
* @apiSuccess (Success 200) {Number} isTransparent 1 if the event is not opaque
* @apiSuccess (Success 200) {Number} sendAppointmentNotifications 1 if notifications must be sent
*
* From [iCalEntityObject+SOGo attributes]
*
* @apiSuccess (Success 200) {String} component "vevent"
* @apiSuccess (Success 200) {String} summary Summary
* @apiSuccess (Success 200) {String} location Location
* @apiSuccess (Success 200) {String} comment Comment
* @apiSuccess (Success 200) {String} createdBy Value of custom header X-SOGo-Component-Created-By or organizer's "SENT-BY"
* @apiSuccess (Success 200) {Number} priority Priority
* @apiSuccess (Success 200) {String[]} [categories] Categories
* @apiSuccess (Success 200) {Object} [organizer] Appointment organizer
* @apiSuccess (Success 200) {String} organizer.name Organizer's name
* @apiSuccess (Success 200) {String} organizer.email Organizer's email address
* @apiSuccess (Success 200) {Object[]} [attendees] List of attendees
* @apiSuccess (Success 200) {String} [attendees.name] Attendee's name
* @apiSuccess (Success 200) {String} attendees.email Attendee's email address
* @apiSuccess (Success 200) {String} [attendees.uid] System user ID
* @apiSuccess (Success 200) {String} attendees.status Attendee's participation status
* @apiSuccess (Success 200) {String} [attendees.role] Attendee's role
* @apiSuccess (Success 200) {String} [attendees.delegatedTo] User that the original request was delegated to
* @apiSuccess (Success 200) {String} [attendees.delegatedFrom] User the request was delegated from
* @apiSuccess (Success 200) {Object[]} [alarm] Alarm definition
* @apiSuccess (Success 200) {String} alarm.action Either display or email
* @apiSuccess (Success 200) {String} alarm.quantity Quantity of units
* @apiSuccess (Success 200) {String} alarm.unit Either MINUTES, HOURS, or DAYS
* @apiSuccess (Success 200) {String} alarm.reference Either BEFORE or AFTER
* @apiSuccess (Success 200) {String} alarm.relation Either START or END
* @apiSuccess (Success 200) {Object[]} [alarm.attendees] List of attendees
* @apiSuccess (Success 200) {String} [alarm.attendees.name] Attendee's name
* @apiSuccess (Success 200) {String} alarm.attendees.email Attendee's email address
* @apiSuccess (Success 200) {String} [alarm.attendees.uid] System user ID
*
* From [iCalRepeatableEntityObject+SOGo attributes]
*
* @apiSuccess (Success 200) {Object} [repeat] Recurrence rule definition
* @apiSuccess (Success 200) {String} repeat.frequency Either daily, (every weekday), weekly, (bi-weekly), monthly, or yearly
* @apiSuccess (Success 200) {Number} repeat.interval Intervals the recurrence rule repeats
* @apiSuccess (Success 200) {String} [repeat.count] Number of occurrences at which to range-bound the recurrence
* @apiSuccess (Success 200) {String} [repeat.until] A Unix epoch value that bounds the recurrence rule in an inclusive manner
* @apiSuccess (Success 200) {Number[]} [repeat.days] List of days of the week
* @apiSuccess (Success 200) {String} repeat.days.day Day of the week (SU, MO, TU, WE, TH, FR, SA)
* @apiSuccess (Success 200) {Number} [repeat.days.occurence] Occurrence of a specific day within the monthly or yearly rule (valures are -5 to 5)
* @apiSuccess (Success 200) {Number[]} [repeat.months] List of months of the year (values are 1 to 12)
* @apiSuccess (Success 200) {Number[]} [repeat.monthdays] Days of the month (values are 1 to 31)
*/
- (id <WOActionResults>) viewAction
{
WOResponse *result;
NSDictionary *data;
NSMutableDictionary *data;
NSCalendarDate *eventStartDate, *eventEndDate;
NSTimeZone *timeZone;
SOGoUserDefaults *ud;
SOGoCalendarComponent *co;
NSString *created_by;
iCalAlarm *anAlarm;
BOOL resetAlarm;
@ -588,7 +652,6 @@
[self event];
result = [self responseWithStatus: 200];
ud = [[context activeUser] userDefaults];
timeZone = [ud timeZone];
eventStartDate = [event startDate];
@ -605,12 +668,10 @@
[componentCalendar retain];
}
created_by = [event createdBy];
// resetAlarm=yes is set only when we are about to show the alarm popup in the Web
// interface of SOGo. See generic.js for details. snoozeAlarm=X is called when the
// user clicks on "Snooze for" X minutes, when the popup is being displayed.
// If either is set to yes, we must find the right alarm.
// If either is set, we must find the right alarm.
resetAlarm = [[[context request] formValueForKey: @"resetAlarm"] boolValue];
snoozeAlarm = [[[context request] formValueForKey: @"snoozeAlarm"] intValue];
@ -640,23 +701,23 @@
}
}
data = [NSDictionary dictionaryWithObjectsAndKeys:
[[componentCalendar displayName] stringByEscapingHTMLString], @"calendar",
[event tag], @"component",
data = [NSMutableDictionary dictionaryWithObjectsAndKeys:
[co nameInContainer], @"id",
[componentCalendar nameInContainer], @"pid",
[componentCalendar displayName], @"calendar",
[dateFormatter formattedDate: eventStartDate], @"startDate",
[dateFormatter formattedTime: eventStartDate], @"startTime",
[dateFormatter formattedDate: eventEndDate], @"endDate",
[dateFormatter formattedTime: eventEndDate], @"endTime",
([event isAllDay] ? @"1": @"0"), @"isAllDay",
[[event summary] stringByEscapingHTMLString], @"summary",
[[event location] stringByEscapingHTMLString], @"location",
[created_by stringByEscapingHTMLString], @"created_by",
[[[event comment] stringByEscapingHTMLString] stringByDetectingURLs], @"description",
[NSNumber numberWithBool: [event isAllDay]], @"isAllDay",
[NSNumber numberWithBool: ![event isOpaque]], @"isTransparent",
nil];
[result appendContentString: [data jsonRepresentation]];
return result;
// Add attributes from iCalEntityObject+SOGo and iCalRepeatableEntityObject+SOGo
[data addEntriesFromDictionary: [event attributes]];
// Return JSON representation
return [self responseWithStatus: 200 andJSONRepresentation: data];
}
- (BOOL) shouldTakeValuesFromRequest: (WORequest *) request
@ -682,7 +743,7 @@
signed int offset;
id o;
[self event];
[self event];
[super takeValuesFromRequest: _rq inContext: _ctx];
if (isAllDay)

View File

@ -1,6 +1,6 @@
/* UIxCalListingActions.m - this file is part of SOGo
*
* Copyright (C) 2006-2014 Inverse inc.
* Copyright (C) 2006-2015 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -308,14 +308,41 @@ static NSArray *tasksFields = nil;
}
}
/**
* Split participants information into arrays and return the string representation of
* their states (0: needs-action, 1: accepted, etc).
*
* @see [iCalPerson descriptionForParticipationStatus:]
*/
- (void) _fixParticipants: (NSMutableDictionary *) theRecord
{
NSArray *mails, *states;
NSMutableArray *statesDescription;
iCalPersonPartStat stat;
NSUInteger count, max;
mails = [[theRecord objectForKey: @"c_partmails"] componentsSeparatedByString: @"\n"];
states = [[theRecord objectForKey: @"c_partstates"] componentsSeparatedByString: @"\n"];
max = [mails count];
statesDescription = [NSMutableArray arrayWithCapacity: max];
for (count = 0; count < max; count++)
{
stat = [[states objectAtIndex: count] intValue];
[statesDescription addObject: [[iCalPerson descriptionForParticipationStatus: stat] lowercaseString]];
}
[theRecord setObject: mails forKey: @"c_partmails"];
[theRecord setObject: statesDescription forKey: @"c_partstates"];
}
- (NSArray *) _fetchFields: (NSArray *) fields
forComponentOfType: (NSString *) component
{
NSEnumerator *folders, *currentInfos;
NSMutableDictionary *newInfo;
NSMutableArray *infos, *newInfoForComponent, *quickInfos, *allInfos, *quickInfosName;
NSMutableArray *infos, *quickInfos, *allInfos, *quickInfosName;
NSNull *marker;
NSString *owner, *role, *calendarName, *filters, *iCalString;
NSString *owner, *role, *calendarName, *iCalString;
NSRange match;
iCalCalendar *calendar;
iCalObject *master;
@ -324,8 +351,7 @@ static NSArray *tasksFields = nil;
SOGoUser *ownerUser;
BOOL isErasable, folderIsRemote, quickInfosFlag = NO;
id currentInfo;
int i, count;
int i;
infos = [NSMutableArray array];
marker = [NSNull null];
@ -437,8 +463,7 @@ static NSArray *tasksFields = nil;
}
if ([fields containsObject: @"ownerIsOrganizer"])
{
// Identifies whether the active user is the organizer
// of this event.
// Identifies whether the owner is the organizer of this event.
NSString *c_orgmail;
c_orgmail = [newInfo objectForKey: @"c_orgmail"];
@ -449,13 +474,8 @@ static NSArray *tasksFields = nil;
[newInfo setObject: [NSNumber numberWithInt: 0]
forKey: @"ownerIsOrganizer"];
}
if (isErasable)
[newInfo setObject: [NSNumber numberWithInt: 1]
forKey: @"erasable"];
else
[newInfo setObject: [NSNumber numberWithInt: 0]
forKey: @"erasable"];
[newInfo setObject: [NSNumber numberWithBool: isErasable]
forKey: @"erasable"];
[newInfo setObject: [currentFolder nameInContainer]
forKey: @"c_folder"];
[newInfo setObject: [currentFolder ownerInContext: context]
@ -465,23 +485,21 @@ static NSArray *tasksFields = nil;
calendarName = @"";
[newInfo setObject: calendarName
forKey: @"calendarName"];
// Fix empty title
if (![[newInfo objectForKey: @"c_title"] length])
[self _fixComponentTitle: newInfo withType: component];
// Possible improvement: only call _fixDates if event is recurrent
// or the view range span a daylight saving time change
[self _fixDates: newInfo];
newInfoForComponent = [NSMutableArray arrayWithArray: [newInfo objectsForKeys: fields
notFoundMarker: marker]];
// Escape HTML
count = [newInfoForComponent count];
for (i = 0; i < count; i++)
{
currentInfo = [newInfoForComponent objectAtIndex: i];
if ([currentInfo respondsToSelector: @selector (stringByEscapingHTMLString)])
[newInfoForComponent replaceObjectAtIndex: i withObject: [currentInfo stringByEscapingHTMLString]];
}
[infos addObject: newInfoForComponent];
// Split linefeed-delimited list of participants emails and statuses
if ([fields containsObject: @"c_partmails"])
[self _fixParticipants: newInfo];
[infos addObject: [newInfo objectsForKeys: fields
notFoundMarker: marker]];
}
}
}
@ -493,12 +511,7 @@ static NSArray *tasksFields = nil;
- (WOResponse *) _responseWithData: (id) data
{
WOResponse *response;
response = [self responseWithStatus: 200];
[response appendContentString: [data jsonRepresentation]];
return response;
return [self responseWithStatus: 200 andJSONRepresentation: data];
}
- (NSString *) _formattedDateForSeconds: (unsigned int) seconds
@ -519,27 +532,37 @@ static NSArray *tasksFields = nil;
return formattedDate;
}
//
// We return:
//
// [[calendar name (full path), complete Event ID (full path), Fire date (UTC)], ..]
//
// Called when each module is loaded or whenever a calendar component is created, modified, deleted
// or whenever there's a {un}subscribe to a calendar.
//
// Workflow :
//
// - for ALL subscribed and ACTIVE calendars
// - returns alarms that will occur in the next 48 hours or the non-triggered alarms
// for non-completed events
//
/**
* @api {get} /so/:username/Calendar/alarmslist Get alarms
* @apiVersion 1.0.0
* @apiName GetAlarmsList
* @apiGroup Calendar
* @apiExample {curl} Example usage:
* curl -i http://localhost/SOGo/so/sogo1/Calendar/alarmslist?browserTime=1286668800
* @apiDescription Called when each module is loaded or whenever a calendar component is created, modified, deleted
* or whenever there's a {un}subscribe to a calendar.
*
* Workflow :
*
* - for ALL subscribed and ACTIVE calendars
* - returns alarms that will occur in the next 48 hours or the non-triggered alarms
* for non-completed events
*
* @apiParam {Number} [browserTime] Epoch time of browser
*
* @apiSuccess (Success 200) {String[]} fields List of fields for each event definition
* @apiSuccess (Success 200) {String[]} alarms List of events
* @apiSuccess (Success 200) {String} alarms.c_folder Calendar ID
* @apiSuccess (Success 200) {String} alarms.c_name Event UID
* @apiSuccess (Success 200) {String} alarms.c_nextalarm Epoch time of event's next alarm
*/
- (WOResponse *) alarmsListAction
{
SOGoAppointmentFolder *currentFolder;
SOGoAppointmentFolders *clientObject;
NSMutableArray *allAlarms;
NSDictionary *data;
NSEnumerator *folders;
WOResponse *response;
unsigned int browserTime, laterTime;
// We look for alarms in the next 48 hours
@ -572,12 +595,12 @@ static NSArray *tasksFields = nil;
}
}
}
data = [NSDictionary dictionaryWithObjectsAndKeys:
[NSArray arrayWithObjects: @"c_folder", @"c_name", @"c_nextalarm", nil], @"fields",
allAlarms, @"alarms", nil];
response = [self responseWithStatus: 200];
[response appendContentString: [allAlarms jsonRepresentation]];
return response;
return [self _responseWithData: data];
}
- (void) checkFilterValue
@ -596,11 +619,51 @@ static NSArray *tasksFields = nil;
}
}
/**
* @api {get} /so/:username/Calendar/eventslist Get events
* @apiVersion 1.0.0
* @apiName GetEventsList
* @apiGroup Calendar
* @apiExample {curl} Example usage:
* curl -i http://localhost/SOGo/so/sogo1/Calendar/eventslist?day=20141201\&filterpopup=view_selectedday
*
* @apiParam {Boolean} [asc] Descending sort when false. Defaults to true (ascending).
* @apiParam {String} [sort] Sort field. Either title, end, location, or calendarName.
* @apiParam {Number} [day] Selected day (YYYYMMDD)
* @apiParam {String} [filterpopup] Time period. Either view_today, view_next7, view_next14, view_next31, view_thismonth, view_future, view_selectedday, or view_all
*
* @apiSuccess (Success 200) {String[]} fields List of fields for each event definition
* @apiSuccess (Success 200) {String[]} events List of events
* @apiSuccess (Success 200) {String} events.c_name Event UID
* @apiSuccess (Success 200) {String} events.c_folder Calendar ID
* @apiSuccess (Success 200) {String} events.calendarName Human readable name of calendar
* @apiSuccess (Success 200) {Number} events.c_status 0: Cancelled, 1: Normal, 2: Tentative
* @apiSuccess (Success 200) {String} events.c_title Title
* @apiSuccess (Success 200) {String} events.c_startdate Epoch time of start date
* @apiSuccess (Success 200) {String} events.c_enddate Epoch time of end date
* @apiSuccess (Success 200) {String} events.c_location Event's location
* @apiSuccess (Success 200) {Number} events.c_isallday 1 if event lasts all day
* @apiSuccess (Success 200) {Number} events.c_classification 0: Public, 1: Private, 2: Confidential
* @apiSuccess (Success 200) {String} events.c_category Category
* @apiSuccess (Success 200) {String[]} events.c_partmails Participants email addresses
* @apiSuccess (Success 200) {String[]} events.c_partstates Participants states
* @apiSuccess (Success 200) {String} events.c_owner Event's owner
* @apiSuccess (Success 200) {Number} events.c_iscycle 1 if the event is cyclic
* @apiSuccess (Success 200) {Number} events.c_nextalarm Epoch time of next alarm
* @apiSuccess (Success 200) {String} events.c_recurrence_id Recurrence ID if event is cyclic
* @apiSuccess (Success 200) {Number} events.isException 1 if recurrence is an exception
* @apiSuccess (Success 200) {Number} events.editable 1 if active user can edit the event
* @apiSuccess (Success 200) {Number} events.erasable 1 if active user can erase the event
* @apiSuccess (Success 200) {Number} events.ownerIsOrganizer 1 if owner is also the organizer
* @apiSuccess (Success 200) {String} events.formatted_startdate Localized start date
* @apiSuccess (Success 200) {String} events.formatted_enddate Localized end date
*/
- (WOResponse *) eventsListAction
{
NSArray *oldEvent;
NSDictionary *data;
NSEnumerator *events;
NSMutableArray *newEvents, *newEvent;
NSMutableArray *fields, *newEvents, *newEvent;
unsigned int interval;
BOOL isAllDay;
NSString *sort, *ascending;
@ -640,7 +703,14 @@ static NSArray *tasksFields = nil;
if (![ascending boolValue])
[newEvents reverseArray];
return [self _responseWithData: newEvents];
// Fields names
fields = [NSMutableArray arrayWithArray: eventsFields];
[fields addObject: @"formatted_startdate"];
[fields addObject: @"formatted_enddate"];
data = [NSDictionary dictionaryWithObjectsAndKeys: fields, @"fields", newEvents, @"events", nil];
return [self _responseWithData: data];
}
static inline void _feedBlockWithDayBasedData (NSMutableDictionary *block, unsigned int start,
@ -1058,7 +1128,6 @@ _computeBlocksPosition (NSArray *blocks)
NSString *fUID;
NSNumber *isActive;
unsigned int count, foldersCount;
int max=0, i;
co = [self clientObject];
folders = [co subFolders];
@ -1076,10 +1145,58 @@ _computeBlocksPosition (NSArray *blocks)
return selectedCalendars;
}
/**
* @api {get} /so/:username/Calendar/eventsblocks Get events blocks
* @apiVersion 1.0.0
* @apiName GetEventsBlocks
* @apiGroup Calendar
* @apiExample {curl} Example usage:
* curl -i http://localhost/SOGo/so/sogo1/Calendar/eventsblocks?day=20141201\&popupfilter=view_selectedday
*
* @apiParam {Number} [sd] Period start date (YYYYMMDD)
* @apiParam {Number} [ed] Period end date (YYYYMMDD)
* @apiParam {String} [view] Formatting view. Either dayview, multicolumndayview, weekview or monthview.
*
* @apiSuccess (Success 200) {String[]} eventsFields List of fields for each event definition
* @apiSuccess (Success 200) {String[]} events List of events
* @apiSuccess (Success 200) {String} events.c_name Event UID
* @apiSuccess (Success 200) {String} events.c_folder Calendar ID
* @apiSuccess (Success 200) {String} events.calendarName Human readable name of calendar
* @apiSuccess (Success 200) {Number} events.c_status 0: Cancelled, 1: Normal, 2: Tentative
* @apiSuccess (Success 200) {String} events.c_title Title
* @apiSuccess (Success 200) {String} events.c_startdate Epoch time of start date
* @apiSuccess (Success 200) {String} events.c_enddate Epoch time of end date
* @apiSuccess (Success 200) {String} events.c_location Event's location
* @apiSuccess (Success 200) {Number} events.c_isallday 1 if event lasts all day
* @apiSuccess (Success 200) {Number} events.c_classification 0: Public, 1: Private, 2: Confidential
* @apiSuccess (Success 200) {String} events.c_category Category
* @apiSuccess (Success 200) {String[]} events.c_partmails Participants email addresses
* @apiSuccess (Success 200) {String[]} events.c_partstates Participants states
* @apiSuccess (Success 200) {String} events.c_owner Event's owner
* @apiSuccess (Success 200) {Number} events.c_iscycle 1 if the event is cyclic
* @apiSuccess (Success 200) {Number} events.c_nextalarm Epoch time of next alarm
* @apiSuccess (Success 200) {String} events.c_recurrence_id Recurrence ID if event is cyclic
* @apiSuccess (Success 200) {Number} events.isException 1 if recurrence is an exception
* @apiSuccess (Success 200) {Number} events.editable 1 if active user can edit the event
* @apiSuccess (Success 200) {Number} events.erasable 1 if active user can erase the event
* @apiSuccess (Success 200) {Number} events.ownerIsOrganizer 1 if owner is also the organizer
* @apiSuccess (Success 200) {Object[]} blocks
* @apiSuccess (Success 200) {Number} blocks.nbr
* @apiSuccess (Success 200) {Number} blocks.start
* @apiSuccess (Success 200) {Number} blocks.position
* @apiSuccess (Success 200) {Number} blocks.length
* @apiSuccess (Success 200) {Number} blocks.siblings
* @apiSuccess (Success 200) {Number} blocks.realSiblings
* @apiSuccess (Success 200) {Object[]} allDayBlocks
* @apiSuccess (Success 200) {Number} allDayBlocks.nbr
* @apiSuccess (Success 200) {Number} allDayBlocks.start
* @apiSuccess (Success 200) {Number} allDayBlocks.length
*/
- (WOResponse *) eventsBlocksAction
{
int count, max;
NSArray *events, *event, *eventsBlocks;
NSArray *events, *event;
NSDictionary *eventsBlocks;
NSMutableArray *allDayBlocks, *blocks, *currentDay, *calendars, *eventsByCalendars, *eventsForCalendar;
NSNumber *eventNbr;
BOOL isAllDay;
@ -1102,7 +1219,11 @@ _computeBlocksPosition (NSArray *blocks)
[eventsForCalendar addObject: [events objectAtIndex:j]];
}
}
eventsBlocks = [NSArray arrayWithObjects:eventsForCalendar, allDayBlocks, blocks, nil];
eventsBlocks = [NSDictionary dictionaryWithObjectsAndKeys:
eventsFields, @"eventsFields",
eventsForCalendar, @"events",
allDayBlocks, @"allDayBlocks",
blocks, @"blocks", nil];
max = [eventsForCalendar count];
for (count = 0; count < max; count++)
{
@ -1129,7 +1250,11 @@ _computeBlocksPosition (NSArray *blocks)
else
{
[self _prepareEventBlocks: &blocks withAllDays: &allDayBlocks];
eventsBlocks = [NSArray arrayWithObjects: events, allDayBlocks, blocks, nil];
eventsBlocks = [NSDictionary dictionaryWithObjectsAndKeys:
eventsFields, @"eventsFields",
events, @"events",
allDayBlocks, @"allDayBlocks",
blocks, @"blocks", nil];
max = [events count];
for (count = 0; count < max; count++)
{
@ -1171,8 +1296,7 @@ _computeBlocksPosition (NSArray *blocks)
if (endDateStamp)
{
now = [NSCalendarDate calendarDate];
taskDate
= [NSCalendarDate dateWithTimeIntervalSince1970: endDateStamp];
taskDate = [NSCalendarDate dateWithTimeIntervalSince1970: endDateStamp];
[taskDate setTimeZone: userTimeZone];
if ([taskDate earlierDate: now] == taskDate)
statusClass = @"overdue";
@ -1191,9 +1315,45 @@ _computeBlocksPosition (NSArray *blocks)
return statusClass;
}
/**
* @api {get} /so/:username/Calendar/taskslist Get tasks
* @apiVersion 1.0.0
* @apiName GetTasksList
* @apiGroup Calendar
* @apiExample {curl} Example usage:
* curl -i http://localhost/SOGo/so/sogo1/Calendar/taskslist?filterpopup=view_all
*
* @apiParam {Number} [show-completed] Show completed tasks when set to 1. Defaults to ignore completed tasks.
* @apiParam {Boolean} [asc] Descending sort when false. Defaults to true (ascending).
* @apiParam {Boolean} [sort] Sort field. Either title, priority, end, location, category, or calendarname.
* @apiParam {Number} [day] Selected day (YYYYMMDD)
* @apiParam {String} [filterpopup] Time period. Either view_today, view_next7, view_next14, view_next31, view_thismonth, view_overdue, view_incomplete, view_not_started, or view_all
* @apiParam {Boolean} [setud] Save 'show-completed' parameter in user's settings
*
* @apiSuccess (Success 200) {String[]} fields List of fields for each event definition
* @apiSuccess (Success 200) {String[]} tasks List of events
* @apiSuccess (Success 200) {String} tasks.c_name Todo UID
* @apiSuccess (Success 200) {String} tasks.c_folder Calendar ID
* @apiSuccess (Success 200) {String} tasks.calendarName Human readable name of calendar
* @apiSuccess (Success 200) {Number} tasks.c_status 0: Needs-action, 1: Completed, 2: In-process, 3: Cancelled
* @apiSuccess (Success 200) {String} tasks.c_title Title
* @apiSuccess (Success 200) {String} tasks.c_enddate End date (epoch time)
* @apiSuccess (Success 200) {Number} tasks.c_classification 0: Public, 1: Private, 2: Confidential
* @apiSuccess (Success 200) {String} tasks.c_location Location
* @apiSuccess (Success 200) {String} tasks.c_category Category
* @apiSuccess (Success 200) {Number} tasks.editable 1 if task is editable by the active user
* @apiSuccess (Success 200) {Number} tasks.erasable 1 if task is erasable by the active user
* @apiSuccess (Success 200) {String} tasks.c_priority Priority (0-9)
* @apiSuccess (Success 200) {String} tasks.c_owner Username of owner
* @apiSuccess (Success 200) {String} tasks.c_recurrence_id Recurrence ID if task is cyclic
* @apiSuccess (Success 200) {Number} tasks.isException 1 if task is cyclic and an exception
* @apiSuccess (Success 200) {String} tasks.status Either completed, overdue, duetoday, or duelater
* @apiSuccess (Success 200) {String} tasks.formatted_enddate Localized end date
*/
- (WOResponse *) tasksListAction
{
NSMutableArray *filteredTasks, *filteredTask;
NSDictionary *data;
NSMutableArray *filteredTasks, *filteredTask, *fields;
NSString *sort, *ascending;
NSString *statusFlag, *tasksView;
SOGoUserSettings *us;
@ -1239,6 +1399,8 @@ _computeBlocksPosition (NSArray *blocks)
if (endDateStamp > 0)
[filteredTask addObject: [self _formattedDateForSeconds: endDateStamp
forAllDay: NO]];
else
[filteredTask addObject: [NSNull null]];
if (([tasksView isEqualToString:@"view_today"] ||
[tasksView isEqualToString:@"view_next7"] ||
@ -1275,8 +1437,15 @@ _computeBlocksPosition (NSArray *blocks)
ascending = [[context request] formValueForKey: @"asc"];
if (![ascending boolValue])
[filteredTasks reverseArray];
return [self _responseWithData: filteredTasks];
// Fields names
fields = [NSMutableArray arrayWithArray: tasksFields];
[fields addObject: @"status"];
[fields addObject: @"formatted_enddate"];
data = [NSDictionary dictionaryWithObjectsAndKeys: fields, @"fields", filteredTasks, @"tasks", nil];
return [self _responseWithData: data];
}
- (WOResponse *) activeTasksAction

View File

@ -1,8 +1,6 @@
/* UIxCalendarSelector.m - this file is part of SOGo
*
* Copyright (C) 2007-2011 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Copyright (C) 2007-2015 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -168,14 +166,30 @@ _intValueFromHex (NSString *hexString)
return ((brightness < 144) ? @"white" : @"black");
}
/**
* @api {get} /so/:username/Calendar/:calendarId/calendarslist Get calendars
* @apiVersion 1.0.0
* @apiName GetCalendarsList
* @apiGroup Calendar
* @apiExample {curl} Example usage:
* curl -i http://localhost/SOGo/so/sogo1/Calendar/calendarslist
*
* @apiSuccess (Success 200) {Object[]} calendars List of calendars
* @apiSuccess (Success 200) {String} id Calendar ID
* @apiSuccess (Success 200) {String} displayName Human readable name
* @apiSuccess (Success 200) {String} owner User ID of owner
* @apiSuccess (Success 200) {String} color Calendar's hex color code
* @apiSuccess (Success 200) {Number} active 1 if the calendar is enabled
* @apiSuccess (Success 200) {Number} activeTasks Number of incompleted tasks
*/
- (WOResponse *) calendarsListAction
{
NSDictionary *data;
WOResponse *response;
response = [self responseWithStatus: 200];
[response setHeader: @"text/plain; charset=utf-8"
forKey: @"content-type"];
[response appendContentString: [[self calendars] jsonRepresentation]];
data = [NSDictionary dictionaryWithObject: [self calendars]
forKey: @"calendars"];
response = [self responseWithStatus: 200 andJSONRepresentation: data];
return response;
}

View File

@ -1,6 +1,6 @@
/* UIxTaskEditor.m - this file is part of SOGo
*
* Copyright (C) 2007-2014 Inverse inc.
* Copyright (C) 2007-2015 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -19,6 +19,7 @@
*/
#import <Foundation/NSDictionary.h>
#import <Foundation/NSValue.h>
#import <NGObjWeb/SoObject.h>
#import <NGObjWeb/SoPermissions.h>
@ -390,13 +391,77 @@
return [self jsCloseWithRefreshMethod: @"refreshTasks()"];
}
/**
* @api {get} /so/:username/Calendar/:calendarId/:todoId/view Get task
* @apiVersion 1.0.0
* @apiName GetTaskView
* @apiGroup Calendar
* @apiExample {curl} Example usage:
* curl -i http://localhost/SOGo/so/sogo1/Calendar/personal/1A5-53489200-2D-6BD99880.ics/view
*
* @apiParam {Number} [resetAlarm] Mark alarm as triggered if set to 1
* @apiParam {Number} [snoozeAlarm] Snooze the alarm for this number of minutes
*
* @apiSuccess (Success 200) {String} id Todo ID
* @apiSuccess (Success 200) {String} pid Calendar ID (todo's folder)
* @apiSuccess (Success 200) {String} calendar Human readable name of calendar
* @apiSuccess (Success 200) {String} startDate Formatted start date
* @apiSuccess (Success 200) {String} startTime Formatted start time
* @apiSuccess (Success 200) {String} dueDate Formatted due date
* @apiSuccess (Success 200) {String} dueTime Formatted due time
* @apiSuccess (Success 200) {NSNumber} percentComplete Percent completion
*
* From [iCalEntityObject+SOGo attributes]
*
* @apiSuccess (Success 200) {String} component "vtodo"
* @apiSuccess (Success 200) {String} summary Summary
* @apiSuccess (Success 200) {String} location Location
* @apiSuccess (Success 200) {String} comment Comment
* @apiSuccess (Success 200) {String} createdBy Value of custom header X-SOGo-Component-Created-By or organizer's "SENT-BY"
* @apiSuccess (Success 200) {Number} priority Priority
* @apiSuccess (Success 200) {String[]} [categories] Categories
* @apiSuccess (Success 200) {Object} [organizer] Appointment organizer
* @apiSuccess (Success 200) {String} organizer.name Organizer's name
* @apiSuccess (Success 200) {String} organizer.email Organizer's email address
* @apiSuccess (Success 200) {Object[]} [attendees] List of attendees
* @apiSuccess (Success 200) {String} [attendees.name] Attendee's name
* @apiSuccess (Success 200) {String} attendees.email Attendee's email address
* @apiSuccess (Success 200) {String} [attendees.uid] System user ID
* @apiSuccess (Success 200) {String} attendees.status Attendee's participation status
* @apiSuccess (Success 200) {String} [attendees.role] Attendee's role
* @apiSuccess (Success 200) {String} [attendees.delegatedTo] User that the original request was delegated to
* @apiSuccess (Success 200) {String} [attendees.delegatedFrom] User the request was delegated from
* @apiSuccess (Success 200) {Object[]} [alarm] Alarm definition
* @apiSuccess (Success 200) {String} alarm.action Either display or email
* @apiSuccess (Success 200) {String} alarm.quantity Quantity of units
* @apiSuccess (Success 200) {String} alarm.unit Either MINUTES, HOURS, or DAYS
* @apiSuccess (Success 200) {String} alarm.reference Either BEFORE or AFTER
* @apiSuccess (Success 200) {String} alarm.relation Either START or END
* @apiSuccess (Success 200) {Object[]} [alarm.attendees] List of attendees
* @apiSuccess (Success 200) {String} [alarm.attendees.name] Attendee's name
* @apiSuccess (Success 200) {String} alarm.attendees.email Attendee's email address
* @apiSuccess (Success 200) {String} [alarm.attendees.uid] System user ID
*
* From [iCalRepeatableEntityObject+SOGo attributes]
*
* @apiSuccess (Success 200) {Object} [repeat] Recurrence rule definition
* @apiSuccess (Success 200) {String} repeat.frequency Either daily, (every weekday), weekly, (bi-weekly), monthly, or yearly
* @apiSuccess (Success 200) {Number} repeat.interval Intervals the recurrence rule repeats
* @apiSuccess (Success 200) {String} [repeat.count] Number of occurrences at which to range-bound the recurrence
* @apiSuccess (Success 200) {String} [repeat.until] A Unix epoch value that bounds the recurrence rule in an inclusive manner
* @apiSuccess (Success 200) {Number[]} [repeat.days] List of days of the week
* @apiSuccess (Success 200) {String} repeat.days.day Day of the week (SU, MO, TU, WE, TH, FR, SA)
* @apiSuccess (Success 200) {Number} [repeat.days.occurence] Occurrence of a specific day within the monthly or yearly rule (valures are -5 to 5)
* @apiSuccess (Success 200) {Number[]} [repeat.months] List of months of the year (values are 1 to 12)
* @apiSuccess (Success 200) {Number[]} [repeat.monthdays] Days of the month (values are 1 to 31)
*/
- (id <WOActionResults>) viewAction
{
WOResponse *result;
NSDictionary *data;
NSMutableDictionary *data;
NSCalendarDate *startDate, *dueDate;
SOGoCalendarComponent *co;
NSTimeZone *timeZone;
SOGoCalendarComponent *co;
SOGoAppointmentFolder *thisFolder;
SOGoUserDefaults *ud;
iCalAlarm *anAlarm;
BOOL resetAlarm;
@ -405,8 +470,8 @@
[self todo];
co = [self clientObject];
thisFolder = [co container];
result = [self responseWithStatus: 200];
ud = [[context activeUser] userDefaults];
timeZone = [ud timeZone];
startDate = [todo startDate];
@ -426,10 +491,10 @@
iCalToDo *master;
master = todo;
[[co container] findEntityForClosestAlarm: &todo
timezone: timeZone
startDate: &startDate
endDate: &dueDate];
[thisFolder findEntityForClosestAlarm: &todo
timezone: timeZone
startDate: &startDate
endDate: &dueDate];
anAlarm = [todo firstDisplayOrAudioAlarm];
@ -449,21 +514,22 @@
}
resetAlarm = [[[context request] formValueForKey: @"resetAlarm"] boolValue];
data = [NSDictionary dictionaryWithObjectsAndKeys:
[todo tag], @"component",
data = [NSMutableDictionary dictionaryWithObjectsAndKeys:
[co nameInContainer], @"id",
[thisFolder nameInContainer], @"pid",
[thisFolder displayName], @"calendar",
(startDate? (id)[dateFormatter formattedDate: startDate] : (id)@""), @"startDate",
(startDate? (id)[dateFormatter formattedTime: startDate] : (id)@""), @"startTime",
(dueDate? (id)[dateFormatter formattedDate: dueDate] : (id)@""), @"dueDate",
(dueDate? (id)[dateFormatter formattedTime: dueDate] : (id)@""), @"dueTime",
([todo hasRecurrenceRules]? @"1": @"0"), @"isReccurent",
[todo summary], @"summary",
[todo location], @"location",
[todo comment], @"description",
[NSNumber numberWithInt: [[todo percentComplete] intValue]], @"percentComplete",
nil];
[result appendContentString: [data jsonRepresentation]];
// Add attributes from iCalEntityObject+SOGo and iCalRepeatableEntityObject+SOGo
[data addEntriesFromDictionary: [todo attributes]];
return result;
// Return JSON representation
return [self responseWithStatus: 200 andJSONRepresentation: data];
}
- (BOOL) shouldTakeValuesFromRequest: (WORequest *) request