summaryrefslogtreecommitdiff
path: root/sublab_project/calendarium/tasks.py
blob: b6939b16fe9c7e6c0b8641e97a57a7a704742f15 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
"""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 calendarium.models import Event


class CalendariumImport(PeriodicTask):
    """Periodic task for importing calendar events.
    """
    run_every = timedelta(hours=1)
    ignore_result = True

    def flush(self, logger):
        """Flushes all previously imported events.
        """
        Event.objects.filter(source=Event.SOURCE_IMPORT).delete()
        logger.debug('Flushed all previously imported events.')

    def fetch_calendar(self, logger):
        """Fetches the calendar events and returns a icalendar.Calendar instance.
        """
        response = urllib2.urlopen(settings.CALENDARIUM_IMPORT_URL)
        logger.debug('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]] = event[fieldinfo[1]].format().encode("utf-8")
                    event_info[fieldinfo[0]] = event_info[fieldinfo[0]].decode("string-escape")
                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.
        """
        logger = self.get_logger(**kwargs)
        event_count = 0
        now = datetime.now()
        after = now - relativedelta(days=1)
        before = now + relativedelta(months=+2)
        logger.info('Importing events from %s to %s' % (after, before))
        try:
            calendar = self.fetch_calendar(logger)
            self.flush(logger)
            for event_info in self.get_events(calendar, after, before):
                event = Event.objects.create(**event_info)
                event_count += 1
                logger.debug('Added event "%s".' % event)
        except urllib2.URLError, error:
            logger.error(error)
        return 'Imported %d events.' % event_count