api: add ics export API view (#16797)

This commit is contained in:
Frédéric Péters 2017-07-26 11:53:09 +02:00
parent 78db869ae2
commit 412844fbdd
4 changed files with 110 additions and 2 deletions

2
debian/control vendored
View File

@ -9,7 +9,7 @@ X-Python-Version: 2.7
Package: wcs
Architecture: all
Depends: ${python:Depends}, python-quixote, python-scgi, graphviz, python-feedparser, python-imaging
Depends: ${python:Depends}, python-quixote, python-scgi, graphviz, python-feedparser, python-imaging, python-vobject
Recommends: python-dns, python-xlwt, python-qrcode, libjs-leaflet, python-magic
Suggests: libapache2-mod-scgi | libapache-mod-scgi, python-libxml2, python-lasso, python-psycopg2
Description: web application to design and set up online forms

View File

@ -1445,6 +1445,56 @@ def test_api_geojson_formdata(pub, local_user):
formdef.store()
resp = get_app(pub).get(sign_uri('/api/forms/test/geojson', user=local_user), status=404)
def test_api_ics_formdata(pub, local_user):
Role.wipe()
role = Role(name='test')
role.store()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'test'
formdef.workflow_roles = {'_receiver': role.id}
formdef.fields = [
fields.StringField(id='0', label='foobar', varname='foobar'),
]
formdef.store()
data_class = formdef.data_class()
data_class.wipe()
# check access is denied if the user has not the appropriate role
resp = get_app(pub).get(sign_uri('/api/forms/test/ics/foobar', user=local_user), status=403)
# even if there's an anonymse parameter
resp = get_app(pub).get(sign_uri('/api/forms/test/ics/foobar?anonymise', user=local_user), status=403)
date = datetime.datetime(2014, 1, 20, 12, 00)
for i in range(30):
formdata = data_class()
formdata.data = {'0': (date + datetime.timedelta(days=i)).strftime('%Y-%m-%d %H:%M')}
formdata.user_id = local_user.id
formdata.just_created()
if i%3 == 0:
formdata.jump_status('new')
else:
formdata.jump_status('finished')
formdata.store()
# add proper role to user
local_user.roles = [role.id]
local_user.store()
# check it gets the data
resp = get_app(pub).get(sign_uri('/api/forms/test/ics/foobar', user=local_user))
assert resp.headers['content-type'] == 'text/calendar; charset=utf-8'
assert resp.body.count('BEGIN:VEVENT') == 10
# check with a filter
resp = get_app(pub).get(sign_uri('/api/forms/test/ics/foobar?filter=done', user=local_user))
assert resp.body.count('BEGIN:VEVENT') == 20
# check 404 on erroneous field var
resp = get_app(pub).get(sign_uri('/api/forms/test/ics/xxx', user=local_user), status=404)
def test_roles(pub, local_user):
Role.wipe()
role = Role(name='Hello World')

View File

@ -121,7 +121,6 @@ class ApiFormPage(BackofficeFormPage):
# otherwise be accessible if the user is the submitter.
self.check_access()
def check_access(self):
if 'anonymise' in get_request().form:
if not is_url_signed() or (get_request().user and get_request().user.is_admin):
@ -136,6 +135,9 @@ class ApiFormPage(BackofficeFormPage):
raise AccessForbiddenError('unsufficient roles')
def _q_lookup(self, component):
if component == 'ics':
return self.ics()
try:
formdata = self.formdef.data_class().get(component)
except KeyError:

View File

@ -20,6 +20,7 @@ import datetime
import json
import time
import urllib
import vobject
try:
import xlwt
@ -36,6 +37,7 @@ from qommon.admin.menu import command_icon
from qommon.backoffice.menu import html_top
from qommon.backoffice.listing import pagination_links
from qommon import misc, get_logger
from qommon.evalutils import make_datetime
from qommon.misc import C_, ellipsize
from qommon.afterjobs import AfterJob
from qommon import emails
@ -1598,6 +1600,57 @@ class FormPage(Directory):
geoloc_key = self.formdef.geolocations.keys()[0]
return json.dumps(geojson_formdatas(items, fields=fields))
def ics(self):
if 'anonymise' in get_request().form:
# api/ will let this pass but we don't want that.
raise errors.AccessForbiddenError()
self.check_access()
formdef = self.formdef
selected_filter = self.get_filter_from_query()
fields = self.get_fields_from_query()
criterias = self.get_criterias_from_query()
query = get_request().form.get('q')
class IcsDirectory(Directory):
# ics/<component> with <component> being the identifier (varname)
# of the field to use as start date (may be a date field or a
# string field).
def _q_lookup(self, component):
for field in formdef.get_all_fields():
if not getattr(field, 'varname', None) == component:
continue
datefield_field_id = field.id
break
else:
raise errors.TraversalError()
user = get_user_from_api_query_string() or get_request().user
formdatas, total_count = FormDefUI(formdef).get_listing_items(
selected_filter, user=user, query=query, criterias=criterias)
cal = vobject.iCalendar()
cal.add('prodid').value = '-//Entr\'ouvert//NON SGML Publik'
for formdata in formdatas:
if not formdata.data.get(datefield_field_id):
continue
vevent = vobject.newFromBehavior('vevent')
vevent.add('uid').value = '%s-%s-%s' % (
get_request().get_server().lower(),
formdef.url_name,
formdata.id)
vevent.add('summary').value = formdata.get_display_name()
vevent.add('dtstart').value = make_datetime(formdata.data[datefield_field_id])
vevent.dtstart.value_param = 'DATE'
vevent.add('url').value = formdata.get_url(backoffice=True)
cal.add(vevent)
get_response().set_content_type('text/calendar')
return cal.serialize()
return IcsDirectory()
def map(self):
get_response().add_javascript(['qommon.map.js'])
html_top('management', '%s - %s' % (_('Form'), self.formdef.name))
@ -1830,6 +1883,9 @@ class FormPage(Directory):
return r.getvalue()
def _q_lookup(self, component):
if component == 'ics':
return self.ics()
try:
filled = self.formdef.data_class().get(component)
except KeyError: