backoffice: allow adding custom user column to management tables (#40031)

This commit is contained in:
Frédéric Péters 2020-07-31 13:56:08 +02:00 committed by Thomas NOEL
parent fe4b237fd9
commit a6315551b5
5 changed files with 94 additions and 16 deletions

View File

@ -651,6 +651,46 @@ def test_backoffice_image_column(pub):
assert 'download?f=4&thumbnail=1' not in resp.text
def test_backoffice_user_columns(pub):
create_superuser(pub)
create_environment(pub)
from wcs.admin.settings import UserFieldsFormDef
user_formdef = UserFieldsFormDef(pub)
user_formdef.fields.append(fields.StringField(id='_first_name', label='name', type='string'))
user_formdef.fields.append(fields.StringField(id='3', label='test', type='string'))
user_formdef.store()
pub.cfg['users']['field_name'] = ['3', '4']
pub.write_cfg()
user1 = pub.user_class(name='userA')
user1.form_data = {'_first_name': 'toto', '3': 'nono'}
user1.set_attributes_from_formdata(user1.form_data)
user1.store()
user2 = pub.user_class(name='userB')
user2.form_data = {'_first_name': 'tutu', '3': 'nunu'}
user2.set_attributes_from_formdata(user2.form_data)
user2.store()
formdef = FormDef.get_by_urlname('form-title')
for i, formdata in enumerate(formdef.data_class().select()):
formdata.user_id = user1.id if bool(i % 2) else user2.id
formdata.store()
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/')
assert resp.text.count('</th>') == 8 # six columns
if not pub.is_using_postgresql():
# no support for relation columns unless using SQL
assert 'user-label$3' not in resp.forms['listing-settings'].fields
return
resp.forms['listing-settings']['user-label$3'].checked = True
resp = resp.forms['listing-settings'].submit()
assert resp.text.count('</th>') == 9
assert '<td>nono</td' in resp
def test_backoffice_card_field_columns(pub):
user = create_superuser(pub)
create_environment(pub)

View File

@ -1428,9 +1428,9 @@ class FormPage(Directory):
attrs = ''
if isinstance(field, RelatedField):
classnames = 'related-field'
if field.parent_field.id in seen_parents:
if field.parent_field_id in seen_parents:
classnames += ' collapsed'
attrs = 'data-relation-attr="%s"' % field.parent_field.id
attrs = 'data-relation-attr="%s"' % field.parent_field_id
elif getattr(field, 'has_relations', False):
classnames = 'has-relations-field'
attrs = 'data-field-id="%s"' % field.id
@ -1538,7 +1538,16 @@ class FormPage(Directory):
yield FakeField('submission_agent', 'submission_agent', _('Submission By'))
yield FakeField('time', 'time', _('Created'))
yield FakeField('last_update_time', 'last_update_time', _('Last Modified'))
# user fields
yield FakeField('user-label', 'user-label', _('User Label'))
if get_publisher().is_using_postgresql():
for field in get_publisher().user_class.get_fields():
if not hasattr(field, 'get_view_value'):
continue
field.has_relations = True
yield UserRelatedField(field)
for field in self.formdef.get_all_fields():
yield field
if not get_publisher().is_using_postgresql():
@ -3161,6 +3170,10 @@ class FakeField(object):
def get_csv_value(self, element, **kwargs):
return [element]
@property
def has_relations(self):
return bool(self.id == 'user-label')
class RelatedField:
is_related_field = True
@ -3170,16 +3183,17 @@ class RelatedField:
def __init__(self, carddef, field, parent_field):
self.carddef = carddef
self.carddef_field = field
self.related_field = field
self.parent_field = parent_field
self.parent_field_id = parent_field.id
@property
def id(self):
return '%s$%s' % (self.parent_field.id, self.carddef_field.id)
return '%s$%s' % (self.parent_field_id, self.related_field.id)
@property
def label(self):
return '%s - %s' % (self.parent_field.label, self.carddef_field.label)
return '%s - %s' % (self.parent_field.label, self.related_field.label)
def get_view_value(self, value, **kwargs):
if value is None:
@ -3200,6 +3214,19 @@ class RelatedField:
return [self.get_view_value(value)]
class UserRelatedField(RelatedField):
# it is named 'user-label' and not 'user' for compatibility with existing
# listings, as the 'classic' user column is named 'user-label'.
parent_field_id = 'user-label'
def __init__(self, field):
self.related_field = field
@property
def label(self):
return _('%s of User') % self.related_field.label
def do_graphs_section(period_start=None, period_end=None, criterias=None):
from wcs import sql
r = TemplateIO(html=True)

View File

@ -102,7 +102,7 @@ class FormDefUI(object):
field_sort_key = 'receipt_time'
elif f.id in ('user-label', 'submission_agent'):
field_sort_key = None
elif hasattr(f, 'column_id'):
elif getattr(f, 'is_related_field', False):
field_sort_key = None
else:
field_sort_key = 'f%s' % f.id

View File

@ -1159,19 +1159,25 @@ class SqlMixin(object):
for field in fields:
if not getattr(field, 'is_related_field', False):
continue
carddef_dataclass = field.carddef.data_class()
carddef_table_alias = 't%s' % id(field.carddef)
carddef_table_decl = 'LEFT JOIN %s AS %s ON (CAST(%s.%s AS INTEGER) = %s.id)' % (
carddef_dataclass._table_name,
carddef_table_alias,
cls._table_name,
get_field_id(field.parent_field),
carddef_table_alias)
if field.parent_field_id == 'user-label':
# relation to user table
carddef_table_alias = 'users'
carddef_table_decl = 'LEFT JOIN users ON (CAST(%s.user_id AS INTEGER) = users.id)' % cls._table_name
else:
carddef_dataclass = field.carddef.data_class()
carddef_table_alias = 't%s' % id(field.carddef)
carddef_table_decl = 'LEFT JOIN %s AS %s ON (CAST(%s.%s AS INTEGER) = %s.id)' % (
carddef_dataclass._table_name,
carddef_table_alias,
cls._table_name,
get_field_id(field.parent_field),
carddef_table_alias)
if carddef_table_decl not in tables:
tables.append(carddef_table_decl)
column_field_id = get_field_id(field.carddef_field)
if field.carddef_field.store_display_value:
column_field_id = get_field_id(field.related_field)
if field.related_field.store_display_value:
column_field_id += '_display'
columns.append('%s.%s' % (carddef_table_alias, column_field_id))
extra_fields.append(field.id)

View File

@ -80,6 +80,11 @@ class User(StorableObject):
from .admin.settings import UserFieldsFormDef
return UserFieldsFormDef()
@classmethod
def get_fields(cls):
formdef = cls.get_formdef()
return formdef.fields or []
@property
def ascii_name(self):
return simplify(self.get_display_name(), space=' ')