This should be able to be achieved by creating ONE new Workflow Task
type that has a relationship to two sets of User Group
s (e.g. a/b or before/after, it is probably best to keep this generic in the model definition).
This new Task
can be created as part of a new Workflow
within the Wagtail admin, and each of the groups linked to the Moderator Group 1 / 2.
Wagtail's methods on the Task
allow you to return approval options based on the Page
model for any created workflow, from here you can look for a method that would be on the class and assign the groups from there.
The benefits of having a bit more of a generic approach is that you could leverage this for any splitting of moderator assignments as part of future Workflow tasks.
Implementation Overview
- 1 - read the Wagatail Docs on how to add a new Task Type and the
Task
model reference to understand this process.
- 2 - Read through the full implementation in the code of the built in
GroupApprovalTask
.
- 3 - In the
GroupApprovalTask
you can see that the methods with overrides all rely on the checking of self.groups
but they all get the page
passed in as a arg to those methods.
- 4 - Create a new
Task
that extends the Wagtail Task
class and on this model create two ManyToManyField
that allow for two sets of user groups being linked (note: you do not have do to this as two fields, you could put a model in the middle but the example below is just the simplest way to get to the gaol).
- 5 - On the
DailyReflectionPage
model create a method get_approval_group_key
which will return maybe a simple Boolean or a 'A' or 'B' based on the business requirements you described above (check the model's date etc)
- 6 - In your custom
Task
create a method that abstracts the checking of the Page
for this method and returns the Tasks' user group. You may want to add some error handling and default values. E.g. get_approval_groups
- 7 - Add a custom method for each of the 'start', 'user_can_access_editor',
page_locked_for_user
, user_can_lock
, user_can_unlock
, get_task_states_user_can_moderate
methods that calls get_approval_group
with the page and returns the values (see the code GroupApprovalTask
for what these should do.
Example Code Snippets
models.py
class DailyReflectionPage(Page):
"""
The Daily Reflection Model
"""
def get_approval_group_key(self):
# custom logic here that checks all the date stuff
if date_is_after_foo:
return 'A'
return 'B'
class SplitGroupApprovalTask(Task):
## note: this is the simplest approach, two fields of linked groups, you could further refine this approach as needed.
groups_a = models.ManyToManyField(
Group,
help_text="Pages at this step in a workflow will be moderated or approved by these groups of users",
related_name="split_task_group_a",
)
groups_b = models.ManyToManyField(
Group,
help_text="Pages at this step in a workflow will be moderated or approved by these groups of users",
related_name="split_task_group_b",
)
admin_form_fields = Task.admin_form_fields + ["groups_a", "groups_b"]
admin_form_widgets = {
"groups_a": forms.CheckboxSelectMultiple,
"groups_b": forms.CheckboxSelectMultiple,
}
def get_approval_groups(self, page):
"""This method gets used by all checks when determining what group to allow/assign this Task to"""
# recommend some checks here, what if `get_approval_group` is not on the Page?
approval_group = page.specific.get_approval_group_key()
if (approval_group == 'A'):
return self.group_a
return self.group_b
# each of the following methods will need to be implemented, all checking for the correct groups for the Page when called
# def start(self, ...etc)
# def user_can_access_editor(self, ...etc)
# def page_locked_for_user(self, ...etc)
# def user_can_lock(self, ...etc)
# def user_can_unlock(self, ...etc)
def get_task_states_user_can_moderate(self, user, **kwargs):
# Note: this has not been tested, however as this method does not get `page` we must find all the tasks allowed indirectly via their TaskState pages
tasks = TaskState.objects.filter(status=TaskState.STATUS_IN_PROGRESS, task=self.task_ptr)
filtered_tasks = []
for task in tasks:
page = task.select_related('page_revision', 'task', 'page_revision__page')
groups = self.get_approval_groups(page)
if groups.filter(id__in=user.groups.all()).exists() or user.is_superuser:
filtered_tasks.append(task)
return TaskState.objects.filter(pk__in=[task.pk for task in filtered_tasks])
def get_actions(self, page, user):
# essentially a copy of this method on `GroupApprovalTask` but with the ability to have a dynamic 'group' returned.
approval_groups = self.get_approval_groups(page)
if approval_groups.filter(id__in=user.groups.all()).exists() or user.is_superuser:
return [
('reject', "Request changes", True),
('approve', "Approve", False),
('approve', "Approve with comment", True),
]
return super().get_actions(page, user)