Projet

Général

Profil

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

Benjamin Dauvergne, 24 septembre 2021 10:00

Télécharger (8,77 ko)

Voir les différences:

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

 tests/admin_pages/test_form.py |  7 +++++
 wcs/admin/forms.py             | 42 ++++++++++++-----------------
 wcs/formdef.py                 | 48 +++++++++++++++++++++++++++++++++-
 wcs/sql.py                     | 22 ++++++++++++++++
 4 files changed, 92 insertions(+), 27 deletions(-)
tests/admin_pages/test_form.py
566 566
    formdata2.status = 'draft'
567 567
    formdata2.store()
568 568

  
569
    formdata3 = data_class()
570
    formdata3.status = 'wf-1'
571
    formdata3.store()
572

  
569 573
    Workflow.wipe()
570 574
    workflow = Workflow(name='Workflow One')
571 575
    workflow.store()
......
587 591
        assert len(resp.forms[0]['mapping-%s' % status.id].options) == 1
588 592
    assert data_class.get(formdata1.id).status == 'wf-new'
589 593
    assert data_class.get(formdata2.id).status == 'draft'
594
    assert data_class.get(formdata3.id).status == 'wf-1'
590 595
    resp = resp.forms[0].submit()
591 596
    assert data_class.get(formdata1.id).status == 'wf-finished'
592 597
    assert data_class.get(formdata2.id).status == 'draft'
598
    assert data_class.get(formdata3.id).status == 'wf-1-invalid-_default'
593 599

  
594 600
    # change to another workflow, with no mapping change
595 601
    workflow2 = workflow
......
610 616
    resp = resp.forms[0].submit()
611 617
    assert data_class.get(formdata1.id).status == 'wf-finished'
612 618
    assert data_class.get(formdata2.id).status == 'draft'
619
    assert data_class.get(formdata3.id).status == 'wf-1-invalid-_default'
613 620

  
614 621

  
615 622
def test_form_submitter_roles(pub):
wcs/admin/forms.py
1099 1099
                if workflow_id is None:
1100 1100
                    workflow_id = self.formdef_default_workflow
1101 1101
                return redirect('workflow-status-remapping?new=%s' % workflow_id)
1102
            self.formdef.workflow_id = workflow_id
1103
            self.formdef.store(comment=_('Workflow change'))
1102
            self.formdef.change_workflow(workflow_id)
1104 1103
            return redirect('.')
1105 1104

  
1106 1105
    def workflow_status_remapping(self):
......
1139 1138
            r += form.render()
1140 1139
            return r.getvalue()
1141 1140
        else:
1142
            get_logger().info(
1143
                'admin - form "%s", workflow is now "%s" (was "%s")'
1144
                % (self.formdef.name, new_workflow.name, self.formdef.workflow.name)
1145
            )
1146
            self.workflow_status_remapping_submit(form)
1147
            if new_workflow.id == self.formdef_default_workflow:
1148
                self.formdef.workflow_id = None
1149
            else:
1150
                self.formdef.workflow_id = new_workflow.id
1151
            self.formdef.store(comment=_('Workflow change'))
1152
            # instruct formdef to update its security rules
1153
            self.formdef.data_class().rebuild_security()
1154
            return redirect('.')
1141
            return self.workflow_status_remapping_submit(form, new_workflow)
1142

  
1143
    def workflow_status_remapping_submit(self, form, new_workflow):
1144
        get_logger().info(
1145
            'admin - form "%s", workflow is now "%s" (was "%s")'
1146
            % (self.formdef.name, new_workflow.name, self.formdef.workflow.name)
1147
        )
1155 1148

  
1156
    def workflow_status_remapping_submit(self, form):
1157 1149
        status_mapping = {}
1158 1150
        for status in self.formdef.workflow.possible_status:
1159
            status_mapping['wf-%s' % status.id] = 'wf-%s' % form.get_widget('mapping-%s' % status.id).parse()
1160
        if any(x[0] != x[1] for x in status_mapping.items()):
1161
            # if there are status changes, update all formdatas (except drafts)
1162
            status_mapping.update({'draft': 'draft'})
1163
            for item in self.formdef.data_class().select([NotEqual('status', 'draft')]):
1164
                item.status = status_mapping.get(item.status)
1165
                if item.evolution:
1166
                    for evo in item.evolution:
1167
                        evo.status = status_mapping.get(evo.status)
1168
                item.store()
1151
            status_mapping[status.id] = form.get_widget('mapping-%s' % status.id).parse()
1152

  
1153
        if new_workflow.id == self.formdef_default_workflow:
1154
            new_workflow_id = None
1155
        else:
1156
            new_workflow_id = new_workflow.id
1157
        self.formdef.change_workflow(new_workflow_id, status_mapping)
1158
        return redirect('.')
1169 1159

  
1170 1160
    def get_preview(self):
1171 1161
        form = Form(action='#', use_tokens=False)
wcs/formdef.py
41 41
from .qommon.form import Form, HtmlWidget, UploadedFile
42 42
from .qommon.misc import JSONEncoder, get_as_datetime, simplify, xml_node_text
43 43
from .qommon.publisher import get_publisher_class
44
from .qommon.storage import Equal, StorableObject, fix_key
44
from .qommon.storage import Equal, NotEqual, StorableObject, fix_key
45 45
from .qommon.substitution import Substitutions
46 46
from .qommon.template import Template
47 47
from .roles import logged_users_role
......
1664 1664
        # chunk contains the fields.
1665 1665
        return pickle.dumps(object, protocol=2) + pickle.dumps(object.fields, protocol=2)
1666 1666

  
1667
    def change_workflow(self, new_workflow_id, status_mapping=None):
1668
        old_workflow = self.get_workflow()
1669

  
1670
        formdata_count = self.data_class().count()
1671
        if formdata_count:
1672
            assert status_mapping, 'status mapping is required if there are formdatas'
1673
            assert all(
1674
                status.id in status_mapping for status in old_workflow.possible_status
1675
            ), 'a status was not mapped'
1676

  
1677
            mapping = {}
1678
            for old_status, new_status in status_mapping.items():
1679
                mapping['wf-%s' % old_status] = 'wf-%s' % new_status
1680
            mapping['draft'] = 'draft'
1681

  
1682
            if any([x[0] != x[1] for x in mapping.items()]):
1683
                # if there are status changes, update all formdatas (except drafts)
1684
                if get_publisher().is_using_postgresql():
1685
                    from . import sql
1686

  
1687
                    sql.formdef_remap_statuses(self, mapping)
1688
                else:
1689

  
1690
                    def map_status(status):
1691
                        if status is None:
1692
                            return None
1693
                        elif status in mapping:
1694
                            return mapping[status]
1695
                        elif '-invalid-' in status:
1696
                            return status
1697
                        else:
1698
                            return '%s-invalid-%s' % (status, old_workflow.id)
1699

  
1700
                    for formdata in self.data_class().select([NotEqual('status', 'draft')]):
1701
                        formdata.status = map_status(formdata.status)
1702
                        if formdata.evolution:
1703
                            for evo in formdata.evolution:
1704
                                evo.status = map_status(evo.status)
1705
                        formdata.store()
1706

  
1707
        self.workflow_id = new_workflow_id
1708
        self.store(comment=_('Workflow change'))
1709
        if formdata_count:
1710
            # instruct formdef to update its security rules
1711
            self.data_class().rebuild_security()
1712

  
1667 1713

  
1668 1714
EmailsDirectory.register(
1669 1715
    'new_user',
wcs/sql.py
3651 3651

  
3652 3652
    conn.commit()
3653 3653
    cur.close()
3654

  
3655

  
3656
@guard_postgres
3657
def formdef_remap_statuses(formdef, mapping):
3658
    conn, cur = get_connection_and_cursor()
3659
    table_name = get_formdef_table_name(formdef)
3660
    evolutions_table_name = table_name + '_evolutions'
3661
    old_workflow_id = formdef.workflow_id or '_default'
3662
    args = []
3663
    case_expression = '(CASE '
3664
    case_expression += 'WHEN status IS NULL THEN NULL '
3665
    for old_id, new_id in mapping.items():
3666
        case_expression += "WHEN status = %s THEN %s "
3667
        args.extend([old_id, new_id])
3668
    case_expression += " WHEN status LIKE '%%-invalid-%%' THEN status "
3669
    case_expression += " ELSE (status || '-invalid-' || %s) END)"
3670
    args.append(old_workflow_id)
3671

  
3672
    cur.execute('BEGIN')
3673
    cur.execute('UPDATE %s SET status = %s WHERE status <> \'draft\'' % (table_name, case_expression), args)
3674
    cur.execute('UPDATE %s SET status = %s' % (evolutions_table_name, case_expression), args)
3675
    cur.execute('COMMIT')
3654
-