diff --git a/tests/admin_pages/test_form.py b/tests/admin_pages/test_form.py index 7760472e2..2415da187 100644 --- a/tests/admin_pages/test_form.py +++ b/tests/admin_pages/test_form.py @@ -765,7 +765,7 @@ def test_form_workflow_link(pub): def test_form_workflow_remapping(pub): AfterJob.wipe() - create_superuser(pub) + user = create_superuser(pub) create_role(pub) FormDef.wipe() @@ -872,6 +872,8 @@ def test_form_workflow_remapping(pub): resp = resp.follow() # -> to job processing page resp = resp.click('Back') assert resp.pyquery('[href="workflow"] .offset').text() == 'Workflow Three' + assert pub.snapshot_class.select_object_history(formdef)[0].comment == 'Workflow change' + assert pub.snapshot_class.select_object_history(formdef)[0].user_id == str(user.id) # run a SQL SELECT and we known all columns are defined. FormDef.get(formdef.id).data_class().select() diff --git a/wcs/admin/forms.py b/wcs/admin/forms.py index 4d0e24c1a..afe8e1f78 100644 --- a/wcs/admin/forms.py +++ b/wcs/admin/forms.py @@ -1140,7 +1140,12 @@ class FormDefPage(Directory, TempfileDirectoryMixin): # there are existing formdata, status will have to be mapped return redirect('workflow-status-remapping?new=%s' % workflow_id) - job = WorkflowChangeJob(formdef=self.formdef, new_workflow_id=workflow_id, status_mapping={}) + job = WorkflowChangeJob( + formdef=self.formdef, + new_workflow_id=workflow_id, + status_mapping={}, + user_id=get_session().user, + ) job.store() get_response().add_after_job(job) return redirect(job.get_processing_url()) @@ -1230,7 +1235,10 @@ class FormDefPage(Directory, TempfileDirectoryMixin): return self.workflow_status_remapping() job = WorkflowChangeJob( - formdef=self.formdef, new_workflow_id=new_workflow.id, status_mapping=status_mapping + formdef=self.formdef, + new_workflow_id=new_workflow.id, + status_mapping=status_mapping, + user_id=get_session().user, ) job.store() get_response().add_after_job(job) @@ -2042,19 +2050,20 @@ class FormsDirectory(AccessControlled, Directory): class WorkflowChangeJob(AfterJob): - def __init__(self, formdef, new_workflow_id, status_mapping): + def __init__(self, formdef, new_workflow_id, status_mapping, user_id): super().__init__( label=_('Updating data for new workflow'), formdef_class=formdef.__class__, formdef_id=formdef.id, new_workflow_id=new_workflow_id, status_mapping=status_mapping, + user_id=user_id, ) def execute(self): formdef = self.kwargs['formdef_class'].get(self.kwargs['formdef_id']) workflow = Workflow.get(self.kwargs['new_workflow_id']) - formdef.change_workflow(workflow, self.kwargs['status_mapping']) + formdef.change_workflow(workflow, self.kwargs['status_mapping'], user_id=self.kwargs.get('user_id')) def done_action_url(self): formdef = self.kwargs['formdef_class'].get(self.kwargs['formdef_id']) diff --git a/wcs/formdef.py b/wcs/formdef.py index 26ed4bdc7..4a2dae797 100644 --- a/wcs/formdef.py +++ b/wcs/formdef.py @@ -1967,7 +1967,7 @@ 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, status_mapping=None): + def change_workflow(self, new_workflow, status_mapping=None, user_id=None): old_workflow = self.get_workflow() formdata_count = self.data_class().count() @@ -2003,7 +2003,7 @@ class FormDef(StorableObject): if function_key not in new_workflow.roles: del self.workflow_roles[function_key] removed_functions.add(function_key) - self.store(comment=_('Workflow change')) + self.store(comment=_('Workflow change'), snapshot_store_user=user_id) if formdata_count: # instruct formdef to update its security rules self.data_class().rebuild_security() diff --git a/wcs/snapshots.py b/wcs/snapshots.py index f6d1ac45a..cf4951623 100644 --- a/wcs/snapshots.py +++ b/wcs/snapshots.py @@ -150,13 +150,21 @@ class Snapshot: ] @classmethod - def snap(cls, instance, comment=None, label=None, store_user=True, application=None): + def snap(cls, instance, comment=None, label=None, store_user=None, application=None): obj = cls() obj.object_type = instance.xml_root_node obj.object_id = instance.id obj.timestamp = now() - if get_session() and store_user: - obj.user_id = get_session().user + # store_user: + # None/True: get user from active session + # False: do not store user + # any value: consider it as user id + # (store_user is explicitely checked to be a boolean, to avoid the "1" integer being treated as True) + if store_user is None or (isinstance(store_user, bool) and store_user is True): + if get_session(): + obj.user_id = get_session().user + elif store_user: + obj.user_id = store_user tree = instance.export_to_xml(include_id=True) # remove position for categories