backoffice: allow selecting user during submission (#8177)

This commit is contained in:
Frédéric Péters 2020-10-20 15:19:07 +02:00
parent ea1255b9dd
commit f03e42545e
7 changed files with 175 additions and 26 deletions

View File

@ -84,11 +84,18 @@ coucou = 1234
def create_user(pub, is_admin=False):
if pub.user_class.select(lambda x: x.name == 'admin'):
user1 = pub.user_class.select(lambda x: x.name == 'admin')[0]
user1.is_admin = is_admin
user1.roles = [x.id for x in Role.select() if x.name == 'foobar']
user1.store()
user1 = None
for user in pub.user_class.select():
if user.name == 'admin':
user1 = user
user1.is_admin = is_admin
user1.roles = [x.id for x in Role.select() if x.name == 'foobar']
user1.store()
elif user.email == 'jean.darmette@triffouilis.fr':
pass # don't remove user created by local_user fixture
else:
user.remove_self()
if user1:
return user1
user1 = pub.user_class(name='admin')
user1.email = 'admin@localhost'
@ -3237,6 +3244,71 @@ def test_backoffice_submission_only_one_check(pub, local_user):
assert 'This form is limited to one per user' in resp
def test_backoffice_submission_user_selection(pub):
user = create_user(pub)
create_environment(pub)
for i in range(10):
random_user = pub.user_class()
random_user.name = 'random user %s' % i
random_user.store()
app = login(get_app(pub))
formdef = FormDef.get_by_urlname('form-title')
formdef.fields = [
fields.PageField(id='0', label='1st page', type='page'),
fields.StringField(id='1', label='Field on 1st page', type='string'),
fields.PageField(id='2', label='2nd page', type='page'),
fields.StringField(id='3', label='Field on 2nd page', type='string'),
]
formdef.backoffice_submission_roles = user.roles[:]
formdef.store()
resp = app.get('/backoffice/submission/')
resp = resp.click(formdef.name)
assert resp.form['submission_channel'].attrs['type'] == 'hidden'
assert resp.pyquery('.submit-user-selection')
resp.form['user_id'] = str(random_user.id) # happens via javascript
resp.form['f1'] = 'test submission'
resp = resp.form.submit('submit') # -> 2nd page
assert not resp.pyquery('.submit-user-selection')
assert '>%s</p>' % random_user.name in resp
resp.form['f3'] = 'baz'
resp = resp.form.submit('submit') # -> validation page
assert 'Check values then click submit.' in resp
assert '<p>%s</p>' % random_user.name in resp
# final submit
resp = resp.form.submit('submit')
formdata_no = resp.location.split('/')[-2]
data_class = formdef.data_class()
assert data_class.get(formdata_no).user.name == random_user.name
# select user on second page
resp = app.get('/backoffice/submission/')
resp = resp.click(formdef.name)
assert resp.form['submission_channel'].attrs['type'] == 'hidden'
resp.form['f1'] = 'test submission'
resp = resp.form.submit('submit') # -> 2nd page
assert resp.pyquery('.submit-user-selection')
resp.form['user_id'] = str(random_user.id) # happens via javascript
resp.form['f3'] = 'baz'
resp = resp.form.submit('submit') # -> validation page
assert 'Check values then click submit.' in resp
assert '<p>%s</p>' % random_user.name in resp
# final submit
resp = resp.form.submit('submit')
formdata_no = resp.location.split('/')[-2]
data_class = formdef.data_class()
assert data_class.get(formdata_no).user.name == random_user.name
def test_backoffice_wscall_failure_display(http_requests, pub):
user = create_user(pub)
create_environment(pub)

View File

@ -44,6 +44,7 @@ from wcs.api_utils import sign_url_auto_orig, is_url_signed, get_user_from_api_q
from .backoffice.management import FormPage as BackofficeFormPage
from .backoffice.management import ManagementDirectory
from .backoffice.data_management import CardPage as BackofficeCardPage
from .backoffice.submission import SubmissionDirectory
def posted_json_data_to_formdata_data(formdef, data):
@ -791,7 +792,11 @@ class ApiUsersDirectory(Directory):
def _q_index(self):
get_response().set_content_type('application/json')
if not (is_url_signed() or (
get_request().user and get_request().user.can_go_in_admin())):
get_request().user and (
get_request().user.can_go_in_admin() or
SubmissionDirectory().is_accessible(get_request().user)))):
# request must be signed, or user must be an administrator or
# allowed to submit forms (as they have a form to select an user).
raise AccessForbiddenError('unsigned request or user has no access to backoffice')
criterias = []

View File

@ -313,6 +313,8 @@ class CardPage(FormPage):
class CardFillPage(FormFillPage):
formdef_class = CardDef
has_channel_support = False
has_user_support = False
def submitted(self, form, *args):
super(CardFillPage, self).submitted(form, *args)

View File

@ -95,11 +95,18 @@ class FormFillPage(PublicFormFillPage):
filling_templates = ['wcs/formdata_filling.html']
validation_templates = ['wcs/formdata_validation.html']
steps_templates = ['wcs/formdata_steps.html']
has_channel_support = True
has_user_support = True
def __init__(self, *args, **kwargs):
super(FormFillPage, self).__init__(*args, **kwargs)
self.selected_submission_channel = None
self.selected_user_id = None
self.remove_draft = RemoveDraftDirectory(self)
if get_publisher().get_site_option('welco_url', 'options'):
# when welco is deployed, do not let agent manually change the
# submission channel
self.has_channel_support = False
def _q_index(self, *args, **kwargs):
# if NameID, return URL or submission channel are in query string,
@ -126,7 +133,8 @@ class FormFillPage(PublicFormFillPage):
self.set_tracking_code(formdata)
return redirect('%s/' % formdata.id)
self.selected_submission_channel = get_request().form.get('submission_channel') or ''
self.selected_submission_channel = get_request().form.get('channel') or get_request().form.get('submission_channel')
self.selected_user_id = get_request().form.get('user_id')
return super(FormFillPage, self)._q_index(*args, **kwargs)
def html_top(self, *args, **kwargs):
@ -182,6 +190,9 @@ class FormFillPage(PublicFormFillPage):
except KeyError: # it may not exist
pass
if formdata and self.selected_user_id:
formdata.user_id = self.selected_user_id
if self.formdef.enable_tracking_codes and not self.edit_mode:
r += htmltext('<h3>%s</h3>') % _('Tracking Code')
if formdata and formdata.tracking_code:
@ -189,38 +200,59 @@ class FormFillPage(PublicFormFillPage):
else:
r += htmltext('<p>-</p>')
welco_url = get_publisher().get_site_option('welco_url', 'options')
if formdata and (formdata.submission_context or formdata.user_id):
if formdata and self.on_validation_page:
if self.has_channel_support and self.selected_submission_channel:
formdata.submission_channel = self.selected_submission_channel
if self.has_user_support and self.selected_user_id:
formdata.user_id = self.selected_user_id
if (formdata and (formdata.submission_context or formdata.user_id)) or self.on_validation_page:
from .management import FormBackOfficeStatusPage
r += FormBackOfficeStatusPage(self.formdef, formdata).get_extra_context_bar()
elif not welco_url and not self.edit_mode:
r += htmltext('<div class="submit-channel-selection" style="display: none;">')
r += htmltext('<h3>%s</h3>') % _('Channel')
r += htmltext('<select>')
for channel_key, channel_label in [('', '-')] + list(FormData.get_submission_channels().items()):
selected = ''
if self.selected_submission_channel == channel_key:
selected = 'selected="selected"'
r += htmltext('<option value="%s" %s>' % (channel_key, selected))
r += htmltext('%s</option>') % channel_label
r += htmltext('</select>')
r += htmltext('</div>')
elif not self.edit_mode:
if self.has_channel_support:
r += htmltext('<div class="submit-channel-selection" style="display: none;">')
r += htmltext('<h3>%s</h3>') % _('Channel')
r += htmltext('<select>')
for channel_key, channel_label in [('', '-')] + list(FormData.get_submission_channels().items()):
selected = ''
if self.selected_submission_channel == channel_key:
selected = 'selected="selected"'
r += htmltext('<option value="%s" %s>' % (channel_key, selected))
r += htmltext('%s</option>') % channel_label
r += htmltext('</select>')
r += htmltext('</div>')
if 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>')
return r.getvalue()
def create_view_form(self, *args, **kwargs):
form = super(FormFillPage, self).create_view_form(*args, **kwargs)
welco_url = get_publisher().get_site_option('welco_url', 'options')
if not welco_url:
if self.has_channel_support:
form.add_hidden('submission_channel', self.selected_submission_channel)
if self.has_user_support:
form.add_hidden('user_id', self.selected_user_id)
return form
def create_form(self, *args, **kwargs):
form = super(FormFillPage, self).create_form(*args, **kwargs)
form.attrs['data-live-url'] = self.formdef.get_backoffice_submission_url() + 'live'
welco_url = get_publisher().get_site_option('welco_url', 'options')
if not welco_url:
if self.has_channel_support:
form.add_hidden('submission_channel', self.selected_submission_channel)
if self.has_user_support:
form.add_hidden('user_id', self.selected_user_id)
return form
def form_side(self, step_no, page, data=None, magictoken=None):
@ -248,8 +280,10 @@ class FormFillPage(PublicFormFillPage):
filled.backoffice_submission = True
if not filled.submission_context:
filled.submission_context = {}
if self.selected_submission_channel:
if self.has_channel_support and self.selected_submission_channel:
filled.submission_channel = self.selected_submission_channel
if self.has_user_support and self.selected_user_id:
filled.user_id = self.selected_user_id
filled.submission_agent_id = str(get_request().user.id)
filled.store()

View File

@ -215,6 +215,7 @@ class FormPage(Directory, FormTemplateMixin):
self.code = TrackingCodesDirectory(self.formdef)
self.action_url = '.'
self.edit_mode = False
self.on_validation_page = False
self.user = get_request().user
get_response().breadcrumb.append( (component + '/', self.formdef.name) )
@ -1375,6 +1376,7 @@ class FormPage(Directory, FormTemplateMixin):
return get_session().get_tempfile_content(t).get_file_pointer().read()
def validating(self, data):
self.on_validation_page = True
get_request().view_name = 'validation'
self.html_top(self.formdef.name)
# fake a GET request to avoid previous page POST data being carried

View File

@ -633,6 +633,11 @@ aside#sidebar select {
margin: 1px 0;
}
aside#sidebar span.select2-container {
width: 100% !important;
min-width: auto !important;
}
div.TextWidget textarea:focus,
div.widget input[type="text"]:focus,
div.TextWidget textarea,

View File

@ -137,6 +137,35 @@ $(function() {
$('input[type=hidden][name=submission_channel]').val($(this).val());
});
/* user id */
var select2_options = {
language: {
errorLoading: function() { return WCS_I18N.s2_errorloading; },
noResults: function () { return WCS_I18N.s2_nomatches; },
inputTooShort: function (input, min) { return WCS_I18N.s2_tooshort; },
loadingMore: function () { return WCS_I18N.s2_loadmore; },
searching: function () { return WCS_I18N.s2_searching; }
},
ajax: {
delay: 250,
dataType: 'json',
data: function(params) {
return {q: params.term, page_limit: 10};
},
processResults: function (data, params) {
return {results: data.data};
},
url: '/api/users/'
},
placeholder: '-'
}
if ($('div.submit-user-selection').length) {
$('div.submit-user-selection select').select2(select2_options);
$('div.submit-user-selection').show().find('select').on('change', function() {
$('input[type=hidden][name=user_id]').val($(this).val());
});
}
/* new action form */
$('#new-action-form select').on('change', function() {
if ($(this).val() == '') {