Extract generic Lock/Unlock views and make page's views extend from them (#9740)

pull/9769/head
Sage Abdullah 2022-12-01 17:02:16 +00:00 zatwierdzone przez Matt Westcott
rodzic d3f9d2e9a3
commit ddbdd51607
7 zmienionych plików z 140 dodań i 55 usunięć

Wyświetl plik

@ -77,6 +77,7 @@ Changelog
* Maintenance: Standardise on `classname` for passing HTML class attributes (LB (Ben Johnston))
* Maintenance: Clean up expanding formset and `InlinePanel` JavaScript initialisation code and adopt a class approach (Matt Westcott)
* Maintenance: Extracted revision and draft state logic from generic views into mixins (Sage Abdullah)
* Maintenance: Extracted generic lock / unlock views from page lock / unlock views (Sage Abdullah)
4.1.2 (xx.xx.xxxx) - IN DEVELOPMENT

Wyświetl plik

@ -94,6 +94,7 @@ depth: 1
* Standardise on `classname` for passing HTML class attributes (LB (Ben Johnston))
* Clean up expanding formset and `InlinePanel` JavaScript initialisation code and adopt a class approach (Matt Westcott)
* Extracted revision and draft state logic from generic views into mixins (Sage Abdullah)
* Extracted generic lock / unlock views from page lock / unlock views (Sage Abdullah)
## Upgrade considerations

Wyświetl plik

@ -106,8 +106,8 @@ urlpatterns = [
name="preview_for_moderation",
),
path("<int:page_id>/privacy/", page_privacy.set_privacy, name="set_privacy"),
path("<int:page_id>/lock/", lock.lock, name="lock"),
path("<int:page_id>/unlock/", lock.unlock, name="unlock"),
path("<int:page_id>/lock/", lock.LockView.as_view(), name="lock"),
path("<int:page_id>/unlock/", lock.UnlockView.as_view(), name="unlock"),
path("<int:page_id>/revisions/", revisions.revisions_index, name="revisions_index"),
path(
"<int:page_id>/revisions/<int:revision_id>/view/",

Wyświetl plik

@ -1,4 +1,4 @@
from .base import WagtailAdminTemplateMixin # noqa
from .base import BaseOperationView, WagtailAdminTemplateMixin # noqa
from .mixins import ( # noqa
BeforeAfterHookMixin,
CreateEditViewOptionalFeaturesMixin,

Wyświetl plik

@ -1,5 +1,13 @@
from django.contrib.admin.utils import quote, unquote
from django.core.exceptions import ImproperlyConfigured
from django.shortcuts import get_object_or_404, redirect
from django.urls import reverse
from django.views import View
from django.views.generic.base import ContextMixin, TemplateResponseMixin
from wagtail.admin import messages
from wagtail.admin.utils import get_valid_next_url_from_request
class WagtailAdminTemplateMixin(TemplateResponseMixin, ContextMixin):
"""
@ -28,3 +36,60 @@ class WagtailAdminTemplateMixin(TemplateResponseMixin, ContextMixin):
context["page_subtitle"] = self.get_page_subtitle()
context["header_icon"] = self.get_header_icon()
return context
class BaseOperationView(View):
"""Base view to perform an operation on a model instance using a POST request."""
model = None
pk_url_kwarg = "pk"
success_message = None
success_message_extra_tags = ""
success_url_name = None
def setup(self, request, *args, **kwargs):
super().setup(request, *args, **kwargs)
self.next_url = get_valid_next_url_from_request(request)
self.object = self.get_object()
def get_object(self):
if not self.model:
raise ImproperlyConfigured(
"Subclasses of wagtail.admin.views.generic.base.BaseOperationView must provide a "
"model attribute or a get_object method"
)
pk = self.kwargs[self.pk_url_kwarg]
if isinstance(pk, str):
pk = unquote(pk)
return get_object_or_404(self.model, pk=pk)
def perform_operation(self):
raise NotImplementedError
def get_success_message(self):
return self.success_message
def add_success_message(self):
success_message = self.get_success_message()
if success_message:
messages.success(
self.request,
success_message,
extra_tags=self.success_message_extra_tags,
)
def get_success_url(self):
if not self.success_url_name:
raise ImproperlyConfigured(
"Subclasses of wagtail.admin.views.generic.base.BaseOperationView must provide a "
"success_url_name attribute or a get_success_url method"
)
if self.next_url:
return self.next_url
return reverse(self.success_url_name, args=[quote(self.object.pk)])
def post(self, request, *args, **kwargs):
self.perform_operation()
self.add_success_message()
return redirect(self.get_success_url())

Wyświetl plik

@ -0,0 +1,46 @@
from django.utils import timezone
from django.utils.text import capfirst
from django.utils.translation import gettext as _
from wagtail.admin.views.generic.base import BaseOperationView
from wagtail.log_actions import log
from wagtail.models import DraftStateMixin
class LockView(BaseOperationView):
success_message_extra_tags = "lock"
def perform_operation(self):
if self.object.locked:
return
self.object.locked = True
self.object.locked_by = self.request.user
self.object.locked_at = timezone.now()
self.object.save(update_fields=["locked", "locked_by", "locked_at"])
log(instance=self.object, action="wagtail.lock", user=self.request.user)
class UnlockView(BaseOperationView):
success_message_extra_tags = "unlock"
def perform_operation(self):
if not self.object.locked:
return
self.object.locked = False
self.object.locked_by = None
self.object.locked_at = None
self.object.save(update_fields=["locked", "locked_by", "locked_at"])
log(instance=self.object, action="wagtail.unlock", user=self.request.user)
def get_success_message(self):
title = str(self.object)
if isinstance(self.object, DraftStateMixin) and self.object.latest_revision:
title = self.object.latest_revision.object_str
return capfirst(
_("%(model_name)s '%(title)s' is now unlocked.")
% {
"model_name": self.model._meta.verbose_name,
"title": title,
}
)

Wyświetl plik

@ -1,67 +1,39 @@
from django.core.exceptions import PermissionDenied
from django.shortcuts import get_object_or_404, redirect
from django.utils import timezone
from django.utils.http import url_has_allowed_host_and_scheme
from django.urls import reverse
from django.utils.translation import gettext as _
from django.views.decorators.http import require_POST
from wagtail.admin import messages
from wagtail.admin.views.generic import lock
from wagtail.models import Page
@require_POST
def lock(request, page_id):
# Get the page
page = get_object_or_404(Page, id=page_id).specific
class PageOperationViewMixin:
model = Page
pk_url_kwarg = "page_id"
# Check permissions
if not page.permissions_for_user(request.user).can_lock():
raise PermissionDenied
# Lock the page
if not page.locked:
page.locked = True
page.locked_by = request.user
page.locked_at = timezone.now()
page.save(user=request.user, log_action="wagtail.lock")
def get_object(self):
return super().get_object().specific
# Redirect
redirect_to = request.POST.get("next", None)
if redirect_to and url_has_allowed_host_and_scheme(
url=redirect_to, allowed_hosts={request.get_host()}
):
return redirect(redirect_to)
else:
return redirect("wagtailadmin_explore", page.get_parent().id)
def get_success_url(self):
if self.next_url:
return self.next_url
return reverse("wagtailadmin_explore", args=[self.object.get_parent().id])
@require_POST
def unlock(request, page_id):
# Get the page
page = get_object_or_404(Page, id=page_id).specific
class LockView(PageOperationViewMixin, lock.LockView):
def perform_operation(self):
if not self.object.permissions_for_user(self.request.user).can_lock():
raise PermissionDenied
return super().perform_operation()
# Check permissions
if not page.permissions_for_user(request.user).can_unlock():
raise PermissionDenied
# Unlock the page
if page.locked:
page.locked = False
page.locked_by = None
page.locked_at = None
page.save(user=request.user, log_action="wagtail.unlock")
class UnlockView(PageOperationViewMixin, lock.UnlockView):
def perform_operation(self):
if not self.object.permissions_for_user(self.request.user).can_unlock():
raise PermissionDenied
return super().perform_operation()
messages.success(
request,
def get_success_message(self):
return (
_("Page '%(page_title)s' is now unlocked.")
% {"page_title": page.get_admin_display_title()},
extra_tags="unlock",
% {"page_title": self.object.get_admin_display_title()},
)
# Redirect
redirect_to = request.POST.get("next", None)
if redirect_to and url_has_allowed_host_and_scheme(
url=redirect_to, allowed_hosts={request.get_host()}
):
return redirect(redirect_to)
else:
return redirect("wagtailadmin_explore", page.get_parent().id)