0001-misc-remap-statuses-in-a-transaction-38579.patch
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 |
- |