Projet

Général

Profil

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

Benjamin Dauvergne, 12 avril 2021 10:10

Télécharger (8,77 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                 | 48 +++++++++++++++++++++++++++++++++-
 wcs/sql.py                     | 22 ++++++++++++++++
 4 files changed, 92 insertions(+), 27 deletions(-)
tests/admin_pages/test_form.py
571 571
    formdata2.status = 'draft'
572 572
    formdata2.store()
573 573

  
574
    formdata3 = data_class()
575
    formdata3.status = 'wf-1'
576
    formdata3.store()
577

  
574 578
    Workflow.wipe()
575 579
    workflow = Workflow(name='Workflow One')
576 580
    workflow.store()
......
592 596
        assert len(resp.forms[0]['mapping-%s' % status.id].options) == 1
593 597
    assert data_class.get(formdata1.id).status == 'wf-new'
594 598
    assert data_class.get(formdata2.id).status == 'draft'
599
    assert data_class.get(formdata3.id).status == 'wf-1'
595 600
    resp = resp.forms[0].submit()
596 601
    assert data_class.get(formdata1.id).status == 'wf-finished'
597 602
    assert data_class.get(formdata2.id).status == 'draft'
603
    assert data_class.get(formdata3.id).status == 'wf-1-invalid-_default'
598 604

  
599 605
    # change to another workflow, with no mapping change
600 606
    workflow2 = workflow
......
615 621
    resp = resp.forms[0].submit()
616 622
    assert data_class.get(formdata1.id).status == 'wf-finished'
617 623
    assert data_class.get(formdata2.id).status == 'draft'
624
    assert data_class.get(formdata3.id).status == 'wf-1-invalid-_default'
618 625

  
619 626

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

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

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

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

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

  
1139 1129
    def get_preview(self):
1140 1130
        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
......
1567 1567
        # chunk contains the fields.
1568 1568
        return pickle.dumps(object, protocol=2) + pickle.dumps(object.fields, protocol=2)
1569 1569

  
1570
    def change_workflow(self, new_workflow_id, status_mapping=None):
1571
        old_workflow = self.get_workflow()
1572

  
1573
        formdata_count = self.data_class().count()
1574
        if formdata_count:
1575
            assert status_mapping, 'status mapping is required if there are formdatas'
1576
            assert all(
1577
                status.id in status_mapping for status in old_workflow.possible_status
1578
            ), 'a status was not mapped'
1579

  
1580
            mapping = {}
1581
            for old_status, new_status in status_mapping.items():
1582
                mapping['wf-%s' % old_status] = 'wf-%s' % new_status
1583
            mapping['draft'] = 'draft'
1584

  
1585
            if any([x[0] != x[1] for x in mapping.items()]):
1586
                # if there are status changes, update all formdatas (except drafts)
1587
                if get_publisher().is_using_postgresql():
1588
                    from . import sql
1589

  
1590
                    sql.formdef_remap_statuses(self, mapping)
1591
                else:
1592

  
1593
                    def map_status(status):
1594
                        if status is None:
1595
                            return None
1596
                        elif status in mapping:
1597
                            return mapping[status]
1598
                        elif '-invalid-' in status:
1599
                            return status
1600
                        else:
1601
                            return '%s-invalid-%s' % (status, old_workflow.id)
1602

  
1603
                    for formdata in self.data_class().select([NotEqual('status', 'draft')]):
1604
                        formdata.status = map_status(formdata.status)
1605
                        if formdata.evolution:
1606
                            for evo in formdata.evolution:
1607
                                evo.status = map_status(evo.status)
1608
                        formdata.store()
1609

  
1610
        self.workflow_id = new_workflow_id
1611
        self.store(comment=_('Workflow change'))
1612
        if formdata_count:
1613
            # instruct formdef to update its security rules
1614
            self.data_class().rebuild_security()
1615

  
1570 1616

  
1571 1617
EmailsDirectory.register(
1572 1618
    'new_user',
wcs/sql.py
3503 3503

  
3504 3504
    conn.commit()
3505 3505
    cur.close()
3506

  
3507

  
3508
@guard_postgres
3509
def formdef_remap_statuses(formdef, mapping):
3510
    conn, cur = get_connection_and_cursor()
3511
    table_name = get_formdef_table_name(formdef)
3512
    evolutions_table_name = table_name + '_evolutions'
3513
    old_workflow_id = formdef.workflow_id or '_default'
3514
    args = []
3515
    case_expression = '(CASE '
3516
    case_expression += 'WHEN status IS NULL THEN NULL '
3517
    for old_id, new_id in mapping.items():
3518
        case_expression += "WHEN status = %s THEN %s "
3519
        args.extend([old_id, new_id])
3520
    case_expression += " WHEN status LIKE '%%-invalid-%%' THEN status "
3521
    case_expression += " ELSE (status || '-invalid-' || %s) END)"
3522
    args.append(old_workflow_id)
3523

  
3524
    cur.execute('BEGIN')
3525
    cur.execute('UPDATE %s SET status = %s WHERE status <> \'draft\'' % (table_name, case_expression), args)
3526
    cur.execute('UPDATE %s SET status = %s' % (evolutions_table_name, case_expression), args)
3527
    cur.execute('COMMIT')
3506
-