misc: keep track of user that changed a workflow in snapshot (#87843)
gitea/wcs/pipeline/head This commit looks good Details

This commit is contained in:
Frédéric Péters 2024-03-06 17:54:36 +01:00
parent 36e1f16a31
commit 23e66ec078
4 changed files with 29 additions and 10 deletions

View File

@ -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()

View File

@ -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'])

View File

@ -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()

View File

@ -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