From 0da7d3faf86c28db41b772c4ccb78d7375bd914a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= Date: Fri, 13 Nov 2015 11:36:55 +0100 Subject: [PATCH] =?UTF-8?q?backoffice:=20add=20a=20"360=C2=B0=20User=20Vie?= =?UTF-8?q?w"=20(#2125)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_backoffice_pages.py | 31 +++++ wcs/backoffice/management.py | 220 +++++++++++++++++++++++++++++++++++- wcs/qommon/static/css/dc2/admin.css | 4 + 3 files changed, 253 insertions(+), 2 deletions(-) diff --git a/tests/test_backoffice_pages.py b/tests/test_backoffice_pages.py index 4c8d6fb..6965f06 100644 --- a/tests/test_backoffice_pages.py +++ b/tests/test_backoffice_pages.py @@ -49,6 +49,7 @@ def create_user(pub, is_admin=False): user1.store() return user1 user1 = pub.user_class(name='admin') + user1.email = 'admin@localhost' user1.is_admin = is_admin user1.store() @@ -1237,3 +1238,33 @@ def test_backoffice_file_field_validation(pub, fargo_url): assert 'Justificatif de domicile validated by Jean Bono on 2014-01-01T01:01:01' in resp.body assert 'Code postal: 13400' in resp.body assert 'Valid from 2014-01-01T01:01:01 to 2014-01-01T01:01:01' in resp.body + +def test_360_user_view(pub): + if not pub.is_using_postgresql(): + pytest.skip('this requires SQL') + return + + user = create_user(pub) + create_environment(pub) + app = login(get_app(pub)) + resp = app.get('/backoffice/management/') + assert '360 User View' in resp.body + resp = resp.click('360 User View') + assert 'Use the search field on the right' in resp.body + + resp.form['q'] = 'admin' + resp = resp.form.submit() + + assert resp.body.count('') + r += htmltext('

%s

') % self.user.display_name + formdef = UserFieldsFormDef() + r += htmltext('
') + for field in formdef.fields: + if not hasattr(field, str('get_view_value')): + continue + value = self.user.form_data.get(field.id) + if not value: + continue + r += htmltext('
') + r += field.label + r += htmltext('
') + r += htmltext('
') + r += field.get_view_value(value) + r += htmltext('
') + r += htmltext('
') + r += htmltext('') + + if formdatas: + categories = {} + formdata_by_category = {} + for formdata in formdatas: + if not formdata.formdef.category_id in categories: + categories[formdata.formdef.category_id] = formdata.formdef.category + formdata_by_category[formdata.formdef.category_id] = [] + formdata_by_category[formdata.formdef.category_id].append(formdata) + cats = categories.values() + Category.sort_by_position(cats) + for cat in cats: + r += htmltext('
') + if len(cats) > 1: + if cat is None: + r += htmltext('

%s

') % _('Misc') + cat_formdatas = formdata_by_category[None] + else: + r += htmltext('

%s

') % cat.name + cat_formdatas = formdata_by_category[cat.id] + else: + cat_formdatas = formdatas + r += htmltext('
    ') + for formdata in cat_formdatas: + status = formdata.get_status() + if status: + status_label = status.name + else: + status_label = _('Unknown') + submit_date = misc.strftime.strftime( + misc.date_format(), formdata.receipt_time) + r += htmltext('
  • %s, ' + '%s ' + '(%s)' % ( + formdata.get_url(backoffice=True), + formdata.formdef.name, + submit_date, status_label)) + r += htmltext('
') + r += htmltext('
') + r += htmltext('') + + return r.getvalue() + + +class UsersViewDirectory(Directory): + _q_exports = [''] + + def _q_traverse(self, path): + if not get_publisher().is_using_postgresql(): + raise errors.TraversalError() + get_response().breadcrumb.append(('users', _('360 User View'))) + return super(UsersViewDirectory, self)._q_traverse(path) + + def get_search_sidebar(self, offset=None, limit=None, order_by=None): + get_response().add_javascript(['jquery.js', 'jquery-ui.js', 'wcs.listing.js']) + get_response().add_css_include('../js/smoothness/jquery-ui-1.10.0.custom.min.css') + + r = TemplateIO(html=True) + r += htmltext('
') + if offset or limit: + if not offset: + offset = 0 + r += htmltext('') % offset + if limit: + r += htmltext('') % limit + + if order_by is None: + order_by = '' + r += htmltext('') % order_by + + r += htmltext('

%s

') % _('Search') + if get_request().form.get('q'): + q = get_request().form.get('q') + if type(q) is not unicode: + q = unicode(q, get_publisher().site_charset) + r += htmltext('') % q.encode(get_publisher().site_charset) + else: + r += htmltext('') + r += htmltext('') % _('Search') + + return r.getvalue() + + def _q_index(self): + html_top('management', _('Management')) + r = TemplateIO(html=True) + + limit = int(get_request().form.get('limit', + get_publisher().get_site_option('default-page-size')) or 20) + offset = int(get_request().form.get('offset', 0)) + order_by = get_request().form.get('order_by', None) or 'name' + query = get_request().form.get('q') + + get_response().filter['sidebar'] = self.get_search_sidebar( + limit=limit, offset=offset, order_by=order_by) + + if not query: + r += htmltext('
') + r += htmltext('
') + r += htmltext('

%s

') % _('Use the search field on the right ' + 'to look for an user.') + r += htmltext('
') + r += htmltext('
') + if get_request().form.get('ajax') == 'true': + get_response().filter = None + return r.getvalue() + + criterias = [] + criteria_fields = [ILike('name', query), ILike('email', query)] + formdef = UserFieldsFormDef() + for field in formdef.fields: + if field.type in ('string', 'text', 'email'): + criteria_fields.append(ILike('f%s' % field.id, query)) + criterias.append(Or(criteria_fields)) + + users = get_publisher().user_class.select(order_by=order_by, + clause=criterias, limit=limit, offset=offset) + total_count = get_publisher().user_class.count(criterias) + + users_cfg = get_cfg('users', {}) + include_name_column = not(users_cfg.get('field_name')) + include_email_column = not(users_cfg.get('field_email')) + r += htmltext('
') + r += htmltext('') + r += htmltext('') + r += htmltext('') + if include_name_column: + r += htmltext('') % _('Name') + if include_email_column: + r += htmltext('') % _('Email') + for field in formdef.fields: + if field.in_listing: + r += htmltext('') % ( + field.id, field.label) + r += htmltext('') + r += htmltext('') + r += htmltext('') + + for user in users: + r += htmltext('') % user.id + if include_name_column: + r += htmltext('') % (user.name or '') + if include_email_column: + r += htmltext('') % (user.email or '') + for field in formdef.fields: + if field.in_listing: + r += htmltext('') % (user.form_data.get(field.id) or '') + r += htmltext('') + + r += htmltext('') + r += htmltext('
%s%s%s
%s%s%s
') + + if (offset > 0) or (total_count > limit > 0): + r += pagination_links(offset, limit, total_count) + + r += htmltext('
') + + if get_request().form.get('ajax') == 'true': + get_response().filter = None + return r.getvalue() + + return r.getvalue() + + def _q_lookup(self, component): + try: + user = get_publisher().user_class.get(component) + return UserViewDirectory(user) + except KeyError: + pass + raise errors.TraversalError() + + class ManagementDirectory(Directory): - _q_exports = ['', 'listing', 'statistics', 'code', 'count'] + _q_exports = ['', 'listing', 'statistics', 'code', 'count', 'users'] + + users = UsersViewDirectory() def is_accessible(self, user): return user.can_go_in_backoffice() @@ -120,6 +335,7 @@ class ManagementDirectory(Directory): if get_publisher().is_using_postgresql() and \ get_publisher().get_site_option('postgresql_views') != 'false': r += htmltext('
  • %s
  • ') % _('Global View') + r += htmltext('
  • %s
  • ') % _('360 User View') r += htmltext('') r += htmltext('') r += self.get_tracking_code_sidebox() diff --git a/wcs/qommon/static/css/dc2/admin.css b/wcs/qommon/static/css/dc2/admin.css index dc28093..43109b2 100644 --- a/wcs/qommon/static/css/dc2/admin.css +++ b/wcs/qommon/static/css/dc2/admin.css @@ -335,6 +335,10 @@ span.activity-done { background-image: none; } +#listing { + margin-bottom: 1em; +} + ul.biglist, table#listing { -webkit-transition: opacity 500ms ease-out; -moz-transition: opacity 500ms ease-out; -- 2.6.2