EventAggregator

Annotated EventAggregatorSupport/Resources.py

347:693940d48e8b
2013-04-30 Paul Boddie Split the EventAggregatorSupport code into separate modules within a common package.
paul@347 1
# -*- coding: iso-8859-1 -*-
paul@347 2
"""
paul@347 3
    MoinMoin - EventAggregator resource acquisition and access
paul@347 4
paul@347 5
    @copyright: 2008, 2009, 2010, 2011, 2012, 2013 by Paul Boddie <paul@boddie.org.uk>
paul@347 6
    @license: GNU GPL (v2 or later), see COPYING.txt for details.
paul@347 7
"""
paul@347 8
paul@347 9
from EventAggregatorSupport.Filter import *
paul@347 10
from EventAggregatorSupport.Types import *
paul@347 11
paul@347 12
from ContentTypeSupport import getContentTypeAndEncoding
paul@347 13
from DateSupport import Date, Month
paul@347 14
from MoinSupport import *
paul@347 15
from MoinRemoteSupport import getCachedResource
paul@347 16
paul@347 17
import codecs
paul@347 18
import urllib
paul@347 19
paul@347 20
try:
paul@347 21
    from cStringIO import StringIO
paul@347 22
except ImportError:
paul@347 23
    from StringIO import StringIO
paul@347 24
paul@347 25
try:
paul@347 26
    import vCalendar
paul@347 27
except ImportError:
paul@347 28
    vCalendar = None
paul@347 29
paul@347 30
# Obtaining event containers and events from such containers.
paul@347 31
paul@347 32
def getEventPages(pages):
paul@347 33
paul@347 34
    "Return a list of events found on the given 'pages'."
paul@347 35
paul@347 36
    # Get real pages instead of result pages.
paul@347 37
paul@347 38
    return map(EventPage, pages)
paul@347 39
paul@347 40
def getAllEventSources(request):
paul@347 41
paul@347 42
    "Return all event sources defined in the Wiki using the 'request'."
paul@347 43
paul@347 44
    sources_page = getattr(request.cfg, "event_aggregator_sources_page", "EventSourcesDict")
paul@347 45
paul@347 46
    # Remote sources are accessed via dictionary page definitions.
paul@347 47
paul@347 48
    return getWikiDict(sources_page, request)
paul@347 49
paul@347 50
def getEventResources(sources, calendar_start, calendar_end, request):
paul@347 51
paul@347 52
    """
paul@347 53
    Return resource objects for the given 'sources' using the given
paul@347 54
    'calendar_start' and 'calendar_end' to parameterise requests to the sources,
paul@347 55
    and the 'request' to access configuration settings in the Wiki.
paul@347 56
    """
paul@347 57
paul@347 58
    sources_dict = getAllEventSources(request)
paul@347 59
    if not sources_dict:
paul@347 60
        return []
paul@347 61
paul@347 62
    # Use dates for the calendar limits.
paul@347 63
paul@347 64
    if isinstance(calendar_start, Date):
paul@347 65
        pass
paul@347 66
    elif isinstance(calendar_start, Month):
paul@347 67
        calendar_start = calendar_start.as_date(1)
paul@347 68
paul@347 69
    if isinstance(calendar_end, Date):
paul@347 70
        pass
paul@347 71
    elif isinstance(calendar_end, Month):
paul@347 72
        calendar_end = calendar_end.as_date(-1)
paul@347 73
paul@347 74
    resources = []
paul@347 75
paul@347 76
    for source in sources:
paul@347 77
        try:
paul@347 78
            details = sources_dict[source].split()
paul@347 79
            url = details[0]
paul@347 80
            format = (details[1:] or ["ical"])[0]
paul@347 81
        except (KeyError, ValueError):
paul@347 82
            pass
paul@347 83
        else:
paul@347 84
            # Prevent local file access.
paul@347 85
paul@347 86
            if url.startswith("file:"):
paul@347 87
                continue
paul@347 88
paul@347 89
            # Parameterise the URL.
paul@347 90
            # Where other parameters are used, care must be taken to encode them
paul@347 91
            # properly.
paul@347 92
paul@347 93
            url = url.replace("{start}", urllib.quote_plus(calendar_start and str(calendar_start) or ""))
paul@347 94
            url = url.replace("{end}", urllib.quote_plus(calendar_end and str(calendar_end) or ""))
paul@347 95
paul@347 96
            # Get a parser.
paul@347 97
            # NOTE: This could be done reactively by choosing a parser based on
paul@347 98
            # NOTE: the content type provided by the URL.
paul@347 99
paul@347 100
            if format == "ical" and vCalendar is not None:
paul@347 101
                parser = vCalendar.parse
paul@347 102
                resource_cls = EventCalendar
paul@347 103
                required_content_type = "text/calendar"
paul@347 104
            else:
paul@347 105
                continue
paul@347 106
paul@347 107
            # Obtain the resource, using a cached version if appropriate.
paul@347 108
paul@347 109
            max_cache_age = int(getattr(request.cfg, "event_aggregator_max_cache_age", "300"))
paul@347 110
            data = getCachedResource(request, url, "EventAggregator", "wiki", max_cache_age)
paul@347 111
            if not data:
paul@347 112
                continue
paul@347 113
paul@347 114
            # Process the entry, parsing the content.
paul@347 115
paul@347 116
            f = StringIO(data)
paul@347 117
            try:
paul@347 118
                url = f.readline()
paul@347 119
paul@347 120
                # Get the content type and encoding, making sure that the data
paul@347 121
                # can be parsed.
paul@347 122
paul@347 123
                content_type, encoding = getContentTypeAndEncoding(f.readline())
paul@347 124
                if content_type != required_content_type:
paul@347 125
                    continue
paul@347 126
paul@347 127
                # Send the data to the parser.
paul@347 128
paul@347 129
                uf = codecs.getreader(encoding or "utf-8")(f)
paul@347 130
                try:
paul@347 131
                    resources.append(resource_cls(url, parser(uf)))
paul@347 132
                finally:
paul@347 133
                    uf.close()
paul@347 134
            finally:
paul@347 135
                f.close()
paul@347 136
paul@347 137
    return resources
paul@347 138
paul@347 139
def getEventsFromResources(resources):
paul@347 140
paul@347 141
    "Return a list of events supplied by the given event 'resources'."
paul@347 142
paul@347 143
    events = []
paul@347 144
paul@347 145
    for resource in resources:
paul@347 146
paul@347 147
        # Get all events described by the resource.
paul@347 148
paul@347 149
        for event in resource.getEvents():
paul@347 150
paul@347 151
            # Remember the event.
paul@347 152
paul@347 153
            events.append(event)
paul@347 154
paul@347 155
    return events
paul@347 156
paul@347 157
# Page-related functions.
paul@347 158
paul@347 159
def fillEventPageFromTemplate(template_page, new_page, event_details, category_pagenames):
paul@347 160
paul@347 161
    """
paul@347 162
    Using the given 'template_page', complete the 'new_page' by copying the
paul@347 163
    template and adding the given 'event_details' (a dictionary of event
paul@347 164
    fields), setting also the 'category_pagenames' to define category
paul@347 165
    membership.
paul@347 166
    """
paul@347 167
paul@347 168
    event_page = EventPage(template_page)
paul@347 169
    new_event_page = EventPage(new_page)
paul@347 170
    new_event_page.copyPage(event_page)
paul@347 171
paul@347 172
    if new_event_page.getFormat() == "wiki":
paul@347 173
        new_event = Event(new_event_page, event_details)
paul@347 174
        new_event_page.setEvents([new_event])
paul@347 175
        new_event_page.setCategoryMembership(category_pagenames)
paul@347 176
        new_event_page.flushEventDetails()
paul@347 177
paul@347 178
    return new_event_page.getBody()
paul@347 179
paul@347 180
# Event selection from request parameters.
paul@347 181
paul@347 182
def getEventsUsingParameters(category_names, search_pattern, remote_sources,
paul@347 183
    calendar_start, calendar_end, resolution, request):
paul@347 184
paul@347 185
    "Get the events according to the resolution of the calendar."
paul@347 186
paul@347 187
    if search_pattern:
paul@347 188
        results         = getPagesForSearch(search_pattern, request)
paul@347 189
    else:
paul@347 190
        results         = []
paul@347 191
paul@347 192
    results            += getAllCategoryPages(category_names, request)
paul@347 193
    pages               = getPagesFromResults(results, request)
paul@347 194
    events              = getEventsFromResources(getEventPages(pages))
paul@347 195
    events             += getEventsFromResources(getEventResources(remote_sources, calendar_start, calendar_end, request))
paul@347 196
    all_shown_events    = getEventsInPeriod(events, getCalendarPeriod(calendar_start, calendar_end))
paul@347 197
    earliest, latest    = getEventLimits(all_shown_events)
paul@347 198
paul@347 199
    # Get a concrete period of time.
paul@347 200
paul@347 201
    first, last = getConcretePeriod(calendar_start, calendar_end, earliest, latest, resolution)
paul@347 202
paul@347 203
    return all_shown_events, first, last
paul@347 204
paul@347 205
# vim: tabstop=4 expandtab shiftwidth=4