Révision caff0735
Ajouté par Frédéric Péters il y a plus de 4 ans
auquotidien/auquotidien.py | ||
---|---|---|
8 | 8 |
from modules import backoffice |
9 | 9 |
from modules import announces_ui |
10 | 10 |
from modules import categories_admin |
11 |
from modules import events_ui |
|
12 | 11 |
from modules import payments_ui |
13 | 12 |
from modules import strongbox_ui |
14 | 13 |
from modules import formpage |
... | ... | |
30 | 29 |
rdb.register_directory('announces', announces_ui.AnnouncesDirectory()) |
31 | 30 |
rdb.register_menu_item('announces/', _('Announces')) |
32 | 31 |
|
33 |
rdb.register_directory('events', events_ui.EventsDirectory()) |
|
34 |
rdb.register_menu_item('events/', _('Events')) |
|
35 |
|
|
36 | 32 |
rdb.register_directory('payments', payments_ui.PaymentsDirectory()) |
37 | 33 |
rdb.register_menu_item('payments/', _('Payments')) |
38 | 34 |
|
auquotidien/modules/admin.py | ||
---|---|---|
17 | 17 |
from wcs.categories import Category |
18 | 18 |
from wcs.qommon.backoffice.menu import html_top |
19 | 19 |
|
20 |
from .events import get_default_event_tags |
|
21 | 20 |
import re |
22 | 21 |
from .abelium_domino_ui import AbeliumDominoDirectory |
23 | 22 |
|
24 | 23 |
|
25 | 24 |
class PanelDirectory(Directory): |
26 |
_q_exports = ['', 'update', 'announces', 'permissions', 'event_keywords',
|
|
25 |
_q_exports = ['', 'update', 'announces', 'permissions', |
|
27 | 26 |
'announce_themes', 'strongbox', 'clicrdv', 'domino'] |
28 | 27 |
label = N_('Control Panel') |
29 | 28 |
|
... | ... | |
77 | 76 |
form.add(SingleSelectWidget, 'forms', title = _('Admin role for forms'), |
78 | 77 |
value = permissions_cfg.get('forms', None), |
79 | 78 |
options = [(None, _('Nobody'), None)] + get_user_roles()) |
80 |
if get_publisher().has_site_option('auquotidien-events'): |
|
81 |
form.add(SingleSelectWidget, 'events', title = _('Admin role for events'), |
|
82 |
value = permissions_cfg.get('events', None), |
|
83 |
options = [(None, _('Nobody'), None)] + get_user_roles()) |
|
84 | 79 |
if get_publisher().has_site_option('auquotidien-announces'): |
85 | 80 |
form.add(SingleSelectWidget, 'announces', title = _('Admin role for announces'), |
86 | 81 |
value = permissions_cfg.get('announces', None), |
... | ... | |
109 | 104 |
else: |
110 | 105 |
from wcs.admin.settings import cfg_submit |
111 | 106 |
cfg_submit(form, 'aq-permissions', |
112 |
('forms', 'events', 'announces', 'payments', 'strongbox')) |
|
113 |
return redirect('..') |
|
114 |
|
|
115 |
def event_keywords(self): |
|
116 |
misc_cfg = get_cfg('misc', {}) |
|
117 |
form = Form(enctype='multipart/form-data') |
|
118 |
form.add(WidgetList, 'event_tags', title = _('Event Keywords'), |
|
119 |
value = misc_cfg.get('event_tags', get_default_event_tags()), |
|
120 |
elemnt_type = StringWidget, |
|
121 |
add_element_label = _('Add Keyword'), |
|
122 |
element_kwargs = {str('render_br'): False, str('size'): 30}) |
|
123 |
|
|
124 |
form.add_submit('submit', _('Submit')) |
|
125 |
form.add_submit('cancel', _('Cancel')) |
|
126 |
|
|
127 |
if form.get_widget('cancel').parse(): |
|
128 |
return redirect('..') |
|
129 |
|
|
130 |
if not form.is_submitted() or form.has_errors(): |
|
131 |
get_response().breadcrumb.append(('aq/event_keywords', _('Event Keywords'))) |
|
132 |
html_top('settings', _('Event Keywords')) |
|
133 |
r = TemplateIO(html=True) |
|
134 |
r += htmltext('<h2>%s</h2>') % _('Event Keywords') |
|
135 |
r += form.render() |
|
136 |
return r.getvalue() |
|
137 |
else: |
|
138 |
from wcs.admin.settings import cfg_submit |
|
139 |
cfg_submit(form, 'misc', ('event_tags',)) |
|
107 |
('forms', 'announces', 'payments', 'strongbox')) |
|
140 | 108 |
return redirect('..') |
141 | 109 |
|
142 | 110 |
def announce_themes(self): |
... | ... | |
250 | 218 |
class SettingsDirectory(wcs.admin.settings.SettingsDirectory): |
251 | 219 |
def _q_index(self): |
252 | 220 |
if not (get_publisher().has_site_option('auquotidien-announces') or |
253 |
get_publisher().has_site_option('auquotidien-events') or |
|
254 | 221 |
get_publisher().has_site_option('auquotidien-payments') or |
255 | 222 |
get_publisher().has_site_option('auquotidien-strongvox')): |
256 | 223 |
return super(SettingsDirectory, self)._q_index() |
... | ... | |
263 | 230 |
if get_publisher().has_site_option('auquotidien-announces'): |
264 | 231 |
r += htmltext('<li><a href="aq/announces">%s</a></li>') % _('Announces Options') |
265 | 232 |
r += htmltext('<li><a href="aq/permissions">%s</a></li>') % _('Permissions') |
266 |
if get_publisher().has_site_option('auquotidien-events'): |
|
267 |
r += htmltext('<li><a href="aq/event_keywords">%s</a></li>') % _('Event Keywords') |
|
268 | 233 |
if get_publisher().has_site_option('auquotidien-announces'): |
269 | 234 |
r += htmltext('<li><a href="aq/announce_themes">%s</a></li>') % _('Announce Themes') |
270 | 235 |
if get_publisher().has_site_option('strongbox'): |
auquotidien/modules/agenda.py | ||
---|---|---|
1 |
import time |
|
2 |
import datetime |
|
3 |
from sets import Set |
|
4 |
|
|
5 |
from quixote.directory import Directory |
|
6 |
from quixote import get_publisher, get_request, redirect, get_session, get_response |
|
7 |
from quixote.html import htmltext, TemplateIO |
|
8 |
|
|
9 |
from wcs.qommon import _ |
|
10 |
from wcs.qommon import misc, template, errors, get_cfg |
|
11 |
from wcs.qommon.form import * |
|
12 |
|
|
13 |
from .events import Event, RemoteCalendar, get_default_event_tags |
|
14 |
|
|
15 |
|
|
16 |
class TagDirectory(Directory): |
|
17 |
def _q_lookup(self, component): |
|
18 |
events = Event.select() |
|
19 |
for remote_calendar in RemoteCalendar.select(): |
|
20 |
if remote_calendar.events: |
|
21 |
events.extend(remote_calendar.events) |
|
22 |
self.events = [x for x in events if component in (x.keywords or [])] |
|
23 |
self.events.sort(lambda x,y: cmp(x.date_start, y.date_start)) |
|
24 |
self.tag = component |
|
25 |
return self.display_events() |
|
26 |
|
|
27 |
def display_events(self): |
|
28 |
template.html_top(_('Agenda')) |
|
29 |
r = TemplateIO(html=True) |
|
30 |
if len(self.events) > 1: |
|
31 |
r += htmltext('<p id="nb-events">') |
|
32 |
r += _('%(nb)d events with %(keyword)s keyword') % { |
|
33 |
'nb': len(self.events), |
|
34 |
'keyword': self.tag |
|
35 |
} |
|
36 |
r += htmltext('</p>') |
|
37 |
|
|
38 |
if self.events: |
|
39 |
r += htmltext('<dl id="events">') |
|
40 |
for ev in self.events: |
|
41 |
r += htmltext(ev.as_html_dt_dd()) |
|
42 |
r += htmltext('</dl>') |
|
43 |
else: |
|
44 |
r += htmltext('<p id="nb-events">') |
|
45 |
r += _('No event registered with the %s keyword.') % self.tag |
|
46 |
r += htmltext('</p>') |
|
47 |
return r.getvalue() |
|
48 |
|
|
49 |
|
|
50 |
class AgendaDirectory(Directory): |
|
51 |
_q_exports = ['', 'icalendar', 'tag', 'atom', 'filter'] |
|
52 |
|
|
53 |
year = None |
|
54 |
month = None |
|
55 |
|
|
56 |
tag = TagDirectory() |
|
57 |
|
|
58 |
def _q_traverse(self, path): |
|
59 |
get_response().breadcrumb.append(('agenda/', _('Agenda'))) |
|
60 |
self.year, self.month = time.localtime()[:2] |
|
61 |
if len(path) >= 1 and path[0].isdigit(): |
|
62 |
self.year, self.month = (None, None) |
|
63 |
self.year = int(path[0]) |
|
64 |
get_response().breadcrumb.append(('%s/' % self.year, self.year)) |
|
65 |
path = path[1:] |
|
66 |
if len(path) >= 1 and path[0] in [str(x) for x in range(1, 13)]: |
|
67 |
self.month = int(path[0]) |
|
68 |
get_response().breadcrumb.append(('%s/' % self.month, |
|
69 |
misc.get_month_name(self.month))) |
|
70 |
path = path[1:] |
|
71 |
if len(path) == 0: |
|
72 |
return redirect(get_request().get_path() + '/') |
|
73 |
return Directory._q_traverse(self, path) |
|
74 |
|
|
75 |
def _q_index(self): |
|
76 |
if self.month: |
|
77 |
r = TemplateIO(html=True) |
|
78 |
r += htmltext(self.display_month_links()) |
|
79 |
r += htmltext(self.display_month()) |
|
80 |
return r.getvalue() |
|
81 |
else: |
|
82 |
return redirect('..') |
|
83 |
|
|
84 |
def display_month(self): |
|
85 |
template.html_top(_('Agenda')) |
|
86 |
events = Event.select() |
|
87 |
remote_cal = get_request().form.get('cal') |
|
88 |
if remote_cal != 'local': |
|
89 |
if remote_cal: |
|
90 |
try: |
|
91 |
events = RemoteCalendar.get(remote_cal).events |
|
92 |
except KeyError: |
|
93 |
raise errors.TraversalError() |
|
94 |
if not events: |
|
95 |
events = [] |
|
96 |
else: |
|
97 |
for remote_calendar in RemoteCalendar.select(): |
|
98 |
if remote_calendar.events: |
|
99 |
events.extend(remote_calendar.events) |
|
100 |
events = [x for x in events if x.in_month(self.year, self.month)] |
|
101 |
events.sort(lambda x,y: cmp(x.date_start, y.date_start)) |
|
102 |
|
|
103 |
r = TemplateIO(html=True) |
|
104 |
if events: |
|
105 |
if len(events) > 1: |
|
106 |
r += htmltext('<p id="nb-events">') |
|
107 |
r += _('%(nb)d events for %(month_name)s %(year)s') % { |
|
108 |
'nb': len(events), |
|
109 |
'month_name': misc.get_month_name(self.month), |
|
110 |
'year': self.year} |
|
111 |
r += htmltext('</p>') |
|
112 |
|
|
113 |
r += htmltext('<dl id="events">') |
|
114 |
for ev in events: |
|
115 |
r += htmltext(ev.as_html_dt_dd()) |
|
116 |
r += htmltext('</dl>') |
|
117 |
else: |
|
118 |
r += htmltext('<p id="nb-events">') |
|
119 |
r += _('No event registered for the month of %s.') % '%s %s' % ( |
|
120 |
misc.get_month_name(self.month), self.year) |
|
121 |
r += htmltext('</p>') |
|
122 |
|
|
123 |
root_url = get_publisher().get_root_url() |
|
124 |
r += htmltext('<div id="agenda-subs">') |
|
125 |
r += htmltext('<p>') |
|
126 |
r += _('You can subscribe to this calendar:') |
|
127 |
r += htmltext('</p>') |
|
128 |
r += htmltext('<ul>') |
|
129 |
r += htmltext(' <li><a href="%sagenda/icalendar" id="par_ical">%s</a></li>') % ( |
|
130 |
root_url, _('iCalendar')) |
|
131 |
r += htmltext(' <li><a href="%sagenda/atom" id="par_rss">%s</a></li>') % ( |
|
132 |
root_url, _('Feed')) |
|
133 |
r += htmltext('</ul>') |
|
134 |
r += htmltext('</div>') |
|
135 |
return r.getvalue() |
|
136 |
|
|
137 |
def display_month_links(self): |
|
138 |
today = datetime.date(*(time.localtime()[:2] + (1,))) |
|
139 |
r = TemplateIO(html=True) |
|
140 |
r += htmltext('<ul id="month-links">') |
|
141 |
for i in range(12): |
|
142 |
r += htmltext('<li>') |
|
143 |
if (today.year, today.month) == (self.year, self.month): |
|
144 |
r += htmltext('<strong>') |
|
145 |
r += '%s %s' % (misc.get_month_name(today.month), today.year) |
|
146 |
r += htmltext('</strong>') |
|
147 |
else: |
|
148 |
root_url = get_publisher().get_root_url() |
|
149 |
r += htmltext('<a href="%sagenda/%s/%s/">') % (root_url, today.year, today.month) |
|
150 |
r += '%s %s' % (misc.get_month_name(today.month), today.year) |
|
151 |
r += htmltext('</a>') |
|
152 |
r += htmltext('</li>') |
|
153 |
today += datetime.timedelta(31) |
|
154 |
r += htmltext('</ul>') |
|
155 |
return r.getvalue() |
|
156 |
|
|
157 |
def display_remote_calendars(self): |
|
158 |
r = TemplateIO(html=True) |
|
159 |
remote_calendars = [x for x in RemoteCalendar.select() if x.label] |
|
160 |
if not remote_calendars: |
|
161 |
return |
|
162 |
remote_calendars.sort(lambda x,y: cmp(x.label, y.label)) |
|
163 |
r += htmltext('<p class="tags">') |
|
164 |
remote_cal = get_request().form.get('cal') |
|
165 |
agenda_root_url = get_publisher().get_root_url() + 'agenda/' |
|
166 |
if remote_cal: |
|
167 |
r += htmltext('<a href="%s">%s</a> ') % (agenda_root_url, _('All')) |
|
168 |
else: |
|
169 |
r += htmltext('<strong><a href="%s">%s</a></strong> ') % (agenda_root_url, _('All')) |
|
170 |
if remote_cal != 'local': |
|
171 |
r += htmltext('<a href="%s?cal=local">%s</a> ') % (agenda_root_url, _('Local')) |
|
172 |
else: |
|
173 |
r += htmltext('<strong><a href="%s?cal=local">%s</a></strong> ') % (agenda_root_url, _('Local')) |
|
174 |
for cal in remote_calendars: |
|
175 |
if remote_cal == str(cal.id): |
|
176 |
r += htmltext('<strong><a href="%s?cal=%s">%s</a></strong> ') % ( |
|
177 |
agenda_root_url, cal.id, cal.label) |
|
178 |
else: |
|
179 |
r += htmltext('<a href="%s?cal=%s">%s</a> ') % (agenda_root_url, cal.id, cal.label) |
|
180 |
r += htmltext('</p>') |
|
181 |
return r.getvalue() |
|
182 |
|
|
183 |
def icalendar(self): |
|
184 |
if not Event.keys(): |
|
185 |
raise errors.TraversalError() |
|
186 |
response = get_response() |
|
187 |
response.set_content_type('text/calendar', 'utf-8') |
|
188 |
vcal = Event.as_vcalendar() |
|
189 |
if type(vcal) is unicode: |
|
190 |
return vcal.encode('utf-8') |
|
191 |
else: |
|
192 |
return vcal |
|
193 |
|
|
194 |
def atom(self): |
|
195 |
response = get_response() |
|
196 |
response.set_content_type('application/atom+xml') |
|
197 |
|
|
198 |
from pyatom import pyatom |
|
199 |
xmldoc = pyatom.XMLDoc() |
|
200 |
feed = pyatom.Feed() |
|
201 |
xmldoc.root_element = feed |
|
202 |
feed.title = get_cfg('misc', {}).get('sitename', 'Publik') + ' - ' + _('Agenda') |
|
203 |
feed.id = get_request().get_url() |
|
204 |
|
|
205 |
author_email = get_cfg('emails', {}).get('reply_to') |
|
206 |
if not author_email: |
|
207 |
author_email = get_cfg('emails', {}).get('from') |
|
208 |
if author_email: |
|
209 |
feed.authors.append(pyatom.Author(author_email)) |
|
210 |
|
|
211 |
feed.links.append(pyatom.Link(get_request().get_url(1) + '/')) |
|
212 |
|
|
213 |
year, month = time.localtime()[:2] |
|
214 |
nyear, nmonth = year, month+1 |
|
215 |
if nmonth > 12: |
|
216 |
nyear, nmonth = nyear+1, 1 |
|
217 |
|
|
218 |
events = [x for x in Event.select() if x.in_month(year, month) or x.in_month(nyear, nmonth)] |
|
219 |
events.sort(lambda x,y: cmp(x.date_start, y.date_start)) |
|
220 |
events.reverse() |
|
221 |
|
|
222 |
for item in events: |
|
223 |
entry = item.get_atom_entry() |
|
224 |
if entry is not None: |
|
225 |
feed.entries.append(entry) |
|
226 |
|
|
227 |
return str(feed) |
|
228 |
|
|
229 |
def filter(self, no_event=False): |
|
230 |
template.html_top(_('Agenda')) |
|
231 |
tags = get_cfg('misc', {}).get('event_tags') |
|
232 |
if not tags: |
|
233 |
tags = get_default_event_tags() |
|
234 |
remote_calendars = [x for x in RemoteCalendar.select() if x.label] |
|
235 |
|
|
236 |
form = Form(enctype='multipart/form-data') |
|
237 |
if tags and remote_calendars: |
|
238 |
form.widgets.append(HtmlWidget('<table id="agenda-filter"><tr><td>')) |
|
239 |
if tags: |
|
240 |
form.add(CheckboxesWidget, 'tags', title=_('Tags'), |
|
241 |
options=[(x,x) for x in tags], |
|
242 |
inline=False) |
|
243 |
if tags and remote_calendars: |
|
244 |
form.widgets.append(HtmlWidget('</td><td>')) |
|
245 |
if remote_calendars: |
|
246 |
remote_calendars.sort(lambda x,y: cmp(x.label, y.label)) |
|
247 |
form.add(CheckboxesWidget, 'calendars', title=_('Calendars'), |
|
248 |
options=[('local', _('Local'))] + [(x.id, x.label) for x in remote_calendars], |
|
249 |
inline=False) |
|
250 |
if tags and remote_calendars: |
|
251 |
form.widgets.append(HtmlWidget('</td></tr></table>')) |
|
252 |
|
|
253 |
form.add_submit('submit', _('Submit')) |
|
254 |
form.add_submit('cancel', _('Cancel')) |
|
255 |
if form.get_widget('cancel').parse(): |
|
256 |
return redirect('.') |
|
257 |
|
|
258 |
if no_event or not form.is_submitted(): |
|
259 |
r = TemplateIO(html=True) |
|
260 |
if no_event: |
|
261 |
r += htmltext('<p id="nb-events">') |
|
262 |
r += _('No events matching the filter.') |
|
263 |
r += htmltext('</p>') |
|
264 |
r += form.render() |
|
265 |
return r.getvalue() |
|
266 |
else: |
|
267 |
return self.filter_submitted(form, tags, remote_calendars) |
|
268 |
|
|
269 |
def filter_submitted(self, form, tags, remote_calendars): |
|
270 |
if remote_calendars: |
|
271 |
selected_remote_calendars = form.get_widget('calendars').parse() |
|
272 |
events = [] |
|
273 |
for remote_calendar in selected_remote_calendars: |
|
274 |
if remote_calendar == 'local': |
|
275 |
events.extend(Event.select()) |
|
276 |
else: |
|
277 |
try: |
|
278 |
events.extend(RemoteCalendar.get(remote_calendar).events) |
|
279 |
except KeyError: |
|
280 |
pass |
|
281 |
else: |
|
282 |
events = Event.select() |
|
283 |
|
|
284 |
events = [x for x in events if x.after_today()] |
|
285 |
|
|
286 |
if tags: |
|
287 |
selected_tags = Set(form.get_widget('tags').parse()) |
|
288 |
if selected_tags and len(selected_tags) != len(tags): |
|
289 |
events = [x for x in events if Set(x.keywords).intersection(selected_tags)] |
|
290 |
|
|
291 |
events.sort(lambda x,y: cmp(x.date_start, y.date_start)) |
|
292 |
|
|
293 |
r = TemplateIO(html=True) |
|
294 |
|
|
295 |
if len(events) > 1: |
|
296 |
r += htmltext('<p id="nb-events">') |
|
297 |
r += htmltext(_('%(nb)d events')) % {'nb': len(events)} |
|
298 |
r += htmltext('</p>') |
|
299 |
|
|
300 |
if events: |
|
301 |
r += htmltext('<dl id="events">') |
|
302 |
for ev in events: |
|
303 |
r += htmltext(ev.as_html_dt_dd()) |
|
304 |
r += htmltext('</dl>') |
|
305 |
return r.getvalue() |
|
306 |
else: |
|
307 |
return self.filter(no_event=True) |
auquotidien/modules/events.py | ||
---|---|---|
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 wcs.qommon import _ |
|
10 |
from wcs.qommon.publisher import get_publisher_class |
|
11 |
from wcs.qommon.storage import StorableObject |
|
12 |
from wcs.qommon.cron import CronJob |
|
13 |
from wcs.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 |
r += htmltext('<a class="external" href="%s">%s</a>') % ( |
|
136 |
self.url, _('More information')) |
|
137 |
r += htmltext('</dd>') |
|
138 |
return r.getvalue() |
|
139 |
|
|
140 |
def get_url(self): |
|
141 |
return '%s/agenda/events/%s/' % (get_publisher().get_frontoffice_url(), self.id) |
|
142 |
|
|
143 |
def get_atom_entry(self): |
|
144 |
from pyatom import pyatom |
|
145 |
entry = pyatom.Entry() |
|
146 |
entry.id = self.get_url() |
|
147 |
entry.title = self.title |
|
148 |
|
|
149 |
entry.content.attrs['type'] = 'html' |
|
150 |
entry.content.text = str('<p>' + htmlescape( |
|
151 |
unicode(self.description, get_publisher().site_charset).encode('utf-8')) + '</p>') |
|
152 |
|
|
153 |
return entry |
|
154 |
|
|
155 |
|
|
156 |
class RemoteCalendar(StorableObject): |
|
157 |
_names = 'remote_calendars' |
|
158 |
|
|
159 |
label = None |
|
160 |
url = None |
|
161 |
content = None |
|
162 |
events = None |
|
163 |
error = None # (time, string, params) |
|
164 |
|
|
165 |
def download_and_parse(self, job=None): |
|
166 |
old_content = self.content |
|
167 |
|
|
168 |
try: |
|
169 |
self.content = urllib2.urlopen(self.url).read() |
|
170 |
except urllib2.HTTPError, e: |
|
171 |
self.error = (time.localtime(), N_('HTTP Error %s on download'), (e.code,)) |
|
172 |
self.store() |
|
173 |
return |
|
174 |
except urllib2.URLError, e: |
|
175 |
self.error = (time.localtime(), N_('Error on download'), ()) |
|
176 |
self.store() |
|
177 |
return |
|
178 |
|
|
179 |
if self.error: |
|
180 |
self.error = None |
|
181 |
self.store() |
|
182 |
|
|
183 |
if self.content == old_content: |
|
184 |
return |
|
185 |
|
|
186 |
self.events = [] |
|
187 |
try: |
|
188 |
parsed_cal = vobject.readOne(self.content) |
|
189 |
except vobject.base.ParseError: |
|
190 |
self.error = (time.localtime(), N_('Failed to parse file'), ()) |
|
191 |
self.store() |
|
192 |
return |
|
193 |
|
|
194 |
site_charset = get_publisher().site_charset |
|
195 |
for vevent in parsed_cal.vevent_list: |
|
196 |
ev = Event() |
|
197 |
ev.title = vevent.summary.value.encode(site_charset, 'replace') |
|
198 |
try: |
|
199 |
ev.url = vevent.url.value.encode(site_charset, 'replace') |
|
200 |
except AttributeError: |
|
201 |
pass |
|
202 |
ev.date_start = vevent.dtstart.value.timetuple() |
|
203 |
try: |
|
204 |
ev.date_end = vevent.dtend.value.timetuple() |
|
205 |
except AttributeError: |
|
206 |
pass |
|
207 |
try: |
|
208 |
ev.description = vevent.description.value.encode(site_charset, 'replace') |
|
209 |
except AttributeError: |
|
210 |
pass |
|
211 |
try: |
|
212 |
ev.keywords = [x.encode(site_charset) for x in vevent.categories.value] |
|
213 |
except AttributeError: |
|
214 |
pass |
|
215 |
self.events.append(ev) |
|
216 |
self.store() |
|
217 |
|
|
218 |
|
|
219 |
def get_error_message(self): |
|
220 |
if not self.error: |
|
221 |
return None |
|
222 |
return '(%s) %s' % (misc.localstrftime(self.error[0]), |
|
223 |
_(self.error[1]) % self.error[2]) |
|
224 |
|
|
225 |
|
|
226 |
def update_remote_calendars(publisher): |
|
227 |
for source in RemoteCalendar.select(): |
|
228 |
source.download_and_parse() |
|
229 |
|
|
230 |
def get_default_event_tags(): |
|
231 |
return [_('All Public'), _('Adults'), _('Children'), _('Free')] |
|
232 |
|
|
233 |
get_publisher_class().register_cronjob(CronJob(update_remote_calendars, minutes = [0])) |
|
234 |
|
auquotidien/modules/events_ui.py | ||
---|---|---|
1 |
import time |
|
2 |
|
|
3 |
from quixote import get_request, get_response, get_session, redirect |
|
4 |
from quixote.directory import Directory, AccessControlled |
|
5 |
from quixote.html import TemplateIO, htmltext |
|
6 |
|
|
7 |
import wcs |
|
8 |
import wcs.admin.root |
|
9 |
|
|
10 |
from wcs.qommon import _ |
|
11 |
from wcs.qommon.backoffice.menu import html_top |
|
12 |
from wcs.qommon.admin.menu import command_icon |
|
13 |
from wcs.qommon import get_cfg |
|
14 |
from wcs.qommon import errors, misc |
|
15 |
from wcs.qommon.form import * |
|
16 |
from wcs.qommon.misc import strftime |
|
17 |
|
|
18 |
from .events import Event, RemoteCalendar, get_default_event_tags |
|
19 |
|
|
20 |
|
|
21 |
|
|
22 |
class RemoteCalendarDirectory(Directory): |
|
23 |
_q_exports = ['', 'edit', 'delete', 'update'] |
|
24 |
|
|
25 |
def __init__(self, calendar): |
|
26 |
self.calendar = calendar |
|
27 |
|
|
28 |
def _q_index(self): |
|
29 |
form = Form(enctype='multipart/form-data') |
|
30 |
form.add_submit('edit', _('Edit')) |
|
31 |
form.add_submit('delete', _('Delete')) |
|
32 |
form.add_submit('update', _('Update')) |
|
33 |
form.add_submit('back', _('Back')) |
|
34 |
|
|
35 |
if form.get_submit() == 'edit': |
|
36 |
return redirect('edit') |
|
37 |
if form.get_submit() == 'update': |
|
38 |
return redirect('update') |
|
39 |
if form.get_submit() == 'delete': |
|
40 |
return redirect('delete') |
|
41 |
if form.get_submit() == 'back': |
|
42 |
return redirect('..') |
|
43 |
|
|
44 |
html_top('events', title = _('Remote Calendar: %s') % self.calendar.label) |
|
45 |
r = TemplateIO(html=True) |
|
46 |
r += htmltext('<h2>%s</h2>') % _('Remote Calendar: %s') % self.calendar.label |
|
47 |
|
|
48 |
r += get_session().display_message() |
|
49 |
|
|
50 |
r += htmltext('<p>') |
|
51 |
self.calendar.url |
|
52 |
if self.calendar.error: |
|
53 |
r += htmltext(' - <span class="error-message">%s</span>') % self.calendar.get_error_message() |
|
54 |
r += htmltext('</p>') |
|
55 |
|
|
56 |
if not self.calendar.content: |
|
57 |
r += htmltext('<p>') |
|
58 |
r += _('No content has been retrieved yet.') |
|
59 |
r += htmltext('</p>') |
|
60 |
else: |
|
61 |
r += htmltext('<ul>') |
|
62 |
for ev in sorted(self.calendar.events, lambda x,y: cmp(x.date_start, y.date_start)): |
|
63 |
r += htmltext('<li>') |
|
64 |
if ev.date_start: |
|
65 |
r += strftime(misc.date_format(), ev.date_start) |
|
66 |
if ev.date_end and ev.date_start[:3] != ev.date_end[:3]: |
|
67 |
r += ' - ' |
|
68 |
r += strftime(misc.date_format(), ev.date_start) |
|
69 |
|
|
70 |
r += ' : ' |
|
71 |
if ev.url: |
|
72 |
r += htmltext('<a href="%s">%s</a>') % (ev.url, ev.title) |
|
73 |
else: |
|
74 |
r += ev.title |
|
75 |
r += htmltext('</li>') |
|
76 |
r += htmltext('</ul>') |
|
77 |
|
|
78 |
r += form.render() |
|
79 |
return r.getvalue() |
|
80 |
|
|
81 |
def edit(self): |
|
82 |
form = self.form() |
|
83 |
if form.get_submit() == 'cancel': |
|
84 |
return redirect('.') |
|
85 |
|
|
86 |
if form.is_submitted() and not form.has_errors(): |
|
87 |
self.submit(form) |
|
88 |
return redirect('..') |
|
89 |
|
|
90 |
html_top('events', title = _('Edit Remote Calendar: %s') % self.calendar.label) |
|
91 |
r = TemplateIO(html=True) |
|
92 |
r += htmltext('<h2>%s</h2>') % _('Edit Remote Calendar: %s') % self.calendar.label |
|
93 |
r += form.render() |
|
94 |
return r.getvalue() |
|
95 |
|
|
96 |
def form(self): |
|
97 |
form = Form(enctype='multipart/form-data') |
|
98 |
form.add(StringWidget, 'label', title = _('Label'), required = True, |
|
99 |
value = self.calendar.label) |
|
100 |
form.add(StringWidget, 'url', title = _('URL'), required = True, |
|
101 |
value = self.calendar.url, size = 40) |
|
102 |
form.add_submit('submit', _('Submit')) |
|
103 |
form.add_submit('cancel', _('Cancel')) |
|
104 |
return form |
|
105 |
|
|
106 |
def submit(self, form): |
|
107 |
for k in ('label', 'url'): |
|
108 |
widget = form.get_widget(k) |
|
109 |
if widget: |
|
110 |
setattr(self.calendar, k, widget.parse()) |
|
111 |
self.calendar.store() |
|
112 |
|
|
113 |
def delete(self): |
|
114 |
form = Form(enctype='multipart/form-data') |
|
115 |
form.widgets.append(HtmlWidget('<p>%s</p>' % _( |
|
116 |
'You are about to irrevocably delete this remote calendar.'))) |
|
117 |
form.add_submit('submit', _('Submit')) |
|
118 |
form.add_submit('cancel', _('Cancel')) |
|
119 |
if form.get_submit() == 'cancel': |
|
120 |
return redirect('..') |
|
121 |
if not form.is_submitted() or form.has_errors(): |
|
122 |
get_response().breadcrumb.append(('delete', _('Delete'))) |
|
123 |
html_top('events', title = _('Delete Remote Calendar')) |
|
124 |
r = TemplateIO(html=True) |
|
125 |
r += htmltext('<h2>%s</h2>') % _('Deleting Remote Calendar: %s') % self.calendar.label |
|
126 |
r += form.render() |
|
127 |
return r.getvalue() |
|
128 |
else: |
|
129 |
self.calendar.remove_self() |
|
130 |
return redirect('..') |
|
131 |
|
|
132 |
def update(self): |
|
133 |
get_session().message = ('info', |
|
134 |
_('Calendar update has been requested, reload in a few moments')) |
|
135 |
get_response().add_after_job('updating remote calendar', |
|
136 |
self.calendar.download_and_parse, |
|
137 |
fire_and_forget = True) |
|
138 |
return redirect('.') |
|
139 |
|
|
140 |
|
|
141 |
|
|
142 |
class RemoteCalendarsDirectory(Directory): |
|
143 |
_q_exports = ['', 'new'] |
|
144 |
|
|
145 |
def _q_traverse(self, path): |
|
146 |
get_response().breadcrumb.append(('remote/', _('Remote Calendars'))) |
|
147 |
return Directory._q_traverse(self, path) |
|
148 |
|
|
149 |
def _q_index(self): |
|
150 |
return redirect('..') |
|
151 |
|
|
152 |
def new(self): |
|
153 |
calendar_ui = RemoteCalendarDirectory(RemoteCalendar()) |
|
154 |
|
|
155 |
form = calendar_ui.form() |
|
156 |
if form.get_submit() == 'cancel': |
|
157 |
return redirect('.') |
|
158 |
|
|
159 |
if form.is_submitted() and not form.has_errors(): |
|
160 |
calendar_ui.submit(form) |
|
161 |
return redirect('%s/' % calendar_ui.calendar.id) |
|
162 |
|
|
163 |
get_response().breadcrumb.append(('new', _('New Remote Calendar'))) |
|
164 |
html_top('events', title = _('New Remote Calendar')) |
|
165 |
r = TemplateIO(html=True) |
|
166 |
r += htmltext('<h2>%s</h2>') % _('New Remote Calendar') |
|
167 |
r += form.render() |
|
168 |
return r.getvalue() |
|
169 |
|
|
170 |
def _q_lookup(self, component): |
|
171 |
try: |
|
172 |
event = RemoteCalendar.get(component) |
|
173 |
except KeyError: |
|
174 |
raise errors.TraversalError() |
|
175 |
get_response().breadcrumb.append((str(event.id), event.label)) |
|
176 |
return RemoteCalendarDirectory(event) |
|
177 |
|
|
178 |
|
|
179 |
class EventDirectory(Directory): |
|
180 |
_q_exports = ['', 'edit', 'delete'] |
|
181 |
|
|
182 |
def __init__(self, event): |
|
183 |
self.event = event |
|
184 |
|
|
185 |
def _q_index(self): |
|
186 |
form = Form(enctype='multipart/form-data') |
|
187 |
form.add_submit('edit', _('Edit')) |
|
188 |
form.add_submit('delete', _('Delete')) |
|
189 |
form.add_submit('back', _('Back')) |
|
190 |
|
|
191 |
if form.get_submit() == 'edit': |
|
192 |
return redirect('edit') |
|
193 |
if form.get_submit() == 'delete': |
|
194 |
return redirect('delete') |
|
195 |
if form.get_submit() == 'back': |
|
196 |
return redirect('..') |
|
197 |
|
|
198 |
html_top('events', title = _('Event: %s') % self.event.title) |
|
199 |
r = TemplateIO(html=True) |
|
200 |
r += htmltext('<h2>%s</h2>') % _('Event: %s') % self.event.title |
|
201 |
r += htmltext('<p>') |
|
202 |
r += self.event.description |
|
203 |
r += htmltext('</p>') |
|
204 |
r += htmltext('<ul>') |
|
205 |
if self.event.location: |
|
206 |
r += htmltext('<li>%s: %s</li>') % (_('Location'), self.event.location) |
|
207 |
if self.event.organizer: |
|
208 |
r += htmltext('<li>%s: %s</li>') % (_('Organizer'), self.event.organizer) |
|
209 |
if self.event.url: |
|
210 |
r += htmltext('<li>%s: <a href="%s">%s</a></li>') % (_('URL'), self.event.url, self.event.url) |
|
211 |
r += htmltext('</ul>') |
|
212 |
|
|
213 |
if self.event.more_infos: |
|
214 |
r += htmltext('<p>') |
|
215 |
r += self.event.more_infos |
|
216 |
r += htmltext('</p>') |
|
217 |
|
|
218 |
r += form.render() |
|
219 |
return r.getvalue() |
|
220 |
|
|
221 |
def edit(self): |
|
222 |
form = self.form() |
|
223 |
if form.get_submit() == 'cancel': |
|
224 |
return redirect('.') |
|
225 |
|
|
226 |
if form.is_submitted() and not form.has_errors(): |
|
227 |
self.submit(form) |
|
228 |
return redirect('..') |
|
229 |
|
|
230 |
html_top('events', title = _('Edit Event: %s') % self.event.title) |
|
231 |
r = TemplateIO(html=True) |
|
232 |
r += htmltext('<h2>%s</h2>') % _('Edit Event: %s') % self.event.title |
|
233 |
r += form.render() |
|
234 |
return r.getvalue() |
|
235 |
|
|
236 |
def form(self): |
|
237 |
form = Form(enctype='multipart/form-data') |
|
238 |
form.add(StringWidget, 'title', title = _('Title'), required = True, |
|
239 |
value = self.event.title) |
|
240 |
form.add(TextWidget, 'description', title = _('Description'), |
|
241 |
cols = 70, rows = 10, |
|
242 |
required = True, value = self.event.description) |
|
243 |
form.add(StringWidget, 'url', title = _('URL'), required = False, |
|
244 |
value = self.event.url, size = 40) |
|
245 |
form.add(DateWidget, 'date_start', title = _('Start Date'), required = True, |
|
246 |
value = strftime(misc.date_format(), self.event.date_start)) |
|
247 |
form.add(DateWidget, 'date_end', title = _('End Date'), required = False, |
|
248 |
value = strftime(misc.date_format(), self.event.date_end)) |
|
249 |
form.add(TextWidget, 'location', title = _('Location'), |
|
250 |
cols = 70, rows = 4, |
|
251 |
required = False, value = self.event.location) |
|
252 |
form.add(StringWidget, 'organizer', title = _('Organizer'), required = False, |
|
253 |
value = self.event.organizer, size = 40) |
|
254 |
form.add(TextWidget, 'more_infos', title = _('More informations'), |
|
255 |
cols = 70, rows = 10, |
|
256 |
required = False, value = self.event.more_infos) |
|
257 |
form.add(TagsWidget, 'keywords', title = _('Keywords'), |
|
258 |
value = self.event.keywords, size = 50, |
|
259 |
known_tags = get_cfg('misc', {}).get('event_tags', get_default_event_tags())) |
|
260 |
form.add_submit('submit', _('Submit')) |
|
261 |
form.add_submit('cancel', _('Cancel')) |
|
262 |
return form |
|
263 |
|
|
264 |
def submit(self, form): |
|
265 |
for k in ('title', 'description', 'url', 'date_start', 'date_end', |
|
266 |
'organizer', 'location', 'more_infos', 'keywords'): |
|
267 |
widget = form.get_widget(k) |
|
268 |
if widget: |
|
269 |
if k in ('date_start', 'date_end'): |
|
270 |
# convert dates to 9-item tuples |
|
271 |
v = widget.parse() |
|
272 |
if v: |
|
273 |
setattr(self.event, k, time.strptime(v, misc.date_format())) |
|
274 |
else: |
|
275 |
setattr(self.event, k, None) |
|
276 |
else: |
|
277 |
setattr(self.event, k, widget.parse()) |
|
278 |
self.event.store() |
|
279 |
|
|
280 |
def delete(self): |
|
281 |
form = Form(enctype='multipart/form-data') |
|
282 |
form.widgets.append(HtmlWidget('<p>%s</p>' % _( |
|
283 |
'You are about to irrevocably delete this event.'))) |
|
284 |
form.add_submit('submit', _('Submit')) |
|
285 |
form.add_submit('cancel', _('Cancel')) |
|
286 |
if form.get_submit() == 'cancel': |
|
287 |
return redirect('..') |
|
288 |
if not form.is_submitted() or form.has_errors(): |
|
289 |
get_response().breadcrumb.append(('delete', _('Delete'))) |
|
290 |
html_top('events', title = _('Delete Event')) |
|
291 |
r = TemplateIO(html=True) |
|
292 |
r += htmltext('<h2>%s</h2>') % _('Deleting Event: %s') % self.event.title |
|
293 |
r += form.render() |
|
294 |
return r.getvalue() |
|
295 |
else: |
|
296 |
self.event.remove_self() |
|
297 |
return redirect('..') |
|
298 |
|
|
299 |
|
|
300 |
|
|
301 |
|
|
302 |
class EventsDirectory(AccessControlled, Directory): |
|
303 |
_q_exports = ['', 'new', 'listing', 'remote'] |
|
304 |
label = N_('Events') |
|
305 |
|
|
306 |
remote = RemoteCalendarsDirectory() |
|
307 |
|
|
308 |
def is_accessible(self, user): |
|
309 |
from .backoffice import check_visibility |
|
310 |
return check_visibility('events', user) |
|
311 |
|
|
312 |
def _q_access(self): |
|
313 |
user = get_request().user |
|
314 |
if not user: |
|
315 |
raise errors.AccessUnauthorizedError() |
|
316 |
|
|
317 |
if not self.is_accessible(user): |
|
318 |
raise errors.AccessForbiddenError( |
|
319 |
public_msg = _('You are not allowed to access Events Management'), |
|
320 |
location_hint = 'backoffice') |
|
321 |
|
|
322 |
get_response().breadcrumb.append(('events/', _('Events'))) |
|
323 |
|
|
324 |
|
|
325 |
def _q_index(self): |
|
326 |
html_top('events', _('Events')) |
|
327 |
r = TemplateIO(html=True) |
|
328 |
|
|
329 |
get_response().filter['sidebar'] = self.get_sidebar() |
|
330 |
|
|
331 |
r += htmltext('<div class="splitcontent-left">') |
|
332 |
|
|
333 |
r += htmltext('<div class="bo-block">') |
|
334 |
events = Event.select() |
|
335 |
r += htmltext('<h2>%s</h2>') % _('Events') |
|
336 |
if not events: |
|
337 |
r += htmltext('<p>') |
|
338 |
r += _('There is no event defined at the moment.') |
|
339 |
r += htmltext('</p>') |
|
340 |
r += htmltext('<ul class="biglist" id="events-list">') |
|
341 |
for l in events: |
|
342 |
event_id = l.id |
|
343 |
r += htmltext('<li class="biglistitem" id="itemId_%s">') % event_id |
|
344 |
r += htmltext('<strong class="label"><a href="%s/">%s</a></strong>') % (event_id, l.title) |
|
345 |
r += ' - ' |
|
346 |
r += l.format_date() |
|
347 |
r += htmltext('<p class="commands">') |
|
348 |
r += command_icon('%s/edit' % event_id, 'edit') |
|
349 |
r += command_icon('%s/delete' % event_id, 'remove') |
|
350 |
r += htmltext('</p></li>') |
|
351 |
r += htmltext('</ul>') |
|
352 |
r += htmltext('</div>') |
|
353 |
r += htmltext('</div>') |
|
354 |
|
|
355 |
r += htmltext('<div class="splitcontent-right">') |
|
356 |
r += htmltext('<div class="bo-block">') |
|
357 |
rcalendars = RemoteCalendar.select() |
|
358 |
r += htmltext('<h2>%s</h2>') % _('Remote Calendars') |
|
359 |
if not rcalendars: |
|
360 |
r += htmltext('<p>') |
|
361 |
r += _('There is no remote calendars defined at the moment.') |
|
362 |
r += htmltext('</p>') |
|
363 |
|
|
364 |
r += htmltext('<ul class="biglist" id="events-list">') |
|
365 |
for l in rcalendars: |
|
366 |
rcal_id = l.id |
|
367 |
r += htmltext('<li class="biglistitem" id="itemId_%s">') % rcal_id |
|
368 |
r += htmltext('<strong class="label"><a href="remote/%s/">%s</a></strong>') % (rcal_id, l.label) |
|
369 |
r += htmltext('<p class="details">') |
|
370 |
r += l.url |
|
371 |
if l.error: |
|
372 |
r += htmltext('<br /><span class="error-message">%s</span>') % l.get_error_message() |
|
373 |
r += htmltext('</p>') |
|
374 |
r += htmltext('<p class="commands">') |
|
375 |
r += command_icon('remote/%s/edit' % rcal_id, 'edit') |
|
376 |
r += command_icon('remote/%s/delete' % rcal_id, 'remove') |
|
377 |
r += htmltext('</p></li>') |
|
378 |
r += htmltext('</ul>') |
|
379 |
r += htmltext('</div>') |
|
380 |
r += htmltext('</div>') |
|
381 |
return r.getvalue() |
|
382 |
|
|
383 |
def get_sidebar(self): |
|
384 |
r = TemplateIO(html=True) |
|
385 |
r += htmltext('<ul id="sidebar-actions">') |
|
386 |
r += htmltext(' <li><a class="new-item" href="new">%s</a></li>') % _('New Event') |
|
387 |
r += htmltext(' <li><a class="new-item" href="remote/new">%s</a></li>') % _('New Remote Calendar') |
|
388 |
r += htmltext('</ul>') |
|
389 |
return r.getvalue() |
|
390 |
|
|
391 |
def new(self): |
|
392 |
event_ui = EventDirectory(Event()) |
|
393 |
|
|
394 |
form = event_ui.form() |
|
395 |
if form.get_submit() == 'cancel': |
|
396 |
return redirect('.') |
|
397 |
|
|
398 |
if form.is_submitted() and not form.has_errors(): |
|
399 |
event_ui.submit(form) |
|
400 |
return redirect('%s/' % event_ui.event.id) |
|
401 |
|
|
402 |
get_response().breadcrumb.append(('new', _('New Event'))) |
|
403 |
html_top('events', title = _('New Event')) |
|
404 |
r = TemplateIO(html=True) |
|
405 |
r += htmltext('<h2>%s</h2>') % _('New Event') |
|
406 |
r += form.render() |
|
407 |
return r.getvalue() |
|
408 |
|
|
409 |
def _q_lookup(self, component): |
|
410 |
try: |
|
411 |
event = Event.get(component) |
|
412 |
except KeyError: |
|
413 |
raise errors.TraversalError() |
|
414 |
get_response().breadcrumb.append((str(event.id), event.title)) |
|
415 |
return EventDirectory(event) |
|
416 |
|
|
417 |
def listing(self): |
|
418 |
return redirect('.') |
auquotidien/modules/root.py | ||
---|---|---|
36 | 36 |
|
37 | 37 |
from .announces import Announce, AnnounceSubscription |
38 | 38 |
from .myspace import MyspaceDirectory |
39 |
from .agenda import AgendaDirectory |
|
40 |
from .events import Event, get_default_event_tags |
|
41 | 39 |
from .payments import PublicPaymentDirectory |
42 | 40 |
from .payments_ui import InvoicesDirectory |
43 | 41 |
|
... | ... | |
760 | 758 |
'saml', 'register', 'ident', 'afterjobs', |
761 | 759 |
('informations-editeur', 'informations_editeur'), |
762 | 760 |
('announces', 'announces_dir'), |
763 |
'myspace', 'services', 'agenda', 'categories', 'user',
|
|
761 |
'myspace', 'services', 'categories', 'user', |
|
764 | 762 |
('tmp-upload', 'tmp_upload'), 'json', '__version__', |
765 | 763 |
'themes', 'pages', 'payment', 'invoices', 'roles', |
766 | 764 |
'api', 'code', 'fargo', 'tryauth', 'auth', 'preview', |
... | ... | |
772 | 770 |
login = AlternateLoginDirectory() |
773 | 771 |
ident = AlternateIdentDirectory() |
774 | 772 |
myspace = MyspaceDirectory() |
775 |
agenda = AgendaDirectory() |
|
776 | 773 |
saml = Saml2Directory() |
777 | 774 |
payment = PublicPaymentDirectory() |
778 | 775 |
invoices = InvoicesDirectory() |
... | ... | |
1095 | 1092 |
r += htmltext('</ul>') |
1096 | 1093 |
r += htmltext('</div>') |
1097 | 1094 |
|
1098 |
if get_cfg('aq-permissions', {}).get('events') and Event.keys(): |
|
1099 |
# if there are events, add a link to the agenda |
|
1100 |
tags = get_cfg('misc', {}).get('event_tags') |
|
1101 |
if not tags: |
|
1102 |
tags = get_default_event_tags() |
|
1103 |
r += htmltext('<h3 id="agenda-link"><a href="%sagenda/">%s</a></h3>') % (root_url, _('Agenda')) |
|
1104 |
|
|
1105 |
if path and path[0] == 'agenda': |
|
1106 |
r += htmltext('<p class="tags">') |
|
1107 |
for tag in tags: |
|
1108 |
r += htmltext('<a href="%sagenda/tag/%s">%s</a> ') % (root_url, tag, tag) |
|
1109 |
r += htmltext('</p>') |
|
1110 |
r += self.agenda.display_remote_calendars() |
|
1111 |
|
|
1112 |
r += htmltext('<p>') |
|
1113 |
r += htmltext(' <a href="%sagenda/filter">%s</a>') % (root_url, _('Advanced Filter')) |
|
1114 |
r += htmltext('</p>') |
|
1115 |
|
|
1116 | 1095 |
v = r.getvalue() |
1117 | 1096 |
if v: |
1118 | 1097 |
r = TemplateIO(html=True) |
auquotidien/modules/template.py | ||
---|---|---|
48 | 48 |
section_title = '<h2 id="announces">%s</h2>\n' % _('Announces to citizens') |
49 | 49 |
if page_title == _('Announces to citizens'): |
50 | 50 |
page_title = '' |
51 |
elif section == 'agenda': |
|
52 |
response.filter['bigdiv'] = 'rub_agenda' |
|
53 |
section_title = '<h2 id="agenda">%s</h2>\n' % _('Agenda') |
|
54 |
if page_title == _('Agenda'): |
|
55 |
page_title = '' |
|
56 | 51 |
elif section and len(section) > 1: |
57 | 52 |
# XXX: this works but is not efficient |
58 | 53 |
if Category.has_urlname(section): |
Formats disponibles : Unified diff
remove support for agenda/events (#37967)