(feat) we now handle optional and non-required attendee states

pull/249/head
Ludovic Marcotte 2019-02-04 11:52:26 -05:00
parent 2901560df9
commit 249671543e
9 changed files with 79 additions and 14 deletions

3
NEWS
View File

@ -3,7 +3,8 @@
Enhancements
- [web] create card from sender or recipient address (#3002, #4610)
- [core] baseDN now accept dynamic domain values (#3685)
- [core] baseDN now accept dynamic domain values (#3685 - sponsored by iRedMail)
- [core] we now handle optional and non-required attendee states
Bug fixes
- [web] fixed all-day event dates with different timezone

View File

@ -62,3 +62,8 @@ vtodo_class2 = "(Confidential task)";
/* Resources */
"Cannot access resource: \"%{Cn} %{SystemEmail}\"" = "Cannot access resource: \"%{Cn} %{SystemEmail}\"";
"Maximum number of simultaneous bookings (%{NumberOfSimultaneousBookings}) reached for resource \"%{Cn} %{SystemEmail}\". The conflicting event is \"%{EventTitle}\", and starts on %{StartDate}." = "Maximum number of simultaneous bookings (%{NumberOfSimultaneousBookings}) reached for resource \"%{Cn} %{SystemEmail}\". The conflicting event is \"%{EventTitle}\", and starts on %{StartDate}.";
/* Participation role */
"Your participation is required to this event" = "Your participation is required to this event";
"Your participation is optional to this event" = "Your participation is optional to this event";
"Your participation is not required to this event" = "Your participation is not required to this event";

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2007-2016 Inverse inc.
Copyright (C) 2007-2019 Inverse inc.
This file is part of SOGo
@ -187,9 +187,17 @@
{
SOGoAppointmentObject *attendeeObject;
iCalCalendar *iCalendarToSave;
iCalPerson *attendee;
SOGoUser *user;
iCalendarToSave = nil;
user = [SOGoUser userWithLogin: theUID];
attendeeObject = [self _lookupEvent: [newEvent uid] forUID: theUID];
attendee = [newEvent userAsAttendee: user];
// If the atttende's role is NON-PARTICIPANT, we write nothing to its calendar
if ([[attendee role] caseInsensitiveCompare: @"NON-PARTICIPANT"] == NSOrderedSame)
return;
if ([newEvent recurrenceId])
{
@ -197,12 +205,11 @@
if ([attendeeObject isNew])
{
iCalEvent *ownerEvent;
SOGoUser *user;
// We check if the attendee that was added to a single occurence is
// present in the master component. If not, we create a calendar with
// a single event for the occurence.
ownerEvent = [[[newEvent parent] events] objectAtIndex: 0];
user = [SOGoUser userWithLogin: theUID];
if (![ownerEvent userAsAttendee: user])
{
@ -339,7 +346,7 @@
}
}
else
[self errorWithFormat: @"Unable to find event with UID %@ in %@'s calendar - skipping delete operation", nameInContainer, theUID];
[self errorWithFormat: @"Unable to find event with UID %@ in %@'s calendar - skipping delete operation. This can be normal for NON-PARTICIPANT attendees.", nameInContainer, theUID];
}
}
@ -1171,6 +1178,10 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
NSException *error;
BOOL addDelegate, removeDelegate;
// If the atttende's role is NON-PARTICIPANT, we write nothing to its calendar
if ([[attendee role] caseInsensitiveCompare: @"NON-PARTICIPANT"] == NSOrderedSame)
return;
error = nil;
eventObject = [self _lookupEvent: eventUID forUID: uid];

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2010-2012 Inverse
Copyright (C) 2010-2019 Inverse
This file is part of SOGo

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2006-2018 Inverse inc.
Copyright (C) 2006-2019 Inverse inc.
This file is part of SOGo.
@ -28,6 +28,7 @@
@class NSMutableDictionary;
@class NSString;
@class NSTimeZone;
@class iCalPerson;
@class iCalRepeatableEntityObject;
@class SOGoDateFormatter;
@ -46,6 +47,7 @@
NSCalendarDate *oldEndDate;
NSCalendarDate *newEndDate;
NSString *organizerName;
iCalPerson *currentAttendee;
NSMutableDictionary *values;
SOGoDateFormatter *dateFormatter;
}
@ -61,6 +63,9 @@
- (void) setOrganizerName: (NSString *) theString;
- (NSString *) organizerName;
- (void) setCurrentAttendee: (iCalPerson *) theAttendee;
- (iCalPerson *) currentAttendee;
- (NSCalendarDate *) oldStartDate;
- (NSCalendarDate *) newStartDate;

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2006-2013 Inverse inc.
Copyright (C) 2006-2019 Inverse inc.
Copyright (C) 2000-2005 SKYRIX Software AG
This file is part of SOGo.
@ -48,6 +48,8 @@
apt = nil;
values = nil;
dateFormatter = RETAIN([[context activeUser] dateFormatterInContext: context]);
organizerName = nil;
currentAttendee = nil;
}
return self;
@ -59,6 +61,7 @@
[apt release];
[previousApt release];
[organizerName release];
[currentAttendee release];
[viewTZ release];
[oldStartDate release];
[newStartDate release];
@ -164,6 +167,16 @@
return organizerName;
}
- (void) setCurrentAttendee: (iCalPerson *) theAttendee
{
ASSIGN(currentAttendee, theAttendee);
}
- (iCalPerson *) currentAttendee
{
return currentAttendee;
}
- (NSString *) sentByText
{
NSDictionary *sentByValues;
@ -293,4 +306,21 @@
return nil;
}
- (NSString *) getParticipationRole
{
if ([[currentAttendee role] caseInsensitiveCompare: @"OPT-PARTICIPANT"] == NSOrderedSame)
{
return [self labelForKey: @"Your participation is optional to this event"
inContext: context];
}
else if ([[currentAttendee role] caseInsensitiveCompare: @"NON-PARTICIPANT"] == NSOrderedSame)
{
return [self labelForKey: @"Your participation is not required to this event"
inContext: context];
}
return [self labelForKey: @"Your participation is required to this event"
inContext: context];
}
@end

View File

@ -1,6 +1,6 @@
/* SOGoCalendarComponent.m - this file is part of SOGo
*
* Copyright (C) 2006-2016 Inverse inc.
* Copyright (C) 2006-2019 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
@ -846,6 +846,7 @@
p = [app pageWithName: pageName inContext: context];
[p setApt: (iCalEvent *) object];
[p setPreviousApt: (iCalEvent *) previousObject];
[p setCurrentAttendee: attendee];
if ([[object organizer] cn] && [[[object organizer] cn] length])
{
@ -893,9 +894,10 @@
/* attach text part to multipart body */
[body addBodyPart: bodyPart];
/* attach calendar part to multipart body */
[body addBodyPart: eventBodyPart];
/* attach calendar part to multipart body only if the participation role is not NON-PARTICIPANT */
if ([[attendee role] caseInsensitiveCompare: @"NON-PARTICIPANT"] != NSOrderedSame)
[body addBodyPart: eventBodyPart];
/* attach multipart body to message */
[msg setBody: body];
[body release];

View File

@ -20,7 +20,12 @@ th, td { font-family: Lucida Grande, Bitstream VeraSans, Tahoma, sans-serif; fon
value="getSubject" const:escapeHTML="NO"/> <small style="font-size: 12px; color: #999;"><var:string
value="organizerName" const:escapeHTML="NO"/><var:string value="sentByText" const:escapeHTML="NO"/></small></h1></td>
</tr>
<var:if condition="location.length"
<tr>
<th></th>
<td><h1 style="font-size: 14px; font-weight: normal;
padding-bottom: 9px; border-bottom: 1px solid #ccc;"><var:string
value="getParticipationRole" const:escapeHTML="NO"/></h1></td>
</tr> <var:if condition="location.length"
><tr>
<th align="right" style="font-weight: bold;"><var:string label:value="location_label" const:escapeHTML="NO"/></th>
<td><var:string value="location" const:escapeHTML="NO"/></td>

View File

@ -20,6 +20,12 @@ th, td { font-family: Lucida Grande, Bitstream VeraSans, Tahoma, sans-serif; fon
value="getSubject" const:escapeHTML="NO"/> <small style="font-size: 12px; color: #999;"><var:string
value="organizerName" const:escapeHTML="NO"/><var:string value="sentByText" const:escapeHTML="NO"/></small></h1></td>
</tr>
<tr>
<th></th>
<td><h1 style="font-size: 14px; font-weight: normal;
padding-bottom: 9px; border-bottom: 1px solid #ccc;"><var:string
value="getParticipationRole" const:escapeHTML="NO"/></h1></td>
</tr>
<tr>
<th></th>
<td><var:string value="bodyStartText" const:escapeHTML="NO"/></td>