Monotone-Parent: 044582e9ad4ddb9d86e36c14f35c91195c979b7c
Monotone-Revision: 8f6b1948a4de37d255b2c1ab1d3f1baa780f455d Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2010-05-06T19:30:14 Monotone-Branch: ca.inverse.sogomaint-2.0.2
parent
861190b68f
commit
320e9256d1
26
ChangeLog
26
ChangeLog
|
@ -1,3 +1,29 @@
|
|||
2010-05-06 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
|
||||
* Tests/Integration/test-caldav-scheduling.py
|
||||
(CalDAVPropertiesTest): new class for testing caldav-specific
|
||||
properties
|
||||
(CalDAVPropertiesTest.testDavScheduleCalendarTransparency): new
|
||||
test method for testing "schedule-calendar-transp".
|
||||
|
||||
* UI/Scheduler/UIxCalendarProperties.m (-includeFreeBusy)
|
||||
(-setIncludeFreeBusy): new template accessors for the equivalent
|
||||
methods below.
|
||||
(-userIsOwner): new accessor that returns whether the current user
|
||||
is the calendar's owner.
|
||||
|
||||
* SoObjects/Appointments/SOGoFreeBusyObject.m
|
||||
(-fetchFreeBusyInfosFrom:to:): test whether the listed calendars
|
||||
must be included in the freebusy.
|
||||
|
||||
* SoObjects/Appointments/SOGoAppointmentFolder.m
|
||||
(-setIncludeInFreeBusy, -includeInFreeBusy): new accessors that
|
||||
determines whether the current calendar is included in the
|
||||
computing of its owner's freebusy.
|
||||
(-davScheduleCalendarTransparency)
|
||||
(-setDavScheduleCalendarTransparency:): equivalent DAV accessors
|
||||
for the above.
|
||||
|
||||
2010-05-05 Francis Lachapelle <flachapelle@inverse.ca>
|
||||
|
||||
* UI/WebServerResources/SchedulerUI.js (tasksListCallback):
|
||||
|
|
|
@ -7812,16 +7812,17 @@ Index: sope-appserver/NGObjWeb/DAVPropMap.plist
|
|||
===================================================================
|
||||
--- sope-appserver/NGObjWeb/DAVPropMap.plist (revision 1664)
|
||||
+++ sope-appserver/NGObjWeb/DAVPropMap.plist (working copy)
|
||||
@@ -157,6 +157,8 @@
|
||||
@@ -157,6 +157,9 @@
|
||||
"{urn:ietf:params:xml:ns:caldav}supported-calendar-data" =
|
||||
davSupportedCalendarDataTypes;
|
||||
"{urn:ietf:params:xml:ns:caldav}calendar-description" = davDescription;
|
||||
+ "{urn:ietf:params:xml:ns:caldav}calendar-timezone" = davCalendarTimeZone;
|
||||
+ "{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL" = davScheduleDefaultCalendarURL;
|
||||
+ "{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp" = davScheduleCalendarTransparency;
|
||||
|
||||
/* CardDAV */
|
||||
"{urn:ietf:params:xml:ns:carddav}addressbook-home-set" = davAddressbookHomeSet;
|
||||
@@ -168,6 +170,8 @@
|
||||
@@ -168,6 +171,8 @@
|
||||
"{http://calendarserver.org/ns/}dropbox-home-URL" = davDropboxHomeURL;
|
||||
"{http://calendarserver.org/ns/}notifications-URL" = davNotificationsURL;
|
||||
"{http://calendarserver.org/ns/}getctag" = davCollectionTag;
|
||||
|
|
|
@ -156,6 +156,9 @@ typedef enum {
|
|||
- (BOOL) synchronizeCalendar;
|
||||
- (void) setSynchronizeCalendar: (BOOL) new;
|
||||
|
||||
- (BOOL) includeInFreeBusy;
|
||||
- (void) setIncludeInFreeBusy: (BOOL) newInclude;
|
||||
|
||||
- (BOOL) importComponent: (iCalEntityObject *) event;
|
||||
- (int) importCalendar: (iCalCalendar *) calendar;
|
||||
|
||||
|
|
|
@ -396,6 +396,26 @@ static NSNumber *sharedYes = nil;
|
|||
inCategory: @"FolderSynchronize"];
|
||||
}
|
||||
|
||||
- (BOOL) includeInFreeBusy
|
||||
{
|
||||
NSNumber *excludeFromFreeBusy;
|
||||
|
||||
excludeFromFreeBusy
|
||||
= [self folderPropertyValueInCategory: @"FreeBusyExclusions"];
|
||||
|
||||
return ![excludeFromFreeBusy boolValue];
|
||||
}
|
||||
|
||||
- (void) setIncludeInFreeBusy: (BOOL) newInclude
|
||||
{
|
||||
NSNumber *excludeFromFreeBusy;
|
||||
|
||||
excludeFromFreeBusy = [NSNumber numberWithBool: !newInclude];
|
||||
|
||||
[self setFolderPropertyValue: excludeFromFreeBusy
|
||||
inCategory: @"FreeBusyExclusions"];
|
||||
}
|
||||
|
||||
/* selection */
|
||||
|
||||
- (NSArray *) calendarUIDs
|
||||
|
@ -2285,6 +2305,34 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
|
|||
return @"";
|
||||
}
|
||||
|
||||
- (NSArray *) davScheduleCalendarTransparency
|
||||
{
|
||||
const NSString *opacity;
|
||||
|
||||
opacity = ([self includeInFreeBusy] ? @"opaque" : @"transparent");
|
||||
|
||||
return [NSArray arrayWithObject: [NSArray arrayWithObjects: opacity,
|
||||
XMLNS_CALDAV,
|
||||
nil]];
|
||||
}
|
||||
|
||||
- (NSException *) setDavScheduleCalendarTransparency: (id) newName
|
||||
{
|
||||
NSException *error;
|
||||
|
||||
error = nil;
|
||||
|
||||
if ([newName rangeOfString: @"opaque"].location != NSNotFound)
|
||||
[self setIncludeInFreeBusy: YES];
|
||||
else if ([newName rangeOfString: @"transparent"].location != NSNotFound)
|
||||
[self setIncludeInFreeBusy: NO];
|
||||
else
|
||||
error = [NSException exceptionWithHTTPStatus: 400
|
||||
reason: @"Bad transparency value."];
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/* vevent UID handling */
|
||||
|
||||
- (NSString *) resourceNameForEventUID: (NSString *) uid
|
||||
|
|
|
@ -254,7 +254,7 @@
|
|||
for (count = 0; count < max; count++)
|
||||
{
|
||||
calFolder = [folders objectAtIndex: count];
|
||||
if (![calFolder isSubscription])
|
||||
if (![calFolder isSubscription] && [calFolder includeInFreeBusy])
|
||||
[infos addObjectsFromArray: [calFolder fetchFreeBusyInfosFrom: startDate
|
||||
to: endDate]];
|
||||
}
|
||||
|
|
|
@ -37,6 +37,88 @@ def fetchUserInfo(login):
|
|||
|
||||
return (displayName, email_nodes[0].childNodes[0].nodeValue)
|
||||
|
||||
class CalDAVPropertiesTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.client = webdavlib.WebDAVClient(hostname, port,
|
||||
username, password)
|
||||
self.test_calendar \
|
||||
= "/SOGo/dav/%s/Calendar/test-dav-properties/" % username
|
||||
mkcol = webdavlib.WebDAVMKCOL(self.test_calendar)
|
||||
self.client.execute(mkcol)
|
||||
|
||||
def tearDown(self):
|
||||
delete = webdavlib.WebDAVDELETE(self.test_calendar)
|
||||
self.client.execute(delete)
|
||||
|
||||
def testDavScheduleCalendarTransparency(self):
|
||||
"""{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp"""
|
||||
|
||||
## PROPFIND
|
||||
propfind = webdavlib.WebDAVPROPFIND(self.test_calendar,
|
||||
["{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp"],
|
||||
0)
|
||||
self.client.execute(propfind)
|
||||
propfind.xpath_namespace = { "D": "DAV:",
|
||||
"C": "urn:ietf:params:xml:ns:caldav" }
|
||||
propstats = propfind.xpath_evaluate('/D:multistatus/D:response/D:propstat/D:prop/C:schedule-calendar-transp')
|
||||
self.assertTrue(len(propstats) > 0,
|
||||
"schedule-calendar-transp not present in response")
|
||||
node = propstats[0]
|
||||
status = propfind.xpath_evaluate('D:status',
|
||||
node.parentNode.parentNode)[0] \
|
||||
.childNodes[0].nodeValue[9:12]
|
||||
self.assertEquals(status, "200",
|
||||
"schedule-calendar-transp marked as 'Not Found' in response")
|
||||
values = node.childNodes
|
||||
nvalues = len(values)
|
||||
self.assertEquals(nvalues, 1,
|
||||
"expected 1 value (%d received)" % nvalues)
|
||||
value = values[0]
|
||||
self.assertEquals(value.__class__.__name__, "Element",
|
||||
"schedule-calendar-transp must be an instance of" \
|
||||
" %s, not %s"
|
||||
% ("Element", value.__class__.__name__))
|
||||
self.assertEquals(value.namespaceURI, "urn:ietf:params:xml:ns:caldav",
|
||||
"schedule-calendar-transp must have a value in"\
|
||||
" namespace '%s', not '%s'"
|
||||
% ("urn:ietf:params:xml:ns:caldav",
|
||||
value.namespaceURI))
|
||||
self.assertTrue(value.tagName == "opaque",
|
||||
"schedule-calendar-transp must be 'opaque' on new" \
|
||||
" collections, not '%s'" % value.tagName)
|
||||
|
||||
## PROPPATCH
|
||||
newValueNode = "{urn:ietf:params:xml:ns:caldav}thisvaluedoesnotexist"
|
||||
proppatch = webdavlib.WebDAVPROPPATCH(self.test_calendar,
|
||||
{"{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp": \
|
||||
{ newValueNode: True }})
|
||||
self.client.execute(proppatch)
|
||||
self.assertEquals(proppatch.response["status"], 400,
|
||||
"expecting failure when setting transparency to" \
|
||||
" an invalid value")
|
||||
|
||||
newValueNode = "{urn:ietf:params:xml:ns:caldav}transparent"
|
||||
proppatch = webdavlib.WebDAVPROPPATCH(self.test_calendar,
|
||||
{"{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp": \
|
||||
{ newValueNode: True }})
|
||||
self.client.execute(proppatch)
|
||||
self.assertEquals(proppatch.response["status"], 207,
|
||||
"failure (%s) setting transparency to" \
|
||||
" 'transparent': '%s'"
|
||||
% (proppatch.response["status"],
|
||||
proppatch.response["body"]))
|
||||
|
||||
newValueNode = "{urn:ietf:params:xml:ns:caldav}opaque"
|
||||
proppatch = webdavlib.WebDAVPROPPATCH(self.test_calendar,
|
||||
{"{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp": \
|
||||
{ newValueNode: True }})
|
||||
self.client.execute(proppatch)
|
||||
self.assertEquals(proppatch.response["status"], 207,
|
||||
"failure (%s) setting transparency to" \
|
||||
" 'transparent': '%s'"
|
||||
% (proppatch.response["status"],
|
||||
proppatch.response["body"]))
|
||||
|
||||
class CalDAVITIPDelegationTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.client = webdavlib.WebDAVClient(hostname, port,
|
||||
|
|
|
@ -512,6 +512,8 @@ vtodo_class2 = "(Tarefa Confidencial)";
|
|||
"Name:" = "Nome:";
|
||||
"Color:" = "Cor:";
|
||||
|
||||
"Include in free-busy" = "Incluir na disponibilidade";
|
||||
|
||||
"Synchronization" = "Synchronization";
|
||||
"Synchronize" = "Synchronize";
|
||||
"Tag:" = "Marca:";
|
||||
|
|
|
@ -512,6 +512,8 @@ vtodo_class2 = "(Důvěrný úkol)";
|
|||
"Name:" = "Název:";
|
||||
"Color:" = "Barva:";
|
||||
|
||||
"Include in free-busy" = "Include in free-busy";
|
||||
|
||||
"Synchronization" = "Synchronizace";
|
||||
"Synchronize" = "Synchronizovat";
|
||||
"Tag:" = "Štítek:";
|
||||
|
|
|
@ -512,6 +512,8 @@ vtodo_class2 = "(Vertrouwelijke taak)";
|
|||
"Name:" = "Naam:";
|
||||
"Color:" = "Kleur:";
|
||||
|
||||
"Include in free-busy" = "In de beschikbaarheid insluiten";
|
||||
|
||||
"Synchronization" = "Synchronization";
|
||||
"Synchronize" = "Synchronize";
|
||||
"Tag:" = "Markering:";
|
||||
|
|
|
@ -512,6 +512,8 @@ vtodo_class2 = "(Confidential task)";
|
|||
"Name:" = "Name:";
|
||||
"Color:" = "Color:";
|
||||
|
||||
"Include in free-busy" = "Include in free-busy";
|
||||
|
||||
"Synchronization" = "Synchronization";
|
||||
"Synchronize" = "Synchronize";
|
||||
"Tag:" = "Tag:";
|
||||
|
|
|
@ -512,6 +512,8 @@ vtodo_class2 = "(Tâche confidentielle)";
|
|||
"Name:" = "Nom :";
|
||||
"Color:" = "Couleur :";
|
||||
|
||||
"Include in free-busy" = "Inclure dans la disponibilité";
|
||||
|
||||
"Synchronization" = "Synchronisation";
|
||||
"Synchronize" = "Synchroniser";
|
||||
"Tag:" = "Label :";
|
||||
|
@ -521,12 +523,12 @@ vtodo_class2 = "(Tâche confidentielle)";
|
|||
"Show tasks" = "Afficher les tâches";
|
||||
|
||||
/* Error messages */
|
||||
"dayFieldInvalid" = "Veuillez spécifier un chiffre superieur ou égal à 1 dans le champ Jours.";
|
||||
"weekFieldInvalid" = "Veuillez spécifier un chiffre superieur ou égal à 1 dans le champ Semaine(s).";
|
||||
"monthFieldInvalid" = "Veuillez spécifier un chiffre superieur ou égal à 1 dans le champ Mois.";
|
||||
"monthDayFieldInvalid" = "Veuillez spécifier un chiffre superieur ou égal à 1 dans la journée du mois.";
|
||||
"yearFieldInvalid" = "Veuillez spécifier un chiffre superieur ou égal à 1 dans le champ Année(s).";
|
||||
"appointmentFieldInvalid" = "Veuillez spécifier un chiffre superieur ou égal à 1 dans le champ rendez-vous.";
|
||||
"dayFieldInvalid" = "Veuillez spécifier un chiffre supérieur ou égal à 1 dans le champ Jours.";
|
||||
"weekFieldInvalid" = "Veuillez spécifier un chiffre supérieur ou égal à 1 dans le champ Semaine(s).";
|
||||
"monthFieldInvalid" = "Veuillez spécifier un chiffre supérieur ou égal à 1 dans le champ Mois.";
|
||||
"monthDayFieldInvalid" = "Veuillez spécifier un chiffre supérieur ou égal à 1 dans la journée du mois.";
|
||||
"yearFieldInvalid" = "Veuillez spécifier un chiffre supérieur ou égal à 1 dans le champ Année(s).";
|
||||
"appointmentFieldInvalid" = "Veuillez spécifier un chiffre supérieur ou égal à 1 dans le champ rendez-vous.";
|
||||
"recurrenceUnsupported" = "Ce type de récurrence n\\'est pas supporté.";
|
||||
"tagNotDefined" = "Vous devez spécifier un label si vous désirez synchroniser ce calendrier.";
|
||||
"tagAlreadyExists" = "Le label spécifié est déjà associé à un autre calendrier. Choisissez-en un autre.";
|
||||
|
|
|
@ -512,6 +512,8 @@ vtodo_class2 = "(Vertrauliche Aufgabe)";
|
|||
"Name:" = "Name:";
|
||||
"Color:" = "Farbe:";
|
||||
|
||||
"Include in free-busy" = "In der Verfügbarkeit einschließen";
|
||||
|
||||
"Synchronization" = "Synchronisation";
|
||||
"Synchronize" = "Synchronisieren";
|
||||
"Tag:" = "Tag:";
|
||||
|
|
|
@ -512,6 +512,8 @@ vtodo_class2 = "(Bizalmas feladat)";
|
|||
"Name:" = "Név:";
|
||||
"Color:" = "Szín:";
|
||||
|
||||
"Include in free-busy" = "Include in free-busy";
|
||||
|
||||
"Synchronization" = "Synchronization";
|
||||
"Synchronize" = "Synchronize";
|
||||
"Tag:" = "Cimke:";
|
||||
|
|
|
@ -512,6 +512,8 @@ vtodo_class2 = "(Attività confidenziale)";
|
|||
"Name:" = "Nome:";
|
||||
"Color:" = "Colore:";
|
||||
|
||||
"Include in free-busy" = "Include in free-busy";
|
||||
|
||||
"Synchronization" = "Synchronization";
|
||||
"Synchronize" = "Synchronize";
|
||||
"Tag:" = "Etichetta:";
|
||||
|
|
|
@ -512,6 +512,8 @@ vtodo_class2 = "(Confidential task)";
|
|||
"Name:" = "Название:";
|
||||
"Color:" = "Цвет:";
|
||||
|
||||
"Include in free-busy" = "Include in free-busy";
|
||||
|
||||
"Synchronization" = "Synchronization";
|
||||
"Synchronize" = "Synchronize";
|
||||
"Tag:" = "Tag:";
|
||||
|
|
|
@ -512,6 +512,8 @@ vtodo_class2 = "(Tarea confidencial)";
|
|||
"Name:" = "Nombre:";
|
||||
"Color:" = "Color:";
|
||||
|
||||
"Include in free-busy" = "Include in free-busy";
|
||||
|
||||
"Synchronization" = "Synchronization";
|
||||
"Synchronize" = "Synchronize";
|
||||
"Tag:" = "Redacción:";
|
||||
|
|
|
@ -512,6 +512,8 @@ vtodo_class2 = "(Konfidentiell uppgift)";
|
|||
"Name:" = "Namn:";
|
||||
"Color:" = "Färg:";
|
||||
|
||||
"Include in free-busy" = "Include in free-busy";
|
||||
|
||||
"Synchronization" = "Synkronisering";
|
||||
"Synchronize" = "Synkronisera";
|
||||
"Tag:" = "Etikett:";
|
||||
|
|
|
@ -70,6 +70,16 @@
|
|||
[calendar setCalendarColor: newColor];
|
||||
}
|
||||
|
||||
- (BOOL) includeInFreeBusy
|
||||
{
|
||||
return [calendar includeInFreeBusy];
|
||||
}
|
||||
|
||||
- (void) setIncludeInFreeBusy: (BOOL) newInclude
|
||||
{
|
||||
[calendar setIncludeInFreeBusy: newInclude];
|
||||
}
|
||||
|
||||
- (BOOL) synchronizeCalendar
|
||||
{
|
||||
return [self mustSynchronize] || [calendar synchronizeCalendar];
|
||||
|
@ -177,6 +187,15 @@
|
|||
return rc;
|
||||
}
|
||||
|
||||
- (BOOL) userIsOwner
|
||||
{
|
||||
NSString *userLogin;
|
||||
|
||||
userLogin = [[context activeUser] login];
|
||||
|
||||
return ([userLogin isEqualToString: [calendar ownerInContext: context]]);
|
||||
}
|
||||
|
||||
- (BOOL) isWebCalendar
|
||||
{
|
||||
return ([calendar isKindOfClass: [SOGoWebAppointmentFolder class]]);
|
||||
|
|
|
@ -512,6 +512,8 @@ vtodo_class2 = "(Tasg gyhoeddus)";
|
|||
"Name:" = "Enw:";
|
||||
"Color:" = "Lliw:";
|
||||
|
||||
"Include in free-busy" = "Include in free-busy";
|
||||
|
||||
"Synchronization" = "Synchronization";
|
||||
"Synchronize" = "Synchronize";
|
||||
"Tag:" = "Tag:";
|
||||
|
|
|
@ -37,6 +37,16 @@
|
|||
id="calendarColor"
|
||||
var:value="calendarColor"
|
||||
/></span></div>
|
||||
<var:if condition="userIsOwner"
|
||||
><div
|
||||
><label><input type="checkbox" const:class="checkBox"
|
||||
name="includeInFreeBusy"
|
||||
id="includeInFreeBusy"
|
||||
var:checked="includeInFreeBusy"
|
||||
/><var:string label:value="Include in free-busy"
|
||||
/></label
|
||||
></div
|
||||
></var:if>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend><var:string label:value="Synchronization"/></legend>
|
||||
|
|
|
@ -2167,6 +2167,10 @@ function onCalendarModify(event) {
|
|||
isWebCalendar = true;
|
||||
}
|
||||
}
|
||||
var owner = selected.getAttribute("owner");
|
||||
if (owner == UserLogin) {
|
||||
height += 24;
|
||||
}
|
||||
if (isWebCalendar)
|
||||
height += 41;
|
||||
else if (calendarID == "/personal")
|
||||
|
|
Loading…
Reference in New Issue