remove support for agenda/events (#37967)

This commit is contained in:
Frédéric Péters 2019-11-26 13:59:57 +01:00
parent d20d0549e9
commit caff073548
7 changed files with 3 additions and 1027 deletions

View File

@ -8,7 +8,6 @@ from modules import admin
from modules import backoffice from modules import backoffice
from modules import announces_ui from modules import announces_ui
from modules import categories_admin from modules import categories_admin
from modules import events_ui
from modules import payments_ui from modules import payments_ui
from modules import strongbox_ui from modules import strongbox_ui
from modules import formpage from modules import formpage
@ -30,9 +29,6 @@ rdb.items = []
rdb.register_directory('announces', announces_ui.AnnouncesDirectory()) rdb.register_directory('announces', announces_ui.AnnouncesDirectory())
rdb.register_menu_item('announces/', _('Announces')) rdb.register_menu_item('announces/', _('Announces'))
rdb.register_directory('events', events_ui.EventsDirectory())
rdb.register_menu_item('events/', _('Events'))
rdb.register_directory('payments', payments_ui.PaymentsDirectory()) rdb.register_directory('payments', payments_ui.PaymentsDirectory())
rdb.register_menu_item('payments/', _('Payments')) rdb.register_menu_item('payments/', _('Payments'))

View File

@ -17,13 +17,12 @@ from wcs.formdef import FormDef
from wcs.categories import Category from wcs.categories import Category
from wcs.qommon.backoffice.menu import html_top from wcs.qommon.backoffice.menu import html_top
from .events import get_default_event_tags
import re import re
from .abelium_domino_ui import AbeliumDominoDirectory from .abelium_domino_ui import AbeliumDominoDirectory
class PanelDirectory(Directory): class PanelDirectory(Directory):
_q_exports = ['', 'update', 'announces', 'permissions', 'event_keywords', _q_exports = ['', 'update', 'announces', 'permissions',
'announce_themes', 'strongbox', 'clicrdv', 'domino'] 'announce_themes', 'strongbox', 'clicrdv', 'domino']
label = N_('Control Panel') label = N_('Control Panel')
@ -77,10 +76,6 @@ class PanelDirectory(Directory):
form.add(SingleSelectWidget, 'forms', title = _('Admin role for forms'), form.add(SingleSelectWidget, 'forms', title = _('Admin role for forms'),
value = permissions_cfg.get('forms', None), value = permissions_cfg.get('forms', None),
options = [(None, _('Nobody'), None)] + get_user_roles()) options = [(None, _('Nobody'), None)] + get_user_roles())
if get_publisher().has_site_option('auquotidien-events'):
form.add(SingleSelectWidget, 'events', title = _('Admin role for events'),
value = permissions_cfg.get('events', None),
options = [(None, _('Nobody'), None)] + get_user_roles())
if get_publisher().has_site_option('auquotidien-announces'): if get_publisher().has_site_option('auquotidien-announces'):
form.add(SingleSelectWidget, 'announces', title = _('Admin role for announces'), form.add(SingleSelectWidget, 'announces', title = _('Admin role for announces'),
value = permissions_cfg.get('announces', None), value = permissions_cfg.get('announces', None),
@ -109,34 +104,7 @@ class PanelDirectory(Directory):
else: else:
from wcs.admin.settings import cfg_submit from wcs.admin.settings import cfg_submit
cfg_submit(form, 'aq-permissions', cfg_submit(form, 'aq-permissions',
('forms', 'events', 'announces', 'payments', 'strongbox')) ('forms', 'announces', 'payments', 'strongbox'))
return redirect('..')
def event_keywords(self):
misc_cfg = get_cfg('misc', {})
form = Form(enctype='multipart/form-data')
form.add(WidgetList, 'event_tags', title = _('Event Keywords'),
value = misc_cfg.get('event_tags', get_default_event_tags()),
elemnt_type = StringWidget,
add_element_label = _('Add Keyword'),
element_kwargs = {str('render_br'): False, str('size'): 30})
form.add_submit('submit', _('Submit'))
form.add_submit('cancel', _('Cancel'))
if form.get_widget('cancel').parse():
return redirect('..')
if not form.is_submitted() or form.has_errors():
get_response().breadcrumb.append(('aq/event_keywords', _('Event Keywords')))
html_top('settings', _('Event Keywords'))
r = TemplateIO(html=True)
r += htmltext('<h2>%s</h2>') % _('Event Keywords')
r += form.render()
return r.getvalue()
else:
from wcs.admin.settings import cfg_submit
cfg_submit(form, 'misc', ('event_tags',))
return redirect('..') return redirect('..')
def announce_themes(self): def announce_themes(self):
@ -250,7 +218,6 @@ class PanelDirectory(Directory):
class SettingsDirectory(wcs.admin.settings.SettingsDirectory): class SettingsDirectory(wcs.admin.settings.SettingsDirectory):
def _q_index(self): def _q_index(self):
if not (get_publisher().has_site_option('auquotidien-announces') or if not (get_publisher().has_site_option('auquotidien-announces') or
get_publisher().has_site_option('auquotidien-events') or
get_publisher().has_site_option('auquotidien-payments') or get_publisher().has_site_option('auquotidien-payments') or
get_publisher().has_site_option('auquotidien-strongvox')): get_publisher().has_site_option('auquotidien-strongvox')):
return super(SettingsDirectory, self)._q_index() return super(SettingsDirectory, self)._q_index()
@ -263,8 +230,6 @@ class SettingsDirectory(wcs.admin.settings.SettingsDirectory):
if get_publisher().has_site_option('auquotidien-announces'): if get_publisher().has_site_option('auquotidien-announces'):
r += htmltext('<li><a href="aq/announces">%s</a></li>') % _('Announces Options') r += htmltext('<li><a href="aq/announces">%s</a></li>') % _('Announces Options')
r += htmltext('<li><a href="aq/permissions">%s</a></li>') % _('Permissions') r += htmltext('<li><a href="aq/permissions">%s</a></li>') % _('Permissions')
if get_publisher().has_site_option('auquotidien-events'):
r += htmltext('<li><a href="aq/event_keywords">%s</a></li>') % _('Event Keywords')
if get_publisher().has_site_option('auquotidien-announces'): if get_publisher().has_site_option('auquotidien-announces'):
r += htmltext('<li><a href="aq/announce_themes">%s</a></li>') % _('Announce Themes') r += htmltext('<li><a href="aq/announce_themes">%s</a></li>') % _('Announce Themes')
if get_publisher().has_site_option('strongbox'): if get_publisher().has_site_option('strongbox'):

View File

@ -1,307 +0,0 @@
import time
import datetime
from sets import Set
from quixote.directory import Directory
from quixote import get_publisher, get_request, redirect, get_session, get_response
from quixote.html import htmltext, TemplateIO
from wcs.qommon import _
from wcs.qommon import misc, template, errors, get_cfg
from wcs.qommon.form import *
from .events import Event, RemoteCalendar, get_default_event_tags
class TagDirectory(Directory):
def _q_lookup(self, component):
events = Event.select()
for remote_calendar in RemoteCalendar.select():
if remote_calendar.events:
events.extend(remote_calendar.events)
self.events = [x for x in events if component in (x.keywords or [])]
self.events.sort(lambda x,y: cmp(x.date_start, y.date_start))
self.tag = component
return self.display_events()
def display_events(self):
template.html_top(_('Agenda'))
r = TemplateIO(html=True)
if len(self.events) > 1:
r += htmltext('<p id="nb-events">')
r += _('%(nb)d events with %(keyword)s keyword') % {
'nb': len(self.events),
'keyword': self.tag
}
r += htmltext('</p>')
if self.events:
r += htmltext('<dl id="events">')
for ev in self.events:
r += htmltext(ev.as_html_dt_dd())
r += htmltext('</dl>')
else:
r += htmltext('<p id="nb-events">')
r += _('No event registered with the %s keyword.') % self.tag
r += htmltext('</p>')
return r.getvalue()
class AgendaDirectory(Directory):
_q_exports = ['', 'icalendar', 'tag', 'atom', 'filter']
year = None
month = None
tag = TagDirectory()
def _q_traverse(self, path):
get_response().breadcrumb.append(('agenda/', _('Agenda')))
self.year, self.month = time.localtime()[:2]
if len(path) >= 1 and path[0].isdigit():
self.year, self.month = (None, None)
self.year = int(path[0])
get_response().breadcrumb.append(('%s/' % self.year, self.year))
path = path[1:]
if len(path) >= 1 and path[0] in [str(x) for x in range(1, 13)]:
self.month = int(path[0])
get_response().breadcrumb.append(('%s/' % self.month,
misc.get_month_name(self.month)))
path = path[1:]
if len(path) == 0:
return redirect(get_request().get_path() + '/')
return Directory._q_traverse(self, path)
def _q_index(self):
if self.month:
r = TemplateIO(html=True)
r += htmltext(self.display_month_links())
r += htmltext(self.display_month())
return r.getvalue()
else:
return redirect('..')
def display_month(self):
template.html_top(_('Agenda'))
events = Event.select()
remote_cal = get_request().form.get('cal')
if remote_cal != 'local':
if remote_cal:
try:
events = RemoteCalendar.get(remote_cal).events
except KeyError:
raise errors.TraversalError()
if not events:
events = []
else:
for remote_calendar in RemoteCalendar.select():
if remote_calendar.events:
events.extend(remote_calendar.events)
events = [x for x in events if x.in_month(self.year, self.month)]
events.sort(lambda x,y: cmp(x.date_start, y.date_start))
r = TemplateIO(html=True)
if events:
if len(events) > 1:
r += htmltext('<p id="nb-events">')
r += _('%(nb)d events for %(month_name)s %(year)s') % {
'nb': len(events),
'month_name': misc.get_month_name(self.month),
'year': self.year}
r += htmltext('</p>')
r += htmltext('<dl id="events">')
for ev in events:
r += htmltext(ev.as_html_dt_dd())
r += htmltext('</dl>')
else:
r += htmltext('<p id="nb-events">')
r += _('No event registered for the month of %s.') % '%s %s' % (
misc.get_month_name(self.month), self.year)
r += htmltext('</p>')
root_url = get_publisher().get_root_url()
r += htmltext('<div id="agenda-subs">')
r += htmltext('<p>')
r += _('You can subscribe to this calendar:')
r += htmltext('</p>')
r += htmltext('<ul>')
r += htmltext(' <li><a href="%sagenda/icalendar" id="par_ical">%s</a></li>') % (
root_url, _('iCalendar'))
r += htmltext(' <li><a href="%sagenda/atom" id="par_rss">%s</a></li>') % (
root_url, _('Feed'))
r += htmltext('</ul>')
r += htmltext('</div>')
return r.getvalue()
def display_month_links(self):
today = datetime.date(*(time.localtime()[:2] + (1,)))
r = TemplateIO(html=True)
r += htmltext('<ul id="month-links">')
for i in range(12):
r += htmltext('<li>')
if (today.year, today.month) == (self.year, self.month):
r += htmltext('<strong>')
r += '%s %s' % (misc.get_month_name(today.month), today.year)
r += htmltext('</strong>')
else:
root_url = get_publisher().get_root_url()
r += htmltext('<a href="%sagenda/%s/%s/">') % (root_url, today.year, today.month)
r += '%s %s' % (misc.get_month_name(today.month), today.year)
r += htmltext('</a>')
r += htmltext('</li>')
today += datetime.timedelta(31)
r += htmltext('</ul>')
return r.getvalue()
def display_remote_calendars(self):
r = TemplateIO(html=True)
remote_calendars = [x for x in RemoteCalendar.select() if x.label]
if not remote_calendars:
return
remote_calendars.sort(lambda x,y: cmp(x.label, y.label))
r += htmltext('<p class="tags">')
remote_cal = get_request().form.get('cal')
agenda_root_url = get_publisher().get_root_url() + 'agenda/'
if remote_cal:
r += htmltext('<a href="%s">%s</a> ') % (agenda_root_url, _('All'))
else:
r += htmltext('<strong><a href="%s">%s</a></strong> ') % (agenda_root_url, _('All'))
if remote_cal != 'local':
r += htmltext('<a href="%s?cal=local">%s</a> ') % (agenda_root_url, _('Local'))
else:
r += htmltext('<strong><a href="%s?cal=local">%s</a></strong> ') % (agenda_root_url, _('Local'))
for cal in remote_calendars:
if remote_cal == str(cal.id):
r += htmltext('<strong><a href="%s?cal=%s">%s</a></strong> ') % (
agenda_root_url, cal.id, cal.label)
else:
r += htmltext('<a href="%s?cal=%s">%s</a> ') % (agenda_root_url, cal.id, cal.label)
r += htmltext('</p>')
return r.getvalue()
def icalendar(self):
if not Event.keys():
raise errors.TraversalError()
response = get_response()
response.set_content_type('text/calendar', 'utf-8')
vcal = Event.as_vcalendar()
if type(vcal) is unicode:
return vcal.encode('utf-8')
else:
return vcal
def atom(self):
response = get_response()
response.set_content_type('application/atom+xml')
from pyatom import pyatom
xmldoc = pyatom.XMLDoc()
feed = pyatom.Feed()
xmldoc.root_element = feed
feed.title = get_cfg('misc', {}).get('sitename', 'Publik') + ' - ' + _('Agenda')
feed.id = get_request().get_url()
author_email = get_cfg('emails', {}).get('reply_to')
if not author_email:
author_email = get_cfg('emails', {}).get('from')
if author_email:
feed.authors.append(pyatom.Author(author_email))
feed.links.append(pyatom.Link(get_request().get_url(1) + '/'))
year, month = time.localtime()[:2]
nyear, nmonth = year, month+1
if nmonth > 12:
nyear, nmonth = nyear+1, 1
events = [x for x in Event.select() if x.in_month(year, month) or x.in_month(nyear, nmonth)]
events.sort(lambda x,y: cmp(x.date_start, y.date_start))
events.reverse()
for item in events:
entry = item.get_atom_entry()
if entry is not None:
feed.entries.append(entry)
return str(feed)
def filter(self, no_event=False):
template.html_top(_('Agenda'))
tags = get_cfg('misc', {}).get('event_tags')
if not tags:
tags = get_default_event_tags()
remote_calendars = [x for x in RemoteCalendar.select() if x.label]
form = Form(enctype='multipart/form-data')
if tags and remote_calendars:
form.widgets.append(HtmlWidget('<table id="agenda-filter"><tr><td>'))
if tags:
form.add(CheckboxesWidget, 'tags', title=_('Tags'),
options=[(x,x) for x in tags],
inline=False)
if tags and remote_calendars:
form.widgets.append(HtmlWidget('</td><td>'))
if remote_calendars:
remote_calendars.sort(lambda x,y: cmp(x.label, y.label))
form.add(CheckboxesWidget, 'calendars', title=_('Calendars'),
options=[('local', _('Local'))] + [(x.id, x.label) for x in remote_calendars],
inline=False)
if tags and remote_calendars:
form.widgets.append(HtmlWidget('</td></tr></table>'))
form.add_submit('submit', _('Submit'))
form.add_submit('cancel', _('Cancel'))
if form.get_widget('cancel').parse():
return redirect('.')
if no_event or not form.is_submitted():
r = TemplateIO(html=True)
if no_event:
r += htmltext('<p id="nb-events">')
r += _('No events matching the filter.')
r += htmltext('</p>')
r += form.render()
return r.getvalue()
else:
return self.filter_submitted(form, tags, remote_calendars)
def filter_submitted(self, form, tags, remote_calendars):
if remote_calendars:
selected_remote_calendars = form.get_widget('calendars').parse()
events = []
for remote_calendar in selected_remote_calendars:
if remote_calendar == 'local':
events.extend(Event.select())
else:
try:
events.extend(RemoteCalendar.get(remote_calendar).events)
except KeyError:
pass
else:
events = Event.select()
events = [x for x in events if x.after_today()]
if tags:
selected_tags = Set(form.get_widget('tags').parse())
if selected_tags and len(selected_tags) != len(tags):
events = [x for x in events if Set(x.keywords).intersection(selected_tags)]
events.sort(lambda x,y: cmp(x.date_start, y.date_start))
r = TemplateIO(html=True)
if len(events) > 1:
r += htmltext('<p id="nb-events">')
r += htmltext(_('%(nb)d events')) % {'nb': len(events)}
r += htmltext('</p>')
if events:
r += htmltext('<dl id="events">')
for ev in events:
r += htmltext(ev.as_html_dt_dd())
r += htmltext('</dl>')
return r.getvalue()
else:
return self.filter(no_event=True)

View File

@ -1,234 +0,0 @@
import time
import datetime
import urllib2
import vobject
from quixote import get_request, get_publisher, get_response
from quixote.html import htmltext, TemplateIO, htmlescape
from wcs.qommon import _
from wcs.qommon.publisher import get_publisher_class
from wcs.qommon.storage import StorableObject
from wcs.qommon.cron import CronJob
from wcs.qommon import misc
class Event(StorableObject):
_names = 'events'
title = None
description = None
url = None
date_start = None
date_end = None
location = None
organizer = None
more_infos = None
keywords = None
def in_month(self, year, month):
if not self.date_end: # a single date
return tuple(self.date_start[:2]) == (year, month)
else:
# an interval
if tuple(self.date_start[:2]) > (year, month): # start later
return False
if tuple(self.date_end[:2]) < (year, month): # ended before
return False
return True
def after_today(self):
today = time.localtime()[:3]
if not self.date_end:
return tuple(self.date_start[:3]) > today
return tuple(self.date_end[:3]) > today
def format_date(self):
d = {
'year_start': self.date_start[0],
'month_start': misc.get_month_name(self.date_start[1]),
'day_start': self.date_start[2]
}
if self.date_end and self.date_start[:3] != self.date_end[:3]:
d.update({
'year_end': self.date_end[0],
'month_end': misc.get_month_name(self.date_end[1]),
'day_end': self.date_end[2]
})
d2 = datetime.date(*self.date_start[:3]) + datetime.timedelta(days=1)
if tuple(self.date_end[:3]) == (d2.year, d2.month, d2.day):
# two consecutive days
if self.date_start[1] == self.date_end[1]:
return _('On %(month_start)s %(day_start)s and %(day_end)s') % d
else:
return _('On %(month_start)s %(day_start)s and %(month_end)s %(day_end)s') % d
else:
if self.date_start[0] == self.date_end[0]: # same year
if self.date_start[1] == self.date_end[1]: # same month
return _('From %(month_start)s %(day_start)s to %(day_end)s') % d
else:
return _('From %(month_start)s %(day_start)s '
'to %(month_end)s %(day_end)s') % d
else:
return _('From %(month_start)s %(day_start)s %(year_start)s '
'to %(month_end)s %(day_end)s %(year_end)s') % d
else:
return _('On %(month_start)s %(day_start)s') % d
def as_vevent(self):
vevent = vobject.newFromBehavior('vevent')
site_charset = get_publisher().site_charset
vevent.add('uid').value = '%04d%02d%02d-%s@%s' % (self.date_start[:3] + (self.id,
get_request().get_server().lower().split(':')[0].rstrip('.')))
vevent.add('summary').value = unicode(self.title, site_charset)
vevent.add('dtstart').value = datetime.date(*self.date_start[:3])
vevent.dtstart.value_param = 'DATE'
if self.date_end:
vevent.add('dtend').value = datetime.date(*self.date_end[:3])
vevent.dtend.value_param = 'DATE'
if self.description:
vevent.add('description').value = unicode(self.description.strip(), site_charset)
if self.url:
vevent.add('url').value = unicode(self.url, site_charset)
if self.location:
vevent.add('location').value = unicode(self.location, site_charset)
if self.organizer:
vevent.add('organizer').value = unicode(self.organizer, site_charset)
if self.keywords:
vevent.add('categories').value = [unicode(x, site_charset) for x in self.keywords]
vevent.add('class').value = 'PUBLIC'
return vevent
def as_vcalendar(cls):
cal = vobject.iCalendar()
cal.add('prodid').value = '-//Entr\'ouvert//NON SGML Publik'
for x in cls.select():
cal.add(x.as_vevent())
return cal.serialize()
as_vcalendar = classmethod(as_vcalendar)
def as_html_dt_dd(self):
root_url = get_publisher().get_root_url()
r = TemplateIO(html=True)
r += htmltext('<dt>')
r += self.format_date()
r += htmltext('</dt>')
r += htmltext('<p><dd><strong>%s</strong>') % self.title
if self.description:
r += ' - ' + self.description
r += htmltext('</p>')
if (self.location or self.organizer or self.more_infos or self.keywords):
r += htmltext('<ul>')
if self.location:
r += htmltext('<li>%s: %s</li>') % (_('Location'), self.location)
if self.organizer:
r += htmltext('<li>%s: %s</li>') % (_('Organizer'), self.organizer)
if self.more_infos:
r += htmltext('<li>%s</li>') % self.more_infos
if self.keywords:
r += htmltext('<li>')
for k in self.keywords:
r += htmltext('<a class="tag" href="%sagenda/tag/%s">%s</a> ') % (root_url, k, k)
r += htmltext('</li>')
r += htmltext('</ul>')
if self.url:
r += htmltext('<a class="external" href="%s">%s</a>') % (
self.url, _('More information'))
r += htmltext('</dd>')
return r.getvalue()
def get_url(self):
return '%s/agenda/events/%s/' % (get_publisher().get_frontoffice_url(), self.id)
def get_atom_entry(self):
from pyatom import pyatom
entry = pyatom.Entry()
entry.id = self.get_url()
entry.title = self.title
entry.content.attrs['type'] = 'html'
entry.content.text = str('<p>' + htmlescape(
unicode(self.description, get_publisher().site_charset).encode('utf-8')) + '</p>')
return entry
class RemoteCalendar(StorableObject):
_names = 'remote_calendars'
label = None
url = None
content = None
events = None
error = None # (time, string, params)
def download_and_parse(self, job=None):
old_content = self.content
try:
self.content = urllib2.urlopen(self.url).read()
except urllib2.HTTPError, e:
self.error = (time.localtime(), N_('HTTP Error %s on download'), (e.code,))
self.store()
return
except urllib2.URLError, e:
self.error = (time.localtime(), N_('Error on download'), ())
self.store()
return
if self.error:
self.error = None
self.store()
if self.content == old_content:
return
self.events = []
try:
parsed_cal = vobject.readOne(self.content)
except vobject.base.ParseError:
self.error = (time.localtime(), N_('Failed to parse file'), ())
self.store()
return
site_charset = get_publisher().site_charset
for vevent in parsed_cal.vevent_list:
ev = Event()
ev.title = vevent.summary.value.encode(site_charset, 'replace')
try:
ev.url = vevent.url.value.encode(site_charset, 'replace')
except AttributeError:
pass
ev.date_start = vevent.dtstart.value.timetuple()
try:
ev.date_end = vevent.dtend.value.timetuple()
except AttributeError:
pass
try:
ev.description = vevent.description.value.encode(site_charset, 'replace')
except AttributeError:
pass
try:
ev.keywords = [x.encode(site_charset) for x in vevent.categories.value]
except AttributeError:
pass
self.events.append(ev)
self.store()
def get_error_message(self):
if not self.error:
return None
return '(%s) %s' % (misc.localstrftime(self.error[0]),
_(self.error[1]) % self.error[2])
def update_remote_calendars(publisher):
for source in RemoteCalendar.select():
source.download_and_parse()
def get_default_event_tags():
return [_('All Public'), _('Adults'), _('Children'), _('Free')]
get_publisher_class().register_cronjob(CronJob(update_remote_calendars, minutes = [0]))

View File

@ -1,418 +0,0 @@
import time
from quixote import get_request, get_response, get_session, redirect
from quixote.directory import Directory, AccessControlled
from quixote.html import TemplateIO, htmltext
import wcs
import wcs.admin.root
from wcs.qommon import _
from wcs.qommon.backoffice.menu import html_top
from wcs.qommon.admin.menu import command_icon
from wcs.qommon import get_cfg
from wcs.qommon import errors, misc
from wcs.qommon.form import *
from wcs.qommon.misc import strftime
from .events import Event, RemoteCalendar, get_default_event_tags
class RemoteCalendarDirectory(Directory):
_q_exports = ['', 'edit', 'delete', 'update']
def __init__(self, calendar):
self.calendar = calendar
def _q_index(self):
form = Form(enctype='multipart/form-data')
form.add_submit('edit', _('Edit'))
form.add_submit('delete', _('Delete'))
form.add_submit('update', _('Update'))
form.add_submit('back', _('Back'))
if form.get_submit() == 'edit':
return redirect('edit')
if form.get_submit() == 'update':
return redirect('update')
if form.get_submit() == 'delete':
return redirect('delete')
if form.get_submit() == 'back':
return redirect('..')
html_top('events', title = _('Remote Calendar: %s') % self.calendar.label)
r = TemplateIO(html=True)
r += htmltext('<h2>%s</h2>') % _('Remote Calendar: %s') % self.calendar.label
r += get_session().display_message()
r += htmltext('<p>')
self.calendar.url
if self.calendar.error:
r += htmltext(' - <span class="error-message">%s</span>') % self.calendar.get_error_message()
r += htmltext('</p>')
if not self.calendar.content:
r += htmltext('<p>')
r += _('No content has been retrieved yet.')
r += htmltext('</p>')
else:
r += htmltext('<ul>')
for ev in sorted(self.calendar.events, lambda x,y: cmp(x.date_start, y.date_start)):
r += htmltext('<li>')
if ev.date_start:
r += strftime(misc.date_format(), ev.date_start)
if ev.date_end and ev.date_start[:3] != ev.date_end[:3]:
r += ' - '
r += strftime(misc.date_format(), ev.date_start)
r += ' : '
if ev.url:
r += htmltext('<a href="%s">%s</a>') % (ev.url, ev.title)
else:
r += ev.title
r += htmltext('</li>')
r += htmltext('</ul>')
r += form.render()
return r.getvalue()
def edit(self):
form = self.form()
if form.get_submit() == 'cancel':
return redirect('.')
if form.is_submitted() and not form.has_errors():
self.submit(form)
return redirect('..')
html_top('events', title = _('Edit Remote Calendar: %s') % self.calendar.label)
r = TemplateIO(html=True)
r += htmltext('<h2>%s</h2>') % _('Edit Remote Calendar: %s') % self.calendar.label
r += form.render()
return r.getvalue()
def form(self):
form = Form(enctype='multipart/form-data')
form.add(StringWidget, 'label', title = _('Label'), required = True,
value = self.calendar.label)
form.add(StringWidget, 'url', title = _('URL'), required = True,
value = self.calendar.url, size = 40)
form.add_submit('submit', _('Submit'))
form.add_submit('cancel', _('Cancel'))
return form
def submit(self, form):
for k in ('label', 'url'):
widget = form.get_widget(k)
if widget:
setattr(self.calendar, k, widget.parse())
self.calendar.store()
def delete(self):
form = Form(enctype='multipart/form-data')
form.widgets.append(HtmlWidget('<p>%s</p>' % _(
'You are about to irrevocably delete this remote calendar.')))
form.add_submit('submit', _('Submit'))
form.add_submit('cancel', _('Cancel'))
if form.get_submit() == 'cancel':
return redirect('..')
if not form.is_submitted() or form.has_errors():
get_response().breadcrumb.append(('delete', _('Delete')))
html_top('events', title = _('Delete Remote Calendar'))
r = TemplateIO(html=True)
r += htmltext('<h2>%s</h2>') % _('Deleting Remote Calendar: %s') % self.calendar.label
r += form.render()
return r.getvalue()
else:
self.calendar.remove_self()
return redirect('..')
def update(self):
get_session().message = ('info',
_('Calendar update has been requested, reload in a few moments'))
get_response().add_after_job('updating remote calendar',
self.calendar.download_and_parse,
fire_and_forget = True)
return redirect('.')
class RemoteCalendarsDirectory(Directory):
_q_exports = ['', 'new']
def _q_traverse(self, path):
get_response().breadcrumb.append(('remote/', _('Remote Calendars')))
return Directory._q_traverse(self, path)
def _q_index(self):
return redirect('..')
def new(self):
calendar_ui = RemoteCalendarDirectory(RemoteCalendar())
form = calendar_ui.form()
if form.get_submit() == 'cancel':
return redirect('.')
if form.is_submitted() and not form.has_errors():
calendar_ui.submit(form)
return redirect('%s/' % calendar_ui.calendar.id)
get_response().breadcrumb.append(('new', _('New Remote Calendar')))
html_top('events', title = _('New Remote Calendar'))
r = TemplateIO(html=True)
r += htmltext('<h2>%s</h2>') % _('New Remote Calendar')
r += form.render()
return r.getvalue()
def _q_lookup(self, component):
try:
event = RemoteCalendar.get(component)
except KeyError:
raise errors.TraversalError()
get_response().breadcrumb.append((str(event.id), event.label))
return RemoteCalendarDirectory(event)
class EventDirectory(Directory):
_q_exports = ['', 'edit', 'delete']
def __init__(self, event):
self.event = event
def _q_index(self):
form = Form(enctype='multipart/form-data')
form.add_submit('edit', _('Edit'))
form.add_submit('delete', _('Delete'))
form.add_submit('back', _('Back'))
if form.get_submit() == 'edit':
return redirect('edit')
if form.get_submit() == 'delete':
return redirect('delete')
if form.get_submit() == 'back':
return redirect('..')
html_top('events', title = _('Event: %s') % self.event.title)
r = TemplateIO(html=True)
r += htmltext('<h2>%s</h2>') % _('Event: %s') % self.event.title
r += htmltext('<p>')
r += self.event.description
r += htmltext('</p>')
r += htmltext('<ul>')
if self.event.location:
r += htmltext('<li>%s: %s</li>') % (_('Location'), self.event.location)
if self.event.organizer:
r += htmltext('<li>%s: %s</li>') % (_('Organizer'), self.event.organizer)
if self.event.url:
r += htmltext('<li>%s: <a href="%s">%s</a></li>') % (_('URL'), self.event.url, self.event.url)
r += htmltext('</ul>')
if self.event.more_infos:
r += htmltext('<p>')
r += self.event.more_infos
r += htmltext('</p>')
r += form.render()
return r.getvalue()
def edit(self):
form = self.form()
if form.get_submit() == 'cancel':
return redirect('.')
if form.is_submitted() and not form.has_errors():
self.submit(form)
return redirect('..')
html_top('events', title = _('Edit Event: %s') % self.event.title)
r = TemplateIO(html=True)
r += htmltext('<h2>%s</h2>') % _('Edit Event: %s') % self.event.title
r += form.render()
return r.getvalue()
def form(self):
form = Form(enctype='multipart/form-data')
form.add(StringWidget, 'title', title = _('Title'), required = True,
value = self.event.title)
form.add(TextWidget, 'description', title = _('Description'),
cols = 70, rows = 10,
required = True, value = self.event.description)
form.add(StringWidget, 'url', title = _('URL'), required = False,
value = self.event.url, size = 40)
form.add(DateWidget, 'date_start', title = _('Start Date'), required = True,
value = strftime(misc.date_format(), self.event.date_start))
form.add(DateWidget, 'date_end', title = _('End Date'), required = False,
value = strftime(misc.date_format(), self.event.date_end))
form.add(TextWidget, 'location', title = _('Location'),
cols = 70, rows = 4,
required = False, value = self.event.location)
form.add(StringWidget, 'organizer', title = _('Organizer'), required = False,
value = self.event.organizer, size = 40)
form.add(TextWidget, 'more_infos', title = _('More informations'),
cols = 70, rows = 10,
required = False, value = self.event.more_infos)
form.add(TagsWidget, 'keywords', title = _('Keywords'),
value = self.event.keywords, size = 50,
known_tags = get_cfg('misc', {}).get('event_tags', get_default_event_tags()))
form.add_submit('submit', _('Submit'))
form.add_submit('cancel', _('Cancel'))
return form
def submit(self, form):
for k in ('title', 'description', 'url', 'date_start', 'date_end',
'organizer', 'location', 'more_infos', 'keywords'):
widget = form.get_widget(k)
if widget:
if k in ('date_start', 'date_end'):
# convert dates to 9-item tuples
v = widget.parse()
if v:
setattr(self.event, k, time.strptime(v, misc.date_format()))
else:
setattr(self.event, k, None)
else:
setattr(self.event, k, widget.parse())
self.event.store()
def delete(self):
form = Form(enctype='multipart/form-data')
form.widgets.append(HtmlWidget('<p>%s</p>' % _(
'You are about to irrevocably delete this event.')))
form.add_submit('submit', _('Submit'))
form.add_submit('cancel', _('Cancel'))
if form.get_submit() == 'cancel':
return redirect('..')
if not form.is_submitted() or form.has_errors():
get_response().breadcrumb.append(('delete', _('Delete')))
html_top('events', title = _('Delete Event'))
r = TemplateIO(html=True)
r += htmltext('<h2>%s</h2>') % _('Deleting Event: %s') % self.event.title
r += form.render()
return r.getvalue()
else:
self.event.remove_self()
return redirect('..')
class EventsDirectory(AccessControlled, Directory):
_q_exports = ['', 'new', 'listing', 'remote']
label = N_('Events')
remote = RemoteCalendarsDirectory()
def is_accessible(self, user):
from .backoffice import check_visibility
return check_visibility('events', user)
def _q_access(self):
user = get_request().user
if not user:
raise errors.AccessUnauthorizedError()
if not self.is_accessible(user):
raise errors.AccessForbiddenError(
public_msg = _('You are not allowed to access Events Management'),
location_hint = 'backoffice')
get_response().breadcrumb.append(('events/', _('Events')))
def _q_index(self):
html_top('events', _('Events'))
r = TemplateIO(html=True)
get_response().filter['sidebar'] = self.get_sidebar()
r += htmltext('<div class="splitcontent-left">')
r += htmltext('<div class="bo-block">')
events = Event.select()
r += htmltext('<h2>%s</h2>') % _('Events')
if not events:
r += htmltext('<p>')
r += _('There is no event defined at the moment.')
r += htmltext('</p>')
r += htmltext('<ul class="biglist" id="events-list">')
for l in events:
event_id = l.id
r += htmltext('<li class="biglistitem" id="itemId_%s">') % event_id
r += htmltext('<strong class="label"><a href="%s/">%s</a></strong>') % (event_id, l.title)
r += ' - '
r += l.format_date()
r += htmltext('<p class="commands">')
r += command_icon('%s/edit' % event_id, 'edit')
r += command_icon('%s/delete' % event_id, 'remove')
r += htmltext('</p></li>')
r += htmltext('</ul>')
r += htmltext('</div>')
r += htmltext('</div>')
r += htmltext('<div class="splitcontent-right">')
r += htmltext('<div class="bo-block">')
rcalendars = RemoteCalendar.select()
r += htmltext('<h2>%s</h2>') % _('Remote Calendars')
if not rcalendars:
r += htmltext('<p>')
r += _('There is no remote calendars defined at the moment.')
r += htmltext('</p>')
r += htmltext('<ul class="biglist" id="events-list">')
for l in rcalendars:
rcal_id = l.id
r += htmltext('<li class="biglistitem" id="itemId_%s">') % rcal_id
r += htmltext('<strong class="label"><a href="remote/%s/">%s</a></strong>') % (rcal_id, l.label)
r += htmltext('<p class="details">')
r += l.url
if l.error:
r += htmltext('<br /><span class="error-message">%s</span>') % l.get_error_message()
r += htmltext('</p>')
r += htmltext('<p class="commands">')
r += command_icon('remote/%s/edit' % rcal_id, 'edit')
r += command_icon('remote/%s/delete' % rcal_id, 'remove')
r += htmltext('</p></li>')
r += htmltext('</ul>')
r += htmltext('</div>')
r += htmltext('</div>')
return r.getvalue()
def get_sidebar(self):
r = TemplateIO(html=True)
r += htmltext('<ul id="sidebar-actions">')
r += htmltext(' <li><a class="new-item" href="new">%s</a></li>') % _('New Event')
r += htmltext(' <li><a class="new-item" href="remote/new">%s</a></li>') % _('New Remote Calendar')
r += htmltext('</ul>')
return r.getvalue()
def new(self):
event_ui = EventDirectory(Event())
form = event_ui.form()
if form.get_submit() == 'cancel':
return redirect('.')
if form.is_submitted() and not form.has_errors():
event_ui.submit(form)
return redirect('%s/' % event_ui.event.id)
get_response().breadcrumb.append(('new', _('New Event')))
html_top('events', title = _('New Event'))
r = TemplateIO(html=True)
r += htmltext('<h2>%s</h2>') % _('New Event')
r += form.render()
return r.getvalue()
def _q_lookup(self, component):
try:
event = Event.get(component)
except KeyError:
raise errors.TraversalError()
get_response().breadcrumb.append((str(event.id), event.title))
return EventDirectory(event)
def listing(self):
return redirect('.')

View File

@ -36,8 +36,6 @@ from wcs.qommon.admin.texts import TextsDirectory
from .announces import Announce, AnnounceSubscription from .announces import Announce, AnnounceSubscription
from .myspace import MyspaceDirectory from .myspace import MyspaceDirectory
from .agenda import AgendaDirectory
from .events import Event, get_default_event_tags
from .payments import PublicPaymentDirectory from .payments import PublicPaymentDirectory
from .payments_ui import InvoicesDirectory from .payments_ui import InvoicesDirectory
@ -760,7 +758,7 @@ class AlternateRootDirectory(OldRootDirectory):
'saml', 'register', 'ident', 'afterjobs', 'saml', 'register', 'ident', 'afterjobs',
('informations-editeur', 'informations_editeur'), ('informations-editeur', 'informations_editeur'),
('announces', 'announces_dir'), ('announces', 'announces_dir'),
'myspace', 'services', 'agenda', 'categories', 'user', 'myspace', 'services', 'categories', 'user',
('tmp-upload', 'tmp_upload'), 'json', '__version__', ('tmp-upload', 'tmp_upload'), 'json', '__version__',
'themes', 'pages', 'payment', 'invoices', 'roles', 'themes', 'pages', 'payment', 'invoices', 'roles',
'api', 'code', 'fargo', 'tryauth', 'auth', 'preview', 'api', 'code', 'fargo', 'tryauth', 'auth', 'preview',
@ -772,7 +770,6 @@ class AlternateRootDirectory(OldRootDirectory):
login = AlternateLoginDirectory() login = AlternateLoginDirectory()
ident = AlternateIdentDirectory() ident = AlternateIdentDirectory()
myspace = MyspaceDirectory() myspace = MyspaceDirectory()
agenda = AgendaDirectory()
saml = Saml2Directory() saml = Saml2Directory()
payment = PublicPaymentDirectory() payment = PublicPaymentDirectory()
invoices = InvoicesDirectory() invoices = InvoicesDirectory()
@ -1095,24 +1092,6 @@ class AlternateRootDirectory(OldRootDirectory):
r += htmltext('</ul>') r += htmltext('</ul>')
r += htmltext('</div>') r += htmltext('</div>')
if get_cfg('aq-permissions', {}).get('events') and Event.keys():
# if there are events, add a link to the agenda
tags = get_cfg('misc', {}).get('event_tags')
if not tags:
tags = get_default_event_tags()
r += htmltext('<h3 id="agenda-link"><a href="%sagenda/">%s</a></h3>') % (root_url, _('Agenda'))
if path and path[0] == 'agenda':
r += htmltext('<p class="tags">')
for tag in tags:
r += htmltext('<a href="%sagenda/tag/%s">%s</a> ') % (root_url, tag, tag)
r += htmltext('</p>')
r += self.agenda.display_remote_calendars()
r += htmltext('<p>')
r += htmltext(' <a href="%sagenda/filter">%s</a>') % (root_url, _('Advanced Filter'))
r += htmltext('</p>')
v = r.getvalue() v = r.getvalue()
if v: if v:
r = TemplateIO(html=True) r = TemplateIO(html=True)

View File

@ -48,11 +48,6 @@ def render_response(publisher, body):
section_title = '<h2 id="announces">%s</h2>\n' % _('Announces to citizens') section_title = '<h2 id="announces">%s</h2>\n' % _('Announces to citizens')
if page_title == _('Announces to citizens'): if page_title == _('Announces to citizens'):
page_title = '' page_title = ''
elif section == 'agenda':
response.filter['bigdiv'] = 'rub_agenda'
section_title = '<h2 id="agenda">%s</h2>\n' % _('Agenda')
if page_title == _('Agenda'):
page_title = ''
elif section and len(section) > 1: elif section and len(section) > 1:
# XXX: this works but is not efficient # XXX: this works but is not efficient
if Category.has_urlname(section): if Category.has_urlname(section):