0
0
mirror of https://github.com/wagtail/wagtail.git synced 2024-12-01 11:41:20 +01:00

Prevent multiple TaskState approvals/rejections. Allow TaskState to be passed through to workflow_action to prevent race conditions: ie reviewer approving while in the meantime edits have been made. Add a new task preview view to allow preview of the revision in moderation in a specific task.

This commit is contained in:
jacobtm 2020-02-03 16:55:43 +00:00 committed by Matt Westcott
parent 4c66ebe36d
commit 3a361c9665
11 changed files with 55 additions and 22 deletions

View File

@ -3,6 +3,5 @@
{% block content %}
<p>{% blocktrans with title=page.get_admin_display_title task=task.name %}The page "{{ title }}" has been approved in moderation stage "{{ task }}".{% endblocktrans %}</p>
<p>{% trans "You can preview the page here:" %} <a href="{{ settings.BASE_URL }}{% url 'wagtailadmin_pages:preview_on_edit' page.id %}">{{ settings.BASE_URL }}{% url 'wagtailadmin_pages:preview_on_edit' page.id %}</a><br/></p>
<p>{% trans "You can edit the page here:"%} <a href="{{ settings.BASE_URL }}{% url 'wagtailadmin_pages:edit' page.id %}">{{ settings.BASE_URL }}{% url 'wagtailadmin_pages:edit' page.id %}</a></p>
{% endblock %}

View File

@ -3,6 +3,5 @@
{% block content %}
{% blocktrans with title=page.get_admin_display_title|safe task=task.name %}The page "{{ title }}" has been approved in moderation stage "{{ task }}".{% endblocktrans %}
{% trans "You can preview the page here:" %} {{ settings.BASE_URL }}{% url 'wagtailadmin_pages:preview_on_edit' page.id %}
{% trans "You can edit the page here:"%} {{ settings.BASE_URL }}{% url 'wagtailadmin_pages:edit' page.id %}
{% endblock %}

View File

@ -3,6 +3,5 @@
{% block content %}
{% blocktrans with title=page.get_admin_display_title|safe task=task.name %}The page "{{ title }}" has been rejected in moderation stage "{{ task }}".{% endblocktrans %}
{% trans "You can edit the page here:"%} {{ settings.BASE_URL }}{% url 'wagtailadmin_pages:edit' page.id %}
{% endblock %}

View File

@ -6,7 +6,7 @@
<p>{% blocktrans with task=task.name title=page.get_admin_display_title %}The page "{{ title }}" has been submitted for approval in moderation stage "{{ task }}".{% endblocktrans %}</p>
<p>
{% trans "You can preview the page here:" %} <a href="{{ settings.BASE_URL }}{% url 'wagtailadmin_pages:preview_on_edit' page.id %}">{{ settings.BASE_URL }}{% url 'wagtailadmin_pages:preview_on_edit' page.id %}</a><br/>
{% trans "You can preview the page here:" %} <a href="{{ settings.BASE_URL }}{% url 'wagtailadmin_pages:workflow_preview' page.id task.id %}">{{ settings.BASE_URL }}{% url 'wagtailadmin_pages:workflow_preview' page.id task.id %}</a><br/>
{% trans "You can edit the page here:" %} <a href="{{ settings.BASE_URL }}{% url 'wagtailadmin_pages:edit' page.id %}">{{ settings.BASE_URL }}{% url 'wagtailadmin_pages:edit' page.id %}</a>
</p>
{% endblock %}

View File

@ -6,7 +6,7 @@
{% blocktrans with task=task.name title=page.get_admin_display_title %}The page "{{ title }}" has been submitted for approval to moderation stage "{{ task }}".{% endblocktrans %}
{% trans "You can preview the page here:" %} {{ settings.BASE_URL }}{% url 'wagtailadmin_pages:preview_on_edit' page.id %}
{% trans "You can preview the page here:" %} {{ settings.BASE_URL }}{% url 'wagtailadmin_pages:workflow_preview' page.id task.id %}
{% trans "You can edit the page here:" %} {{ settings.BASE_URL }}{% url 'wagtailadmin_pages:edit' page.id %}
{% endblock %}

View File

@ -6,7 +6,6 @@
<p>{% blocktrans with workflow=workflow.name title=page.get_admin_display_title %}The page "{{ title }}" has been submitted for moderation to workflow "{{ workflow }}".{% endblocktrans %}</p>
<p>
{% trans "You can preview the page here:" %} <a href="{{ settings.BASE_URL }}{% url 'wagtailadmin_pages:preview_on_edit' page.id %}">{{ settings.BASE_URL }}{% url 'wagtailadmin_pages:preview_on_edit' page.id %}</a><br/>
{% trans "You can edit the page here:" %} <a href="{{ settings.BASE_URL }}{% url 'wagtailadmin_pages:edit' page.id %}">{{ settings.BASE_URL }}{% url 'wagtailadmin_pages:edit' page.id %}</a>
</p>
{% endblock %}

View File

@ -6,7 +6,6 @@
{% blocktrans with workflow=workflow.name title=page.get_admin_display_title %}The page "{{ title }}" has been submitted for moderation to workflow "{{ workflow }}".{% endblocktrans %}
{% trans "You can preview the page here:" %} {{ settings.BASE_URL }}{% url 'wagtailadmin_pages:preview_on_edit' page.id %}
{% trans "You can edit the page here:" %} {{ settings.BASE_URL }}{% url 'wagtailadmin_pages:edit' page.id %}
{% endblock %}

View File

@ -174,12 +174,11 @@
actionFieldElement.value = buttonElement.dataset.workflowAction;
formElement.appendChild(actionFieldElement);
var nextFieldElement = document.createElement('input');
nextFieldElement.type = 'hidden';
nextFieldElement.name = 'next';
{% url 'wagtailadmin_home' as dashboard_url %}
nextFieldElement.value = '{{ dashboard_url|escapejs }}';
formElement.appendChild(nextFieldElement);
var taskFieldElement = document.createElement('input');
taskFieldElement.type = 'hidden';
taskFieldElement.name = 'task_id';
taskFieldElement.value = {{ current_task_state.id }};
formElement.appendChild(taskFieldElement);
document.body.appendChild(formElement);
formElement.submit();

View File

@ -26,6 +26,7 @@ urlpatterns = [
path('<int:page_id>/copy/', pages.copy, name='copy'),
path('workflow/action/<int:page_id>/', pages.workflow_action, name='workflow_action'),
path('workflow/preview/<int:page_id>/<int:task_id>/', pages.preview_revision_for_task, name='workflow_preview'),
path('moderation/<int:revision_id>/approve/', pages.approve_moderation, name='approve_moderation'),
path('moderation/<int:revision_id>/reject/', pages.reject_moderation, name='reject_moderation'),

View File

@ -651,11 +651,7 @@ def edit(request, page_id):
'has_unsaved_changes': has_unsaved_changes,
'page_locked': page_perms.page_locked(),
'workflow_actions': page.current_workflow_task.get_actions(page, request.user) if page.current_workflow_task else [],
'task_statuses': task_statuses,
'current_task_number': current_task_number,
'task_name': task_name,
'workflow_name': workflow_name,
'total_tasks': total_tasks
'current_task_state': page.current_workflow_task_state
})
@ -1196,20 +1192,27 @@ def workflow_action(request, page_id):
redirect_to = request.POST.get('next', None)
if not redirect_to or not is_safe_url(url=redirect_to, allowed_hosts={request.get_host()}):
redirect_to = reverse('wagtailadmin_explore', args=[page.get_parent().id])
redirect_to = reverse('wagtailadmin_pages:edit', args=[page_id])
if not page.workflow_in_progress():
messages.error(request, _("The page '{0}' is not currently awaiting moderation.").format(page.get_admin_display_title()))
return redirect(redirect_to)
actions = page.current_workflow_task.get_actions(page, request.user)
task_state_id = request.POST.get('task_state_id', None)
task_state = TaskState.objects.get(id=task_state_id) if task_state_id else page.current_workflow_task_state
task_state = task_state.specific
task = task_state.task.specific
actions = task.get_actions(page, request.user)
action_name = request.POST.get('action')
if action_name not in set(action[0] for action in actions):
raise PermissionDenied
page.current_workflow_task.on_action(page.current_workflow_task_state, request.user, action_name)
task.on_action(task_state, request.user, action_name)
return redirect(redirect_to)
@ -1236,6 +1239,33 @@ def preview_for_moderation(request, revision_id):
})
@require_GET
def preview_revision_for_task(request, page_id, task_id):
"""Preview the revision linked to the in-progress TaskState of a specified Task. This enables pages in moderation
to be edited and new TaskStates linked to the new revisions created, with preview links remaining valid"""
page = Page.objects.get(id=page_id)
task = Task.objects.get(id=task_id).specific
try:
task_state = TaskState.objects.get(page_revision__page=page, task=task, status=TaskState.STATUS_IN_PROGRESS)
except TaskState.DoesNotExist:
messages.error(request, _("The page '{0}' is not currently awaiting moderation in task '{1}'.").format(page.get_admin_display_title(), task.name))
return redirect('wagtailadmin_home')
revision = task_state.page_revision
if not task.get_actions(page, request.user):
raise PermissionDenied
page_to_view = revision.as_page_object()
# TODO: provide workflow actions within this view
return page_to_view.make_preview_request(request, page.default_preview_mode, extra_request_attrs={
'revision_id': revision.id
})
@require_POST
def lock(request, page_id):
# Get the page

View File

@ -9,7 +9,7 @@ from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
from django.core import checks
from django.core.cache import cache
from django.core.exceptions import ValidationError
from django.core.exceptions import ValidationError, PermissionDenied
from django.core.handlers.base import BaseHandler
from django.core.handlers.wsgi import WSGIRequest
from django.db import models, transaction
@ -2742,12 +2742,16 @@ class WorkflowState(models.Model):
return Task.objects.filter(workflow_tasks__workflow=self.workflow, active=True).exclude(Q(task_states__page_revision=self.page.get_latest_revision()), Q(task_states__status=TaskState.STATUS_APPROVED) | Q(task_states__status=TaskState.STATUS_SKIPPED)).order_by('workflow_tasks__sort_order').first()
def cancel(self, user=None):
if self.status != self.STATUS_IN_PROGRESS:
raise PermissionDenied
self.status = 'cancelled'
self.save()
workflow_cancelled.send(sender=self.__class__, instance=self, user=user)
@transaction.atomic
def finish(self, user=None):
if self.status != self.STATUS_IN_PROGRESS:
raise PermissionDenied
self.status = 'approved'
self.save()
self.on_finish()
@ -2827,6 +2831,8 @@ class TaskState(models.Model):
@transaction.atomic
def approve(self, user=None):
if self.status != self.STATUS_IN_PROGRESS:
raise PermissionDenied
self.status = 'approved'
self.finished_at = timezone.now()
self.save()
@ -2836,6 +2842,8 @@ class TaskState(models.Model):
@transaction.atomic
def reject(self, user=None):
if self.status != self.STATUS_IN_PROGRESS:
raise PermissionDenied
self.status = 'rejected'
self.finished_at = timezone.now()
self.save()