Projet

Général

Profil

0001-backoffice-allow-selecting-user-during-submission-81.patch

Frédéric Péters, 23 octobre 2020 16:32

Télécharger (15,4 ko)

Voir les différences:

Subject: [PATCH] backoffice: allow selecting user during submission (#8177)

 tests/test_backoffice_pages.py       | 82 ++++++++++++++++++++++++++--
 wcs/api.py                           |  7 ++-
 wcs/backoffice/data_management.py    |  2 +
 wcs/backoffice/submission.py         | 74 ++++++++++++++++++-------
 wcs/forms/root.py                    |  2 +
 wcs/qommon/static/css/dc2/admin.css  |  5 ++
 wcs/qommon/static/js/qommon.admin.js | 27 +++++++++
 7 files changed, 173 insertions(+), 26 deletions(-)
tests/test_backoffice_pages.py
87 87

  
88 88

  
89 89
def create_user(pub, is_admin=False):
90
    if pub.user_class.select(lambda x: x.name == 'admin'):
91
        user1 = pub.user_class.select(lambda x: x.name == 'admin')[0]
92
        user1.is_admin = is_admin
93
        user1.roles = [x.id for x in Role.select() if x.name == 'foobar']
94
        user1.store()
90
    user1 = None
91
    for user in pub.user_class.select():
92
        if user.name == 'admin':
93
            user1 = user
94
            user1.is_admin = is_admin
95
            user1.roles = [x.id for x in Role.select() if x.name == 'foobar']
96
            user1.store()
97
        elif user.email == 'jean.darmette@triffouilis.fr':
98
            pass  # don't remove user created by local_user fixture
99
        else:
100
            user.remove_self()
101
    if user1:
95 102
        return user1
96 103
    user1 = pub.user_class(name='admin')
97 104
    user1.email = 'admin@localhost'
......
3527 3534
    assert 'This form is limited to one per user' in resp
3528 3535

  
3529 3536

  
3537
def test_backoffice_submission_user_selection(pub):
3538
    user = create_user(pub)
3539
    create_environment(pub)
3540

  
3541
    for i in range(10):
3542
        random_user = pub.user_class()
3543
        random_user.name = 'random user %s' % i
3544
        random_user.store()
3545

  
3546
    app = login(get_app(pub))
3547

  
3548
    formdef = FormDef.get_by_urlname('form-title')
3549
    formdef.fields = [
3550
        fields.PageField(id='0', label='1st page', type='page'),
3551
        fields.StringField(id='1', label='Field on 1st page', type='string'),
3552
        fields.PageField(id='2', label='2nd page', type='page'),
3553
        fields.StringField(id='3', label='Field on 2nd page', type='string'),
3554
    ]
3555

  
3556
    formdef.backoffice_submission_roles = user.roles[:]
3557
    formdef.store()
3558
    resp = app.get('/backoffice/submission/')
3559
    resp = resp.click(formdef.name)
3560

  
3561
    assert resp.form['submission_channel'].attrs['type'] == 'hidden'
3562
    assert resp.pyquery('.submit-user-selection')
3563
    resp.form['user_id'] = str(random_user.id)  # happens via javascript
3564
    resp.form['f1'] = 'test submission'
3565
    resp = resp.form.submit('submit')  # -> 2nd page
3566
    assert not resp.pyquery('.submit-user-selection')
3567
    assert '>%s</p>' % random_user.name in resp
3568
    resp.form['f3'] = 'baz'
3569
    resp = resp.form.submit('submit')  # -> validation page
3570
    assert 'Check values then click submit.' in resp
3571
    assert '<p>%s</p>' % random_user.name in resp
3572

  
3573
    # final submit
3574
    resp = resp.form.submit('submit')
3575

  
3576
    formdata_no = resp.location.split('/')[-2]
3577
    data_class = formdef.data_class()
3578
    assert data_class.get(formdata_no).user.name == random_user.name
3579

  
3580
    # select user on second page
3581
    resp = app.get('/backoffice/submission/')
3582
    resp = resp.click(formdef.name)
3583

  
3584
    assert resp.form['submission_channel'].attrs['type'] == 'hidden'
3585
    resp.form['f1'] = 'test submission'
3586
    resp = resp.form.submit('submit')  # -> 2nd page
3587
    assert resp.pyquery('.submit-user-selection')
3588
    resp.form['user_id'] = str(random_user.id)  # happens via javascript
3589
    resp.form['f3'] = 'baz'
3590
    resp = resp.form.submit('submit')  # -> validation page
3591
    assert 'Check values then click submit.' in resp
3592
    assert '<p>%s</p>' % random_user.name in resp
3593

  
3594
    # final submit
3595
    resp = resp.form.submit('submit')
3596

  
3597
    formdata_no = resp.location.split('/')[-2]
3598
    data_class = formdef.data_class()
3599
    assert data_class.get(formdata_no).user.name == random_user.name
3600

  
3601

  
3530 3602
def test_backoffice_wscall_failure_display(http_requests, pub):
3531 3603
    user = create_user(pub)
3532 3604
    create_environment(pub)
wcs/api.py
44 44

  
45 45
from .backoffice.management import FormPage as BackofficeFormPage
46 46
from .backoffice.management import ManagementDirectory
47
from .backoffice.submission import SubmissionDirectory
47 48

  
48 49

  
49 50
def posted_json_data_to_formdata_data(formdef, data):
......
760 761
    def _q_index(self):
761 762
        get_response().set_content_type('application/json')
762 763
        if not (is_url_signed() or (
763
                get_request().user and get_request().user.can_go_in_admin())):
764
                get_request().user and (
765
                    get_request().user.can_go_in_admin() or
766
                    SubmissionDirectory().is_accessible(get_request().user)))):
767
            # request must be signed, or user must be an administrator or
768
            # allowed to submit forms (as they have a form to select an user).
764 769
            raise AccessForbiddenError('unsigned request or user has no access to backoffice')
765 770

  
766 771
        criterias = []
wcs/backoffice/data_management.py
305 305

  
306 306
class CardFillPage(FormFillPage):
307 307
    formdef_class = CardDef
308
    has_channel_support = False
309
    has_user_support = False
308 310

  
309 311
    def submitted(self, form, *args):
310 312
        super(CardFillPage, self).submitted(form, *args)
wcs/backoffice/submission.py
95 95
    filling_templates = ['wcs/formdata_filling.html']
96 96
    validation_templates = ['wcs/formdata_validation.html']
97 97
    steps_templates = ['wcs/formdata_steps.html']
98
    has_channel_support = True
99
    has_user_support = True
98 100

  
99 101
    def __init__(self, *args, **kwargs):
100 102
        super(FormFillPage, self).__init__(*args, **kwargs)
101 103
        self.selected_submission_channel = None
104
        self.selected_user_id = None
102 105
        self.remove_draft = RemoveDraftDirectory(self)
106
        if get_publisher().get_site_option('welco_url', 'options'):
107
            # when welco is deployed, do not let agent manually change the
108
            # submission channel
109
            self.has_channel_support = False
103 110

  
104 111
    def _q_index(self, *args, **kwargs):
105 112
        # if NameID, return URL or submission channel are in query string,
......
126 133
            self.set_tracking_code(formdata)
127 134
            return redirect('%s/' % formdata.id)
128 135

  
129
        self.selected_submission_channel = get_request().form.get('submission_channel') or ''
136
        self.selected_submission_channel = get_request().form.get('channel') or get_request().form.get('submission_channel')
137
        self.selected_user_id = get_request().form.get('user_id')
130 138
        return super(FormFillPage, self)._q_index(*args, **kwargs)
131 139

  
132 140
    def html_top(self, *args, **kwargs):
......
182 190
                except KeyError:  # it may not exist
183 191
                    pass
184 192

  
193
            if formdata and self.selected_user_id:
194
                formdata.user_id = self.selected_user_id
195

  
185 196
        if self.formdef.enable_tracking_codes and not self.edit_mode:
186 197
            r += htmltext('<h3>%s</h3>') % _('Tracking Code')
187 198
            if formdata and formdata.tracking_code:
......
189 200
            else:
190 201
                r += htmltext('<p>-</p>')
191 202

  
192
        welco_url = get_publisher().get_site_option('welco_url', 'options')
193
        if formdata and (formdata.submission_context or formdata.user_id):
203
        if formdata and self.on_validation_page:
204
            if self.has_channel_support and self.selected_submission_channel:
205
                formdata.submission_channel = self.selected_submission_channel
206
            if self.has_user_support and self.selected_user_id:
207
                formdata.user_id = self.selected_user_id
208

  
209
        if (formdata and (formdata.submission_context or formdata.user_id)) or self.on_validation_page:
194 210
            from .management import FormBackOfficeStatusPage
195 211
            r += FormBackOfficeStatusPage(self.formdef, formdata).get_extra_context_bar()
196
        elif not welco_url and not self.edit_mode:
197
            r += htmltext('<div class="submit-channel-selection" style="display: none;">')
198
            r += htmltext('<h3>%s</h3>') % _('Channel')
199
            r += htmltext('<select>')
200
            for channel_key, channel_label in [('', '-')] + list(FormData.get_submission_channels().items()):
201
                selected = ''
202
                if self.selected_submission_channel == channel_key:
203
                    selected = 'selected="selected"'
204
                r += htmltext('<option value="%s" %s>' % (channel_key, selected))
205
                r += htmltext('%s</option>') % channel_label
206
            r += htmltext('</select>')
207
            r += htmltext('</div>')
212
        elif not self.edit_mode:
213
            if self.has_channel_support:
214
                r += htmltext('<div class="submit-channel-selection" style="display: none;">')
215
                r += htmltext('<h3>%s</h3>') % _('Channel')
216
                r += htmltext('<select>')
217
                for channel_key, channel_label in [('', '-')] + list(FormData.get_submission_channels().items()):
218
                    selected = ''
219
                    if self.selected_submission_channel == channel_key:
220
                        selected = 'selected="selected"'
221
                    r += htmltext('<option value="%s" %s>' % (channel_key, selected))
222
                    r += htmltext('%s</option>') % channel_label
223
                r += htmltext('</select>')
224
                r += htmltext('</div>')
225

  
226
            if self.has_user_support:
227
                r += htmltext('<div class="submit-user-selection" style="display: none;">')
228
                get_response().add_javascript(['select2.js'])
229
                r += htmltext('<h3>%s</h3>') % _('Associated User')
230
                r += htmltext('<select>')
231
                if self.selected_user_id:
232
                    r += htmltext('<option value="%s">%s</option>') % (
233
                        self.selected_user_id,
234
                        get_publisher().user_class.get(self.selected_user_id)
235
                    )
236
                r += htmltext('</select>')
237
                r += htmltext('</div>')
208 238

  
209 239
        return r.getvalue()
210 240

  
211 241
    def create_view_form(self, *args, **kwargs):
212 242
        form = super(FormFillPage, self).create_view_form(*args, **kwargs)
213
        welco_url = get_publisher().get_site_option('welco_url', 'options')
214
        if not welco_url:
243
        if self.has_channel_support:
215 244
            form.add_hidden('submission_channel', self.selected_submission_channel)
245
        if self.has_user_support:
246
            form.add_hidden('user_id', self.selected_user_id)
216 247
        return form
217 248

  
218 249
    def create_form(self, *args, **kwargs):
219 250
        form = super(FormFillPage, self).create_form(*args, **kwargs)
220 251
        form.attrs['data-live-url'] = self.formdef.get_backoffice_submission_url() + 'live'
221
        welco_url = get_publisher().get_site_option('welco_url', 'options')
222
        if not welco_url:
252
        if self.has_channel_support:
223 253
            form.add_hidden('submission_channel', self.selected_submission_channel)
254
        if self.has_user_support:
255
            form.add_hidden('user_id', self.selected_user_id)
224 256
        return form
225 257

  
226 258
    def form_side(self, step_no, page, data=None, magictoken=None):
......
248 280
        filled.backoffice_submission = True
249 281
        if not filled.submission_context:
250 282
            filled.submission_context = {}
251
        if self.selected_submission_channel:
283
        if self.has_channel_support and self.selected_submission_channel:
252 284
            filled.submission_channel = self.selected_submission_channel
285
        if self.has_user_support and self.selected_user_id:
286
            filled.user_id = self.selected_user_id
253 287
        filled.submission_agent_id = str(get_request().user.id)
254 288
        filled.store()
255 289

  
wcs/forms/root.py
215 215
        self.code = TrackingCodesDirectory(self.formdef)
216 216
        self.action_url = '.'
217 217
        self.edit_mode = False
218
        self.on_validation_page = False
218 219
        self.user = get_request().user
219 220
        get_response().breadcrumb.append( (component + '/', self.formdef.name) )
220 221

  
......
1371 1372
        return get_session().get_tempfile_content(t).get_file_pointer().read()
1372 1373

  
1373 1374
    def validating(self, data):
1375
        self.on_validation_page = True
1374 1376
        get_request().view_name = 'validation'
1375 1377
        self.html_top(self.formdef.name)
1376 1378
        # fake a GET request to avoid previous page POST data being carried
wcs/qommon/static/css/dc2/admin.css
633 633
	margin: 1px 0;
634 634
}
635 635

  
636
aside#sidebar span.select2-container {
637
	width: 100% !important;
638
	min-width: auto !important;
639
}
640

  
636 641
div.TextWidget textarea:focus,
637 642
div.widget input[type="text"]:focus,
638 643
div.TextWidget textarea,
wcs/qommon/static/js/qommon.admin.js
137 137
      $('input[type=hidden][name=submission_channel]').val($(this).val());
138 138
    });
139 139

  
140
    /* user id */
141
    var select2_options = {
142
      language: {
143
        errorLoading: function() { return WCS_I18N.s2_errorloading; },
144
        noResults: function () { return WCS_I18N.s2_nomatches; },
145
        inputTooShort: function (input, min) { return WCS_I18N.s2_tooshort; },
146
        loadingMore: function () { return WCS_I18N.s2_loadmore; },
147
        searching: function () { return WCS_I18N.s2_searching; }
148
      },
149
      ajax: {
150
        delay: 250,
151
        dataType: 'json',
152
        data: function(params) {
153
          return {q: params.term, page_limit: 10};
154
        },
155
        processResults: function (data, params) {
156
          return {results: data.data};
157
        },
158
        url: '/api/users/'
159
      },
160
      placeholder: '-'
161
    }
162
    $('div.submit-user-selection select').select2(select2_options);
163
    $('div.submit-user-selection').show().find('select').on('change', function() {
164
      $('input[type=hidden][name=user_id]').val($(this).val());
165
    });
166

  
140 167
    /* new action form */
141 168
    $('#new-action-form select').on('change', function() {
142 169
      if ($(this).val() == '') {
143
-