Projet

Général

Profil

0001-tracking_code-add-tests-on-formdata-access-38073.patch

Nicolas Roche, 08 janvier 2020 11:48

Télécharger (17 ko)

Voir les différences:

Subject: [PATCH] tracking_code: add tests on formdata access (#38073)

 tests/test_tracking_code.py | 385 +++++++++++++++++++++++++++++++++++-
 1 file changed, 381 insertions(+), 4 deletions(-)
tests/test_tracking_code.py
1 1
import pytest
2
import contextlib
3
import re
2 4

  
5
from quixote import cleanup
6
from wcs import fields
7
from wcs.wf.form import FormWorkflowStatusItem, WorkflowFormFieldsFormDef
3 8
from wcs.formdef import FormDef
9
from wcs.qommon.ident.password_accounts import PasswordAccount
10
from wcs.roles import Role
11
from wcs.workflows import Workflow, ChoiceWorkflowStatusItem
4 12

  
5
from utilities import create_temporary_pub, clean_temporary_pub
13
from utilities import get_app, login, create_temporary_pub, clean_temporary_pub
6 14

  
7 15
def pytest_generate_tests(metafunc):
8 16
    if 'pub' in metafunc.fixturenames:
9 17
        metafunc.parametrize('pub', ['pickle', 'sql'], indirect=True)
10 18

  
19
def teardown_module(module):
20
    clean_temporary_pub()
21

  
11 22
@pytest.fixture
12 23
def pub(request):
13
    return create_temporary_pub(sql_mode=(request.param == 'sql'))
24
    cleanup()
25
    pub = create_temporary_pub(sql_mode=(request.param == 'sql'))
26
    pub.cfg['identification'] = {'methods': ['password']}
27
    pub.cfg['language'] = {'language': 'en'}
28
    pub.write_cfg()
29
    return pub
14 30

  
15
def teardown_module(module):
16
    clean_temporary_pub()
31
@pytest.fixture
32
def users(pub):
33
    def create_user(name):
34
        user = pub.user_class()
35
        user.email = '%s@example.net' % name
36
        user.name = name
37
        user.store()
38
        account = PasswordAccount(id=name)
39
        account.set_password(name)
40
        account.user_id = user.id
41
        account.store()
42

  
43
        user_formdef = UserFieldsFormDef(pub)
44
        user_formdef.fields = [
45
            fields.StringField(
46
                id='_first_name', label='first name',
47
                type='string', extra_css_class='autocomplete-given-name'),
48
        ]
49
        user_formdef.store()
50
        user.form_data = {'_first_name': name}
51
        user.set_attributes_from_formdata(user.form_data)
52
        user.store()
53
        return user
54

  
55
    from wcs.admin.settings import UserFieldsFormDef
56
    formdef = UserFieldsFormDef(pub)
57
    formdef.url_name = 'user'
58
    formdef.id = 'bof'
59
    formdef.data_class().wipe()
60

  
61
    pub.user_class.wipe()
62
    PasswordAccount.wipe()
63
    user1 = create_user('user1')
64
    user2 = create_user('user2')
65
    agent1 = create_user('agent1')
66
    agent2 = create_user('agent2')
67
    admin1 = create_user('admin1')
68
    Role.wipe()
69
    role1 = Role(name='Submiters')
70
    role1.allows_backoffice_access = True
71
    role1.store()
72
    role2 = Role(name='Receivers')
73
    role2.store()
74
    agent1.roles = [role1.id]
75
    agent1.store()
76
    agent2.roles = [role2.id]
77
    agent2.store()
78
    admin1.is_admin = True
79
    admin1.store()
80
    return None, user1, user2, agent1, agent2, admin1  # None for anonymous
81

  
82
def create_formdef():
83
    FormDef.wipe()
84
    formdef = FormDef()
85
    formdef.name = 'test'
86
    formdef.fields = []
87
    formdef.store()
88
    return formdef
89

  
90
def get_displayed_tracking_code(resp):
91
    tracking_code = None
92
    if 'Forms - test' in resp.text:
93
        # frontoffice
94
        for a_tag in resp.html.findAll('a'):
95
            if 'code/' in a_tag['href']:
96
                tracking_code = a_tag.text
97
                break
98
    elif 'Back Office of wcs - test' in resp.text:
99
        # backoffice
100
        for h3_tag in resp.html.findAll('h3'):
101
            if h3_tag.text == 'Tracking Code':
102
                tracking_code = h3_tag.next_sibling.next_element
103
                break
104
    assert tracking_code
105
    return tracking_code
17 106

  
18 107
def test_tracking_code(pub):
19 108
    klass = pub.tracking_code_class
......
74 163

  
75 164
    assert marker.get('done') # makes sure we got to the real new id code
76 165
    assert klass.count() == 2
166

  
167
def test_access_to_formdata(pub, users, nocache):
168
    """
169
    1-  Direct access to ressources
170
     a-  Drafts
171

  
172
    | sumitter / accesser | anonymous | user1 | user2 | agent1 | agent2 | admin1 |
173
    +---------------------+-----------+-------+-------+--------+--------+--------+
174
    | anonymous           |  login    | deny  | deny  | deny   | deny   | deny   |
175
    | agent1 (submiter))  |  login    | deny  | deny  | deny   | deny   | deny   |
176
    | user1               |  login    | allow | deny  | deny   | deny   | deny   |
177

  
178
     b-  Demands
179

  
180
    | sumitter / accesser | anonymous | user1 | user2 | agent1 | agent2 | admin1 |
181
    +---------------------+-----------+-------+-------+--------+--------+--------+
182
    | anonymous           |  login    | deny  | deny  | deny   | back   | back   |
183
    | agent1 (submiter)   |  login    | deny  | deny  | deny   | back   | back   |
184
    | user1               |  login    | allow | deny  | deny   | back   | back   |
185

  
186
    2- New user on prefill fields when accessing using tracking code :
187
     a-  Drafts
188

  
189
    | sumitter / accesser | anonymous | user1 | user2 | agent1 | agent2 | admin1 |
190
    +---------------------+-----------+-------+-------+--------+--------+--------+
191
    | anonymous           | anonymous | user1 | user2 | agent1 | agent2 | admin  |
192
    | agent1 (submiter)   | anonymous | user1 | user2 | agent1 | agent2 | admin  |
193
    | user1               | anonymous | user1 | user2 | agent1 | agent2 | admin  |
194

  
195
     b-  Demands (evolving into Workflows forms)
196

  
197
    | sumitter / accesser | anonymous | user1 | user2 | agent1 | agent2 | admin1 |
198
    +---------------------+-----------+-------+-------+--------+--------+--------+
199
    | anonymous           | anonymous | user1 | user2 | agent1 | agent2 | admin  |
200
    | agent1 (submiter)   | anonymous | user1 | user2 | agent1 | agent2 | admin  |
201
    | user1               | anonymous | user1 | user2 | agent1 | agent2 | admin  |
202
    """
203
    (anonymous, user1, user2, agent1, agent2, admin1) = users
204
    tracking_code = None
205
    formdata_id = None
206
    is_draft = None
207
    formdef = create_formdef()
208
    formdef.fields = [
209
        fields.PageField(id='0', label='1st page', type='page'),
210
        fields.CommentField(
211
            id='2', type='comment', display_locations=['validation', 'summary'],
212
            label='{{form_user_display_name}}'),
213
        fields.StringField(
214
            id='3', label='prefill-string-page1', required=False,
215
            prefill={'type': 'string', 'value': '{{form_user_display_name}}'}),
216
        fields.StringField(
217
            id='p3', label='prefill-user-page1', required=False,
218
            prefill={'type': 'user', 'value': '_first_name'}),
219

  
220
        # updated on draft using tracking code
221
        fields.PageField(id='4', label='2nd page', type='page'),
222
        fields.StringField(
223
            id='4', label='prefill-string-page2', required=False,
224
            prefill={'type': 'string', 'value': '{{form_user_display_name}}'}),
225

  
226
        fields.StringField(
227
            id='p4', label='prefill-user-page2', required=False,
228
            prefill={'type': 'user', 'value': '_first_name'}),
229
    ]
230
    formdef.backoffice_submission_roles = agent1.roles[:]
231
    formdef.workflow_roles = {'_receiver': agent2.roles[0]}
232
    formdef.enable_tracking_codes = True
233
    formdef.store()
234

  
235
    Workflow.wipe()
236
    workflow = Workflow(name='test')
237
    st1 = workflow.add_status('Status1')
238
    st2 = workflow.add_status('Status2')
239

  
240
    display_form = FormWorkflowStatusItem()
241
    display_form.formdef = WorkflowFormFieldsFormDef(item=display_form)
242
    display_form.formdef.fields = [
243
        # updated on workflow using tracking code
244
        fields.StringField(
245
            id='5', label='prefill-string-workflow', required=False,
246
            prefill={'type': 'string', 'value': '{{form_user_display_name}}'}),
247
        fields.StringField(
248
            id='p5', label='prefill-user-workflow', required=False,
249
            prefill={'type': 'user', 'value': '_first_name'}),
250
    ]
251
    display_form.by = ['_submitter']
252
    display_form.parent = st2
253

  
254
    jump = ChoiceWorkflowStatusItem()
255
    jump.id = '_jump'
256
    jump.label = 'Go form'
257
    jump.by = ['_submitter']
258
    jump.status = st2.id
259
    jump.parent = st1
260

  
261
    st1.items.append(jump)
262
    st2.items.append(display_form)
263
    workflow.store()
264

  
265
    formdef.workflow_id = workflow.id
266
    formdef.store()
267

  
268
    @contextlib.contextmanager
269
    def submit(user, is_front=True):
270
        """submit form or draft"""
271
        pub.session_manager.session_class.wipe()
272
        app = get_app(pub)
273

  
274
        if user:
275
            app = login(app, username=user.name, password=user.name)
276
        if is_front:
277
            resp = app.get('/test/')
278
            assert '<h3>Tracking code</h3>' in resp.text
279
        else:
280
            resp = app.get('/backoffice/submission/test/')
281
            assert '<h3>Tracking Code</h3>' in resp.text
282

  
283
        formdef.data_class().wipe()
284
        resp = resp.form.submit('submit')  # submit page 1
285
        tracking_code = get_displayed_tracking_code(resp)
286

  
287
        if not is_draft:
288
            resp = resp.form.submit('submit')  # submit page 2
289
            resp = resp.form.submit('submit')  # submit form
290

  
291
        assert formdef.data_class().count() == 1
292
        formdata = formdef.data_class().select()[0]
293
        assert formdata.is_draft() == is_draft
294
        assert formdata.tracking_code == tracking_code
295
        yield (tracking_code, formdata.id)
296

  
297
    def check_direct_access(user, access=None):
298
        """direct access from the URLs"""
299
        pub.session_manager.session_class.wipe()
300
        app = get_app(pub)
301
        if user:
302
            app = login(app, username=user.name, password=user.name)
303

  
304
        if is_draft:
305
            if access == 'deny':
306
                resp = app.get('/test/%s' % formdata_id, status=403)
307
                return
308

  
309
            resp = app.get('/test/%s' % formdata_id)
310

  
311
            if access == 'login':
312
                assert resp.location.startswith('http://example.net/login/?next=')
313
            elif access == 'front':
314
                assert 'http://example.net/test/?mt=' in resp.location
315
                resp = resp.follow()
316
                assert '<title>Forms - test</title>' in resp.text
317
                assert get_displayed_tracking_code(resp) == tracking_code
318
            else:
319
                assert access in ('login', 'deny', 'front')
320
        else:
321
            resp = app.get('/test/%s' % formdata_id)
322
            assert resp.location == 'http://example.net/test/%s/' % formdata_id
323

  
324
            if access == 'deny':
325
                resp = resp.follow(status=403)
326
            elif access == 'login':
327
                resp = resp.follow()
328
                assert resp.location.startswith('http://example.net/login/?next=')
329
            elif access == 'front':
330
                resp = resp.follow()
331
                assert '<title>Forms - test</title>' in resp.text
332
                assert get_displayed_tracking_code(resp) == tracking_code
333
            elif access == 'back':
334
                resp = resp.follow()
335
                assert resp.location == 'http://example.net/backoffice/management/test/%s/' % formdata_id
336
                resp = resp.follow()
337
                assert ' <title>Back Office of wcs - test - %s</title>' % formdata_id in resp.text
338
            else:
339
                assert access in ('login', 'deny', 'front',  'back')
340

  
341
    def check_tracking_code_access(user, owner=None, new_owner=None):
342
        """
343
        load the formdata using the tracking code and prefill user name fields.
344
        new_owner is used to show that user fields change on drafts.
345
        """
346
        pub.session_manager.session_class.wipe()
347
        app = get_app(pub)
348

  
349
        # access form sumary/draft
350
        if user:
351
            app = login(app, username=user.name, password=user.name)
352
        resp = app.get('/')
353
        resp.forms[0]['code'] = tracking_code
354
        resp = resp.forms[0].submit()
355
        resp = resp.follow()
356
        resp = resp.follow()
357
        resp = resp.follow()
358
        assert '<title>Forms - test</title>' in resp.text
359

  
360
        if is_draft:
361
            resp = resp.forms[1].submit('submit')  # submit page 2
362
        else:
363
            resp = resp.form.submit('button_jump')  # go to display_form
364
            resp = resp.follow()
365

  
366
        def get_comment_value():
367
            html = resp.html.find('div', attrs={'class': 'comment-field'})
368
            if html:
369
                return html.p.text
370
            else:  # empty comment is not displayed in summary
371
                return ''
372

  
373
        def get_field_value(field_label):
374
            # validation page
375
            for html in resp.html.find_all('div', attrs={'class': 'WcsExtraStringWidget'}):
376
                if html.label.text == field_label:
377
                    return html.input.get('value') or ''
378
            # summary
379
            for html in resp.html.find_all('div', attrs={'class': 'field'}):
380
                if html.span.text == field_label:
381
                    return html.div.text
382
            return ''  # empty field is not displayed in summary
383

  
384
        formdata = formdef.data_class().select()[0]
385
        formdata_user = getattr(formdata.user, 'name', '')
386
        expected_owner = getattr(owner, 'name', '')
387
        expected_new_owner = getattr(new_owner, 'name', '')
388

  
389
        if is_draft:
390
            if new_owner:
391
                assert formdata_user == expected_new_owner  # !!
392
            else:  # formdata_user is not overidden by anonymous user
393
                assert formdata_user == expected_owner
394
            assert get_comment_value() == expected_new_owner  # !!
395
            assert get_field_value('prefill-string-page1') == expected_owner
396
            assert get_field_value('prefill-user-page1') == expected_owner
397
            assert get_field_value('prefill-string-page2') == expected_new_owner  # !!
398
            assert get_field_value('prefill-user-page2') == expected_new_owner  # !!
399
        else:
400
            assert formdata_user == expected_owner
401
            assert get_comment_value() == expected_owner
402
            assert get_field_value('prefill-string-page1') == expected_owner
403
            assert get_field_value('prefill-user-page1') == expected_owner
404
            assert get_field_value('prefill-string-workflow') == expected_owner
405
            assert get_field_value('prefill-user-workflow') == expected_new_owner  # !!
406

  
407
    # direct access to formdata
408
    is_draft = True  # drafts
409
    with submit(anonymous, is_front=True) as (tracking_code, formdata_id):
410
        access = ('login', 'deny', 'deny', 'deny', 'deny', 'deny')
411
        for i in range(len(users)):
412
            check_direct_access(users[i], access[i])
413
    with submit(agent1, is_front=False) as (tracking_code, formdata_id):
414
        access = ('login', 'deny', 'deny', 'deny', 'deny', 'deny')
415
        for i in range(len(users)):
416
            check_direct_access(users[i], access[i])
417
    with submit(user1, is_front=True) as (tracking_code, formdata_id):
418
        access = ('login', 'front', 'deny', 'deny', 'deny', 'deny')
419
        for i in range(len(users)):
420
            check_direct_access(users[i], access[i])
421

  
422
    is_draft = False  # demands
423
    with submit(anonymous, is_front=True) as (tracking_code, formdata_id):
424
        access = ('login', 'deny', 'deny', 'deny', 'back', 'back')
425
        for i in range(len(users)):
426
            check_direct_access(users[i], access[i])
427
    with submit(agent1, is_front=False) as (tracking_code, formdata_id):
428
        access = ('login', 'deny', 'deny', 'deny', 'back', 'back')
429
        for i in range(len(users)):
430
            check_direct_access(users[i], access[i])
431
    with submit(user1, is_front=True) as (tracking_code, formdata_id):
432
        access = ('login', 'front', 'deny', 'deny', 'back', 'back')
433
        for i in range(len(users)):
434
            check_direct_access(users[i], access[i])
435

  
436
    # access to formdata using the tracking code
437
    is_draft = True  # drafts
438
    for user in users:
439
        with submit(anonymous, is_front=True) as (tracking_code, formdata_id):
440
            check_tracking_code_access(user, owner=anonymous, new_owner=user)
441
        with submit(agent1, is_front=False) as (tracking_code, formdata_id):
442
            check_tracking_code_access(user, owner=anonymous, new_owner=user)
443
        with submit(user1, is_front=True) as (tracking_code, formdata_id):
444
            check_tracking_code_access(user, owner=user1, new_owner=user)
445

  
446
    is_draft = False  # demands
447
    for user in users:
448
        with submit(anonymous, is_front=True) as (tracking_code, formdata_id):
449
            check_tracking_code_access(user, owner=anonymous, new_owner=user)
450
        with submit(agent1, is_front=False) as (tracking_code, formdata_id):
451
            check_tracking_code_access(user, owner=anonymous, new_owner=user)
452
        with submit(user1, is_front=True) as (tracking_code, formdata_id):
453
            check_tracking_code_access(user, owner=user1, new_owner=user)
77
-