From 64ce5c5a0c8bcefa0a2056e854f8177880d549ea Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= <fpeters@entrouvert.com>
Date: Sat, 5 Dec 2020 14:55:23 +0100
Subject: [PATCH 4/5] backoffice: convert mass action execution to afterjob
 class (#48407)

---
 wcs/backoffice/management.py | 115 ++++++++++++++++++++---------------
 1 file changed, 67 insertions(+), 48 deletions(-)

diff --git a/wcs/backoffice/management.py b/wcs/backoffice/management.py
index 84579a6af..f9847544a 100644
--- a/wcs/backoffice/management.py
+++ b/wcs/backoffice/management.py
@@ -1827,14 +1827,15 @@ class FormPage(Directory):
     def listing_top_actions(self):
         return ''
 
-    def get_multi_actions(self, user, status_filter):
-        global_actions = self.formdef.workflow.get_global_manual_actions()
+    @classmethod
+    def get_multi_actions(self, formdef, user, status_filter):
+        global_actions = formdef.workflow.get_global_manual_actions()
 
         if status_filter not in ('open', 'waiting', 'done', 'all'):
             # when the listing is filtered on a specific status, include
             # manual jumps with identifiers
             try:
-                status = self.formdef.workflow.get_status(status_filter)
+                status = formdef.workflow.get_status(status_filter)
             except KeyError:
                 status = None
             else:
@@ -1887,8 +1888,8 @@ class FormPage(Directory):
         if get_request().get_query():
             qs = '?' + get_request().get_query()
 
-        multi_actions = self.get_multi_actions(get_request().user,
-                status_filter=selected_filter)
+        multi_actions = self.get_multi_actions(
+                self.formdef, get_request().user, status_filter=selected_filter)
         multi_form = Form(id='multi-actions')
         for action in multi_actions:
             attrs = {}
@@ -1947,55 +1948,21 @@ class FormPage(Directory):
         return r.getvalue()
 
     def submit_multi(self, action, selected_filter, query, criterias):
-        class ActionJob(object):
-            def __init__(self, formdef, query_string, action, item_ids):
-                self.formdef = formdef
-                self.query_string = query_string
-                self.action = action
-                self.item_ids = item_ids
-                self.user = get_request().user
-
-            def execute(self, job=None):
-                # sort formdatas so we know for sure the processing order
-                formdatas = self.formdef.data_class().get_ids(
-                        item_ids,
-                        order_by='receipt_time')
-                job.completion_status = '{}/{}'.format(0, len(formdatas))
-                job.store()
-                publisher = get_publisher()
-                if formdatas:
-                    oldest_lazy_form = formdatas[0].get_as_lazy()
-                for i, formdata in enumerate(formdatas):
-                    publisher.substitutions.reset()
-                    publisher.substitutions.feed(publisher)
-                    publisher.substitutions.feed(self.user)
-                    publisher.substitutions.feed(self.formdef)
-                    publisher.substitutions.feed(formdata)
-                    publisher.substitutions.feed({
-                        'oldest_form': oldest_lazy_form,
-                        'mass_action_index': i,
-                        'mass_action_length': len(formdatas),
-                    })
-                    if getattr(self.action['action'], 'status_action', False):
-                        # manual jump action
-                        from wcs.wf.jump import jump_and_perform
-                        jump_and_perform(formdata, self.action['action'].action)
-                    else:
-                        # global action
-                        formdata.perform_global_action(self.action['action'].id, self.user)
-                    job.completion_status = '{}/{}'.format(i+1, len(formdatas))
-                    job.store()
-
         item_ids = get_request().form['select[]']
         if '_all' in item_ids:
             item_ids = FormDefUI(self.formdef).get_listing_item_ids(
                         selected_filter, user=get_request().user, query=query,
                         criterias=criterias)
-        action_job = ActionJob(self.formdef, get_request().get_query(), action, item_ids)
+
         job = get_response().add_after_job(
-                _('Executing task "%s" on forms') % action['action'].name,
-                action_job.execute)
-        job.query_string = get_request().get_query()
+                MassActionAfterJob(
+                    label=_('Executing task "%s" on forms') % action['action'].name,
+                    formdef=self.formdef,
+                    user_id=get_request().user.id,
+                    status_filter=selected_filter,
+                    query_string=get_request().get_query(),
+                    action_id=action['action'].id,
+                    item_ids=item_ids))
         job.store()
         return redirect('./?job=%s' % job.id)
 
@@ -3469,3 +3436,55 @@ def format_time(t, units = 2):
             return _('%(minutes)d minute(s) and %(seconds)d seconds') % {
                     'minutes': minutes, 'seconds': seconds}
     return _('%d seconds') % seconds
+
+
+class MassActionAfterJob(AfterJob):
+    def __init__(self, formdef, **kwargs):
+        super().__init__(
+            formdef_class=formdef.__class__,
+            formdef_id=formdef.id,
+            **kwargs)
+        self.query_string = kwargs.get('query_string')
+
+    def execute(self):
+        formdef = self.kwargs['formdef_class'].get(self.kwargs['formdef_id'])
+        item_ids = self.kwargs['item_ids']
+        action_id = self.kwargs['action_id']
+        status_filter = self.kwargs['status_filter']
+        user = get_publisher().user_class.get(self.kwargs['user_id'])
+
+        multi_actions = FormPage.get_multi_actions(formdef, user, status_filter)
+        for action in multi_actions:
+            if action['action'].id == action_id:
+                break
+        else:
+            # action not found
+            return
+
+        formdatas = formdef.data_class().get_ids(item_ids, order_by='receipt_time')
+        self.completion_status = '{}/{}'.format(0, len(formdatas))
+        self.store()
+
+        publisher = get_publisher()
+        if formdatas:
+            oldest_lazy_form = formdatas[0].get_as_lazy()
+        for i, formdata in enumerate(formdatas):
+            publisher.substitutions.reset()
+            publisher.substitutions.feed(publisher)
+            publisher.substitutions.feed(user)
+            publisher.substitutions.feed(formdef)
+            publisher.substitutions.feed(formdata)
+            publisher.substitutions.feed({
+                'oldest_form': oldest_lazy_form,
+                'mass_action_index': i,
+                'mass_action_length': len(formdatas),
+            })
+            if getattr(action['action'], 'status_action', False):
+                # manual jump action
+                from wcs.wf.jump import jump_and_perform
+                jump_and_perform(formdata, action['action'].action)
+            else:
+                # global action
+                formdata.perform_global_action(action['action'].id, user)
+            self.completion_status = '{}/{}'.format(i + 1, len(formdatas))
+            self.store()
-- 
2.29.2

