Project

General

Profile

Download (8.74 KB) Statistics
| Branch: | Tag: | Revision:

root / extra / modules / events.py @ 2750dbae

1 fa229320 Frédéric Péters
import time
2
import datetime
3 e9618ee5 Frédéric Péters
import urllib2
4
import vobject
5 fa229320 Frédéric Péters
6 587ad081 Frédéric Péters
from quixote import get_request, get_publisher, get_response
7 2e24fab0 Frédéric Péters
from quixote.html import htmltext, TemplateIO, htmlescape
8 32791ec9 Frédéric Péters
9 e9618ee5 Frédéric Péters
from qommon.publisher import get_publisher_class
10 9c8e4e26 Frédéric Péters
from qommon.storage import StorableObject
11 e9618ee5 Frédéric Péters
from qommon.cron import CronJob
12 fa229320 Frédéric Péters
from qommon import misc
13 9c8e4e26 Frédéric Péters
14
class Event(StorableObject):
15
    _names = 'events'
16
17
    title = None
18
    description = None
19
    url = None
20
    date_start = None
21
    date_end = None
22 689b3329 Frédéric Péters
    location = None
23
    organizer = None
24
    more_infos = None
25 587ad081 Frédéric Péters
    keywords = None
26 9c8e4e26 Frédéric Péters
27 fa229320 Frédéric Péters
    def in_month(self, year, month):
28
        if not self.date_end: # a single date
29
            return tuple(self.date_start[:2]) == (year, month)
30
        else:
31
            # an interval
32
            if tuple(self.date_start[:2]) > (year, month): # start later
33
                return False
34
            if tuple(self.date_end[:2]) < (year, month): # ended before
35
                return False
36
        return True
37
38 c6ebe114 Frédéric Péters
    def after_today(self):
39
        today = time.localtime()[:3]
40
        if not self.date_end:
41
            return tuple(self.date_start[:3]) > today
42
        return tuple(self.date_end[:3]) > today
43
44 fa229320 Frédéric Péters
    def format_date(self):
45
        d = {
46
            'year_start': self.date_start[0],
47
            'month_start': misc.get_month_name(self.date_start[1]),
48
            'day_start': self.date_start[2]
49
            }
50 e9618ee5 Frédéric Péters
        if self.date_end and self.date_start[:3] != self.date_end[:3]:
51 fa229320 Frédéric Péters
            d.update({
52
                'year_end': self.date_end[0],
53
                'month_end': misc.get_month_name(self.date_end[1]),
54
                'day_end': self.date_end[2]
55
                })
56 689b3329 Frédéric Péters
            d2 = datetime.date(*self.date_start[:3]) + datetime.timedelta(days=1)
57
            if tuple(self.date_end[:3]) == (d2.year, d2.month, d2.day):
58
                # two consecutive days
59 fa229320 Frédéric Péters
                if self.date_start[1] == self.date_end[1]:
60
                    return _('On %(month_start)s %(day_start)s and %(day_end)s') % d
61
                else:
62
                    return _('On %(month_start)s %(day_start)s and %(month_end)s %(day_end)s') % d
63
            else:
64
                if self.date_start[0] == self.date_end[0]: # same year
65
                    if self.date_start[1] == self.date_end[1]: # same month
66
                        return _('From %(month_start)s %(day_start)s to %(day_end)s') % d
67
                    else:
68
                        return _('From %(month_start)s %(day_start)s '
69
                                 'to %(month_end)s %(day_end)s') % d
70
                else:
71
                    return _('From %(month_start)s %(day_start)s %(year_start)s '
72
                             'to %(month_end)s %(day_end)s %(year_end)s') % d
73
        else:
74
            return _('On %(month_start)s %(day_start)s') % d
75 32791ec9 Frédéric Péters
76
    def as_vevent(self):
77 5c42eb84 Frédéric Péters
        vevent = vobject.newFromBehavior('vevent')
78 8f5cf58d Frédéric Péters
        site_charset = get_publisher().site_charset
79 5c42eb84 Frédéric Péters
        vevent.add('uid').value = '%04d%02d%02d-%s@%s' % (self.date_start[:3] + (self.id,
80
            get_request().get_server().lower().split(':')[0].rstrip('.')))
81 8f5cf58d Frédéric Péters
        vevent.add('summary').value = unicode(self.title, site_charset)
82 5c42eb84 Frédéric Péters
        vevent.add('dtstart').value = datetime.date(*self.date_start[:3])
83
        vevent.dtstart.value_param = 'DATE'
84 32791ec9 Frédéric Péters
        if self.date_end:
85 5c42eb84 Frédéric Péters
            vevent.add('dtend').value = datetime.date(*self.date_end[:3])
86
            vevent.dtend.value_param = 'DATE'
87 32791ec9 Frédéric Péters
        if self.description:
88 8f5cf58d Frédéric Péters
            vevent.add('description').value = unicode(self.description.strip(), site_charset)
89 5c42eb84 Frédéric Péters
        if self.url:
90 8f5cf58d Frédéric Péters
            vevent.add('url').value = unicode(self.url, site_charset)
91 689b3329 Frédéric Péters
        if self.location:
92 8f5cf58d Frédéric Péters
            vevent.add('location').value = unicode(self.location, site_charset)
93 689b3329 Frédéric Péters
        if self.organizer:
94 8f5cf58d Frédéric Péters
            vevent.add('organizer').value = unicode(self.organizer, site_charset)
95 587ad081 Frédéric Péters
        if self.keywords:
96 3f63f609 Frédéric Péters
            vevent.add('categories').value = [unicode(x, site_charset) for x in self.keywords]
97 5c42eb84 Frédéric Péters
        vevent.add('class').value = 'PUBLIC'
98
        return vevent
99 32791ec9 Frédéric Péters
100
    def as_vcalendar(cls):
101 5c42eb84 Frédéric Péters
        cal = vobject.iCalendar()
102
        cal.add('prodid').value = '-//Entr\'ouvert//NON SGML Au Quotidien'
103
        for x in cls.select():
104
            cal.add(x.as_vevent())
105
        return cal.serialize()
106 32791ec9 Frédéric Péters
    as_vcalendar = classmethod(as_vcalendar)
107 587ad081 Frédéric Péters
    
108
    def as_html_dt_dd(self):
109
        root_url = get_publisher().get_root_url()
110
        r = TemplateIO(html=True)
111
        r += htmltext('<dt>')
112
        r += self.format_date()
113
        r += htmltext('</dt>')
114
        r += htmltext('<p><dd><strong>%s</strong>') % self.title
115
        if self.description:
116
            r += ' - ' + self.description
117
        r += htmltext('</p>')
118
        if (self.location or self.organizer or self.more_infos or self.keywords):
119
            r += htmltext('<ul>')
120
            if self.location:
121
                r += htmltext('<li>%s: %s</li>') % (_('Location'), self.location)
122
            if self.organizer:
123
                r += htmltext('<li>%s: %s</li>') % (_('Organizer'), self.organizer)
124
            if self.more_infos:
125
                r += htmltext('<li>%s</li>') % self.more_infos
126
            if self.keywords:
127
                r += htmltext('<li>')
128
                for k in self.keywords:
129 e048398f Frédéric Péters
                    r += htmltext('<a class="tag" href="%sagenda/tag/%s">%s</a> ') % (root_url, k, k)
130 587ad081 Frédéric Péters
                r += htmltext('</li>')
131
            r += htmltext('</ul>')
132
133
        if self.url:
134
            if get_response().iframe_mode:
135
                r += htmltext('<a class="external" href="%s" target="_top">%s</a>') % (
136
                        self.url, _('More information'))
137
            else:
138
                r += htmltext('<a class="external" href="%s">%s</a>') % (
139
                        self.url, _('More information'))
140
        r += htmltext('</dd>')
141
        return r.getvalue()
142
143 2e24fab0 Frédéric Péters
    def get_url(self):
144
        from quixote import get_request
145
        return '%s://%s%sagenda/events/%s/' % (
146
                get_request().get_scheme(), get_request().get_server(),
147
                get_publisher().get_root_url(), self.id)
148 587ad081 Frédéric Péters
149
150 2e24fab0 Frédéric Péters
    def get_atom_entry(self):
151
        from pyatom import pyatom
152
        entry = pyatom.Entry()
153
        entry.id = self.get_url()
154
        entry.title = self.title
155
156
        entry.content.attrs['type'] = 'html'
157
        entry.content.text = str('<p>' + htmlescape(
158
                    unicode(self.description, get_publisher().site_charset).encode('utf-8')) + '</p>')
159
160
        return entry
161 32791ec9 Frédéric Péters
162 e9618ee5 Frédéric Péters
163 922ddfc0 Frédéric Péters
class RemoteCalendar(StorableObject):
164
    _names = 'remote_calendars'
165 e9618ee5 Frédéric Péters
166
    label = None
167
    url = None
168
    content = None
169
    events = None
170 922ddfc0 Frédéric Péters
    error = None  # (time, string, params)
171 e9618ee5 Frédéric Péters
172 3abf4120 Frédéric Péters
    def download_and_parse(self, job=None):
173 e9618ee5 Frédéric Péters
        old_content = self.content
174
175 0cef6aec Frédéric Péters
        try:
176
            self.content = urllib2.urlopen(self.url).read()
177
        except urllib2.HTTPError, e:
178
            self.error = (time.localtime(), N_('HTTP Error %s on download'), (e.code,))
179
            self.store()
180
            return
181
        except urllib2.URLError, e:
182
            self.error = (time.localtime(), N_('Error on download'), ())
183
            self.store()
184
            return
185 c24322d1 Frédéric Péters
186 0cef6aec Frédéric Péters
        if self.error:
187
            self.error = None
188
            self.store()
189 e9618ee5 Frédéric Péters
190
        if self.content == old_content:
191
            return
192
193
        self.events = []
194 c24322d1 Frédéric Péters
        try:
195
            parsed_cal = vobject.readOne(self.content)
196
        except vobject.base.ParseError:
197 9ac7b14f Frédéric Péters
            self.error = (time.localtime(), N_('Failed to parse file'), ())
198 c24322d1 Frédéric Péters
            self.store()
199
            return
200
201 8f5cf58d Frédéric Péters
        site_charset = get_publisher().site_charset
202 e9618ee5 Frédéric Péters
        for vevent in parsed_cal.vevent_list:
203
            ev = Event()
204 0bb23ca5 Frédéric Péters
            ev.title = vevent.summary.value.encode(site_charset, 'replace')
205 e9618ee5 Frédéric Péters
            try:
206 0bb23ca5 Frédéric Péters
                ev.url = vevent.url.value.encode(site_charset, 'replace')
207 e9618ee5 Frédéric Péters
            except AttributeError:
208
                pass
209
            ev.date_start = vevent.dtstart.value.timetuple()
210 f28e21cc Frédéric Péters
            try:
211
                ev.date_end = vevent.dtend.value.timetuple()
212
            except AttributeError:
213
                pass
214 e9618ee5 Frédéric Péters
            try:
215 0bb23ca5 Frédéric Péters
                ev.description = vevent.description.value.encode(site_charset, 'replace')
216 e9618ee5 Frédéric Péters
            except AttributeError:
217
                pass
218 f01b9a49 Frédéric Péters
            try:
219 e048398f Frédéric Péters
                ev.keywords = [x.encode(site_charset) for x in vevent.categories.value]
220 f01b9a49 Frédéric Péters
            except AttributeError:
221
                pass
222 e9618ee5 Frédéric Péters
            self.events.append(ev)
223
        self.store()
224
225 922ddfc0 Frédéric Péters
        
226
    def get_error_message(self):
227
        if not self.error:
228
            return None
229
        return '(%s) %s' % (misc.localstrftime(self.error[0]),
230
                _(self.error[1]) % self.error[2])
231
232
233
def update_remote_calendars(publisher):
234
    for source in RemoteCalendar.select():
235 e9618ee5 Frédéric Péters
        source.download_and_parse()
236
237 587ad081 Frédéric Péters
def get_default_event_tags():
238
    return [_('All Public'), _('Adults'), _('Children'), _('Free')]
239
240 922ddfc0 Frédéric Péters
get_publisher_class().register_cronjob(CronJob(update_remote_calendars, minutes = [0]))