From 35cde66c17295f49172e28ec448f1658294ef786 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= Date: Tue, 5 May 2015 23:44:40 +0200 Subject: [PATCH 1/2] backoffice: move management of submitted forms to a subdirectory (#7151) --- tests/test_backoffice_pages.py | 24 +- tests/test_formdata.py | 2 +- wcs/api.py | 2 +- wcs/backoffice/management.py | 1244 ++++++++++++++++++++++++++++++++++++++++ wcs/backoffice/root.py | 1223 +-------------------------------------- wcs/formdef.py | 2 +- 6 files changed, 1272 insertions(+), 1225 deletions(-) create mode 100644 wcs/backoffice/management.py diff --git a/tests/test_backoffice_pages.py b/tests/test_backoffice_pages.py index 56cbc7c..01abd75 100644 --- a/tests/test_backoffice_pages.py +++ b/tests/test_backoffice_pages.py @@ -163,11 +163,11 @@ def test_backoffice_listing(pub): create_superuser(pub) create_environment() app = login(get_app(pub)) - resp = app.get('/backoffice/form-title/') + resp = app.get('/backoffice/management/form-title/') assert resp.body.count('data-link') == 17 # check status filter - resp = app.get('/backoffice/form-title/') + resp = app.get('/backoffice/management/form-title/') resp.forms[0]['filter'] = 'done' resp = resp.forms[0].submit() if getattr(pub, 'pgconn', None): @@ -191,7 +191,7 @@ def test_backoffice_columns(pub): create_superuser(pub) create_environment() app = login(get_app(pub)) - resp = app.get('/backoffice/form-title/') + resp = app.get('/backoffice/management/form-title/') assert resp.body.count('') == 6 # five columns resp.forms[0]['1'].checked = False resp = resp.forms[0].submit() @@ -203,7 +203,7 @@ def test_backoffice_filter(pub): create_superuser(pub) create_environment() app = login(get_app(pub)) - resp = app.get('/backoffice/form-title/') + resp = app.get('/backoffice/management/form-title/') assert resp.forms[0]['filter-status'].checked == True resp.forms[0]['filter-status'].checked = False resp.forms[0]['filter-2'].checked = True @@ -229,12 +229,12 @@ def test_backoffice_csv(pub): create_superuser(pub) create_environment() app = login(get_app(pub)) - resp = app.get('/backoffice/form-title/') + resp = app.get('/backoffice/management/form-title/') resp = resp.click('CSV Export') assert resp.headers['content-type'].startswith('text/') assert len(resp.body.splitlines()) == 18 # 17 + header line - resp = app.get('/backoffice/form-title/') + resp = app.get('/backoffice/management/form-title/') resp.forms[0]['filter'] = 'all' resp = resp.forms[0].submit() resp = resp.click('CSV Export') @@ -244,7 +244,7 @@ def test_backoffice_ods(pub): create_superuser(pub) create_environment() app = login(get_app(pub)) - resp = app.get('/backoffice/form-title/') + resp = app.get('/backoffice/management/form-title/') resp = resp.click('Open Document Format Export') assert resp.headers['content-type'] == 'application/vnd.oasis.opendocument.spreadsheet' assert 'filename=form-title.ods' in resp.headers['content-disposition'] @@ -254,7 +254,7 @@ def test_backoffice_statistics(pub): create_superuser(pub) create_environment() app = login(get_app(pub)) - resp = app.get('/backoffice/form-title/') + resp = app.get('/backoffice/management/form-title/') resp = resp.click('Statistics') assert 'Total number of records: 50' in resp.body assert 'New: 17' in resp.body @@ -272,7 +272,7 @@ def test_backoffice_statistics_status_filter(pub): create_superuser(pub) create_environment() app = login(get_app(pub)) - resp = app.get('/backoffice/form-title/') + resp = app.get('/backoffice/management/form-title/') resp = resp.click('Statistics') assert 'filter' not in resp.forms[0].fields # status is not displayed by default @@ -302,7 +302,7 @@ def test_backoffice_statistics_status_select(pub): create_superuser(pub) create_environment() app = login(get_app(pub)) - resp = app.get('/backoffice/form-title/') + resp = app.get('/backoffice/management/form-title/') resp = resp.click('Statistics') resp.forms[0]['filter-2'].checked = True @@ -325,7 +325,7 @@ def test_backoffice_handling(pub): form_class = FormDef.get_by_urlname('form-title').data_class() number31 = [x for x in form_class.select() if x.data['1'] == 'FOO BAR 30'][0].id app = login(get_app(pub)) - resp = app.get('/backoffice/form-title/') + resp = app.get('/backoffice/management/form-title/') resp = resp.click(href='%s/' % number31) assert (' with the number %s.' % number31) in resp.body resp.forms[0]['comment'] = 'HELLO WORLD' diff --git a/tests/test_formdata.py b/tests/test_formdata.py index 34de23c..a7e99aa 100644 --- a/tests/test_formdata.py +++ b/tests/test_formdata.py @@ -56,7 +56,7 @@ def test_saved(pub): assert substvars.get('form_number') == '1' assert substvars.get('form_number_raw') == '1' assert substvars.get('form_url').endswith('/foobar/1/') - assert substvars.get('form_url_backoffice').endswith('/backoffice/foobar/1/') + assert substvars.get('form_url_backoffice').endswith('/backoffice/management/foobar/1/') assert substvars.get('form_status_url').endswith('/foobar/1/status') def test_display_id(pub): diff --git a/wcs/api.py b/wcs/api.py index b940f28..662778b 100644 --- a/wcs/api.py +++ b/wcs/api.py @@ -120,7 +120,7 @@ def sign_string(s, key, algo='sha256', timedelta=30): # import backoffice.root.FormPage after get_user_from_api_query_string # to avoid circular dependencies -from backoffice.root import FormPage as BackofficeFormPage +from backoffice.management import FormPage as BackofficeFormPage class ApiFormPage(BackofficeFormPage): diff --git a/wcs/backoffice/management.py b/wcs/backoffice/management.py new file mode 100644 index 0000000..43beca4 --- /dev/null +++ b/wcs/backoffice/management.py @@ -0,0 +1,1244 @@ +# w.c.s. - web application for online forms +# Copyright (C) 2005-2015 Entr'ouvert +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . + +import csv +import cStringIO +import datetime +import json +import time + +try: + import xlwt +except ImportError: + xlwt = None + +from quixote import get_session, get_publisher, get_request, get_response, redirect +from quixote.directory import Directory +from quixote.html import TemplateIO, htmltext + +from qommon.backoffice.menu import html_top +from qommon import misc, get_logger +from qommon.afterjobs import AfterJob +from qommon import errors +from qommon import ods +from qommon.form import * +from qommon.storage import Equal, NotEqual, LessOrEqual, GreaterOrEqual, Or + +from wcs.forms.backoffice import FormDefUI +from wcs.forms.common import FormStatusPage + +from wcs.categories import Category +from wcs.formdef import FormDef + + +class ManagementDirectory(Directory): + _q_exports = ['', 'statistics'] + + def _q_traverse(self, path): + get_response().breadcrumb.append(('management/', _('Management'))) + return super(ManagementDirectory, self)._q_traverse(path) + + def _q_index(self): + html_top('management', _('Management')) + get_response().filter['sidebar'] = self.get_sidebar() + r = TemplateIO(html=True) + + user = get_request().user + + forms_without_pending_stuff = [] + forms_with_pending_stuff = [] + + def append_form_entry(formdef): + formdef_data_class = formdef.data_class() + count_forms = formdef_data_class.count() - len(formdef_data_class.get_ids_with_indexed_value('status', 'draft')) + not_endpoint_status = formdef.workflow.get_not_endpoint_status() + not_endpoint_status_ids = ['wf-%s' % x.id for x in not_endpoint_status] + pending_forms = [] + for status in not_endpoint_status_ids: + pending_forms.extend(formdef_data_class.get_ids_with_indexed_value( + 'status', status)) + + if formdef.acl_read != 'all' and pending_forms: + concerned_ids = set() + formdata_class = formdef.data_class() + user_roles = set(user.roles or []) + for role in user_roles: + concerned_ids |= set(formdata_class.get_ids_with_indexed_value( + 'concerned_roles', str(role))) + pending_forms = set(pending_forms).intersection(concerned_ids) + + if len(pending_forms) == 0: + forms_without_pending_stuff.append((formdef, len(pending_forms), count_forms)) + else: + forms_with_pending_stuff.append((formdef, len(pending_forms), count_forms)) + + if user: + for formdef in FormDef.select(order_by='name', ignore_errors=True): + if formdef.disabled: + continue + if user.is_admin or formdef.is_of_concern_for_user(user): + append_form_entry(formdef) + + if forms_with_pending_stuff: + r += htmltext('
') + r += htmltext('

%s

') % _('Forms in your care') + r += self.display_forms(forms_with_pending_stuff) + r += htmltext('
') + + if forms_without_pending_stuff: + r += htmltext('
') + r += htmltext('

%s

') % _('Other Forms') + r += self.display_forms(forms_without_pending_stuff) + r += htmltext('
') + + return r.getvalue() + + def get_sidebar(self): + r = TemplateIO(html=True) + r += htmltext('
') + r += htmltext('') + r += htmltext('
') + return r.getvalue() + + def get_stats_sidebar(self): + get_response().add_javascript(['jquery.js']) + DateWidget.prepare_javascript() + form = Form(use_tokens=False) + form.add(DateWidget, 'start', title=_('Start Date')) + form.add(DateWidget, 'end', title=_('End Date')) + form.add_submit('submit', _('Submit')) + + r = TemplateIO(html=True) + r += htmltext('

%s

') % _('Period') + r += form.render() + + r += htmltext('

%s

') % _('Shortcuts') + r += htmltext('