Source code for jmb.core.utils.ics

"""
.. _ics:

Send a calendar event
=====================

There are many different types of calendar events, distinguished by the 
method:

:PUBLISH_: when you just want to inform people of an event
:REQUEST_: when you require a response


example::

    info = dict(
       location='My location',
       dtstart=datetime(2008, 6, 2, 15, 30),
       dtend=datetime(2008, 6, 2, 24, 00),
       organizer=('adentella@thundersystems.it', 'Sandro Dentella')
    )
 
    msg = EmailMessageCalendar(title, summary, from_email, recipient_list)
    event = msg.get_event(info)
    msg.set_attendee(event, email2, full_name) # Required for ``REQUEST``
    msg.attach_calendar(event, 'PUBLISH')
    msg.send()
 

.. autoclass:: EmailMessageCalendar
   :members: get_event, attach_calendar, set_attendee, set_organizer


.. _PUBLISH: http://tools.ietf.org/html/rfc2446#section-3.2.1
.. _REQUEST: http://tools.ietf.org/html/rfc2446#section-3.2.2
"""


from __future__ import unicode_literals

import uuid
import email
import datetime as dt
import icalendar
import pytz

from django.utils import six
from django.core.mail.message import EmailMessage


[docs]class EmailMessageCalendar(EmailMessage): """An EmailMessage capable of creating a correct Ics attachment """ filename = "meeting.ics" # default properties for the event
[docs] def set_organizer(self, event, email, full_name=None): """Set the organizer of the meeting :arg email: the email :arg full_name: the full name """ organizer = icalendar.vCalAddress('MAILTO:%s' % email) organizer.params['cn'] = icalendar.vText(full_name) event['organizer'] = organizer
[docs] def set_attendee(self, event, email, full_name=None): """Set an attendee of the meeting. Required if method is ``REQUEST`` :arg email: the email :arg full_name: the full name """ attendee = icalendar.vCalAddress('MAILTO:%s' % email) if full_name: attendee.params['cn'] = icalendar.vText(full_name) attendee.params['ROLE'] = icalendar.vText('REQ-PARTICIPANT') event.add('attendee', attendee, encode=0)
[docs] def get_event(self, props=None, meth='PUBLISH'): """Return a basic event to be added to a calendar event. ``uuid`` and ``dtstamp`` are added by default if not present. ``attendee and `organizer`` can be eather email or tuple (email, common_name) and will be correctly adde using :meth:`set_organizer` and meth:`set_attendee`. :arg props: a dict of properties to be added to the event. read rfc_ to get more info on usable params :arg meth: the method of the calendar that will be created. Default: ``PUBLISH`` .. _rfc: http://tools.ietf.org/html/rfc2446#section-3.2.2 """ assert props or event, "An event or a dict of properties must be provided" tz = pytz.timezone("Europe/Rome") event = icalendar.Event() if not 'uuid' in props: props['uuid'] = uuid.uuid1().hex if not 'dtstamp' in props: props['dtstamp'] = tz.localize(dt.datetime.now()) for key, value in props.items(): if key.lower() == 'organizer': if isinstance(value, six.string_types): self.set_organizer(event, value) else: self.set_organizer(event, value[0], value[1] if len(value) > 1 else '') elif key.lower() == 'attendee': if isinstance(value, six.string_types): self.set_attendee(event, value) else: self.set_attendee(event, value[0], value[1:] if len(value) > 1 else '') else: event.add(key, value) return event
def create_ics_attachment(self, cal): part = email.MIMEBase.MIMEBase('text', "calendar", method="REQUEST", name=self.filename) part.set_payload(cal.to_ical()) #email.Encoders.encode_base64(part) email.Encoders.encode_7or8bit(part) part.add_header('Content-Description', self.filename) part.add_header("Content-class", "urn:content-classes:calendarmessage") part.add_header("Filename", self.filename) part.add_header("Path", self.filename) return part def get_calendar(self, meth): """Return an icalendar.Calendar containing event You may wish to customize this to add alarms or other events :arg event: the icalendar.Event :arg meth: the method declared in the calendar. Defaults to 'PUBLISH', You may prefere 'REQUEST' if you want a reply. It you use ``REQUEST`` you must add attendee """ cal = icalendar.Calendar() cal.add('prodid', '-//Jumbo framework//') cal.add('version', '2.0') cal.add('method', meth) return cal
[docs] def attach_calendar(self, events, meth='PUBLISH', calendar=None): """ Set a calendar """ calendar = calendar or self.get_calendar(meth) if not isinstance(events, (tuple, list, set)): events = [events] for event in events: calendar.add_component(event) part = self.create_ics_attachment(calendar) self.attach(part)