Projet

Général

Profil

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

Benjamin Dauvergne, 29 mars 2021 11:39

Télécharger (8,63 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
1084 1084
                if workflow_id is None:
1085 1085
                    workflow_id = self.formdef_default_workflow
1086 1086
                return redirect('workflow-status-remapping?new=%s' % workflow_id)
1087
            self.formdef.workflow_id = workflow_id
1088
            self.formdef.store(comment=_('Workflow change'))
1087
            self.formdef.change_workflow(workflow_id)
1089 1088
            return redirect('.')
1090 1089

  
1091 1090
    def workflow_status_remapping(self):
......
1124 1123
            r += form.render()
1125 1124
            return r.getvalue()
1126 1125
        else:
1127
            get_logger().info(
1128
                'admin - form "%s", workflow is now "%s" (was "%s")'
1129
                % (self.formdef.name, new_workflow.name, self.formdef.workflow.name)
1130
            )
1131
            self.workflow_status_remapping_submit(form)
1132
            if new_workflow.id == self.formdef_default_workflow:
1133
                self.formdef.workflow_id = None
1134
            else:
1135
                self.formdef.workflow_id = new_workflow.id
1136
            self.formdef.store(comment=_('Workflow change'))
1137
            # instruct formdef to update its security rules
1138
            self.formdef.data_class().rebuild_security()
1139
            return redirect('.')
1126
            return self.workflow_status_remapping_submit(form, new_workflow)
1127

  
1128
    def workflow_status_remapping_submit(self, form, new_workflow):
1129
        get_logger().info(
1130
            'admin - form "%s", workflow is now "%s" (was "%s")'
1131
            % (self.formdef.name, new_workflow.name, self.formdef.workflow.name)
1132
        )
1140 1133

  
1141
    def workflow_status_remapping_submit(self, form):
1142 1134
        status_mapping = {}
1143 1135
        for status in self.formdef.workflow.possible_status:
1144
            status_mapping['wf-%s' % status.id] = 'wf-%s' % form.get_widget('mapping-%s' % status.id).parse()
1145
        if any(x[0] != x[1] for x in status_mapping.items()):
1146
            # if there are status changes, update all formdatas (except drafts)
1147
            status_mapping.update({'draft': 'draft'})
1148
            for item in self.formdef.data_class().select([NotEqual('status', 'draft')]):
1149
                item.status = status_mapping.get(item.status)
1150
                if item.evolution:
1151
                    for evo in item.evolution:
1152
                        evo.status = status_mapping.get(evo.status)
1153
                item.store()
1136
            status_mapping[status.id] = form.get_widget('mapping-%s' % status.id).parse()
1137

  
1138
        if new_workflow.id == self.formdef_default_workflow:
1139
            new_workflow_id = None
1140
        else:
1141
            new_workflow_id = new_workflow.id
1142
        self.formdef.change_workflow(new_workflow_id, status_mapping)
1143
        return redirect('.')
1154 1144

  
1155 1145
    def get_preview(self):
1156 1146
        form = Form(action='#', use_tokens=False)
wcs/formdef.py
54 54
from .qommon.misc import xml_node_text
55 55
from .qommon.publisher import get_publisher_class
56 56
from .qommon.storage import Equal
57
from .qommon.storage import NotEqual
57 58
from .qommon.storage import StorableObject
58 59
from .qommon.storage import fix_key
59 60
from .qommon.substitution import Substitutions
......
1582 1583
        # chunk contains the fields.
1583 1584
        return pickle.dumps(object, protocol=2) + pickle.dumps(object.fields, protocol=2)
1584 1585

  
1586
    def change_workflow(self, new_workflow_id, status_mapping=None):
1587
        old_workflow = self.get_workflow()
1588

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

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

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

  
1606
                    sql.formdef_remap_statuses(self, mapping)
1607
                else:
1608

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

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

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

  
1585 1632

  
1586 1633
EmailsDirectory.register(
1587 1634
    'new_user',
wcs/sql.py
3508 3508

  
3509 3509
    conn.commit()
3510 3510
    cur.close()
3511

  
3512

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

  
3529
    cur.execute('BEGIN')
3530
    cur.execute('UPDATE %s SET status = %s WHERE status <> \'draft\'' % (table_name, case_expression), args)
3531
    cur.execute('UPDATE %s SET status = %s' % (evolutions_table_name, case_expression), args)
3532
    cur.execute('COMMIT')
3511
-