[CalendarServer-changes] [14565] CalendarServer/trunk
source_changes at macosforge.org
source_changes at macosforge.org
Wed Mar 11 16:50:22 PDT 2015
Revision: 14565
http://trac.calendarserver.org//changeset/14565
Author: cdaboo at apple.com
Date: 2015-03-11 16:50:22 -0700 (Wed, 11 Mar 2015)
Log Message:
-----------
Optimize addStructuredLocation and properly handle multiple locations.
Modified Paths:
--------------
CalendarServer/trunk/twistedcaldav/ical.py
CalendarServer/trunk/txdav/caldav/datastore/sql.py
CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py
Modified: CalendarServer/trunk/twistedcaldav/ical.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/ical.py 2015-03-11 23:43:31 UTC (rev 14564)
+++ CalendarServer/trunk/twistedcaldav/ical.py 2015-03-11 23:50:22 UTC (rev 14565)
@@ -1103,7 +1103,7 @@
"""
if isinstance(property, str):
- for property in self.properties(property):
+ for property in tuple(self.properties(property)):
self.removeProperty(property)
else:
self._pycalendar.removeProperty(property._pycalendar)
@@ -1120,7 +1120,7 @@
@type pname: C{str}
"""
- for property in self.properties(pname):
+ for property in tuple(self.properties(pname)):
self.removeProperty(property)
for component in self.subcomponents():
Modified: CalendarServer/trunk/txdav/caldav/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/sql.py 2015-03-11 23:43:31 UTC (rev 14564)
+++ CalendarServer/trunk/txdav/caldav/datastore/sql.py 2015-03-11 23:50:22 UTC (rev 14565)
@@ -3139,39 +3139,62 @@
X-APPLE-STRUCTURED-LOCATION property and update the LOCATION property
to contain the name and street address.
"""
+
+ cache = {}
dir = self.directoryService()
for sub in component.subcomponents():
+ locations = []
+ removed = False
for attendee in sub.getAllAttendeeProperties():
if attendee.parameterValue("CUTYPE") == "ROOM":
value = attendee.value()
- loc = yield dir.recordWithCalendarUserAddress(value)
- if loc is not None:
- uid = getattr(loc, "associatedAddress", "")
- if uid:
- addr = yield dir.recordWithUID(uid)
- if addr is not None:
- street = getattr(addr, "streetAddress", "")
- geo = getattr(addr, "geographicLocation", "")
- if street and geo:
- title = attendee.parameterValue("CN")
- params = {
- "X-ADDRESS": street,
- "X-APPLE-RADIUS": "71",
- "X-TITLE": title,
- }
- structured = Property(
- "X-APPLE-STRUCTURED-LOCATION",
- geo.encode("utf-8"), params=params,
- valuetype=Value.VALUETYPE_URI
- )
- sub.replaceProperty(structured)
- newLocProperty = Property(
- "LOCATION",
- "{0}\n{1}".format(title, street.encode("utf-8"))
- )
- sub.replaceProperty(newLocProperty)
+ # Cache record based data once per-attendee
+ if value not in cache:
+ cache[value] = None
+ loc = yield dir.recordWithCalendarUserAddress(value)
+ if loc is not None:
+ uid = getattr(loc, "associatedAddress", "")
+ if uid:
+ addr = yield dir.recordWithUID(uid)
+ if addr is not None:
+ street = getattr(addr, "streetAddress", "")
+ geo = getattr(addr, "geographicLocation", "")
+ if street and geo:
+ title = attendee.parameterValue("CN")
+ cache[value] = (street, geo, title,)
+ # Use the cached data if present
+ entry = cache[value]
+ if entry is not None:
+ street, geo, title = entry
+ params = {
+ "X-ADDRESS": street,
+ "X-APPLE-RADIUS": "71",
+ "X-TITLE": title,
+ }
+ structured = Property(
+ "X-APPLE-STRUCTURED-LOCATION",
+ geo.encode("utf-8"), params=params,
+ valuetype=Value.VALUETYPE_URI
+ )
+
+ # The first time we have any X- prop, remove all existing ones
+ if not removed:
+ sub.removeProperty("X-APPLE-STRUCTURED-LOCATION")
+ removed = True
+ sub.addProperty(structured)
+ locations.append("{0}\n{1}".format(title, street.encode("utf-8")))
+
+ # Update the LOCATION if X-'s were added
+ if locations:
+ newLocProperty = Property(
+ "LOCATION",
+ "; ".join(locations)
+ )
+ sub.replaceProperty(newLocProperty)
+
+
@inlineCallbacks
def decorateHostedStatus(self, component):
"""
@@ -3235,6 +3258,10 @@
internal_request=is_internal,
))
+ # Structured locations for organizer non-splits only
+ if scheduler.state == "organizer" and internal_state != ComponentUpdateState.SPLIT_OWNER:
+ yield self.addStructuredLocation(component)
+
# Group attendees - though not during a split
if scheduler.state == "organizer" and internal_state != ComponentUpdateState.SPLIT_OWNER:
changed = yield self.reconcileGroupAttendees(component, inserting)
@@ -3478,9 +3505,6 @@
# Default/duplicate alarms
self.processAlarms(component, inserting)
- # Process structured location
- yield self.addStructuredLocation(component)
-
# Process hosted status
if config.HostedStatus.Enabled:
yield self.decorateHostedStatus(component)
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py 2015-03-11 23:43:31 UTC (rev 14564)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py 2015-03-11 23:50:22 UTC (rev 14565)
@@ -2518,6 +2518,123 @@
@inlineCallbacks
+ def test_setComponent_structuredLocation_Multiple(self):
+ """
+ Verify multiple ROOM attendees result in multiple X-APPLE-STRUCTURED-LOCATION properties
+ added, as well as updated multi-valued LOCATION properties.
+ """
+
+ data = """BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//Apple Inc.//Mac OS X 10.9.1//EN
+BEGIN:VEVENT
+UID:561F5DBB-3F38-4B3A-986F-DD05CBAF554F
+DTSTART:20131211T164500Z
+DURATION:PT1H
+ATTENDEE;CN=Conference Room One;CUTYPE=ROOM;PARTSTAT=ACCEPTED;ROLE=REQ-PARTICIPAN
+ T;SCHEDULE-STATUS=2.0:urn:x-uid:room-addr-1
+ATTENDEE;CN=Conference Room Two;CUTYPE=ROOM;PARTSTAT=ACCEPTED;ROLE=REQ-PARTICIPAN
+ T;SCHEDULE-STATUS=2.0:urn:x-uid:room-addr-2
+ATTENDEE;CN=User 01;CUTYPE=INDIVIDUAL;EMAIL=user01 at example.com;PARTSTAT=AC
+ CEPTED:urn:x-uid:user01
+CREATED:20131211T221854Z
+DTSTAMP:20131211T230632Z
+ORGANIZER;CN=User 01;EMAIL=user01 at example.com:urn:x-uid:user01
+RRULE:FREQ=DAILY;COUNT=5
+SEQUENCE:8
+SUMMARY:locations
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+UID:561F5DBB-3F38-4B3A-986F-DD05CBAF554F
+RECURRENCE-ID:20131214T164500Z
+DTSTART:20131214T160000Z
+DURATION:PT1H
+ATTENDEE;CN=Conference Room Two;CUTYPE=ROOM;PARTSTAT=ACCEPTED;ROLE=REQ-PARTICIPAN
+ T;SCHEDULE-STATUS=2.0:urn:x-uid:room-addr-2
+ATTENDEE;CN=User 01;CUTYPE=INDIVIDUAL;EMAIL=user01 at example.com;PARTSTAT=AC
+ CEPTED:urn:x-uid:user01
+CREATED:20131211T221854Z
+DTSTAMP:20131211T230632Z
+ORGANIZER;CN=User 01;EMAIL=user01 at example.com:urn:x-uid:user01
+SEQUENCE:8
+SUMMARY:locations
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+ calendar = yield self.calendarUnderTest(name="calendar", home="user01")
+ yield calendar.createCalendarObjectWithName(
+ "structured.ics",
+ Component.fromString(data)
+ )
+
+ yield self.commit()
+
+ cobj = yield self.calendarObjectUnderTest(
+ name="structured.ics",
+ calendar_name="calendar",
+ home="user01"
+ )
+ comp = yield cobj.component()
+ components = list(comp.subcomponents())
+
+ # Check first component
+ locProp = components[0].getProperty("LOCATION")
+ self.assertEquals(
+ locProp.value(),
+ "Room with Address 1\n1 Infinite Loop, Cupertino, CA 95014; Room with Address 2\n2 Infinite Loop, Cupertino, CA 95014"
+ )
+ structProps = tuple(components[0].properties("X-APPLE-STRUCTURED-LOCATION"))
+ self.assertEqual(len(structProps), 2)
+ self.assertEquals(
+ set([structProp.value() for structProp in structProps]),
+ set(("geo:37.331741,-122.030333", "geo:37.332633,-122.030502",))
+ )
+
+ # Check second component
+ locProp = components[1].getProperty("LOCATION")
+ self.assertEquals(
+ locProp.value(),
+ "Room with Address 2\n2 Infinite Loop, Cupertino, CA 95014"
+ )
+ structProps = tuple(components[1].properties("X-APPLE-STRUCTURED-LOCATION"))
+ self.assertEqual(len(structProps), 1)
+ self.assertEquals(
+ structProps[0].value(),
+ "geo:37.332633,-122.030502"
+ )
+
+ yield self.commit()
+
+ cal = yield self.calendarUnderTest(
+ name="calendar",
+ home="room-addr-1"
+ )
+ cobjs = yield cal.calendarObjects()
+ self.assertEqual(len(cobjs), 1)
+ comp = yield cobjs[0].component()
+ components = list(comp.subcomponents())
+
+ # Check first component
+ locProp = components[0].getProperty("LOCATION")
+ self.assertEquals(
+ locProp.value(),
+ "Room with Address 1\n1 Infinite Loop, Cupertino, CA 95014; Room with Address 2\n2 Infinite Loop, Cupertino, CA 95014"
+ )
+ structProps = tuple(components[0].properties("X-APPLE-STRUCTURED-LOCATION"))
+ self.assertEqual(len(structProps), 2)
+ self.assertEquals(
+ set([structProp.value() for structProp in structProps]),
+ set(("geo:37.331741,-122.030333", "geo:37.332633,-122.030502",))
+ )
+
+ yield self.commit()
+
+
+ @inlineCallbacks
def test_setComponent_externalPrincipal(self):
"""
Verify attendees who are not locally hosted have X-APPLE-HOSTED-STATUS=EXTERNAL
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20150311/f62d655d/attachment-0001.html>
More information about the calendarserver-changes
mailing list