backoffice: add user selection support on edit page (#49812)

This commit is contained in:
Frédéric Péters 2021-02-02 16:29:39 +01:00
parent 2be30c3668
commit 8ead3895a3
6 changed files with 169 additions and 18 deletions

View File

@ -2755,6 +2755,105 @@ def test_backoffice_wfedit_and_data_source_with_field_info(pub):
resp = resp.follow()
def test_backoffice_wfedit_and_user_selection(pub):
user = create_user(pub)
create_environment(pub)
formdef = FormDef.get_by_urlname('form-title')
form_class = formdef.data_class()
number31 = [x for x in form_class.select() if x.data['1'] == 'FOO BAR 30'][0]
number31.store()
# attach a custom workflow
workflow = Workflow(name='wfedit')
st1 = workflow.add_status('Status1', number31.status.split('-')[1])
wfedit = EditableWorkflowStatusItem()
wfedit.id = '_wfedit'
wfedit.by = [user.roles[0]]
st1.items.append(wfedit)
wfedit.parent = st1
workflow.store()
formdef.workflow_id = workflow.id
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/%s/' % number31.id)
assert (' with the number %s.' % number31.get_display_id()) in resp.text
assert 'Associated User' not in resp
resp = resp.form.submit('button_wfedit')
resp = resp.follow()
assert resp.pyquery('.submit-user-selection')
resp.form['user_id'] = str(user.id) # happens via javascript
resp = resp.form.submit('submit')
resp = resp.follow()
assert 'Associated User' in resp
assert formdef.data_class().get(number31.id).user_id == str(user.id)
def test_backoffice_wfedit_and_user_selection_multi_page(pub):
user = create_user(pub)
create_environment(pub)
formdef = FormDef.get_by_urlname('form-title')
formdef.fields.insert(0, fields.PageField(id='0', label='1st page', type='page'))
formdef.fields.append(fields.PageField(id='4', label='2nd page', type='page'))
form_class = formdef.data_class()
number31 = [x for x in form_class.select() if x.data['1'] == 'FOO BAR 30'][0]
number31.store()
# attach a custom workflow
workflow = Workflow(name='wfedit')
st1 = workflow.add_status('Status1', number31.status.split('-')[1])
wfedit = EditableWorkflowStatusItem()
wfedit.id = '_wfedit'
wfedit.by = [user.roles[0]]
st1.items.append(wfedit)
wfedit.parent = st1
workflow.store()
formdef.workflow_id = workflow.id
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/%s/' % number31.id)
assert (' with the number %s.' % number31.get_display_id()) in resp.text
assert 'Associated User' not in resp
resp = resp.form.submit('button_wfedit')
resp = resp.follow()
assert resp.pyquery('.submit-user-selection')
resp.form['user_id'] = str(user.id) # happens via javascript
resp = resp.form.submit('submit') # -> 2nd page
assert resp.pyquery('.submit-user-selection')
resp = resp.form.submit('submit') # -> save changes
resp = resp.follow()
assert 'Associated User' in resp
assert formdef.data_class().get(number31.id).user_id == str(user.id)
number31.store() # save and lose associated user id
resp = app.get('/backoffice/management/form-title/%s/' % number31.id)
assert (' with the number %s.' % number31.get_display_id()) in resp.text
assert 'Associated User' not in resp
resp = resp.form.submit('button_wfedit')
resp = resp.follow()
assert resp.pyquery('.submit-user-selection')
resp = resp.form.submit('submit') # -> 2nd page
assert resp.pyquery('.submit-user-selection')
resp.form['user_id'] = str(user.id) # happens via javascript
resp = resp.form.submit('submit') # -> save changes
resp = resp.follow()
assert 'Associated User' in resp
assert formdef.data_class().get(number31.id).user_id == str(user.id)
def test_global_listing(pub):
if not pub.is_using_postgresql():
pytest.skip('this requires SQL')

View File

@ -603,3 +603,43 @@ def test_block_card_item_link(pub, blocks_feature):
resp = app.get('/backoffice/management' + resp.request.path)
assert '<div class="value"><a href="http://example.net/backoffice/data/foo/%s/">card plop</a></div></div>' % card.id in resp
assert '<div class="value"><a href="http://example.net/backoffice/data/foo/%s/">card plop2</a></div></div>' % card2.id in resp
def test_carddata_edit_user_selection(pub):
CardDef.wipe()
user = create_user(pub)
carddef = CardDef()
carddef.name = 'foo'
carddef.fields = [
fields.StringField(id='1', label='Test', type='string', varname='foo'),
]
carddef.backoffice_submission_roles = user.roles
carddef.workflow_roles = {'_editor': user.roles[0]}
carddef.store()
carddef.data_class().wipe()
carddata = carddef.data_class()()
carddata.data = {'1': 'plop'}
carddata.just_created()
carddata.store()
app = login(get_app(pub))
resp = app.get('/backoffice/data/foo/%s/' % carddata.id)
assert 'Edit Card' in resp.text
resp = resp.form.submit('button_editable')
resp = resp.follow()
assert 'Associated User' not in resp
carddef.user_support = 'optional'
carddef.store()
resp = app.get('/backoffice/data/foo/%s/' % carddata.id)
assert 'Edit Card' in resp.text
resp = resp.form.submit('button_editable')
resp = resp.follow()
assert 'Associated User' in resp
assert resp.pyquery('.submit-user-selection')
resp.form['user_id'] = str(user.id) # happens via javascript
resp = resp.form.submit('submit') # -> save changes
resp = resp.follow()
assert 'Associated User' in resp
assert carddef.data_class().get(carddata.id).user_id == str(user.id)

View File

@ -2549,7 +2549,7 @@ class FormBackOfficeStatusPage(FormStatusPage):
return response
def get_extra_context_bar(self):
def get_extra_context_bar(self, parent=None):
formdata = self.filled
r = TemplateIO(html=True)
@ -2636,7 +2636,7 @@ class FormBackOfficeStatusPage(FormStatusPage):
r += self.get_extra_submission_context_bar()
r += self.get_extra_submission_channel_bar()
r += self.get_extra_submission_user_id_bar()
r += self.get_extra_submission_user_id_bar(parent=parent)
r += self.get_extra_geolocation_bar()
if formdata.formdef.lateral_template:
r += htmltext('<div data-async-url="%slateral-block"></div>' % formdata.get_url(backoffice=True))
@ -2705,10 +2705,10 @@ class FormBackOfficeStatusPage(FormStatusPage):
return r.getvalue()
def get_extra_submission_user_id_bar(self):
def get_extra_submission_user_id_bar(self, parent):
formdata = self.filled
r = TemplateIO(html=True)
if formdata.user_id and formdata.get_user():
if formdata and formdata.user_id and formdata.get_user():
r += htmltext('<div class="extra-context">')
r += htmltext('<h3>%s</h3>') % _('Associated User')
users_cfg = get_cfg('users', {})
@ -2722,6 +2722,24 @@ class FormBackOfficeStatusPage(FormStatusPage):
else:
r += htmltext('<p>%s</p>') % formdata.get_user().display_name
r += htmltext('</div>')
elif parent and parent.has_user_support and parent.edit_mode:
r += self.get_extra_submission_user_selection_bar(parent=parent)
return r.getvalue()
def get_extra_submission_user_selection_bar(self, parent=None):
r = TemplateIO(html=True)
r += htmltext('<div class="submit-user-selection" style="display: none;">')
get_response().add_javascript(['select2.js'])
r += htmltext('<h3>%s</h3>') % _('Associated User')
r += htmltext('<select>')
if parent and parent.selected_user_id:
r += htmltext('<option value="%s">%s</option>') % (
parent.selected_user_id,
get_publisher().user_class.get(parent.selected_user_id, ignore_errors=True)
)
r += htmltext('</select>')
r += htmltext('</div>')
return r.getvalue()
def get_extra_geolocation_bar(self):

View File

@ -227,7 +227,7 @@ class FormFillPage(PublicFormFillPage):
from .management import FormBackOfficeStatusPage
if self.on_validation_page or self.edit_mode:
if formdata:
r += FormBackOfficeStatusPage(self.formdef, formdata).get_extra_context_bar()
r += FormBackOfficeStatusPage(self.formdef, formdata).get_extra_context_bar(parent=self)
else:
if formdata and formdata.submission_context and \
set(formdata.submission_context.keys()) != {'return_url'}:
@ -249,19 +249,10 @@ class FormFillPage(PublicFormFillPage):
r += htmltext('</div>')
if formdata and formdata.user_id:
r += FormBackOfficeStatusPage(self.formdef, formdata).get_extra_submission_user_id_bar()
r += FormBackOfficeStatusPage(self.formdef, formdata).get_extra_submission_user_id_bar(parent=self)
elif self.has_user_support:
r += htmltext('<div class="submit-user-selection" style="display: none;">')
get_response().add_javascript(['select2.js'])
r += htmltext('<h3>%s</h3>') % _('Associated User')
r += htmltext('<select>')
if self.selected_user_id:
r += htmltext('<option value="%s">%s</option>') % (
self.selected_user_id,
get_publisher().user_class.get(self.selected_user_id, ignore_errors=True)
)
r += htmltext('</select>')
r += htmltext('</div>')
r += FormBackOfficeStatusPage(self.formdef, formdata).get_extra_submission_user_selection_bar(parent=self)
if self.formdef.submission_lateral_template:
r += htmltext('<div data-async-url="%slateral-block"></div>' % self.formdef.get_backoffice_submission_url())
return r.getvalue()

View File

@ -156,7 +156,7 @@ class FormStatusPage(Directory, FormTemplateMixin):
if not q in self._q_exports:
self._q_exports.append(q)
if self.formdef.workflow and register_workflow_subdirs:
if self.formdata and self.formdef.workflow and register_workflow_subdirs:
for name, directory in self.formdef.workflow.get_subdirectories(self.filled):
self._q_exports.append(name)
setattr(self, name, directory)

View File

@ -1362,6 +1362,9 @@ class FormPage(Directory, FormTemplateMixin):
if k.startswith(WorkflowBackofficeFieldsFormDef.field_prefix):
new_data[k] = v
self.edited_data.data = new_data
if getattr(self, 'selected_user_id', None):
# user selection in backoffice
self.edited_data.user_id = self.selected_user_id
self.edited_data.store()
# remove previous vars and formdata from substitution variables
self.clean_submission_context()