Projet

Général

Profil

Télécharger (8,63 ko) Statistiques
| Branche: | Tag: | Révision:

root / auquotidien / modules / events.py @ 8b02623d

1
import time
2
import datetime
3
import urllib2
4
import vobject
5

    
6
from quixote import get_request, get_publisher, get_response
7
from quixote.html import htmltext, TemplateIO, htmlescape
8

    
9
from qommon import _
10
from qommon.publisher import get_publisher_class
11
from qommon.storage import StorableObject
12
from qommon.cron import CronJob
13
from qommon import misc
14

    
15
class Event(StorableObject):
16
    _names = 'events'
17

    
18
    title = None
19
    description = None
20
    url = None
21
    date_start = None
22
    date_end = None
23
    location = None
24
    organizer = None
25
    more_infos = None
26
    keywords = None
27

    
28
    def in_month(self, year, month):
29
        if not self.date_end: # a single date
30
            return tuple(self.date_start[:2]) == (year, month)
31
        else:
32
            # an interval
33
            if tuple(self.date_start[:2]) > (year, month): # start later
34
                return False
35
            if tuple(self.date_end[:2]) < (year, month): # ended before
36
                return False
37
        return True
38

    
39
    def after_today(self):
40
        today = time.localtime()[:3]
41
        if not self.date_end:
42
            return tuple(self.date_start[:3]) > today
43
        return tuple(self.date_end[:3]) > today
44

    
45
    def format_date(self):
46
        d = {
47
            'year_start': self.date_start[0],
48
            'month_start': misc.get_month_name(self.date_start[1]),
49
            'day_start': self.date_start[2]
50
            }
51
        if self.date_end and self.date_start[:3] != self.date_end[:3]:
52
            d.update({
53
                'year_end': self.date_end[0],
54
                'month_end': misc.get_month_name(self.date_end[1]),
55
                'day_end': self.date_end[2]
56
                })
57
            d2 = datetime.date(*self.date_start[:3]) + datetime.timedelta(days=1)
58
            if tuple(self.date_end[:3]) == (d2.year, d2.month, d2.day):
59
                # two consecutive days
60
                if self.date_start[1] == self.date_end[1]:
61
                    return _('On %(month_start)s %(day_start)s and %(day_end)s') % d
62
                else:
63
                    return _('On %(month_start)s %(day_start)s and %(month_end)s %(day_end)s') % d
64
            else:
65
                if self.date_start[0] == self.date_end[0]: # same year
66
                    if self.date_start[1] == self.date_end[1]: # same month
67
                        return _('From %(month_start)s %(day_start)s to %(day_end)s') % d
68
                    else:
69
                        return _('From %(month_start)s %(day_start)s '
70
                                 'to %(month_end)s %(day_end)s') % d
71
                else:
72
                    return _('From %(month_start)s %(day_start)s %(year_start)s '
73
                             'to %(month_end)s %(day_end)s %(year_end)s') % d
74
        else:
75
            return _('On %(month_start)s %(day_start)s') % d
76

    
77
    def as_vevent(self):
78
        vevent = vobject.newFromBehavior('vevent')
79
        site_charset = get_publisher().site_charset
80
        vevent.add('uid').value = '%04d%02d%02d-%s@%s' % (self.date_start[:3] + (self.id,
81
            get_request().get_server().lower().split(':')[0].rstrip('.')))
82
        vevent.add('summary').value = unicode(self.title, site_charset)
83
        vevent.add('dtstart').value = datetime.date(*self.date_start[:3])
84
        vevent.dtstart.value_param = 'DATE'
85
        if self.date_end:
86
            vevent.add('dtend').value = datetime.date(*self.date_end[:3])
87
            vevent.dtend.value_param = 'DATE'
88
        if self.description:
89
            vevent.add('description').value = unicode(self.description.strip(), site_charset)
90
        if self.url:
91
            vevent.add('url').value = unicode(self.url, site_charset)
92
        if self.location:
93
            vevent.add('location').value = unicode(self.location, site_charset)
94
        if self.organizer:
95
            vevent.add('organizer').value = unicode(self.organizer, site_charset)
96
        if self.keywords:
97
            vevent.add('categories').value = [unicode(x, site_charset) for x in self.keywords]
98
        vevent.add('class').value = 'PUBLIC'
99
        return vevent
100

    
101
    def as_vcalendar(cls):
102
        cal = vobject.iCalendar()
103
        cal.add('prodid').value = '-//Entr\'ouvert//NON SGML Publik'
104
        for x in cls.select():
105
            cal.add(x.as_vevent())
106
        return cal.serialize()
107
    as_vcalendar = classmethod(as_vcalendar)
108
    
109
    def as_html_dt_dd(self):
110
        root_url = get_publisher().get_root_url()
111
        r = TemplateIO(html=True)
112
        r += htmltext('<dt>')
113
        r += self.format_date()
114
        r += htmltext('</dt>')
115
        r += htmltext('<p><dd><strong>%s</strong>') % self.title
116
        if self.description:
117
            r += ' - ' + self.description
118
        r += htmltext('</p>')
119
        if (self.location or self.organizer or self.more_infos or self.keywords):
120
            r += htmltext('<ul>')
121
            if self.location:
122
                r += htmltext('<li>%s: %s</li>') % (_('Location'), self.location)
123
            if self.organizer:
124
                r += htmltext('<li>%s: %s</li>') % (_('Organizer'), self.organizer)
125
            if self.more_infos:
126
                r += htmltext('<li>%s</li>') % self.more_infos
127
            if self.keywords:
128
                r += htmltext('<li>')
129
                for k in self.keywords:
130
                    r += htmltext('<a class="tag" href="%sagenda/tag/%s">%s</a> ') % (root_url, k, k)
131
                r += htmltext('</li>')
132
            r += htmltext('</ul>')
133

    
134
        if self.url:
135
            if get_response().iframe_mode:
136
                r += htmltext('<a class="external" href="%s" target="_top">%s</a>') % (
137
                        self.url, _('More information'))
138
            else:
139
                r += htmltext('<a class="external" href="%s">%s</a>') % (
140
                        self.url, _('More information'))
141
        r += htmltext('</dd>')
142
        return r.getvalue()
143

    
144
    def get_url(self):
145
        return '%s/agenda/events/%s/' % (get_publisher().get_frontoffice_url(), self.id)
146

    
147
    def get_atom_entry(self):
148
        from pyatom import pyatom
149
        entry = pyatom.Entry()
150
        entry.id = self.get_url()
151
        entry.title = self.title
152

    
153
        entry.content.attrs['type'] = 'html'
154
        entry.content.text = str('<p>' + htmlescape(
155
                    unicode(self.description, get_publisher().site_charset).encode('utf-8')) + '</p>')
156

    
157
        return entry
158

    
159

    
160
class RemoteCalendar(StorableObject):
161
    _names = 'remote_calendars'
162

    
163
    label = None
164
    url = None
165
    content = None
166
    events = None
167
    error = None  # (time, string, params)
168

    
169
    def download_and_parse(self, job=None):
170
        old_content = self.content
171

    
172
        try:
173
            self.content = urllib2.urlopen(self.url).read()
174
        except urllib2.HTTPError, e:
175
            self.error = (time.localtime(), N_('HTTP Error %s on download'), (e.code,))
176
            self.store()
177
            return
178
        except urllib2.URLError, e:
179
            self.error = (time.localtime(), N_('Error on download'), ())
180
            self.store()
181
            return
182

    
183
        if self.error:
184
            self.error = None
185
            self.store()
186

    
187
        if self.content == old_content:
188
            return
189

    
190
        self.events = []
191
        try:
192
            parsed_cal = vobject.readOne(self.content)
193
        except vobject.base.ParseError:
194
            self.error = (time.localtime(), N_('Failed to parse file'), ())
195
            self.store()
196
            return
197

    
198
        site_charset = get_publisher().site_charset
199
        for vevent in parsed_cal.vevent_list:
200
            ev = Event()
201
            ev.title = vevent.summary.value.encode(site_charset, 'replace')
202
            try:
203
                ev.url = vevent.url.value.encode(site_charset, 'replace')
204
            except AttributeError:
205
                pass
206
            ev.date_start = vevent.dtstart.value.timetuple()
207
            try:
208
                ev.date_end = vevent.dtend.value.timetuple()
209
            except AttributeError:
210
                pass
211
            try:
212
                ev.description = vevent.description.value.encode(site_charset, 'replace')
213
            except AttributeError:
214
                pass
215
            try:
216
                ev.keywords = [x.encode(site_charset) for x in vevent.categories.value]
217
            except AttributeError:
218
                pass
219
            self.events.append(ev)
220
        self.store()
221

    
222
        
223
    def get_error_message(self):
224
        if not self.error:
225
            return None
226
        return '(%s) %s' % (misc.localstrftime(self.error[0]),
227
                _(self.error[1]) % self.error[2])
228

    
229

    
230
def update_remote_calendars(publisher):
231
    for source in RemoteCalendar.select():
232
        source.download_and_parse()
233

    
234
def get_default_event_tags():
235
    return [_('All Public'), _('Adults'), _('Children'), _('Free')]
236

    
237
get_publisher_class().register_cronjob(CronJob(update_remote_calendars, minutes = [0]))
238

    
(15-15/27)