"""Celery tasks. """ from datetime import datetime, timedelta from dateutil.relativedelta import relativedelta import urllib2 from celery.task import PeriodicTask from django.conf import settings from dateutil.rrule import rrulestr import icalendar from models import Event class CalendariumImport(PeriodicTask): """Periodic task for importing calendar events. """ run_every = timedelta(hours=1) ignore_result = True def flush(self): """Flushes all previously imported events. """ Event.objects.filter(source=Event.SOURCE_IMPORT).delete() self.logger.info('Flushed all previously imported events.') def fetch_calendar(self): """Fetches the calendar events and returns a icalendar.Calendar instance. """ response = urllib2.urlopen(settings.CALENDARIUM_IMPORT_URL) self.logger.info('Fetched calendar from %s' % settings.CALENDARIUM_IMPORT_URL) return icalendar.Calendar.from_string(response.read()) def get_events(self, calendar, after, before): """Yields all events in calendar as dictionary. Only events after (including) after will be shown. Recurring events til before (inclusively) will be shown. """ for event in calendar.walk('vevent'): event_fields = [ # dest, src, default ('name', 'summary', 'unknown Event'), ('description', 'description', ''), ] event_info = {} for fieldinfo in event_fields: try: event_info[fieldinfo[0]] = str(event[fieldinfo[1]]) except KeyError: event_info[fieldinfo[0]] = fieldinfo[2] start = icalendar.vDatetime.from_ical(event['dtstart'].ical()) end = icalendar.vDatetime.from_ical(event['dtend'].ical()) if 'rrule' in event: rrule = rrulestr(event['rrule'].ical(), dtstart=start) duration = end - start for occurence in rrule.between(after, before, True): event_info['start'] = occurence event_info['end'] = occurence + duration yield event_info else: if start >= after: event_info['start'] = start event_info['end'] = end yield event_info def run(self, **kwargs): """Imports all events. """ self.logger = self.get_logger(**kwargs) now = datetime.now() after = now - relativedelta(days=1) before = now + relativedelta(months=+2) self.logger.info('Importing events from %s to %s' % (after, before)) try: calendar = self.fetch_calendar() self.flush() for event_info in self.get_events(calendar, after, before): event = Event.objects.create(**event_info) self.logger.info('Added event "%s".' % event) except urllib2.URLError, error: self.logger.error(error)