277 lines
11 KiB
Python
277 lines
11 KiB
Python
from django import forms
|
|
from django.conf import settings
|
|
from django.utils.translation import gettext as _
|
|
from django.utils.translation import ngettext
|
|
|
|
from wagtail.admin import widgets
|
|
from wagtail.models import Page, PageViewRestriction
|
|
|
|
from .models import WagtailAdminModelForm
|
|
from .view_restrictions import BaseViewRestrictionForm
|
|
|
|
|
|
class CopyForm(forms.Form):
|
|
def __init__(self, *args, **kwargs):
|
|
# CopyPage must be passed a 'page' kwarg indicating the page to be copied
|
|
self.page = kwargs.pop("page")
|
|
self.user = kwargs.pop("user", None)
|
|
can_publish = kwargs.pop("can_publish")
|
|
super().__init__(*args, **kwargs)
|
|
self.fields["new_title"] = forms.CharField(
|
|
initial=self.page.title, label=_("New title")
|
|
)
|
|
allow_unicode = getattr(settings, "WAGTAIL_ALLOW_UNICODE_SLUGS", True)
|
|
self.fields["new_slug"] = forms.SlugField(
|
|
initial=self.page.slug,
|
|
label=_("New slug"),
|
|
allow_unicode=allow_unicode,
|
|
widget=widgets.SlugInput,
|
|
)
|
|
self.fields["new_parent_page"] = forms.ModelChoiceField(
|
|
initial=self.page.get_parent(),
|
|
queryset=Page.objects.all(),
|
|
widget=widgets.AdminPageChooser(can_choose_root=True, user_perms="copy_to"),
|
|
label=_("New parent page"),
|
|
help_text=_("This copy will be a child of this given parent page."),
|
|
)
|
|
pages_to_copy = self.page.get_descendants(inclusive=True)
|
|
subpage_count = pages_to_copy.count() - 1
|
|
if subpage_count > 0:
|
|
self.fields["copy_subpages"] = forms.BooleanField(
|
|
required=False,
|
|
initial=True,
|
|
label=_("Copy subpages"),
|
|
help_text=ngettext(
|
|
"This will copy %(count)s subpage.",
|
|
"This will copy %(count)s subpages.",
|
|
subpage_count,
|
|
)
|
|
% {"count": subpage_count},
|
|
)
|
|
|
|
if can_publish:
|
|
pages_to_publish_count = pages_to_copy.live().count()
|
|
if pages_to_publish_count > 0:
|
|
# In the specific case that there are no subpages, customise the field label and help text
|
|
if subpage_count == 0:
|
|
label = _("Publish copied page")
|
|
help_text = _(
|
|
"This page is live. Would you like to publish its copy as well?"
|
|
)
|
|
else:
|
|
label = _("Publish copies")
|
|
help_text = ngettext(
|
|
"%(count)s of the pages being copied is live. Would you like to publish its copy?",
|
|
"%(count)s of the pages being copied are live. Would you like to publish their copies?",
|
|
pages_to_publish_count,
|
|
) % {"count": pages_to_publish_count}
|
|
|
|
self.fields["publish_copies"] = forms.BooleanField(
|
|
required=False, initial=False, label=label, help_text=help_text
|
|
)
|
|
|
|
# Note that only users who can publish in the new parent page can create an alias.
|
|
# This is because alias pages must always match their original page's state.
|
|
self.fields["alias"] = forms.BooleanField(
|
|
required=False,
|
|
initial=False,
|
|
label=_("Alias"),
|
|
help_text=_("Keep the new pages updated with future changes"),
|
|
)
|
|
|
|
def clean(self):
|
|
cleaned_data = super().clean()
|
|
|
|
# Make sure the slug isn't already in use
|
|
slug = cleaned_data.get("new_slug")
|
|
|
|
# New parent page given in form or parent of source, if parent_page is empty
|
|
parent_page = cleaned_data.get("new_parent_page") or self.page.get_parent()
|
|
|
|
# check if user is allowed to create a page at given location.
|
|
if not parent_page.permissions_for_user(self.user).can_add_subpage():
|
|
self._errors["new_parent_page"] = self.error_class(
|
|
[
|
|
_('You do not have permission to copy to page "%(page_title)s"')
|
|
% {
|
|
"page_title": parent_page.specific_deferred.get_admin_display_title()
|
|
}
|
|
]
|
|
)
|
|
|
|
# Count the pages with the same slug within the context of our copy's parent page
|
|
if slug and parent_page.get_children().filter(slug=slug).count():
|
|
self._errors["new_slug"] = self.error_class(
|
|
[
|
|
_(
|
|
'This slug is already in use within the context of its parent page "%(parent_page_title)s"'
|
|
)
|
|
% {"parent_page_title": parent_page}
|
|
]
|
|
)
|
|
# The slug is no longer valid, hence remove it from cleaned_data
|
|
del cleaned_data["new_slug"]
|
|
|
|
# Don't allow recursive copies into self
|
|
if cleaned_data.get("copy_subpages") and (
|
|
self.page == parent_page or parent_page.is_descendant_of(self.page)
|
|
):
|
|
self._errors["new_parent_page"] = self.error_class(
|
|
[_("You cannot copy a page into itself when copying subpages")]
|
|
)
|
|
|
|
return cleaned_data
|
|
|
|
|
|
class PageViewRestrictionForm(BaseViewRestrictionForm):
|
|
def __init__(self, *args, **kwargs):
|
|
# get the list of private page options from the page
|
|
private_page_options = kwargs.pop("private_page_options", [])
|
|
|
|
super().__init__(*args, **kwargs)
|
|
|
|
if not getattr(settings, "WAGTAIL_PRIVATE_PAGE_OPTIONS", {}).get(
|
|
"SHARED_PASSWORD", True
|
|
):
|
|
self.fields["restriction_type"].choices = [
|
|
choice
|
|
for choice in PageViewRestriction.RESTRICTION_CHOICES
|
|
if choice[0] != PageViewRestriction.PASSWORD
|
|
]
|
|
del self.fields["password"]
|
|
# Remove the fields that are not allowed for the page
|
|
self.fields["restriction_type"].choices = [
|
|
choice
|
|
for choice in self.fields["restriction_type"].choices
|
|
if choice[0] in private_page_options
|
|
or choice[0] == PageViewRestriction.NONE
|
|
]
|
|
|
|
class Meta:
|
|
model = PageViewRestriction
|
|
fields = ("restriction_type", "password", "groups")
|
|
|
|
|
|
class WagtailAdminPageForm(WagtailAdminModelForm):
|
|
comment_notifications = forms.BooleanField(
|
|
widget=forms.CheckboxInput(), required=False
|
|
)
|
|
|
|
def __init__(
|
|
self,
|
|
data=None,
|
|
files=None,
|
|
parent_page=None,
|
|
subscription=None,
|
|
*args,
|
|
**kwargs,
|
|
):
|
|
self.subscription = subscription
|
|
|
|
initial = kwargs.pop("initial", {})
|
|
if self.subscription:
|
|
initial["comment_notifications"] = subscription.comment_notifications
|
|
|
|
super().__init__(data, files, *args, initial=initial, **kwargs)
|
|
|
|
self.parent_page = parent_page
|
|
|
|
if not self.show_comments_toggle:
|
|
del self.fields["comment_notifications"]
|
|
|
|
@property
|
|
def show_comments_toggle(self):
|
|
return "comments" in self.__class__.formsets
|
|
|
|
def save(self, commit=True):
|
|
# Save comment notifications updates to PageSubscription
|
|
if self.show_comments_toggle and self.subscription:
|
|
self.subscription.comment_notifications = self.cleaned_data[
|
|
"comment_notifications"
|
|
]
|
|
if commit:
|
|
self.subscription.save()
|
|
|
|
return super().save(commit=commit)
|
|
|
|
def is_valid(self):
|
|
comments = self.formsets.get("comments")
|
|
# Remove the comments formset if the management form is invalid
|
|
if comments and not comments.management_form.is_valid():
|
|
del self.formsets["comments"]
|
|
return super().is_valid()
|
|
|
|
def clean(self):
|
|
cleaned_data = super().clean()
|
|
if "slug" in self.cleaned_data:
|
|
page_slug = cleaned_data["slug"]
|
|
if not Page._slug_is_available(page_slug, self.parent_page, self.instance):
|
|
self.add_error(
|
|
"slug",
|
|
forms.ValidationError(
|
|
_(
|
|
"The slug '%(page_slug)s' is already in use within the parent page"
|
|
)
|
|
% {"page_slug": page_slug}
|
|
),
|
|
)
|
|
|
|
return cleaned_data
|
|
|
|
|
|
class MoveForm(forms.Form):
|
|
def __init__(self, *args, **kwargs):
|
|
self.page_to_move = kwargs.pop("page_to_move")
|
|
self.target_parent_models = kwargs.pop("target_parent_models")
|
|
|
|
super().__init__(*args, **kwargs)
|
|
|
|
self.fields["new_parent_page"] = forms.ModelChoiceField(
|
|
initial=self.page_to_move.get_parent(),
|
|
queryset=Page.objects.all(),
|
|
widget=widgets.AdminPageMoveChooser(
|
|
can_choose_root=True,
|
|
user_perms="move_to",
|
|
target_models=self.target_parent_models,
|
|
pages_to_move=[self.page_to_move.pk],
|
|
),
|
|
label=_("New parent page"),
|
|
help_text=_("Select a new parent for this page."),
|
|
)
|
|
|
|
|
|
class ParentChooserForm(forms.Form):
|
|
def __init__(self, child_page_type, user, *args, **kwargs):
|
|
self.child_page_type = child_page_type
|
|
self.user = user
|
|
super().__init__(*args, **kwargs)
|
|
self.fields["parent_page"] = forms.ModelChoiceField(
|
|
queryset=Page.objects.all(),
|
|
widget=widgets.AdminPageChooser(
|
|
target_models=self.child_page_type.allowed_parent_page_models(),
|
|
can_choose_root=True,
|
|
user_perms="add_subpage",
|
|
),
|
|
label=_("Parent page"),
|
|
help_text=_("The new page will be a child of this given parent page."),
|
|
)
|
|
|
|
def clean_parent_page(self):
|
|
parent_page = self.cleaned_data["parent_page"].specific_deferred
|
|
if not parent_page.permissions_for_user(self.user).can_add_subpage():
|
|
raise forms.ValidationError(
|
|
_('You do not have permission to create a page under "%(page_title)s".')
|
|
% {"page_title": parent_page.get_admin_display_title()}
|
|
)
|
|
if not self.child_page_type.can_create_at(parent_page):
|
|
raise forms.ValidationError(
|
|
_(
|
|
'You cannot create a page of type "%(page_type)s" under "%(page_title)s".'
|
|
)
|
|
% {
|
|
"page_type": self.child_page_type.get_verbose_name(),
|
|
"page_title": parent_page.get_admin_display_title(),
|
|
}
|
|
)
|
|
return parent_page
|