JSONinfy [SOGoUserHomePage readFreeBusyAction]

pull/91/head
Francis Lachapelle 2015-06-04 13:31:06 -04:00
parent 8124faa6d4
commit 4cece88a42
1 changed files with 185 additions and 115 deletions

View File

@ -87,20 +87,42 @@
return [self redirectToLocation: [moduleURL absoluteString]]; return [self redirectToLocation: [moduleURL absoluteString]];
} }
- (void) _fillFreeBusyItems: (unsigned int *) items - (NSDictionary *) _freeBusyFromStartDate: (NSCalendarDate *) startDate
count: (unsigned int) itemCount toEndDate: (NSCalendarDate *) endDate
withRecords: (NSArray *) records forFreeBusy: (SOGoFreeBusyObject *) fb
fromStartDate: (NSCalendarDate *) startDate andContact: (NSString *) uid
toEndDate: (NSCalendarDate *) endDate
{ {
NSCalendarDate *start, *end;
NSMutableDictionary *freeBusy, *dayData, *hourData;
NSArray *records;
NSArray *emails, *partstates; NSArray *emails, *partstates;
NSCalendarDate *currentDate; NSCalendarDate *currentDate, *currentStartDate, *currentEndDate;
NSDictionary *record; NSDictionary *record;
NSString *dayKey, *hourKey, *minuteKey;
NSEnumerator *freeBusyList, *dayList, *hourList;
SOGoUser *user; SOGoUser *user;
int quarter, lastQuarter, recordCount, recordMax, count, i, type, maxBookings, isResource;
int recordCount, recordMax, count, startInterval, endInterval, i, type, maxBookings, isResource, delta; // We "copy" the start/end date because -fetchFreeBusyInfosFrom will mess
// with the timezone and we don't want that to properly calculate the delta
// DO NOT USE -copy HERE - it'll simply return [self retain].
start = [NSCalendarDate dateWithYear: [startDate yearOfCommonEra]
month: [startDate monthOfYear]
day: [startDate dayOfMonth]
hour: [startDate hourOfDay]
minute: [startDate minuteOfHour]
second: [startDate secondOfMinute]
timeZone: [startDate timeZone]];
recordMax = [records count]; end = [NSCalendarDate dateWithYear: [endDate yearOfCommonEra]
month: [endDate monthOfYear]
day: [endDate dayOfMonth]
hour: [endDate hourOfDay]
minute: [endDate minuteOfHour]
second: [endDate secondOfMinute]
timeZone: [endDate timeZone]];
freeBusy = [NSMutableDictionary dictionary];
user = [SOGoUser userWithLogin: [[self clientObject] ownerInContext: context] roles: nil]; user = [SOGoUser userWithLogin: [[self clientObject] ownerInContext: context] roles: nil];
maxBookings = [user numberOfSimultaneousBookings]; maxBookings = [user numberOfSimultaneousBookings];
isResource = [user isResource]; isResource = [user isResource];
@ -108,6 +130,8 @@
// Fetch freebusy information if the user is NOT a resource or if multiplebookings isn't unlimited // Fetch freebusy information if the user is NOT a resource or if multiplebookings isn't unlimited
if (!isResource || maxBookings != 0) if (!isResource || maxBookings != 0)
{ {
records = [fb fetchFreeBusyInfosFrom: start to: end forContact: uid];
recordMax = [records count];
for (recordCount = 0; recordCount < recordMax; recordCount++) for (recordCount = 0; recordCount < recordMax; recordCount++)
{ {
record = [records objectAtIndex: recordCount]; record = [records objectAtIndex: recordCount];
@ -147,35 +171,111 @@
if (type == 1) if (type == 1)
{ {
// User is busy for this event; update items bit string // User is busy for this event
currentDate = [record objectForKey: @"startDate"]; currentStartDate = [record objectForKey: @"startDate"];
if ([currentDate earlierDate: startDate] == currentDate) currentEndDate = [record objectForKey: @"endDate"];
startInterval = 0; dayKey = [currentStartDate shortDateString];
else dayData = [freeBusy objectForKey: dayKey];
startInterval = ([currentDate timeIntervalSinceDate: startDate] if (!dayData)
/ INTERVALSECONDS);
delta = [[currentDate timeZoneDetail] timeZoneSecondsFromGMT] - [[startDate timeZoneDetail] timeZoneSecondsFromGMT];
startInterval += (delta/INTERVALSECONDS);
startInterval = (startInterval < -(HALFPADDING) ? -(HALFPADDING) : startInterval);
currentDate = [record objectForKey: @"endDate"];
if ([currentDate earlierDate: endDate] == endDate)
endInterval = itemCount - 1;
else
endInterval = ([currentDate timeIntervalSinceDate: startDate]
/ INTERVALSECONDS);
delta = [[currentDate timeZoneDetail] timeZoneSecondsFromGMT] - [[startDate timeZoneDetail] timeZoneSecondsFromGMT];
endInterval += (delta/INTERVALSECONDS);
endInterval = (endInterval < 0 ? 0 : endInterval);
endInterval = (endInterval > itemCount+HALFPADDING ? itemCount+HALFPADDING : endInterval);
// Update bit string representation
// If the user is a resource with restristed amount of bookings, keep the sum of overlapping events
for (count = startInterval; count < endInterval; count++)
{ {
*(items + count) = (isResource && maxBookings > 0) ? *(items + count) + 1 : 1; dayData = [NSMutableDictionary dictionary];
[freeBusy setObject: dayData forKey: dayKey];
}
if ([currentStartDate earlierDate: startDate] == currentStartDate)
currentStartDate = startDate;
currentDate = [NSCalendarDate dateWithYear: [currentStartDate yearOfCommonEra]
month: [currentStartDate monthOfYear]
day: [currentStartDate dayOfMonth]
hour: [currentStartDate hourOfDay]
minute: 0
second: 0
timeZone: [currentStartDate timeZone]];
// Increment counters for quarters of first hour
hourKey = [NSString stringWithFormat: @"%u", [currentDate hourOfDay]];
hourData = [dayData objectForKey: hourKey];
if (!hourData)
{
hourData = [NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt: 0], @"0",
[NSNumber numberWithInt: 0], @"15",
[NSNumber numberWithInt: 0], @"30",
[NSNumber numberWithInt: 0], @"45",
nil];
[dayData setObject: hourData forKey: hourKey];
}
quarter = (int)([currentStartDate minuteOfHour] / 15 + 0.5);
if ([currentEndDate timeIntervalSinceDate: currentDate] < 3600)
lastQuarter = (int)([currentEndDate minuteOfHour] / 15 + 0.5);
else
lastQuarter = 4;
for (i = 0; i < lastQuarter; i++) {
if (i >= quarter)
{
minuteKey = [NSString stringWithFormat: @"%u", i*15];
count = [[hourData objectForKey: minuteKey] intValue] + 1;
[hourData setObject: [NSNumber numberWithInt: count] forKey: minuteKey];
}
}
currentDate = [currentDate dateByAddingYears:0 months:0 days:0 hours:1 minutes:0 seconds:0];
// Increment counters of fully busy hours
while ([currentDate compare: currentEndDate] == NSOrderedAscending &&
[currentEndDate timeIntervalSinceDate: currentDate] >= 3600) // 1 hour
{
hourKey = [NSString stringWithFormat: @"%u", [currentDate hourOfDay]];
hourData = [dayData objectForKey: hourKey];
if (!hourData)
{
hourData = [NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt: 1], @"0",
[NSNumber numberWithInt: 1], @"15",
[NSNumber numberWithInt: 1], @"30",
[NSNumber numberWithInt: 1], @"45",
nil];
[dayData setObject: hourData forKey: hourKey];
}
else
{
for (i = 0; i < 4; i++)
{
minuteKey = [NSString stringWithFormat: @"%u", i*15];
count = [[hourData objectForKey: minuteKey] intValue] + 1;
[hourData setObject: [NSNumber numberWithInt: count] forKey: minuteKey];
}
}
currentDate = [currentDate dateByAddingYears:0 months:0 days:0 hours:1 minutes:0 seconds:0];
}
// Increment counters for quarters of last hour
if ([currentEndDate timeIntervalSinceDate: currentDate] > 0)
{
hourKey = [NSString stringWithFormat: @"%u", [currentDate hourOfDay]];
hourData = [dayData objectForKey: hourKey];
if (!hourData)
{
hourData = [NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt: 0], @"0",
[NSNumber numberWithInt: 0], @"15",
[NSNumber numberWithInt: 0], @"30",
[NSNumber numberWithInt: 0], @"45",
nil];
[dayData setObject: hourData forKey: hourKey];
}
quarter = (int)([currentEndDate minuteOfHour] / 15 + 0.5);
for (i = 0; i < 4; i++)
{
if (i < quarter)
{
minuteKey = [NSString stringWithFormat: @"%u", i*15];
if (isResource)
count = [[hourData objectForKey: minuteKey] intValue] + 1;
else
count = 1;
[hourData setObject: [NSNumber numberWithInt: count] forKey: minuteKey];
}
}
} }
} }
} }
@ -183,88 +283,44 @@
if (maxBookings > 0) if (maxBookings > 0)
{ {
// Reset the freebusy for the periods that are bellow the maximum number of bookings // Reset the freebusy for the periods that are bellow the maximum number of bookings
for (count = 0; count < itemCount; count++) freeBusyList = [freeBusy objectEnumerator];
while ((dayData = [freeBusyList nextObject]))
{ {
if (*(items + count) < maxBookings) dayList = [dayData objectEnumerator];
*(items + count) = 0; while ((hourData = [dayList nextObject]))
else {
*(items + count) = 1; hourList = [hourData keyEnumerator];
while ((minuteKey = [hourList nextObject]))
{
count = [[hourData objectForKey: minuteKey] intValue];
if (count < maxBookings)
i = 0;
else
i = 1;
if (i != count)
[hourData setObject: [NSNumber numberWithInt: i] forKey: minuteKey];
}
}
} }
} }
} }
}
// return freeBusy;
//
//
- (NSString *) _freeBusyFromStartDate: (NSCalendarDate *) startDate
toEndDate: (NSCalendarDate *) endDate
forFreeBusy: (SOGoFreeBusyObject *) fb
andContact: (NSString *) uid
{
NSCalendarDate *start, *end;
NSMutableArray *freeBusy;
unsigned int *freeBusyItems;
NSTimeInterval interval;
unsigned int count, intervals;
// We "copy" the start/end date because -fetchFreeBusyInfosFrom will mess
// with the timezone and we don't want that to properly calculate the delta
// DO NOT USE -copy HERE - it'll simply return [self retain].
start = [NSCalendarDate dateWithYear: [startDate yearOfCommonEra]
month: [startDate monthOfYear]
day: [startDate dayOfMonth]
hour: [startDate hourOfDay]
minute: [startDate minuteOfHour]
second: [startDate secondOfMinute]
timeZone: [startDate timeZone]];
end = [NSCalendarDate dateWithYear: [endDate yearOfCommonEra]
month: [endDate monthOfYear]
day: [endDate dayOfMonth]
hour: [endDate hourOfDay]
minute: [endDate minuteOfHour]
second: [endDate secondOfMinute]
timeZone: [endDate timeZone]];
interval = [endDate timeIntervalSinceDate: startDate] + 60;
// Slices of 15 minutes. The +8 is to take into account that we can
// have a timezone change during the freebusy lookup. We have +4 at the
// beginning and +4 at the end.
intervals = interval / INTERVALSECONDS + PADDING;
// Build a bit string representation of the freebusy data for the period
freeBusyItems = calloc(intervals, sizeof (unsigned int));
[self _fillFreeBusyItems: (freeBusyItems+HALFPADDING)
count: (intervals-PADDING)
withRecords: [fb fetchFreeBusyInfosFrom: start to: end forContact: uid]
fromStartDate: startDate
toEndDate: endDate];
// Convert bit string to a NSArray. We also skip by the default the non-requested information.
freeBusy = [NSMutableArray arrayWithCapacity: intervals];
for (count = HALFPADDING; count < (intervals-HALFPADDING); count++)
{
[freeBusy addObject: [NSString stringWithFormat: @"%d", *(freeBusyItems + count)]];
}
free(freeBusyItems);
// Return a NSString representation
return [freeBusy componentsJoinedByString: @","];
} }
- (id <WOActionResults>) readFreeBusyAction - (id <WOActionResults>) readFreeBusyAction
{ {
WOResponse *response;
SOGoFreeBusyObject *freebusy; SOGoFreeBusyObject *freebusy;
NSCalendarDate *startDate, *endDate; NSCalendarDate *startDate, *endDate;
NSDictionary *jsonResponse;
NSString *queryDay, *uid; NSString *queryDay, *uid;
NSTimeZone *uTZ; NSTimeZone *uTZ;
SOGoUser *user; SOGoUser *user;
unsigned int httpStatus;
user = [context activeUser]; user = [context activeUser];
uTZ = [[user userDefaults] timeZone]; uTZ = [[user userDefaults] timeZone];
httpStatus = 200;
uid = [self queryParameterForKey: @"uid"]; uid = [self queryParameterForKey: @"uid"];
queryDay = [self queryParameterForKey: @"sday"]; queryDay = [self queryParameterForKey: @"sday"];
@ -281,28 +337,42 @@
inTimeZone: uTZ]; inTimeZone: uTZ];
if ([startDate earlierDate: endDate] == endDate) if ([startDate earlierDate: endDate] == endDate)
response = [self responseWithStatus: 403 {
andString: @"Start date is later than end date."]; httpStatus = 403;
jsonResponse = [NSDictionary dictionaryWithObjectsAndKeys:
@"failure", @"status",
@"Start date is later than end date.", @"message",
nil];
}
else else
{ {
freebusy = [self clientObject]; freebusy = [self clientObject];
response jsonResponse = [self _freeBusyFromStartDate: startDate
= [self responseWithStatus: 200 toEndDate: endDate
andString: [self _freeBusyFromStartDate: startDate forFreeBusy: freebusy
toEndDate: endDate andContact: uid];
forFreeBusy: freebusy
andContact: uid]];
} }
} }
else else
response = [self responseWithStatus: 403 {
andString: @"Invalid end date."]; httpStatus = 403;
jsonResponse = [NSDictionary dictionaryWithObjectsAndKeys:
@"failure", @"status",
@"Invalid end date.", @"message",
nil];
}
} }
else else
response = [self responseWithStatus: 403 {
andString: @"Invalid start date."]; httpStatus = 403;
jsonResponse = [NSDictionary dictionaryWithObjectsAndKeys:
@"failure", @"status",
@"Invalid start date.", @"message",
nil];
}
return response; return [self responseWithStatus: httpStatus
andJSONRepresentation: jsonResponse];
} }
- (NSString *) _logoutRedirectURL - (NSString *) _logoutRedirectURL