From a6f1df35f5f50760107bfed7e2112047bf6ca317 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Thu, 26 Nov 2020 15:35:19 +0100 Subject: [PATCH] misc: remap statuses in a transaction (#38579) --- wcs/admin/forms.py | 39 ++++++++++++++------------------------- wcs/formdef.py | 35 +++++++++++++++++++++++++++++++++++ wcs/sql.py | 17 +++++++++++++++++ 3 files changed, 66 insertions(+), 25 deletions(-) diff --git a/wcs/admin/forms.py b/wcs/admin/forms.py index 8ef84d0f..8b6050ba 100644 --- a/wcs/admin/forms.py +++ b/wcs/admin/forms.py @@ -864,8 +864,7 @@ class FormDefPage(Directory): if workflow_id is None: workflow_id = self.formdef_default_workflow return redirect('workflow-status-remapping?new=%s' % workflow_id) - self.formdef.workflow_id = workflow_id - self.formdef.store(comment=_('Workflow change')) + self.formdef.change_workflow(workflow_id) return redirect('.') def workflow_status_remapping(self): @@ -898,32 +897,22 @@ class FormDefPage(Directory): r += form.render() return r.getvalue() else: - get_logger().info('admin - form "%s", workflow is now "%s" (was "%s")' % ( - self.formdef.name, new_workflow.name, self.formdef.workflow.name)) - self.workflow_status_remapping_submit(form) - if new_workflow.id == self.formdef_default_workflow: - self.formdef.workflow_id = None - else: - self.formdef.workflow_id = new_workflow.id - self.formdef.store(comment=_('Workflow change')) - # instruct formdef to update its security rules - self.formdef.data_class().rebuild_security() - return redirect('.') + return self.workflow_status_remapping_submit(form, new_workflow) + + def workflow_status_remapping_submit(self, form, new_workflow): + get_logger().info('admin - form "%s", workflow is now "%s" (was "%s")' % ( + self.formdef.name, new_workflow.name, self.formdef.workflow.name)) - def workflow_status_remapping_submit(self, form): status_mapping = {} for status in self.formdef.workflow.possible_status: - status_mapping['wf-%s' % status.id] = 'wf-%s' % \ - form.get_widget('mapping-%s' % status.id).parse() - if any([x[0] != x[1] for x in status_mapping.items()]): - # if there are status changes, update all formdatas - status_mapping.update({'draft': 'draft'}) - for item in self.formdef.data_class().select(): - item.status = status_mapping.get(item.status) - if item.evolution: - for evo in item.evolution: - evo.status = status_mapping.get(evo.status) - item.store() + status_mapping[status.id] = form.get_widget('mapping-%s' % status.id).parse() + + if new_workflow.id == self.formdef_default_workflow: + new_workflow_id = None + else: + new_workflow_id = new_workflow.id + self.formdef.change_workflow(new_workflow_id, status_mapping) + return redirect('.') def get_preview(self): form = Form(action='#', use_tokens=False) diff --git a/wcs/formdef.py b/wcs/formdef.py index bfeef5a4..6a99df55 100644 --- a/wcs/formdef.py +++ b/wcs/formdef.py @@ -1517,6 +1517,41 @@ class FormDef(StorableObject): # chunk contains the fields. return pickle.dumps(object, protocol=2) + pickle.dumps(object.fields, protocol=2) + def change_workflow(self, new_workflow_id, status_mapping=None): + old_workflow = self.get_workflow() + + formdata_count = self.data_class().count() + if formdata_count > 0: + assert status_mapping, 'status mapping is required if there are formdatas' + assert all(status.id in status_mapping for status in old_workflow.possible_status), ( + 'a status was not mapped' + ) + + mapping = {} + for old_status, new_status in status_mapping.items(): + mapping['wf-%s' % old_status] = 'wf-%s' % new_status + mapping['draft'] = 'draft' + + if get_publisher().is_using_postgresql(): + from . import sql + sql.formdef_remap_statuses(self, mapping) + else: + if any([x[0] != x[1] for x in mapping.items()]): + # if there are status changes, update all formdatas + mapping.update({'draft': 'draft'}) + for item in self.data_class().select(): + item.status = mapping.get(item.status) + if item.evolution: + for evo in item.evolution: + evo.status = mapping.get(evo.status) + item.store() + + self.workflow_id = new_workflow_id + self.store(comment=_('Workflow change')) + if formdata_count > 0: + # instruct formdef to update its security rules + self.data_class().rebuild_security() + from .qommon.admin.emails import EmailsDirectory diff --git a/wcs/sql.py b/wcs/sql.py index 09d7d188..6e57e44a 100644 --- a/wcs/sql.py +++ b/wcs/sql.py @@ -2874,3 +2874,20 @@ def reindex(): conn.commit() cur.close() + + +@guard_postgres +def formdef_remap_statuses(formdef, mapping): + conn, cur = get_connection_and_cursor() + table_name = get_formdef_table_name(formdef) + evolutions_table_name = table_name + '_evolutions' + old_workflow_id = formdef.workflow_id + case_expression = '(CASE ' + for old_id, new_id in mapping.items(): + case_expression += "WHEN status = '%s' THEN '%s' " % (old_id, new_id) + case_expression += " ELSE ('old-%s-' || status) END)" % old_workflow_id + + cur.execute('BEGIN') + cur.execute('UPDATE %s SET status = %s' % (table_name, case_expression)) + cur.execute('UPDATE %s SET status = %s' % (evolutions_table_name, case_expression)) + cur.execute('COMMIT') -- 2.29.2