misc: move filter fields ("FakeField") to their own module (#57779)
This commit is contained in:
parent
e905fd8f2c
commit
f7ec9ad128
|
@ -149,14 +149,14 @@ def test_backoffice_submission_agent_column(pub):
|
|||
|
||||
app = login(get_app(pub))
|
||||
resp = app.get('/backoffice/management/form-title/')
|
||||
assert 'submission_agent' not in resp.forms['listing-settings'].fields
|
||||
assert 'submission-agent' not in resp.forms['listing-settings'].fields
|
||||
|
||||
formdef.backoffice_submission_roles = [role]
|
||||
formdef.store()
|
||||
|
||||
resp = app.get('/backoffice/management/form-title/')
|
||||
assert resp.text.count('</th>') == 6 # four columns
|
||||
resp.forms['listing-settings']['submission_agent'].checked = True
|
||||
resp.forms['listing-settings']['submission-agent'].checked = True
|
||||
resp = resp.forms['listing-settings'].submit()
|
||||
assert resp.text.count('</th>') == 7 # five columns
|
||||
assert resp.text.count('data-link') == 1 # 1 row
|
||||
|
@ -172,7 +172,7 @@ def test_backoffice_submission_agent_column(pub):
|
|||
formdata.store()
|
||||
|
||||
resp = app.get('/backoffice/management/form-title/')
|
||||
resp.forms['listing-settings']['submission_agent'].checked = True
|
||||
resp.forms['listing-settings']['submission-agent'].checked = True
|
||||
resp = resp.forms['listing-settings'].submit()
|
||||
assert resp.text.count('>agent<') == 1
|
||||
|
||||
|
|
|
@ -1426,7 +1426,7 @@ def test_backoffice_submission_agent_filter(pub):
|
|||
app = login(get_app(pub))
|
||||
resp = app.get('/backoffice/management/form-title/?limit=100')
|
||||
# enable submission-agent column
|
||||
resp.forms['listing-settings']['submission_agent'].checked = True
|
||||
resp.forms['listing-settings']['submission-agent'].checked = True
|
||||
resp = resp.forms['listing-settings'].submit()
|
||||
assert resp.text.count('>userA<') > 0
|
||||
assert resp.text.count('>userB<') > 0
|
||||
|
|
|
@ -516,7 +516,7 @@ def test_criteria_repr():
|
|||
|
||||
|
||||
def test_related_field_repr():
|
||||
from wcs.backoffice.management import RelatedField
|
||||
from wcs.backoffice.filter_fields import RelatedField
|
||||
|
||||
related_field = RelatedField(None, field=StringField(label='foo'), parent_field=StringField(label='bar'))
|
||||
assert 'foo' in repr(related_field)
|
||||
|
|
|
@ -0,0 +1,298 @@
|
|||
# w.c.s. - web application for online forms
|
||||
# Copyright (C) 2005-2024 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
import datetime
|
||||
|
||||
from django.utils.encoding import force_str
|
||||
|
||||
from wcs.qommon import _, misc
|
||||
|
||||
|
||||
class FilterField:
|
||||
can_include_in_listing = True
|
||||
id = None
|
||||
key = None
|
||||
label = None
|
||||
addable = True
|
||||
include_in_statistics = False
|
||||
geojson_label = None
|
||||
store_display_value = None
|
||||
store_structured_value = None
|
||||
|
||||
def __init__(self):
|
||||
self.varname = self.id.replace('-', '_')
|
||||
self.contextual_id = self.id
|
||||
self.contextual_varname = self.varname
|
||||
self.geojson_label = force_str(self.geojson_label or self.label)
|
||||
|
||||
def get_view_value(self, value):
|
||||
# just here to quack like a duck
|
||||
return None
|
||||
|
||||
def get_csv_heading(self):
|
||||
return [self.label]
|
||||
|
||||
def get_csv_value(self, element, **kwargs):
|
||||
return [element]
|
||||
|
||||
@property
|
||||
def has_relations(self):
|
||||
False
|
||||
return bool(self.id == 'user-label')
|
||||
|
||||
|
||||
class RelatedField:
|
||||
is_related_field = True
|
||||
key = 'related-field'
|
||||
varname = None
|
||||
related_field = None
|
||||
can_include_in_listing = True
|
||||
|
||||
def __init__(self, carddef, field, parent_field):
|
||||
self.carddef = carddef
|
||||
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.related_field.id)
|
||||
|
||||
@property
|
||||
def contextual_id(self):
|
||||
return self.id
|
||||
|
||||
@property
|
||||
def label(self):
|
||||
return '%s - %s' % (self.parent_field.label, self.related_field.label)
|
||||
|
||||
def __repr__(self):
|
||||
return '<%s (card: %r, parent: %r, related: %r)>' % (
|
||||
self.__class__.__name__,
|
||||
self.carddef,
|
||||
self.parent_field.label,
|
||||
self.related_field.label,
|
||||
)
|
||||
|
||||
@property
|
||||
def store_display_value(self):
|
||||
return self.related_field.store_display_value
|
||||
|
||||
@property
|
||||
def store_structured_value(self):
|
||||
return self.related_field.store_structured_value
|
||||
|
||||
def get_view_value(self, value, **kwargs):
|
||||
if value is None:
|
||||
return ''
|
||||
if isinstance(value, bool):
|
||||
return _('Yes') if value else _('No')
|
||||
if isinstance(value, datetime.date):
|
||||
return misc.strftime(misc.date_format(), value)
|
||||
return value
|
||||
|
||||
def get_view_short_value(self, value, max_len=30, **kwargs):
|
||||
return self.get_view_value(value)
|
||||
|
||||
def get_csv_heading(self):
|
||||
if self.related_field:
|
||||
return self.related_field.get_csv_heading()
|
||||
return [self.label]
|
||||
|
||||
def get_csv_value(self, value, **kwargs):
|
||||
if self.related_field:
|
||||
return self.related_field.get_csv_value(value, **kwargs)
|
||||
return [self.get_view_value(value)]
|
||||
|
||||
def get_column_field_id(self):
|
||||
from wcs.sql import get_field_id
|
||||
|
||||
return get_field_id(self.related_field)
|
||||
|
||||
|
||||
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'
|
||||
store_display_value = None
|
||||
store_structured_value = None
|
||||
|
||||
def __init__(self, field):
|
||||
self.related_field = field
|
||||
|
||||
def __repr__(self):
|
||||
return '<%s (field: %r)>' % (
|
||||
self.__class__.__name__,
|
||||
self.related_field.label,
|
||||
)
|
||||
|
||||
@property
|
||||
def label(self):
|
||||
return _('%s of User') % self.related_field.label
|
||||
|
||||
|
||||
class UserLabelRelatedField(UserRelatedField):
|
||||
# custom user-label column, targetting the "name" (= full name) column
|
||||
# of the users table
|
||||
id = 'user-label'
|
||||
key = 'user-label'
|
||||
varname = 'user_label'
|
||||
has_relations = True
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def __repr__(self):
|
||||
return '<UserLabelRelatedField>'
|
||||
|
||||
def get_column_field_id(self):
|
||||
return 'name'
|
||||
|
||||
@property
|
||||
def label(self):
|
||||
return _('User Label')
|
||||
|
||||
|
||||
class DisplayNameFilterField(FilterField):
|
||||
id = 'name'
|
||||
key = 'display_name'
|
||||
label = _('Name')
|
||||
|
||||
|
||||
class StatusFilterField(FilterField):
|
||||
id = 'status'
|
||||
key = 'status'
|
||||
label = _('Status')
|
||||
include_in_statistics = True
|
||||
|
||||
|
||||
class UserVisibleStatusField(FilterField):
|
||||
id = 'user-visible-status'
|
||||
key = 'user-visible-status'
|
||||
label = _('Status (for user)')
|
||||
geolabel_status = _('Status')
|
||||
|
||||
|
||||
class InternalIdFilterField(FilterField):
|
||||
id = 'internal-id'
|
||||
key = 'internal-id'
|
||||
label = _('Identifier')
|
||||
|
||||
|
||||
class PeriodStartFilterField(FilterField):
|
||||
id = 'start'
|
||||
key = 'period-date'
|
||||
label = _('Start')
|
||||
|
||||
|
||||
class PeriodEndFilterField(FilterField):
|
||||
id = 'end'
|
||||
key = 'period-date'
|
||||
label = _('End')
|
||||
|
||||
|
||||
class PeriodStartUpdateTimeFilterField(FilterField):
|
||||
id = 'start-mtime'
|
||||
key = 'period-date'
|
||||
label = _('Start (modification time)')
|
||||
|
||||
|
||||
class PeriodEndUpdateTimeFilterField(FilterField):
|
||||
id = 'end-mtime'
|
||||
key = 'period-date'
|
||||
label = _('End (modification time)')
|
||||
|
||||
|
||||
class UserIdFilterField(FilterField):
|
||||
id = 'user'
|
||||
key = 'user-id'
|
||||
label = _('User')
|
||||
|
||||
|
||||
class UserFunctionFilterField(FilterField):
|
||||
id = 'user-function'
|
||||
key = 'user-function'
|
||||
label = _('Current User Function')
|
||||
|
||||
|
||||
class SubmissionAgentFilterField(FilterField):
|
||||
id = 'submission-agent'
|
||||
key = 'submission-agent'
|
||||
label = _('Submission Agent')
|
||||
addable = False
|
||||
|
||||
|
||||
class SubmissionChannelFilterField(FilterField):
|
||||
id = 'submission_channel'
|
||||
key = 'submission_channel'
|
||||
label = _('Channel')
|
||||
|
||||
|
||||
class CriticalityLevelFilterFiled(FilterField):
|
||||
id = 'criticality-level'
|
||||
key = 'criticality-level'
|
||||
label = _('Criticality Level')
|
||||
|
||||
|
||||
class DigestFilterField(FilterField):
|
||||
id = 'digest'
|
||||
key = 'digest'
|
||||
label = _('Digest')
|
||||
|
||||
|
||||
class IdFilterField(FilterField):
|
||||
id = 'id'
|
||||
key = 'id'
|
||||
|
||||
def __init__(self, label):
|
||||
super().__init__()
|
||||
self.label = label
|
||||
|
||||
|
||||
class TimeFilterField(FilterField):
|
||||
id = 'time'
|
||||
key = 'time'
|
||||
label = _('Created')
|
||||
|
||||
|
||||
class LastUpdateFilterField(FilterField):
|
||||
id = 'last_update_time'
|
||||
key = 'last_update_time'
|
||||
label = _('Last Modified')
|
||||
|
||||
|
||||
class AnonymisedFilterField(FilterField):
|
||||
id = 'anonymised'
|
||||
key = 'anonymised'
|
||||
label = _('Anonymised')
|
||||
|
||||
|
||||
class NumberFilterField(FilterField):
|
||||
id = 'number'
|
||||
key = 'number'
|
||||
label = _('Number')
|
||||
|
||||
|
||||
class IdentifierFilterField(FilterField):
|
||||
id = 'identifier'
|
||||
key = 'identifier'
|
||||
label = _('Identifier')
|
||||
|
||||
|
||||
class DistanceFilterField(FilterField):
|
||||
id = 'distance'
|
||||
key = 'distance'
|
||||
label = _('Distance')
|
|
@ -34,6 +34,7 @@ from quixote.http_request import parse_query
|
|||
|
||||
from wcs.api_access import ApiAccess
|
||||
from wcs.api_utils import get_query_flag, get_user_from_api_query_string
|
||||
from wcs.backoffice import filter_fields
|
||||
from wcs.backoffice.pagination import pagination_links
|
||||
from wcs.carddef import CardDef
|
||||
from wcs.categories import Category
|
||||
|
@ -761,8 +762,8 @@ class ManagementDirectory(Directory):
|
|||
criterias = self.get_global_listing_criterias()
|
||||
formdatas = sql.AnyFormData.select(criterias + [NotNull('geoloc_base_x'), Null('anonymised')])
|
||||
fields = [
|
||||
FakeField('name', 'display_name', _('Name')),
|
||||
FakeField('status', 'status', _('Status')),
|
||||
filter_fields.DisplayNameFilterField(),
|
||||
filter_fields.StatusFilterField(),
|
||||
]
|
||||
get_response().set_content_type('application/json')
|
||||
return json.dumps(geojson_formdatas(formdatas, fields=fields), cls=misc.JSONEncoder)
|
||||
|
@ -1147,7 +1148,7 @@ class FormPage(Directory, TempfileDirectoryMixin):
|
|||
'period-date',
|
||||
'user-id',
|
||||
'user-function',
|
||||
'submission-agent-id',
|
||||
'submission-agent',
|
||||
'date',
|
||||
'distance',
|
||||
'criticality-level',
|
||||
|
@ -1166,25 +1167,24 @@ class FormPage(Directory, TempfileDirectoryMixin):
|
|||
|
||||
waitpoint_status = self.formdef.workflow.get_waitpoint_status()
|
||||
fake_fields = [
|
||||
FakeField('internal-id', 'internal-id', _('Identifier')),
|
||||
FakeField('start', 'period-date', _('Start')),
|
||||
FakeField('end', 'period-date', _('End')),
|
||||
FakeField('user', 'user-id', _('User')),
|
||||
FakeField('user-function', 'user-function', _('Current User Function')),
|
||||
FakeField('submission-agent', 'submission-agent-id', _('Submission Agent'), addable=False),
|
||||
filter_fields.InternalIdFilterField(),
|
||||
filter_fields.PeriodStartFilterField(),
|
||||
filter_fields.PeriodEndFilterField(),
|
||||
filter_fields.UserIdFilterField(),
|
||||
filter_fields.UserFunctionFilterField(),
|
||||
]
|
||||
if self.formdef.workflow.criticality_levels:
|
||||
fake_fields.append(FakeField('criticality-level', 'criticality-level', _('Criticality Level')))
|
||||
fake_fields.append(filter_fields.CriticalityLevelFilterFiled())
|
||||
default_filters = self.get_default_filters(mode)
|
||||
|
||||
filter_fields = []
|
||||
available_fields = []
|
||||
for field in fake_fields + list(self.get_formdef_fields()):
|
||||
field.enabled = False
|
||||
if field.key not in self.get_filterable_field_types() + ['status']:
|
||||
continue
|
||||
if field.key == 'status' and not waitpoint_status:
|
||||
continue
|
||||
filter_fields.append(field)
|
||||
available_fields.append(field)
|
||||
|
||||
if getattr(field, 'block_field', None):
|
||||
field.label = '%s / %s' % (field.block_field.label, field.label)
|
||||
|
@ -1263,7 +1263,7 @@ class FormPage(Directory, TempfileDirectoryMixin):
|
|||
result += htmltext('</div>')
|
||||
return result
|
||||
|
||||
for filter_field in filter_fields:
|
||||
for filter_field in available_fields:
|
||||
if not filter_field.enabled:
|
||||
continue
|
||||
|
||||
|
@ -1346,7 +1346,7 @@ class FormPage(Directory, TempfileDirectoryMixin):
|
|||
)
|
||||
r += render_widget(widget, operators=[])
|
||||
|
||||
elif filter_field.key == 'submission-agent-id':
|
||||
elif filter_field.key == 'submission-agent':
|
||||
r += HiddenWidget(filter_field_key, value=filter_field_value).render()
|
||||
if filter_field_value:
|
||||
filtered_user = get_publisher().user_class.get(filter_field_value, ignore_errors=True)
|
||||
|
@ -1485,7 +1485,7 @@ class FormPage(Directory, TempfileDirectoryMixin):
|
|||
# field filter dialog content
|
||||
r += htmltext('<div style="display: none;">')
|
||||
r += htmltext('<ul id="field-filter" class="objects-list">')
|
||||
for field in filter_fields:
|
||||
for field in available_fields:
|
||||
addable = getattr(field, 'addable', True)
|
||||
r += htmltext('<li %s>') % ('' if addable else 'hidden')
|
||||
r += htmltext('<label for="fields-filter-%s">') % field.contextual_id
|
||||
|
@ -1591,7 +1591,7 @@ class FormPage(Directory, TempfileDirectoryMixin):
|
|||
classnames = 'has-relations-field'
|
||||
attrs = 'data-field-id="%s"' % field.id
|
||||
seen_parents.add(field.id)
|
||||
elif isinstance(field, RelatedField):
|
||||
elif isinstance(field, filter_fields.RelatedField):
|
||||
classnames = 'related-field'
|
||||
if field.parent_field_id in seen_parents:
|
||||
classnames += ' collapsed'
|
||||
|
@ -1874,24 +1874,24 @@ class FormPage(Directory, TempfileDirectoryMixin):
|
|||
return redirect('..')
|
||||
|
||||
def get_formdef_fields(self, include_block_items_fields=False):
|
||||
yield FakeField('id', 'id', _('Identifier') if self.formdef.id_template else _('Number'))
|
||||
yield filter_fields.IdFilterField(label=_('Identifier') if self.formdef.id_template else _('Number'))
|
||||
if self.formdef.default_digest_template:
|
||||
yield FakeField('digest', 'digest', _('Digest'))
|
||||
yield FakeField('submission_channel', 'submission_channel', _('Channel'))
|
||||
yield filter_fields.DigestFilterField()
|
||||
yield filter_fields.SubmissionChannelFilterField()
|
||||
if self.formdef.backoffice_submission_roles:
|
||||
yield FakeField('submission_agent', 'submission_agent', _('Submission By'))
|
||||
yield FakeField('time', 'time', _('Created'))
|
||||
yield FakeField('last_update_time', 'last_update_time', _('Last Modified'))
|
||||
yield filter_fields.SubmissionAgentFilterField()
|
||||
yield filter_fields.TimeFilterField()
|
||||
yield filter_fields.LastUpdateFilterField()
|
||||
|
||||
# user fields
|
||||
# user-label field but as a custom field, to get full name of user
|
||||
# using a sql join clause.
|
||||
yield UserLabelRelatedField()
|
||||
yield filter_fields.UserLabelRelatedField()
|
||||
for field in get_publisher().user_class.get_fields():
|
||||
if not field.can_include_in_listing:
|
||||
continue
|
||||
field.has_relations = True
|
||||
yield UserRelatedField(field)
|
||||
yield filter_fields.UserRelatedField(field)
|
||||
|
||||
for field in self.formdef.iter_fields(include_block_fields=True):
|
||||
if getattr(field, 'block_field', None):
|
||||
|
@ -1917,17 +1917,12 @@ class FormPage(Directory, TempfileDirectoryMixin):
|
|||
if not card_field.can_include_in_listing:
|
||||
continue
|
||||
field.has_relations = True
|
||||
yield RelatedField(carddef, card_field, field)
|
||||
yield filter_fields.RelatedField(carddef, card_field, field)
|
||||
|
||||
yield FakeField('status', 'status', _('Status'), include_in_statistics=True)
|
||||
yield filter_fields.StatusFilterField()
|
||||
if any(x.get_visibility_mode() != 'all' for x in self.formdef.workflow.possible_status):
|
||||
yield FakeField(
|
||||
'user-visible-status',
|
||||
'user-visible-status',
|
||||
_('Status (for user)'),
|
||||
geojson_label=_('Status'),
|
||||
)
|
||||
yield FakeField('anonymised', 'anonymised', _('Anonymised'))
|
||||
yield filter_fields.UserVisibleStatusField()
|
||||
yield filter_fields.AnonymisedFilterField()
|
||||
|
||||
def get_default_columns(self):
|
||||
if self.view:
|
||||
|
@ -2004,18 +1999,18 @@ class FormPage(Directory, TempfileDirectoryMixin):
|
|||
statistics_fields_only=False,
|
||||
):
|
||||
fake_fields = [
|
||||
FakeField('internal-id', 'internal-id', _('Identifier')),
|
||||
FakeField('number', 'number', _('Number')),
|
||||
FakeField('identifier', 'identifier', _('Identifier')),
|
||||
FakeField('start', 'period-date', _('Start')),
|
||||
FakeField('end', 'period-date', _('End')),
|
||||
FakeField('start-mtime', 'period-date', _('Start (modification time)')),
|
||||
FakeField('end-mtime', 'period-date', _('End (modification time)')),
|
||||
FakeField('user', 'user-id', _('User')),
|
||||
FakeField('user-function', 'user-function', _('Current User Function')),
|
||||
FakeField('submission-agent', 'submission-agent-id', _('Submission Agent')),
|
||||
FakeField('distance', 'distance', _('Distance')),
|
||||
FakeField('criticality-level', 'criticality-level', _('Criticality Level')),
|
||||
filter_fields.InternalIdFilterField(),
|
||||
filter_fields.NumberFilterField(),
|
||||
filter_fields.IdentifierFilterField(),
|
||||
filter_fields.PeriodStartFilterField(),
|
||||
filter_fields.PeriodEndFilterField(),
|
||||
filter_fields.PeriodStartUpdateTimeFilterField(),
|
||||
filter_fields.PeriodEndUpdateTimeFilterField(),
|
||||
filter_fields.UserIdFilterField(),
|
||||
filter_fields.UserFunctionFilterField(),
|
||||
filter_fields.SubmissionAgentFilterField(),
|
||||
filter_fields.DistanceFilterField(),
|
||||
filter_fields.CriticalityLevelFilterFiled(),
|
||||
]
|
||||
criterias = []
|
||||
|
||||
|
@ -2108,7 +2103,7 @@ class FormPage(Directory, TempfileDirectoryMixin):
|
|||
# allow for short form, with a single query parameter
|
||||
filters_dict['filter-user-function-value'] = filters_dict.get('filter-user-function')
|
||||
|
||||
if filter_field.key == 'submission-agent-id':
|
||||
if filter_field.key == 'submission-agent':
|
||||
# convert uuid based filter into local id filter
|
||||
name_id = filters_dict.get('filter-submission-agent-uuid')
|
||||
if name_id:
|
||||
|
@ -2301,7 +2296,7 @@ class FormPage(Directory, TempfileDirectoryMixin):
|
|||
criterias.append(Nothing())
|
||||
else:
|
||||
criterias.append(Equal('user_id', filter_field_value))
|
||||
elif filter_field.key == 'submission-agent-id':
|
||||
elif filter_field.key == 'submission-agent':
|
||||
criterias.append(Equal('submission_agent_id', filter_field_value))
|
||||
elif filter_field.key == 'user-function':
|
||||
user_object = None
|
||||
|
@ -4208,148 +4203,6 @@ class FormBackOfficeStatusPage(FormStatusPage):
|
|||
return self.test_tool_result()
|
||||
|
||||
|
||||
class FakeField:
|
||||
can_include_in_listing = True
|
||||
|
||||
def __init__(self, id, type_key, label, addable=True, include_in_statistics=False, geojson_label=None):
|
||||
self.id = id
|
||||
self.contextual_id = self.id
|
||||
self.key = type_key
|
||||
self.label = force_str(label)
|
||||
self.fake = True
|
||||
self.varname = id.replace('-', '_')
|
||||
self.contextual_varname = self.varname
|
||||
self.store_display_value = None
|
||||
self.store_structured_value = None
|
||||
self.addable = addable
|
||||
self.include_in_statistics = include_in_statistics
|
||||
self.geojson_label = force_str(geojson_label or self.label)
|
||||
|
||||
def get_view_value(self, value):
|
||||
# just here to quack like a duck
|
||||
return None
|
||||
|
||||
def get_csv_heading(self):
|
||||
return [self.label]
|
||||
|
||||
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
|
||||
key = 'related-field'
|
||||
varname = None
|
||||
related_field = None
|
||||
can_include_in_listing = True
|
||||
|
||||
def __init__(self, carddef, field, parent_field):
|
||||
self.carddef = carddef
|
||||
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.related_field.id)
|
||||
|
||||
@property
|
||||
def contextual_id(self):
|
||||
return self.id
|
||||
|
||||
@property
|
||||
def label(self):
|
||||
return '%s - %s' % (self.parent_field.label, self.related_field.label)
|
||||
|
||||
def __repr__(self):
|
||||
return '<%s (card: %r, parent: %r, related: %r)>' % (
|
||||
self.__class__.__name__,
|
||||
self.carddef,
|
||||
self.parent_field.label,
|
||||
self.related_field.label,
|
||||
)
|
||||
|
||||
@property
|
||||
def store_display_value(self):
|
||||
return self.related_field.store_display_value
|
||||
|
||||
@property
|
||||
def store_structured_value(self):
|
||||
return self.related_field.store_structured_value
|
||||
|
||||
def get_view_value(self, value, **kwargs):
|
||||
if value is None:
|
||||
return ''
|
||||
if isinstance(value, bool):
|
||||
return _('Yes') if value else _('No')
|
||||
if isinstance(value, datetime.date):
|
||||
return misc.strftime(misc.date_format(), value)
|
||||
return value
|
||||
|
||||
def get_view_short_value(self, value, max_len=30, **kwargs):
|
||||
return self.get_view_value(value)
|
||||
|
||||
def get_csv_heading(self):
|
||||
if self.related_field:
|
||||
return self.related_field.get_csv_heading()
|
||||
return [self.label]
|
||||
|
||||
def get_csv_value(self, value, **kwargs):
|
||||
if self.related_field:
|
||||
return self.related_field.get_csv_value(value, **kwargs)
|
||||
return [self.get_view_value(value)]
|
||||
|
||||
def get_column_field_id(self):
|
||||
return get_field_id(self.related_field)
|
||||
|
||||
|
||||
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'
|
||||
store_display_value = None
|
||||
store_structured_value = None
|
||||
|
||||
def __init__(self, field):
|
||||
self.related_field = field
|
||||
|
||||
def __repr__(self):
|
||||
return '<%s (field: %r)>' % (
|
||||
self.__class__.__name__,
|
||||
self.related_field.label,
|
||||
)
|
||||
|
||||
@property
|
||||
def label(self):
|
||||
return _('%s of User') % self.related_field.label
|
||||
|
||||
|
||||
class UserLabelRelatedField(UserRelatedField):
|
||||
# custom user-label column, targetting the "name" (= full name) column
|
||||
# of the users table
|
||||
id = 'user-label'
|
||||
key = 'user-label'
|
||||
varname = 'user_label'
|
||||
has_relations = True
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def __repr__(self):
|
||||
return '<UserLabelRelatedField>'
|
||||
|
||||
def get_column_field_id(self):
|
||||
return 'name'
|
||||
|
||||
@property
|
||||
def label(self):
|
||||
return _('User Label')
|
||||
|
||||
|
||||
def do_graphs_section(period_start=None, period_end=None, criterias=None):
|
||||
from wcs import sql
|
||||
|
||||
|
|
|
@ -47,6 +47,17 @@ class CustomView(StorableObject):
|
|||
|
||||
xml_root_node = 'custom_view'
|
||||
|
||||
def migrate(self):
|
||||
changed = False
|
||||
# 2024-04-10
|
||||
if self.columns and 'submission_agent' in [x['id'] for x in self.columns['list']]:
|
||||
self.columns['list'] = [
|
||||
{'id': x['id'].replace('submission_agent', 'submission-agent')} for x in self.columns['list']
|
||||
]
|
||||
changed = True
|
||||
if changed:
|
||||
self.store()
|
||||
|
||||
@property
|
||||
def user(self):
|
||||
return get_publisher().user_class.get(self.user_id)
|
||||
|
|
|
@ -990,7 +990,7 @@ class FormData(StorableObject):
|
|||
return StatusFieldValue(self.get_visible_status(user=None))
|
||||
if field.key == 'submission_channel':
|
||||
return self.get_submission_channel_label()
|
||||
if field.key == 'submission_agent':
|
||||
if field.key == 'submission-agent':
|
||||
try:
|
||||
agent_user = self.submission_agent_id
|
||||
return get_publisher().user_class.get(agent_user).display_name
|
||||
|
|
|
@ -19,6 +19,7 @@ import urllib.parse
|
|||
from quixote import get_publisher, get_request, get_session, redirect
|
||||
from quixote.html import TemplateIO, htmltext
|
||||
|
||||
from wcs.backoffice.filter_fields import FilterField
|
||||
from wcs.backoffice.pagination import pagination_links
|
||||
from wcs.roles import logged_users_role
|
||||
from wcs.sql_criterias import Contains, FtsMatch, Intersects, Not, NotContains, Null, StrictNotEqual
|
||||
|
@ -145,11 +146,11 @@ class FormDefUI:
|
|||
return htmltext('<span title="%s">%s</span>') % (label, misc.ellipsize(label, 20))
|
||||
|
||||
for f in fields:
|
||||
if getattr(f, 'fake', False):
|
||||
if isinstance(f, FilterField):
|
||||
field_sort_key = f.id
|
||||
if f.id == 'time':
|
||||
field_sort_key = 'receipt_time'
|
||||
elif f.id in ('user-label', 'submission_agent'):
|
||||
elif f.id in ('user-label', 'submission-agent'):
|
||||
field_sort_key = None
|
||||
elif getattr(f, 'is_related_field', False):
|
||||
field_sort_key = None
|
||||
|
@ -390,7 +391,7 @@ class FormDefUI:
|
|||
'user-label': 'cell-user',
|
||||
'status': 'cell-status',
|
||||
'anonymised': 'cell-anonymised',
|
||||
'submission_agent': 'cell-submission-agent',
|
||||
'submission-agent': 'cell-submission-agent',
|
||||
}.get(f.key)
|
||||
if css_class:
|
||||
r += htmltext('<td class="%s">' % css_class)
|
||||
|
|
|
@ -233,9 +233,9 @@ class LazyFormDefObjectsManager:
|
|||
return qs
|
||||
|
||||
def filter_by_internal_id(self, value, op='eq'):
|
||||
from wcs.backoffice.management import FakeField
|
||||
from wcs.backoffice.filter_fields import InternalIdFilterField
|
||||
|
||||
field = FakeField('internal-id', 'internal-id', 'fake')
|
||||
field = InternalIdFilterField()
|
||||
operators = self.get_field_allowed_operators(field)
|
||||
if op not in [o[0] for o in operators]:
|
||||
self.report_error(
|
||||
|
|
Loading…
Reference in New Issue