Projet

Général

Profil

0001-misc-remap-statuses-in-a-transaction-38579.patch

Benjamin Dauvergne, 22 mars 2021 11:44

Télécharger (8,6 ko)

Voir les différences:

Subject: [PATCH] misc: remap statuses in a transaction (#38579)

 tests/admin_pages/test_form.py |  7 +++++
 wcs/admin/forms.py             | 42 ++++++++++++------------------
 wcs/formdef.py                 | 47 ++++++++++++++++++++++++++++++++++
 wcs/sql.py                     | 22 ++++++++++++++++
 4 files changed, 92 insertions(+), 26 deletions(-)
tests/admin_pages/test_form.py
517 517
    formdata2.status = 'draft'
518 518
    formdata2.store()
519 519

  
520
    formdata3 = data_class()
521
    formdata3.status = 'wf-1'
522
    formdata3.store()
523

  
520 524
    Workflow.wipe()
521 525
    workflow = Workflow(name='Workflow One')
522 526
    workflow.store()
......
538 542
        assert len(resp.forms[0]['mapping-%s' % status.id].options) == 1
539 543
    assert data_class.get(formdata1.id).status == 'wf-new'
540 544
    assert data_class.get(formdata2.id).status == 'draft'
545
    assert data_class.get(formdata3.id).status == 'wf-1'
541 546
    resp = resp.forms[0].submit()
542 547
    assert data_class.get(formdata1.id).status == 'wf-finished'
543 548
    assert data_class.get(formdata2.id).status == 'draft'
549
    assert data_class.get(formdata3.id).status == 'wf-1-invalid-_default'
544 550

  
545 551
    # change to another workflow, with no mapping change
546 552
    workflow2 = workflow
......
561 567
    resp = resp.forms[0].submit()
562 568
    assert data_class.get(formdata1.id).status == 'wf-finished'
563 569
    assert data_class.get(formdata2.id).status == 'draft'
570
    assert data_class.get(formdata3.id).status == 'wf-1-invalid-_default'
564 571

  
565 572

  
566 573
def test_form_submitter_roles(pub):
wcs/admin/forms.py
1069 1069
                if workflow_id is None:
1070 1070
                    workflow_id = self.formdef_default_workflow
1071 1071
                return redirect('workflow-status-remapping?new=%s' % workflow_id)
1072
            self.formdef.workflow_id = workflow_id
1073
            self.formdef.store(comment=_('Workflow change'))
1072
            self.formdef.change_workflow(workflow_id)
1074 1073
            return redirect('.')
1075 1074

  
1076 1075
    def workflow_status_remapping(self):
......
1109 1108
            r += form.render()
1110 1109
            return r.getvalue()
1111 1110
        else:
1112
            get_logger().info(
1113
                'admin - form "%s", workflow is now "%s" (was "%s")'
1114
                % (self.formdef.name, new_workflow.name, self.formdef.workflow.name)
1115
            )
1116
            self.workflow_status_remapping_submit(form)
1117
            if new_workflow.id == self.formdef_default_workflow:
1118
                self.formdef.workflow_id = None
1119
            else:
1120
                self.formdef.workflow_id = new_workflow.id
1121
            self.formdef.store(comment=_('Workflow change'))
1122
            # instruct formdef to update its security rules
1123
            self.formdef.data_class().rebuild_security()
1124
            return redirect('.')
1111
            return self.workflow_status_remapping_submit(form, new_workflow)
1112

  
1113
    def workflow_status_remapping_submit(self, form, new_workflow):
1114
        get_logger().info(
1115
            'admin - form "%s", workflow is now "%s" (was "%s")'
1116
            % (self.formdef.name, new_workflow.name, self.formdef.workflow.name)
1117
        )
1125 1118

  
1126
    def workflow_status_remapping_submit(self, form):
1127 1119
        status_mapping = {}
1128 1120
        for status in self.formdef.workflow.possible_status:
1129
            status_mapping['wf-%s' % status.id] = 'wf-%s' % form.get_widget('mapping-%s' % status.id).parse()
1130
        if any([x[0] != x[1] for x in status_mapping.items()]):
1131
            # if there are status changes, update all formdatas (except drafts)
1132
            status_mapping.update({'draft': 'draft'})
1133
            for item in self.formdef.data_class().select([NotEqual('status', 'draft')]):
1134
                item.status = status_mapping.get(item.status)
1135
                if item.evolution:
1136
                    for evo in item.evolution:
1137
                        evo.status = status_mapping.get(evo.status)
1138
                item.store()
1121
            status_mapping[status.id] = form.get_widget('mapping-%s' % status.id).parse()
1122

  
1123
        if new_workflow.id == self.formdef_default_workflow:
1124
            new_workflow_id = None
1125
        else:
1126
            new_workflow_id = new_workflow.id
1127
        self.formdef.change_workflow(new_workflow_id, status_mapping)
1128
        return redirect('.')
1139 1129

  
1140 1130
    def get_preview(self):
1141 1131
        form = Form(action='#', use_tokens=False)
wcs/formdef.py
50 50
from .qommon.storage import Equal
51 51
from .qommon.storage import StorableObject
52 52
from .qommon.storage import fix_key
53
from .qommon.storage import NotEqual
53 54
from .qommon.substitution import Substitutions
54 55
from .roles import logged_users_role
55 56

  
......
1580 1581
        # chunk contains the fields.
1581 1582
        return pickle.dumps(object, protocol=2) + pickle.dumps(object.fields, protocol=2)
1582 1583

  
1584
    def change_workflow(self, new_workflow_id, status_mapping=None):
1585
        old_workflow = self.get_workflow()
1586

  
1587
        formdata_count = self.data_class().count()
1588
        if formdata_count:
1589
            assert status_mapping, 'status mapping is required if there are formdatas'
1590
            assert all(
1591
                status.id in status_mapping for status in old_workflow.possible_status
1592
            ), 'a status was not mapped'
1593

  
1594
            mapping = {}
1595
            for old_status, new_status in status_mapping.items():
1596
                mapping['wf-%s' % old_status] = 'wf-%s' % new_status
1597
            mapping['draft'] = 'draft'
1598

  
1599
            if any([x[0] != x[1] for x in mapping.items()]):
1600
                # if there are status changes, update all formdatas (except drafts)
1601
                if get_publisher().is_using_postgresql():
1602
                    from . import sql
1603

  
1604
                    sql.formdef_remap_statuses(self, mapping)
1605
                else:
1606

  
1607
                    def map_status(status):
1608
                        if status is None:
1609
                            return None
1610
                        elif status in mapping:
1611
                            return mapping[status]
1612
                        elif '-invalid-' in status:
1613
                            return status
1614
                        else:
1615
                            return '%s-invalid-%s' % (status, old_workflow.id)
1616

  
1617
                    for formdata in self.data_class().select([NotEqual('status', 'draft')]):
1618
                        formdata.status = map_status(formdata.status)
1619
                        if formdata.evolution:
1620
                            for evo in formdata.evolution:
1621
                                evo.status = map_status(evo.status)
1622
                        formdata.store()
1623

  
1624
        self.workflow_id = new_workflow_id
1625
        self.store(comment=_('Workflow change'))
1626
        if formdata_count:
1627
            # instruct formdef to update its security rules
1628
            self.data_class().rebuild_security()
1629

  
1583 1630

  
1584 1631
from .qommon.admin.emails import EmailsDirectory
1585 1632

  
wcs/sql.py
3511 3511

  
3512 3512
    conn.commit()
3513 3513
    cur.close()
3514

  
3515

  
3516
@guard_postgres
3517
def formdef_remap_statuses(formdef, mapping):
3518
    conn, cur = get_connection_and_cursor()
3519
    table_name = get_formdef_table_name(formdef)
3520
    evolutions_table_name = table_name + '_evolutions'
3521
    old_workflow_id = formdef.workflow_id or '_default'
3522
    args = []
3523
    case_expression = '(CASE '
3524
    case_expression += 'WHEN status IS NULL THEN NULL '
3525
    for old_id, new_id in mapping.items():
3526
        case_expression += "WHEN status = %s THEN %s "
3527
        args.extend([old_id, new_id])
3528
    case_expression += " WHEN status LIKE '%%-invalid-%%' THEN status "
3529
    case_expression += " ELSE (status || '-invalid-' || %s) END)"
3530
    args.append(old_workflow_id)
3531

  
3532
    cur.execute('BEGIN')
3533
    cur.execute('UPDATE %s SET status = %s WHERE status <> \'draft\'' % (table_name, case_expression), args)
3534
    cur.execute('UPDATE %s SET status = %s' % (evolutions_table_name, case_expression), args)
3535
    cur.execute('COMMIT')
3514
-