[CalendarServer-changes] [3257] CalendarServer/branches/users/sagen/localization-3218/twistedcaldav

source_changes at macosforge.org source_changes at macosforge.org
Wed Oct 29 10:51:37 PDT 2008


Revision: 3257
          http://trac.macosforge.org/projects/calendarserver/changeset/3257
Author:   sagen at apple.com
Date:     2008-10-29 10:51:37 -0700 (Wed, 29 Oct 2008)
Log Message:
-----------
Invites now have properly formatted organizer/attendee names and email addresses

Modified Paths:
--------------
    CalendarServer/branches/users/sagen/localization-3218/twistedcaldav/ical.py
    CalendarServer/branches/users/sagen/localization-3218/twistedcaldav/mail.py

Modified: CalendarServer/branches/users/sagen/localization-3218/twistedcaldav/ical.py
===================================================================
--- CalendarServer/branches/users/sagen/localization-3218/twistedcaldav/ical.py	2008-10-29 17:04:16 UTC (rev 3256)
+++ CalendarServer/branches/users/sagen/localization-3218/twistedcaldav/ical.py	2008-10-29 17:51:37 UTC (rev 3257)
@@ -1255,6 +1255,25 @@
 
         return results
 
+    def getAllAttendeeProperties(self):
+        """
+        Yield all attendees as Property objects.  Works on either a VCALENDAR or
+        on a component.
+        @return: a generator yielding Property objects
+        """
+
+        # Extract appropriate sub-component if this is a VCALENDAR
+        if self.name() == "VCALENDAR":
+            for component in self.subcomponents():
+                if component.name() != "VTIMEZONE":
+                    for attendee in component.getAllAttendeeProperties():
+                        yield attendee
+        else:
+            # Find the primary subcomponent
+            for attendee in self.properties("ATTENDEE"):
+                yield attendee
+
+
     def getMaskUID(self):
         """
         Get the X-CALENDARSEREVR-MASK-UID value. Works on either a VCALENDAR or on a component.

Modified: CalendarServer/branches/users/sagen/localization-3218/twistedcaldav/mail.py
===================================================================
--- CalendarServer/branches/users/sagen/localization-3218/twistedcaldav/mail.py	2008-10-29 17:04:16 UTC (rev 3256)
+++ CalendarServer/branches/users/sagen/localization-3218/twistedcaldav/mail.py	2008-10-29 17:51:37 UTC (rev 3257)
@@ -42,6 +42,7 @@
 from twistedcaldav.log import Logger, LoggingMixIn
 from twistedcaldav.resource import CalDAVResource
 from twistedcaldav.scheduling.scheduler import IMIPScheduler
+from twistedcaldav.scheduling.cuaddress import normalizeCUAddr
 from twistedcaldav.sql import AbstractSQLDatabase
 from twistedcaldav.localization import translationTo
 
@@ -663,7 +664,23 @@
         pre, post = serverAddress.split('@')
         addressWithToken = "%s+%s@%s" % (pre, token, post)
 
-        attendees = list(calendar.getAttendees())
+        attendees = []
+        for attendeeProp in calendar.getAllAttendeeProperties():
+            params = attendeeProp.params()
+            cutype = params.get('CUTYPE', (None,))[0]
+            if cutype == "INDIVIDUAL":
+                cn = params.get("CN", (None,))[0]
+                cuaddr = normalizeCUAddr(attendeeProp.value())
+                if cuaddr.startswith("mailto:"):
+                    mailto = cuaddr[7:]
+                    if not cn:
+                        cn = mailto
+                else:
+                    mailto = None
+
+                if cn or mailto:
+                    attendees.append( (cn, mailto) )
+
         calendar.getOrganizerProperty().setValue("mailto:%s" %
             (addressWithToken,))
 
@@ -676,11 +693,16 @@
         # address if available.  Otherwise it will be the server's email
         # address (without # + addressing)
         if organizer.startswith("mailto:"):
-            fromAddr = organizer[7:]
+            orgEmail = fromAddr = organizer[7:]
         else:
             fromAddr = serverAddress
-        cn = calendar.getOrganizerProperty().params().get('CN',
-            ['Calendar Server'])[0]
+            orgEmail = None
+        cn = calendar.getOrganizerProperty().params().get('CN', (None,))[0]
+        if cn is None:
+            cn = 'Calendar Server'
+            orgCN = orgEmail
+        else:
+            orgCN = cn
         formattedFrom = "%s <%s>" % (cn, fromAddr)
 
         # Reply-to address will be the server+token address
@@ -690,8 +712,9 @@
             raise ValueError("ATTENDEE address '%s' must be mailto: for iMIP operation." % (attendee,))
         attendee = attendee[7:]
 
-        msgId, message = self.generateEmail(calendar, organizer, attendees,
-            formattedFrom, addressWithToken, attendee, language=language)
+        msgId, message = self.generateEmail(calendar, orgEmail, orgCN,
+            attendees, formattedFrom, addressWithToken, attendee,
+            language=language)
 
         self.log_debug("Sending: %s" % (message,))
         def _success(result, msgId, fromAddr, toAddr):
@@ -709,11 +732,10 @@
         deferred.addErrback(_failure, msgId, fromAddr, toAddr)
 
 
-    def generateEmail(self, calendar, organizer, attendees, fromAddress,
+    def generateEmail(self, calendar, orgEmail, orgCN, attendees, fromAddress,
         replyToAddress, toAddress, language='en'):
 
-        details = self.getEventDetails(calendar, organizer, attendees,
-            language=language)
+        details = self.getEventDetails(calendar, language=language)
 
         with translationTo(language):
             msg = MIMEMultipart()
@@ -746,17 +768,31 @@
             details['attLabel'] = _("Attendees")
             details['locLabel'] = _("Location")
 
+
+            plainAttendeeList = []
+            for cn, mailto in attendees:
+                if cn:
+                    plainAttendeeList.append(cn if not mailto else
+                        "%s <%s>" % (cn, mailto))
+                elif mailto:
+                    plainAttendeeList.append("<%s>" % (mailto,))
+
+            details['plainAttendees'] = ", ".join(plainAttendeeList)
+
+            details['plainOrganizer'] = (orgCN if not orgEmail else
+                "%s <%s>" % (orgCN, orgEmail))
+
             # plain text version
             plainTemplate = u"""%(inviteLabel)s: %(summary)s
 
-%(orgLabel)s: %(organizerName)s %(organizerAddr)s
+%(orgLabel)s: %(plainOrganizer)s
 %(locLabel)s: %(location)s
 %(dateLabel)s: %(dateInfo)s
 %(timeLabel)s: %(timeInfo)s
 %(durationLabel)s: %(durationInfo)s
 %(recurrenceLabel)s: %(recurrenceInfo)s
 %(descLabel)s: %(description)s
-%(attLabel)s: %(attendees)s
+%(attLabel)s: %(plainAttendees)s
 """
 
             # TODO: work on cancellations
@@ -773,6 +809,23 @@
             msgHtmlRelated = MIMEMultipart("related", type="text/html")
             msgAlt.attach(msgHtmlRelated)
 
+
+            htmlAttendees = []
+            for cn, mailto in attendees:
+                if mailto:
+                    htmlAttendees.append('<a href="mailto:%s">%s</a>' %
+                        (mailto, cn))
+                else:
+                    htmlAttendees.append(cn)
+
+            details['htmlAttendees'] = ", ".join(htmlAttendees)
+
+            if orgEmail:
+                details['htmlOrganizer'] = '<a href="mailto:%s">%s</a>' % (
+                    orgEmail, orgCN)
+            else:
+                details['htmlOrganizer'] = orgCN
+
             htmlTemplate = u"""<html>
     <body><div>
     <img src="cid:ical.jpg"/>
@@ -781,7 +834,7 @@
 
     <h1>%(summary)s</h1>
     <p>
-    <h3>%(orgLabel)s:</h3> %(organizerName)s %(organizerAddr)s
+    <h3>%(orgLabel)s:</h3> %(htmlOrganizer)s
     </p>
     <p>
     <h3>%(locLabel)s:</h3> %(location)s
@@ -802,7 +855,7 @@
     <h3>%(descLabel)s:</h3> %(description)s
     </p>
     <p>
-    <h3>%(attLabel)s:</h3> %(attendees)s
+    <h3>%(attLabel)s:</h3> %(htmlAttendees)s
     </p>
 
     """
@@ -840,7 +893,7 @@
         return msgId, msg.as_string()
 
 
-    def getEventDetails(self, calendar, organizer, attendees, language='en'):
+    def getEventDetails(self, calendar, language='en'):
 
         # Get the most appropriate component
         component = calendar.masterComponent()
@@ -849,19 +902,6 @@
 
         results = { }
 
-        # The organizer in calendar has already been replaced with
-        # special token address
-        results['organizerAddr'] = organizer
-
-        organizerProp = component.getOrganizerProperty()
-        if "CN" in organizerProp.params():
-            results['organizerName'] = organizerProp.params()["CN"][0]
-        else:
-            results['organizerName'] = ''
-
-        # TODO: get attendee names if available
-        results['attendees'] = ", ".join(attendees)
-
         summary = component.propertyValue("SUMMARY")
         if summary is None:
             summary = ""
@@ -882,7 +922,7 @@
             results['timeInfo'], results['durationInfo'] = trans.time(component)
 
 
-            for propertyName in ("RRULE", "REDATE", "EXRULE", "EXDATE",
+            for propertyName in ("RRULE", "RDATE", "EXRULE", "EXDATE",
                 "RECURRENCE-ID"):
                 if component.hasProperty(propertyName):
                     results['recurrenceInfo'] = _("Repeating")
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20081029/89a21e96/attachment-0001.html>


More information about the calendarserver-changes mailing list