Projet

Général

Profil

0001-wf-add-assign-carddata-action-57962.patch

Lauréline Guérin, 25 novembre 2021 15:40

Télécharger (34,2 ko)

Voir les différences:

Subject: [PATCH 1/2] wf: add assign carddata action (#57962)

 tests/admin_pages/test_workflow.py |  94 +++++
 tests/workflow/test_carddata.py    | 610 ++++++++++++++++++++++++++++-
 wcs/wf/assign_carddata.py          |  71 ++++
 wcs/wf/create_formdata.py          |  40 +-
 wcs/wf/external_workflow.py        |   1 +
 wcs/workflows.py                   |   2 +
 6 files changed, 799 insertions(+), 19 deletions(-)
 create mode 100644 wcs/wf/assign_carddata.py
tests/admin_pages/test_workflow.py
16 16
from wcs.qommon.errors import ConnectionError
17 17
from wcs.qommon.form import UploadedFile
18 18
from wcs.qommon.http_request import HTTPRequest
19
from wcs.wf.assign_carddata import AssignCarddataWorkflowStatusItem
19 20
from wcs.wf.create_carddata import CreateCarddataWorkflowStatusItem
20 21
from wcs.wf.create_formdata import CreateFormdataWorkflowStatusItem, Mapping
21 22
from wcs.wf.dispatch import DispatchWorkflowStatusItem
......
2508 2509
    assert Workflow.get(wf.id).possible_status[0].items[0].target_id == '{{ form_var_plop_id }}'
2509 2510

  
2510 2511

  
2512
def test_workflows_assign_carddata_action_options(pub):
2513
    create_superuser(pub)
2514

  
2515
    Workflow.wipe()
2516
    wf = Workflow(name='assign card')
2517
    st = wf.add_status('New')
2518
    assign_carddata = AssignCarddataWorkflowStatusItem()
2519
    assign_carddata.parent = st
2520
    st.items.append(assign_carddata)
2521
    wf.store()
2522

  
2523
    app = login(get_app(pub))
2524

  
2525
    if not pub.site_options.has_section('options'):
2526
        pub.site_options.add_section('options')
2527

  
2528
    app = login(get_app(pub))
2529

  
2530
    for value in ['false', 'true']:
2531
        # no python expressions
2532
        pub.site_options.set('options', 'disable-python-expressions', value)
2533
        with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd:
2534
            pub.site_options.write(fd)
2535
        resp = app.get('/backoffice/workflows/%s/status/%s/items/1/' % (wf.id, st.id))
2536
        assert resp.form['target_id$type'].options == [
2537
            ('text', False, 'Text'),
2538
            ('template', False, 'Template'),
2539
        ]
2540
        assert resp.form['user_association_template$type'].options == [
2541
            ('text', False, 'Text'),
2542
            ('template', False, 'Template'),
2543
        ]
2544
        assert resp.form['condition$type'].options == [
2545
            ('django', False, 'Django Expression'),
2546
        ]
2547

  
2548

  
2549
def test_workflows_assign_carddata_action(pub):
2550
    create_superuser(pub)
2551
    Workflow.wipe()
2552
    CardDef.wipe()
2553

  
2554
    wf = Workflow(name='assign card')
2555
    st = wf.add_status('Update card', 'st')
2556
    wf.store()
2557

  
2558
    carddef = CardDef()
2559
    carddef.name = 'My card'
2560
    carddef.fields = [
2561
        fields.StringField(id='1', label='string'),
2562
    ]
2563
    carddef.store()
2564

  
2565
    app = login(get_app(pub))
2566

  
2567
    resp = app.get('/backoffice/workflows/%s/status/%s/' % (wf.id, st.id))
2568
    assert 'Assign Card Data' in [o[0] for o in resp.forms[0]['action-formdata-action'].options]
2569

  
2570
    resp.forms[0]['action-formdata-action'] = 'Assign Card Data'
2571
    resp = resp.forms[0].submit().follow()
2572
    assert 'Assign Card Data (not configured)' in resp.text
2573

  
2574
    resp = app.get('/backoffice/workflows/%s/status/%s/items/1/' % (wf.id, st.id))
2575
    resp.forms[0]['formdef_slug'] = 'my-card'
2576
    resp = resp.forms[0].submit('submit')
2577
    assert 'Assign Card Data (not configured)' not in resp.text
2578
    assert Workflow.get(wf.id).possible_status[0].items[0].target_mode == 'all'
2579
    assert Workflow.get(wf.id).possible_status[0].items[0].target_id is None
2580
    assert Workflow.get(wf.id).possible_status[0].items[0].user_association_mode is None
2581
    assert Workflow.get(wf.id).possible_status[0].items[0].user_association_template is None
2582

  
2583
    resp = app.get('/backoffice/workflows/%s/status/%s/items/1/' % (wf.id, st.id))
2584
    resp.forms[0]['target_mode'] = 'manual'
2585
    resp.forms[0]['target_id$type'] = 'template'
2586
    resp.forms[0]['target_id$value_template'] = '{{ form_var_plop_id }}'
2587
    resp.forms[0]['user_association_mode'] = 'keep-user'
2588
    resp = resp.forms[0].submit('submit')
2589
    assert Workflow.get(wf.id).possible_status[0].items[0].target_mode == 'manual'
2590
    assert Workflow.get(wf.id).possible_status[0].items[0].target_id == '{{ form_var_plop_id }}'
2591
    assert Workflow.get(wf.id).possible_status[0].items[0].user_association_mode == 'keep-user'
2592
    assert Workflow.get(wf.id).possible_status[0].items[0].user_association_template is None
2593

  
2594
    resp = app.get('/backoffice/workflows/%s/status/%s/items/1/' % (wf.id, st.id))
2595
    resp.forms[0]['user_association_mode'] = 'custom'
2596
    resp.forms[0]['user_association_template$type'] = 'template'
2597
    resp.forms[0]['user_association_template$value_template'] = '{{ form_var_user_id }}'
2598
    resp = resp.forms[0].submit('submit')
2599
    assert Workflow.get(wf.id).possible_status[0].items[0].user_association_mode == 'custom'
2600
    assert (
2601
        Workflow.get(wf.id).possible_status[0].items[0].user_association_template == '{{ form_var_user_id }}'
2602
    )
2603

  
2604

  
2511 2605
def test_workflows_criticality_levels(pub):
2512 2606
    create_superuser(pub)
2513 2607

  
tests/workflow/test_carddata.py
10 10
from wcs.formdef import FormDef
11 11
from wcs.qommon.http_request import HTTPRequest
12 12
from wcs.qommon.upload_storage import PicklableUpload
13
from wcs.wf.assign_carddata import AssignCarddataWorkflowStatusItem
13 14
from wcs.wf.create_carddata import CreateCarddataWorkflowStatusItem
14 15
from wcs.wf.create_formdata import CreateFormdataWorkflowStatusItem, Mapping
15 16
from wcs.wf.edit_carddata import EditCarddataWorkflowStatusItem
......
435 436
    user.email = 'test@example.net'
436 437
    user.name_identifiers = ['xyz']
437 438
    user.store()
439
    user2 = two_pubs.user_class()
440
    user2.store()
438 441

  
439 442
    carddef = CardDef()
440 443
    carddef.name = 'My card'
......
507 510

  
508 511
    formdata = FormDef.get(formdef.id).data_class()()
509 512
    formdata.data = {}
510
    formdata.user_id = user.id
513
    formdata.user_id = user2.id
511 514
    formdata.just_created()
512 515
    formdata.perform_workflow()
513 516

  
......
522 525

  
523 526
    formdata = FormDef.get(formdef.id).data_class()()
524 527
    formdata.data = {}
525
    formdata.user_id = user.id
528
    formdata.user_id = user2.id
526 529
    formdata.just_created()
527 530
    formdata.perform_workflow()
528 531

  
......
549 552
        assert two_pubs.loggederror_class.count() == 1
550 553
        logged_error = two_pubs.loggederror_class.select()[0]
551 554
        assert logged_error.summary == 'Failed to attach user (not found: "zzz")'
552
        assert logged_error.formdata_id == str(carddef.data_class().select()[0].id)
555
        assert logged_error.formdata_id == str(formdata.id)
553 556

  
554 557
    # user association on invalid template
555 558
    carddef.data_class().wipe()
......
590 593
    ]
591 594
    carddef.digest_templates = {'default': '{{ form_var_first_name }} {{ form_var_last_name }}'}
592 595
    carddef.store()
596
    carddef.data_class().wipe()
593 597

  
594 598
    carddata = carddef.data_class()()
595 599
    carddata.data = {'0': 'Foo', '1': 'Bar', '2': 'l'}
......
677 681
        StringField(id='2', label='Kids number', varname='kids_number'),
678 682
    ]
679 683
    carddef.store()
684
    carddef.data_class().wipe()
680 685

  
681 686
    wf = Workflow(name='Card create and update')
682 687
    st1 = wf.add_status('Create card', 'st1')
......
1039 1044
    carddata_reloaded = carddata.get(carddata.id)
1040 1045
    assert carddata_reloaded.data['0'] == 'HELLO'
1041 1046
    assert carddata_reloaded.status == 'wf-2'
1047

  
1048

  
1049
def test_assign_carddata_with_data_sourced_object(pub):
1050
    FormDef.wipe()
1051
    CardDef.wipe()
1052
    pub.user_class.wipe()
1053

  
1054
    user = pub.user_class()
1055
    user.email = 'test@example.net'
1056
    user.name_identifiers = ['xyz']
1057
    user.store()
1058

  
1059
    carddef = CardDef()
1060
    carddef.name = 'Person'
1061
    carddef.fields = [
1062
        StringField(id='0', label='First Name', varname='first_name'),
1063
        StringField(id='1', label='Last Name', varname='last_name'),
1064
    ]
1065
    carddef.digest_templates = {'default': '{{ form_var_first_name }} {{ form_var_last_name }}'}
1066
    carddef.store()
1067
    carddef.data_class().wipe()
1068

  
1069
    carddata = carddef.data_class()()
1070
    carddata.data = {'0': 'Foo', '1': 'Bar'}
1071
    carddata.store()
1072

  
1073
    wf = Workflow(name='Card update')
1074
    st1 = wf.add_status('Assign card', 'st1')
1075

  
1076
    assign = AssignCarddataWorkflowStatusItem()
1077
    assign.formdef_slug = carddef.url_name
1078
    assign.user_association_mode = 'keep-user'
1079
    assign.id = 'assign'
1080
    st1.items.append(assign)
1081
    assign.parent = st1
1082
    wf.store()
1083

  
1084
    datasource = {'type': 'carddef:%s' % carddef.url_name}
1085
    formdef = FormDef()
1086
    formdef.name = 'Persons'
1087
    formdef.fields = [
1088
        ItemField(id='0', label='Person', type='item', varname='person', data_source=datasource),
1089
    ]
1090
    formdef.workflow = wf
1091
    formdef.store()
1092

  
1093
    formdata = formdef.data_class()()
1094
    formdata.data = {'0': '1'}
1095
    formdata.user_id = user.id
1096
    formdata.store()
1097
    formdata.just_created()
1098
    formdata.perform_workflow()
1099

  
1100
    data = carddef.data_class().select()[0]
1101
    assert data.user_id == user.id
1102

  
1103

  
1104
def test_assign_carddata_with_linked_object(pub):
1105
    FormDef.wipe()
1106
    CardDef.wipe()
1107
    pub.user_class.wipe()
1108

  
1109
    user = pub.user_class()
1110
    user.email = 'test@example.net'
1111
    user.name_identifiers = ['xyz']
1112
    user.store()
1113

  
1114
    carddef = CardDef()
1115
    carddef.name = 'Parent'
1116
    carddef.fields = [
1117
        StringField(id='0', label='First Name', varname='first_name'),
1118
        StringField(id='1', label='Last Name', varname='last_name'),
1119
    ]
1120
    carddef.store()
1121
    carddef.data_class().wipe()
1122

  
1123
    wf = Workflow(name='Card create and assign')
1124
    st1 = wf.add_status('Create card', 'st1')
1125
    create = CreateCarddataWorkflowStatusItem()
1126
    create.formdef_slug = carddef.url_name
1127
    create.user_association_mode = None
1128
    create.mappings = [
1129
        Mapping(field_id='0', expression='{{ form_var_first_name }}'),
1130
        Mapping(field_id='1', expression='{{ form_var_last_name }}'),
1131
    ]
1132
    st1.items.append(create)
1133
    create.parent = st1
1134
    jump = JumpWorkflowStatusItem()
1135
    jump.id = '_jump'
1136
    jump.by = ['_submitter', '_receiver']
1137
    jump.status = 'st2'
1138
    st1.items.append(jump)
1139
    jump.parent = st1
1140

  
1141
    st2 = wf.add_status('Assign card', 'st2')
1142
    assign = AssignCarddataWorkflowStatusItem()
1143
    assign.formdef_slug = carddef.url_name
1144
    assign.user_association_mode = 'keep-user'
1145
    assign.id = 'assign'
1146
    st2.items.append(assign)
1147
    assign.parent = st2
1148
    wf.store()
1149

  
1150
    formdef = FormDef()
1151
    formdef.name = 'Parents'
1152
    formdef.fields = [
1153
        StringField(id='0', label='First Name', varname='first_name'),
1154
        StringField(id='1', label='Last Name', varname='last_name'),
1155
    ]
1156
    formdef.workflow = wf
1157
    formdef.store()
1158

  
1159
    formdata = formdef.data_class()()
1160
    formdata.data = {'0': 'Parent', '1': 'Foo'}
1161
    formdata.user_id = user.id
1162
    formdata.store()
1163
    formdata.just_created()
1164
    formdata.perform_workflow()
1165

  
1166
    assert carddef.data_class().count() == 1
1167
    card_data = carddef.data_class().select()[0]
1168
    assert card_data.user_id == user.id
1169

  
1170

  
1171
def test_assign_carddata_manual_targeting(two_pubs):
1172
    if not two_pubs.is_using_postgresql():
1173
        pytest.skip('this requires SQL')
1174
        return
1175

  
1176
    FormDef.wipe()
1177
    CardDef.wipe()
1178
    two_pubs.loggederror_class.wipe()
1179
    two_pubs.user_class.wipe()
1180

  
1181
    user = two_pubs.user_class()
1182
    user.email = 'test@example.net'
1183
    user.name_identifiers = ['xyz']
1184
    user.store()
1185

  
1186
    # carddef
1187
    carddef = CardDef()
1188
    carddef.name = 'Parent'
1189
    carddef.fields = [
1190
        StringField(id='0', label='First Name', varname='first_name'),
1191
        StringField(id='1', label='Last Name', varname='last_name'),
1192
    ]
1193
    carddef.store()
1194
    carddef.data_class().wipe()
1195

  
1196
    # and sample carddatas
1197
    for i in range(1, 4):
1198
        carddata = carddef.data_class()()
1199
        carddata.data = {
1200
            '0': 'First name %s' % i,
1201
            '1': 'Last name %s' % i,
1202
        }
1203
        carddata.store()
1204

  
1205
    # formdef workflow that will assign carddata
1206
    wf = Workflow(name='Card create and Assign')
1207
    st1 = wf.add_status('Create card', 'st1')
1208
    # create linked carddata
1209
    create = CreateCarddataWorkflowStatusItem()
1210
    create.formdef_slug = carddef.url_name
1211
    create.user_association_mode = None
1212
    create.mappings = [
1213
        Mapping(field_id='0', expression='{{ form_var_first_name }}'),
1214
        Mapping(field_id='1', expression='{{ form_var_last_name }}'),
1215
    ]
1216
    st1.items.append(create)
1217
    create.parent = st1
1218
    jump = JumpWorkflowStatusItem()
1219
    jump.id = '_jump'
1220
    jump.by = ['_submitter', '_receiver']
1221
    jump.status = 'st2'
1222
    st1.items.append(jump)
1223
    jump.parent = st1
1224

  
1225
    st2 = wf.add_status('Assign card', 'st2')
1226
    assign = AssignCarddataWorkflowStatusItem()
1227
    assign.formdef_slug = carddef.url_name
1228
    assign.target_mode = 'manual'  # not configured
1229
    assign.user_association_mode = 'keep-user'
1230
    assign.id = 'assign'
1231
    st2.items.append(assign)
1232
    assign.parent = st2
1233
    wf.store()
1234

  
1235
    # associated formdef
1236
    formdef = FormDef()
1237
    formdef.name = 'Parents'
1238
    datasource = {'type': 'carddef:%s' % carddef.url_name}
1239
    formdef.fields = [
1240
        StringField(id='0', label='First Name', varname='first_name'),
1241
        StringField(id='1', label='Last Name', varname='last_name'),
1242
        StringField(id='2', label='string', varname='string'),
1243
        ItemField(id='3', label='Card', type='item', varname='card', data_source=datasource),
1244
    ]
1245
    formdef.workflow = wf
1246
    formdef.store()
1247

  
1248
    # create formdatas
1249

  
1250
    # target not configured
1251
    formdata = formdef.data_class()()
1252
    formdata.data = {
1253
        '0': 'Parent',
1254
        '1': 'Foo',
1255
        '2': '1',
1256
        '3': '3',  # set from datasource
1257
    }
1258
    # set parent
1259
    formdata.submission_context = {
1260
        'orig_object_type': 'carddef',
1261
        'orig_formdata_id': '2',
1262
        'orig_formdef_id': str(carddef.id),
1263
    }
1264
    formdata.user_id = user.id
1265
    formdata.store()
1266
    formdata.just_created()
1267
    formdata.perform_workflow()
1268

  
1269
    assert carddef.data_class().count() == 4
1270
    assert carddef.data_class().get(1).user_id is None
1271
    assert carddef.data_class().get(2).user_id is None
1272
    assert carddef.data_class().get(3).user_id is None
1273
    assert carddef.data_class().get(4).user_id is None
1274
    assert two_pubs.loggederror_class.count() == 0
1275

  
1276
    # configure target
1277
    assign.target_id = '{{ form_var_string }}'  # == '1'
1278
    wf.store()
1279
    formdata = formdef.data_class()()
1280
    formdata.data = {
1281
        '0': 'Parent',
1282
        '1': 'Foo',
1283
        '2': '1',
1284
        '3': '3',  # set from datasource
1285
    }
1286
    # set parent
1287
    formdata.submission_context = {
1288
        'orig_object_type': 'carddef',
1289
        'orig_formdata_id': '2',
1290
        'orig_formdef_id': str(carddef.id),
1291
    }
1292
    formdata.user_id = user.id
1293
    formdata.store()
1294
    formdata.just_created()
1295
    formdata.perform_workflow()
1296
    assert carddef.data_class().count() == 5
1297
    assert carddef.data_class().get(1).user_id == str(user.id)
1298
    assert carddef.data_class().get(2).user_id is None
1299
    assert carddef.data_class().get(3).user_id is None
1300
    assert carddef.data_class().get(4).user_id is None
1301
    assert carddef.data_class().get(5).user_id is None
1302
    assert two_pubs.loggederror_class.count() == 0
1303

  
1304
    # target not found
1305
    assign.target_id = '42{{ form_var_string }}'  # == '424'
1306
    wf.store()
1307
    formdata = formdef.data_class()()
1308
    formdata.data = {
1309
        '0': 'Parent',
1310
        '1': 'Foo',
1311
        '2': '4',
1312
        '3': '3',  # set from datasource
1313
    }
1314
    # set parent
1315
    formdata.submission_context = {
1316
        'orig_object_type': 'carddef',
1317
        'orig_formdata_id': '2',
1318
        'orig_formdef_id': str(carddef.id),
1319
    }
1320
    formdata.user_id = user.id
1321
    formdata.store()
1322
    formdata.just_created()
1323
    formdata.perform_workflow()
1324
    assert carddef.data_class().count() == 6
1325
    assert carddef.data_class().get(1).user_id == str(user.id)
1326
    assert carddef.data_class().get(2).user_id is None
1327
    assert carddef.data_class().get(3).user_id is None
1328
    assert carddef.data_class().get(4).user_id is None  # not changed
1329
    assert carddef.data_class().get(5).user_id is None
1330
    assert carddef.data_class().get(6).user_id is None
1331
    assert two_pubs.loggederror_class.count() == 1
1332
    logged_error = two_pubs.loggederror_class.select()[0]
1333
    assert logged_error.summary == 'Could not find targeted "Parent" object by id 424'
1334

  
1335
    # slug not or badly configured
1336
    assign.target_id = '{{ form_var_string }}'  # == '5'
1337
    assign.formdef_slug = None
1338
    wf.store()
1339
    formdata = formdef.data_class()()
1340
    formdata.data = {
1341
        '0': 'Parent',
1342
        '1': 'Foo',
1343
        '2': '5',
1344
        '3': '3',  # set from datasource
1345
    }
1346
    # set parent
1347
    formdata.submission_context = {
1348
        'orig_object_type': 'carddef',
1349
        'orig_formdata_id': '2',
1350
        'orig_formdef_id': str(carddef.id),
1351
    }
1352
    formdata.user_id = user.id
1353
    formdata.store()
1354
    formdata.just_created()
1355
    formdata.perform_workflow()
1356
    assert carddef.data_class().count() == 7
1357
    assert carddef.data_class().get(1).user_id == str(user.id)
1358
    assert carddef.data_class().get(2).user_id is None
1359
    assert carddef.data_class().get(3).user_id is None
1360
    assert carddef.data_class().get(4).user_id is None
1361
    assert carddef.data_class().get(5).user_id is None  # not changed
1362
    assert carddef.data_class().get(6).user_id is None
1363
    assert carddef.data_class().get(7).user_id is None
1364

  
1365

  
1366
def test_assign_carddata_targeting_itself(pub):
1367
    CardDef.wipe()
1368
    pub.user_class.wipe()
1369

  
1370
    user = pub.user_class()
1371
    user.email = 'test@example.net'
1372
    user.name_identifiers = ['xyz']
1373
    user.store()
1374

  
1375
    carddef = CardDef()
1376
    carddef.name = 'Foo Card'
1377
    carddef.fields = [
1378
        StringField(id='0', label='foo', varname='foo'),
1379
    ]
1380
    carddef.store()
1381
    carddef.data_class().wipe()
1382

  
1383
    # card workflow: assign itself then jump to second status
1384
    card_wf = Workflow(name='Card workflow')
1385
    st1 = card_wf.add_status('Status1')
1386
    st2 = card_wf.add_status('Status2')
1387

  
1388
    assign = AssignCarddataWorkflowStatusItem()
1389
    assign.id = '_assign'
1390
    assign.formdef_slug = carddef.url_name
1391
    assign.target_mode = 'manual'
1392
    assign.target_id = '{{ form_internal_id }}'  # itself
1393
    assign.user_association_mode = 'custom'
1394
    assign.user_association_template = 'xyz'
1395
    assign.parent = st1
1396
    st1.items.append(assign)
1397

  
1398
    jump = JumpWorkflowStatusItem()
1399
    jump.id = '_jump'
1400
    jump.status = st2.id
1401
    st1.items.append(jump)
1402
    jump.parent = st1
1403

  
1404
    card_wf.store()
1405

  
1406
    carddef.workflow = card_wf
1407
    carddef.store()
1408

  
1409
    # create some cardata
1410
    for i in range(1, 4):
1411
        carddata = carddef.data_class()()
1412
        carddata.data = {
1413
            '0': 'foo %s' % i,
1414
        }
1415
        carddata.user_id = 42
1416
        carddata.store()
1417
        # run workflow, verify that carddata is assign
1418
        carddata.just_created()
1419
        carddata.perform_workflow()
1420
        assert carddata.user_id == user.id
1421
        assert carddata.status == 'wf-%s' % st2.id
1422

  
1423

  
1424
def test_assign_carddata_from_created_object(pub):
1425
    FormDef.wipe()
1426
    CardDef.wipe()
1427
    pub.user_class.wipe()
1428

  
1429
    user = pub.user_class()
1430
    user.email = 'test@example.net'
1431
    user.name_identifiers = ['xyz']
1432
    user.store()
1433

  
1434
    carddef = CardDef()
1435
    carddef.name = 'Card'
1436
    carddef.fields = [
1437
        StringField(id='0', label='Card Field', varname='card_field'),
1438
    ]
1439
    carddef.store()
1440
    carddef.data_class().wipe()
1441

  
1442
    formdef = FormDef()
1443
    formdef.name = 'Form'
1444
    formdef.fields = [
1445
        StringField(id='0', label='Form Field', varname='form_field'),
1446
    ]
1447
    formdef.store()
1448

  
1449
    # card workflow: create formdata then jump to second status
1450
    card_wf = Workflow(name='Card workflow')
1451
    st1 = card_wf.add_status('Status1')
1452
    st2 = card_wf.add_status('Status2')
1453

  
1454
    create = CreateFormdataWorkflowStatusItem()
1455
    create.id = '_create'
1456
    create.formdef_slug = formdef.url_name
1457
    create.mappings = [
1458
        Mapping(field_id='0', expression='...'),
1459
    ]
1460
    create.parent = st1
1461
    st1.items.append(create)
1462

  
1463
    jump = JumpWorkflowStatusItem()
1464
    jump.id = '_jump'
1465
    jump.status = st2.id
1466
    st1.items.append(jump)
1467
    jump.parent = st1
1468

  
1469
    # form workflow: assign parent card data
1470
    form_wf = Workflow(name='Form workflow')
1471
    st1 = form_wf.add_status('Status1')
1472
    assign = AssignCarddataWorkflowStatusItem()
1473
    assign.formdef_slug = carddef.url_name
1474
    assign.user_association_mode = 'custom'
1475
    assign.user_association_template = 'xyz'
1476
    assign.id = 'assign'
1477
    st1.items.append(assign)
1478
    assign.parent = st1
1479
    form_wf.store()
1480

  
1481
    carddef.workflow = card_wf
1482
    carddef.store()
1483

  
1484
    formdef.workflow = form_wf
1485
    formdef.store()
1486

  
1487
    carddata = carddef.data_class()()
1488
    carddata.data = {'0': 'Foo'}
1489
    carddata.store()
1490
    carddata.just_created()
1491
    carddata.perform_workflow()
1492
    assert carddata.user_id == user.id
1493

  
1494
    carddata_reloaded = carddata.get(carddata.id)
1495
    assert carddata_reloaded.status == 'wf-2'
1496
    assert carddata_reloaded.user_id == user.id
1497

  
1498

  
1499
def test_assign_carddata_user_association(two_pubs):
1500
    CardDef.wipe()
1501
    FormDef.wipe()
1502
    two_pubs.user_class.wipe()
1503

  
1504
    user = two_pubs.user_class()
1505
    user.email = 'test@example.net'
1506
    user.name_identifiers = ['xyz']
1507
    user.store()
1508
    user2 = two_pubs.user_class()
1509
    user2.store()
1510

  
1511
    carddef = CardDef()
1512
    carddef.name = 'Person'
1513
    carddef.fields = [
1514
        StringField(id='0', label='First Name', varname='first_name'),
1515
        StringField(id='1', label='Last Name', varname='last_name'),
1516
    ]
1517
    carddef.digest_templates = {'default': '{{ form_var_first_name }} {{ form_var_last_name }}'}
1518
    carddef.user_support = 'optional'
1519
    carddef.store()
1520
    carddef.data_class().wipe()
1521

  
1522
    carddata = carddef.data_class()()
1523
    carddata.data = {'0': 'Foo', '1': 'Bar'}
1524
    carddata.user_id = user2.id
1525
    carddata.store()
1526

  
1527
    wf = Workflow(name='assign-carddata')
1528
    wf.possible_status = Workflow.get_default_workflow().possible_status[:]
1529
    assign = AssignCarddataWorkflowStatusItem()
1530
    assign.label = 'Assign CardDef'
1531
    assign.varname = 'mycard'
1532
    assign.id = '_assign'
1533
    assign.formdef_slug = carddef.url_name
1534
    assign.parent = wf.possible_status[1]
1535
    wf.possible_status[1].items.insert(0, assign)
1536
    wf.store()
1537

  
1538
    datasource = {'type': 'carddef:%s' % carddef.url_name}
1539
    formdef = FormDef()
1540
    formdef.name = 'Persons'
1541
    formdef.fields = [
1542
        ItemField(id='0', label='Person', type='item', varname='person', data_source=datasource),
1543
    ]
1544
    formdef.workflow = wf
1545
    formdef.store()
1546

  
1547
    formdata = formdef.data_class()()
1548
    formdata.data = {'0': '1'}
1549
    formdata.user_id = user.id
1550
    formdata.just_created()
1551
    formdata.perform_workflow()
1552

  
1553
    assert carddef.data_class().select()[0].user is None
1554

  
1555
    # keep user
1556
    carddata.user_id = user2.id
1557
    carddata.store()
1558
    assign.user_association_mode = 'keep-user'
1559
    wf.store()
1560

  
1561
    formdata = FormDef.get(formdef.id).data_class()()
1562
    formdata.data = {'0': '1'}
1563
    formdata.user_id = user.id
1564
    formdata.just_created()
1565
    formdata.perform_workflow()
1566

  
1567
    assert carddef.data_class().select()[0].user.id == user.id
1568

  
1569
    # user association on direct user
1570
    carddata.user_id = user2.id
1571
    carddata.store()
1572
    assign.user_association_mode = 'custom'
1573
    assign.user_association_template = '{{ form_user }}'
1574
    wf.store()
1575

  
1576
    formdata = FormDef.get(formdef.id).data_class()()
1577
    formdata.data = {'0': '1'}
1578
    formdata.user_id = user.id
1579
    formdata.just_created()
1580
    formdata.perform_workflow()
1581

  
1582
    assert carddef.data_class().select()[0].user.id == user.id
1583

  
1584
    # user association on user email
1585
    carddata.user_id = user2.id
1586
    carddata.store()
1587
    assign.user_association_mode = 'custom'
1588
    assign.user_association_template = 'test@example.net'
1589
    wf.store()
1590

  
1591
    formdata = FormDef.get(formdef.id).data_class()()
1592
    formdata.data = {'0': '1'}
1593
    formdata.just_created()
1594
    formdata.perform_workflow()
1595

  
1596
    assert carddef.data_class().select()[0].user.id == user.id
1597

  
1598
    # user association on name id
1599
    carddata.user_id = user2.id
1600
    carddata.store()
1601
    assign.user_association_mode = 'custom'
1602
    assign.user_association_template = 'xyz'
1603
    wf.store()
1604

  
1605
    formdata = FormDef.get(formdef.id).data_class()()
1606
    formdata.data = {'0': '1'}
1607
    formdata.just_created()
1608
    formdata.perform_workflow()
1609

  
1610
    assert carddef.data_class().select()[0].user.id == user.id
1611

  
1612
    # user association on invalid user
1613
    carddata.user_id = user2.id
1614
    carddata.store()
1615
    assign.user_association_mode = 'custom'
1616
    assign.user_association_template = 'zzz'
1617
    wf.store()
1618

  
1619
    formdata = FormDef.get(formdef.id).data_class()()
1620
    formdata.data = {'0': '1'}
1621
    formdata.just_created()
1622
    if two_pubs.loggederror_class:
1623
        two_pubs.loggederror_class.wipe()
1624
    formdata.perform_workflow()
1625

  
1626
    assert carddef.data_class().select()[0].user is None
1627
    if two_pubs.loggederror_class:
1628
        assert two_pubs.loggederror_class.count() == 1
1629
        logged_error = two_pubs.loggederror_class.select()[0]
1630
        assert logged_error.summary == 'Failed to attach user (not found: "zzz")'
1631
        assert logged_error.formdata_id == str(formdata.id)
1632

  
1633
    # user association on invalid template
1634
    carddata.user_id = user2.id
1635
    carddata.store()
1636
    assign.user_association_mode = 'custom'
1637
    assign.user_association_template = '{% %}'
1638
    wf.store()
1639

  
1640
    formdata = FormDef.get(formdef.id).data_class()()
1641
    formdata.data = {'0': '1'}
1642
    formdata.just_created()
1643
    formdata.perform_workflow()
1644

  
1645
    assert carddef.data_class().select()[0].user is None
wcs/wf/assign_carddata.py
1
# w.c.s. - web application for online forms
2
# Copyright (C) 2005-2021  Entr'ouvert
3
#
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, see <http://www.gnu.org/licenses/>.
16

  
17

  
18
from quixote import get_publisher
19

  
20
from wcs.qommon import _
21
from wcs.wf.create_carddata import CreateCarddataWorkflowStatusItem
22
from wcs.wf.external_workflow import ExternalWorkflowGlobalAction
23
from wcs.workflows import register_item_class
24

  
25

  
26
class AssignCarddataWorkflowStatusItem(CreateCarddataWorkflowStatusItem, ExternalWorkflowGlobalAction):
27
    description = _('Assign Card Data')
28
    key = 'assign_carddata'
29
    automatic_targetting = _('Assign linked cards')
30
    manual_targetting = _('Specify the identifier of the card which will be assigned')
31
    always_show_user_fields = True
32
    allow_python = False
33
    django_only = True
34

  
35
    def get_parameters(self):
36
        return (
37
            'formdef_slug',
38
            'target_mode',
39
            'target_id',
40
            'user_association_mode',
41
            'user_association_template',
42
            'condition',
43
        )
44

  
45
    @property
46
    def slug(self):
47
        # act only on linked carddefs
48
        return 'carddef:%s' % self.formdef_slug
49

  
50
    def get_line_details(self):
51
        if not self.formdef:
52
            return _('not configured')
53
        return self.formdef.name
54

  
55
    def perform(self, formdata):
56
        carddef = self.formdef
57
        if not carddef:
58
            return
59

  
60
        formdata.store()
61

  
62
        for target_data in self.iter_target_datas(formdata, carddef):
63
            self.assign_user(dest=target_data, src=formdata)
64
            with get_publisher().substitutions.freeze():
65
                target_data.store()
66

  
67
        # update local object as it may have modified itself
68
        formdata.refresh_from_storage()
69

  
70

  
71
register_item_class(AssignCarddataWorkflowStatusItem)
wcs/wf/create_formdata.py
365 365
                ],
366 366
                value=self.user_association_mode,
367 367
                attrs={'data-dynamic-display-parent': 'true'},
368
                advanced=bool(self.user_association_mode),
368
                advanced=not getattr(self, 'always_show_user_fields', False)
369
                and bool(self.user_association_mode),
369 370
            )
370 371
        if 'user_association_template' in parameters:
371 372
            form.add(
......
377 378
                    'data-dynamic-display-child-of': '%suser_association_mode' % prefix,
378 379
                    'data-dynamic-display-value': 'custom',
379 380
                },
380
                advanced=bool(self.user_association_mode),
381
                advanced=not getattr(self, 'always_show_user_fields', False)
382
                and bool(self.user_association_mode),
383
                allow_python=getattr(self, 'allow_python', True),
381 384
            )
382 385
        if 'keep_submission_context' in parameters:
383 386
            form.add(
......
493 496
            return _('not configured')
494 497
        return self.formdef.name
495 498

  
496
    def perform(self, formdata):
497
        formdef = self.formdef
498
        if not formdef or not (self.mappings or self.map_fields_by_varname):
499
            return
500

  
501
        new_formdata = formdef.data_class()()
502
        new_formdata.receipt_time = time.localtime()
503

  
499
    def assign_user(self, dest, src):
504 500
        if self.user_association_mode == 'keep-user':
505
            new_formdata.user_id = formdata.user_id
501
            dest.user_id = src.user_id
506 502
        elif self.user_association_mode == 'custom' and self.user_association_template:
507 503
            with get_publisher().complex_data():
508 504
                try:
509 505
                    value = self.compute(
510 506
                        self.user_association_template,
511
                        formdata=formdata,
507
                        formdata=src,
512 508
                        raises=True,
513 509
                        allow_complex=True,
514 510
                        status_item=self,
......
524 520
            if isinstance(value, LazyUser):
525 521
                value = value._user
526 522
            if isinstance(value, get_publisher().user_class):
527
                new_formdata.user = value
523
                dest.user = value
528 524
            else:
529
                new_formdata.user = get_publisher().user_class.lookup_by_string(value)
530
                if value and not new_formdata.user:
525
                dest.user = get_publisher().user_class.lookup_by_string(value)
526
                if value and not dest.user:
531 527
                    get_publisher().record_error(
532 528
                        _('Failed to attach user (not found: "%s")') % value,
533
                        formdata=formdata,
529
                        formdata=src,
534 530
                        status_item=self,
535 531
                    )
532
        else:
533
            dest.user_id = None
534

  
535
    def perform(self, formdata):
536
        formdef = self.formdef
537
        if not formdef or not (self.mappings or self.map_fields_by_varname):
538
            return
539

  
540
        new_formdata = formdef.data_class()()
541
        new_formdata.receipt_time = time.localtime()
542

  
543
        self.assign_user(dest=new_formdata, src=formdata)
536 544

  
537 545
        if self.keep_submission_context:
538 546
            new_formdata.submission_context = formdata.submission_context or {}
wcs/wf/external_workflow.py
153 153
                    'data-dynamic-display-child-of': 'target_mode',
154 154
                    'data-dynamic-display-value': 'manual',
155 155
                },
156
                allow_python=getattr(self, 'allow_python', True),
156 157
            )
157 158

  
158 159
        if 'trigger_id' in parameters and form.get('%sslug' % prefix):
wcs/workflows.py
2176 2176
                value=self.condition,
2177 2177
                size=40,
2178 2178
                advanced=not (self.condition),
2179
                django_only=getattr(self, 'django_only', False),
2179 2180
            )
2180 2181

  
2181 2182
        if 'attachments' in parameters:
......
3564 3565
def load_extra():
3565 3566
    from .wf import aggregation_email  # noqa pylint: disable=unused-import
3566 3567
    from .wf import anonymise  # noqa pylint: disable=unused-import
3568
    from .wf import assign_carddata  # noqa pylint: disable=unused-import
3567 3569
    from .wf import attachment  # noqa pylint: disable=unused-import
3568 3570
    from .wf import backoffice_fields  # noqa pylint: disable=unused-import
3569 3571
    from .wf import create_carddata  # noqa pylint: disable=unused-import
3570
-