Пример #1
0
    def form_invalid(self, form):
        # even if the page is locked due to not having permissions, the original submitter can still cancel the workflow
        if self.is_cancelling_workflow:
            self.workflow_state.cancel(user=self.request.user)
            self.add_cancel_workflow_confirmation_message()

        if self.page_perms.page_locked():
            messages.error(self.request,
                           _("The page could not be saved as it is locked"))
        else:
            messages.validation_error(
                self.request,
                _("The page could not be saved due to validation errors"),
                self.form)
        self.errors_debug = (repr(self.form.errors) + repr([
            (name, formset.errors)
            for (name, formset) in self.form.formsets.items() if formset.errors
        ]))
        self.has_unsaved_changes = True

        self.edit_handler = self.edit_handler.bind_to(form=self.form)
        self.add_legacy_moderation_warning()
        self.page_for_status = self.get_page_for_status()

        return self.render_to_response(self.get_context_data())
Пример #2
0
def edit(request, app_label, model_name, pk):
    model = get_snippet_model_from_url_params(app_label, model_name)

    permission = get_permission_name('change', model)
    if not request.user.has_perm(permission):
        return permission_denied(request)

    instance = get_object_or_404(model, pk=unquote(pk))

    for fn in hooks.get_hooks('before_edit_snippet'):
        result = fn(request, instance)
        if hasattr(result, 'status_code'):
            return result

    edit_handler = get_snippet_edit_handler(model)
    edit_handler = edit_handler.bind_to(instance=instance, request=request)
    form_class = edit_handler.get_form_class()

    if request.method == 'POST':
        form = form_class(request.POST, request.FILES, instance=instance)

        if form.is_valid():
            form.save()

            messages.success(
                request,
                _("%(snippet_type)s '%(instance)s' updated.") % {
                    'snippet_type': capfirst(model._meta.verbose_name),
                    'instance': instance
                },
                buttons=[
                    messages.button(
                        reverse('wagtailsnippets:edit',
                                args=(app_label, model_name,
                                      quote(instance.pk))), _('Edit'))
                ])

            for fn in hooks.get_hooks('after_edit_snippet'):
                result = fn(request, instance)
                if hasattr(result, 'status_code'):
                    return result

            return redirect('wagtailsnippets:list', app_label, model_name)
        else:
            messages.validation_error(
                request, _("The snippet could not be saved due to errors."),
                form)
    else:
        form = form_class(instance=instance)

    edit_handler = edit_handler.bind_to(form=form)

    return TemplateResponse(
        request, 'wagtailsnippets/snippets/edit.html', {
            'model_opts': model._meta,
            'instance': instance,
            'edit_handler': edit_handler,
            'form': form,
        })
Пример #3
0
    def form_invalid(self, form):
        messages.validation_error(
            self.request, _("The page could not be created due to validation errors"), self.form
        )
        self.has_unsaved_changes = True
        self.edit_handler = self.edit_handler.bind_to(form=self.form)

        return self.render_to_response(self.get_context_data())
Пример #4
0
def edit(request, app_name, model_name, site_pk):
    model = get_model_from_url_params(app_name, model_name)
    if not user_can_edit_setting_type(request.user, model):
        raise PermissionDenied
    site = get_object_or_404(Site, pk=site_pk)

    setting_type_name = model._meta.verbose_name

    instance = model.for_site(site)
    edit_handler = get_setting_edit_handler(model)
    edit_handler = edit_handler.bind_to(instance=instance, request=request)
    form_class = edit_handler.get_form_class()

    if request.method == "POST":
        form = form_class(request.POST, request.FILES, instance=instance)

        if form.is_valid():
            with transaction.atomic():
                form.save()
                log(instance, "wagtail.edit")

            messages.success(
                request,
                _("%(setting_type)s updated.") % {
                    "setting_type": capfirst(setting_type_name),
                    "instance": instance
                },
            )
            return redirect("wagtailsettings:edit", app_name, model_name,
                            site.pk)
        else:
            messages.validation_error(
                request, _("The setting could not be saved due to errors."),
                form)
    else:
        form = form_class(instance=instance)

    edit_handler = edit_handler.bind_to(form=form)

    # Show a site switcher form if there are multiple sites
    site_switcher = None
    if Site.objects.count() > 1:
        site_switcher = SiteSwitchForm(site, model)

    return TemplateResponse(
        request,
        "wagtailsettings/edit.html",
        {
            "opts": model._meta,
            "setting_type_name": setting_type_name,
            "instance": instance,
            "edit_handler": edit_handler,
            "form": form,
            "site": site,
            "site_switcher": site_switcher,
            "tabbed": isinstance(edit_handler, TabbedInterface),
        },
    )
Пример #5
0
def edit(request, app_label, model_name, pk):
    model = get_snippet_model_from_url_params(app_label, model_name)

    permission = get_permission_name('change', model)
    if not request.user.has_perm(permission):
        return permission_denied(request)

    instance = get_object_or_404(model, pk=unquote(pk))
    edit_handler = get_snippet_edit_handler(model)
    edit_handler = edit_handler.bind_to(instance=instance, request=request)
    form_class = edit_handler.get_form_class()

    if request.method == 'POST':
        form = form_class(request.POST, request.FILES, instance=instance)

        if form.is_valid():
            form.save()

            messages.success(request,
                             _("{snippet_type} '{instance}' updated.").format(
                                 snippet_type=capfirst(
                                     model._meta.verbose_name_plural),
                                 instance=instance),
                             buttons=[
                                 messages.button(
                                     reverse('wagtailsnippets:edit',
                                             args=(app_label, model_name,
                                                   quote(instance.pk))),
                                     _('Edit'))
                             ])
            return redirect('wagtailsnippets:list', app_label, model_name)
        else:
            messages.validation_error(
                request, _("The snippet could not be saved due to errors."),
                form)
    else:
        form = form_class(instance=instance)

    edit_handler = edit_handler.bind_to(form=form)

    return render(
        request,
        'wagtailsnippets/snippets/edit.html',
        {
            # original version of snippets.py does not include 'can delete snippets'
            'can_delete_snippets':
            request.user.has_perm(get_permission_name('delete', model)),
            'model_opts':
            model._meta,
            'instance':
            instance,
            'edit_handler':
            edit_handler,
            'form':
            form,
        })
Пример #6
0
def edit(request, app_name, model_name, site_pk):
    model = get_model_from_url_params(app_name, model_name)
    if not user_can_edit_setting_type(request.user, model):
        raise PermissionDenied
    site = get_object_or_404(Site, pk=site_pk)

    setting_type_name = model._meta.verbose_name

    instance = model.for_site(site)
    edit_handler = get_setting_edit_handler(model)
    form_class = edit_handler.get_form_class()

    if request.method == 'POST':
        form = form_class(request.POST, request.FILES, instance=instance)

        if form.is_valid():
            form.save()

            messages.success(
                request,
                _("{setting_type} updated.").format(
                    setting_type=capfirst(setting_type_name),
                    instance=instance))
            return redirect('wagtailsettings:edit', app_name, model_name,
                            site.pk)
        else:
            messages.validation_error(
                request, _("The setting could not be saved due to errors."),
                form)
            edit_handler = edit_handler.bind_to_instance(instance=instance,
                                                         form=form,
                                                         request=request)
    else:
        form = form_class(instance=instance)
        edit_handler = edit_handler.bind_to_instance(instance=instance,
                                                     form=form,
                                                     request=request)

    # Show a site switcher form if there are multiple sites
    site_switcher = None
    if Site.objects.count() > 1:
        site_switcher = SiteSwitchForm(site, model)

    return render(
        request, 'wagtailsettings/edit.html', {
            'opts': model._meta,
            'setting_type_name': setting_type_name,
            'instance': instance,
            'edit_handler': edit_handler,
            'form': form,
            'site': site,
            'site_switcher': site_switcher,
            'tabbed': isinstance(edit_handler, TabbedInterface),
        })
Пример #7
0
def edit(request, app_name, model_name, site_pk):
    model = get_model_from_url_params(app_name, model_name)
    if not user_can_edit_setting_type(request.user, model):
        raise PermissionDenied
    site = get_object_or_404(Site, pk=site_pk)

    setting_type_name = model._meta.verbose_name

    instance = model.for_site(site)
    edit_handler = get_setting_edit_handler(model)
    form_class = edit_handler.get_form_class()

    if request.method == 'POST':
        form = form_class(request.POST, request.FILES, instance=instance)

        if form.is_valid():
            form.save()

            messages.success(
                request,
                _("{setting_type} updated.").format(
                    setting_type=capfirst(setting_type_name),
                    instance=instance
                )
            )
            return redirect('wagtailsettings:edit', app_name, model_name, site.pk)
        else:
            messages.validation_error(
                request, _("The setting could not be saved due to errors."), form
            )
            edit_handler = edit_handler.bind_to_instance(
                instance=instance, form=form, request=request)
    else:
        form = form_class(instance=instance)
        edit_handler = edit_handler.bind_to_instance(
            instance=instance, form=form, request=request)

    # Show a site switcher form if there are multiple sites
    site_switcher = None
    if Site.objects.count() > 1:
        site_switcher = SiteSwitchForm(site, model)

    return render(request, 'wagtailsettings/edit.html', {
        'opts': model._meta,
        'setting_type_name': setting_type_name,
        'instance': instance,
        'edit_handler': edit_handler,
        'form': form,
        'site': site,
        'site_switcher': site_switcher,
        'tabbed': isinstance(edit_handler, TabbedInterface),
    })
Пример #8
0
def edit(request, app_label, model_name, pk):
    model = get_snippet_model_from_url_params(app_label, model_name)

    permission = get_permission_name('change', model)
    if not request.user.has_perm(permission):
        return permission_denied(request)

    instance = get_object_or_404(model, pk=unquote(pk))
    edit_handler = get_snippet_edit_handler(model)
    form_class = edit_handler.get_form_class()

    if request.method == 'POST':
        form = form_class(request.POST, request.FILES, instance=instance)

        if form.is_valid():
            form.save()

            messages.success(
                request,
                _("{snippet_type} '{instance}' updated.").format(
                    snippet_type=capfirst(model._meta.verbose_name_plural),
                    instance=instance
                ),
                buttons=[
                    messages.button(reverse(
                        'wagtailsnippets:edit', args=(app_label, model_name, quote(instance.pk))
                    ), _('Edit'))
                ]
            )
            return redirect('wagtailsnippets:list', app_label, model_name)
        else:
            messages.validation_error(
                request, _("The snippet could not be saved due to errors."), form
            )
            edit_handler = edit_handler.bind_to_instance(instance=instance,
                                                         form=form,
                                                         request=request)
    else:
        form = form_class(instance=instance)
        edit_handler = edit_handler.bind_to_instance(instance=instance,
                                                     form=form,
                                                     request=request)

    return render(request, 'wagtailsnippets/snippets/edit.html', {
        'model_opts': model._meta,
        'instance': instance,
        'edit_handler': edit_handler,
        'form': form,
    })
def create(request, app_label, model_name):
    model = get_snippet_model_from_url_params(app_label, model_name)

    permission = get_permission_name('add', model)
    if not request.user.has_perm(permission):
        return permission_denied(request)

    instance = model()
    edit_handler = get_snippet_edit_handler(model)
    form_class = edit_handler.get_form_class()

    if request.method == 'POST':
        form = form_class(request.POST, request.FILES, instance=instance)

        if form.is_valid():
            form.save()

            messages.success(request,
                             _("{snippet_type} '{instance}' created.").format(
                                 snippet_type=capfirst(
                                     model._meta.verbose_name),
                                 instance=instance),
                             buttons=[
                                 messages.button(
                                     reverse('wagtailsnippets:edit',
                                             args=(app_label, model_name,
                                                   quote(instance.pk))),
                                     _('Edit'))
                             ])
            return redirect('wagtailsnippets:list', app_label, model_name)
        else:
            messages.validation_error(
                request, _("The snippet could not be created due to errors."),
                form)
            edit_handler = edit_handler.bind_to_instance(instance=instance,
                                                         form=form,
                                                         request=request)
    else:
        form = form_class(instance=instance)
        edit_handler = edit_handler.bind_to_instance(instance=instance,
                                                     form=form,
                                                     request=request)

    return render(request, 'wagtailsnippets/snippets/create.html', {
        'model_opts': model._meta,
        'edit_handler': edit_handler,
        'form': form,
    })
Пример #10
0
def create(request, content_type_app_name, content_type_model_name,
           parent_page_id):
    parent_page = get_object_or_404(Page, id=parent_page_id).specific
    parent_page_perms = parent_page.permissions_for_user(request.user)
    if not parent_page_perms.can_add_subpage():
        raise PermissionDenied

    try:
        content_type = ContentType.objects.get_by_natural_key(
            content_type_app_name, content_type_model_name)
    except ContentType.DoesNotExist:
        raise Http404

    # Get class
    page_class = content_type.model_class()

    # Make sure the class is a descendant of Page
    if not issubclass(page_class, Page):
        raise Http404

    # page must be in the list of allowed subpage types for this parent ID
    if page_class not in parent_page.creatable_subpage_models():
        raise PermissionDenied

    if not page_class.can_create_at(parent_page):
        raise PermissionDenied

    for fn in hooks.get_hooks('before_create_page'):
        result = fn(request, parent_page, page_class)
        if hasattr(result, 'status_code'):
            return result

    page = page_class(owner=request.user)
    edit_handler = page_class.get_edit_handler()
    form_class = edit_handler.get_form_class()

    next_url = get_valid_next_url_from_request(request)

    if request.method == 'POST':
        form = form_class(request.POST,
                          request.FILES,
                          instance=page,
                          parent_page=parent_page)

        if form.is_valid():
            page = form.save(commit=False)

            # Save page
            parent_page.add_child(instance=page)

            # Save revision
            page.save_revision(
                user=request.user,
                submitted_for_moderation=False,
            )

            messages.success(
                request,
                _('Page \'{0}\' created.').format(
                    page.get_admin_display_title()))

            for fn in hooks.get_hooks('after_create_page'):
                result = fn(request, page)
                if hasattr(result, 'status_code'):
                    return result

            # Just saving - remain on edit page for further edits
            target_url = reverse('experiments_oneyouvariant_edit',
                                 args=[page.id])
            if next_url:
                # Ensure the 'next' url is passed through again if present
                target_url += '?next=%s' % urlquote(next_url)
            return redirect(target_url)

        else:
            messages.validation_error(
                request,
                _('The page could not be created due to validation errors'),
                form)
            edit_handler = edit_handler.bind_to_instance(instance=page,
                                                         form=form,
                                                         request=request)
            has_unsaved_changes = True
    else:
        parent_page_json = parent_page.to_json()
        page = page_class.from_json(parent_page_json)
        slug = hashlib.sha224(
            base64.b64encode(str(time.time()).encode('utf-8'))).hexdigest()
        page.slug = '%s-v%s' % (page.slug, slug[:6])
        page.title = '%s (describe the variant)' % page.title

        signals.init_new_page.send(sender=create,
                                   page=page,
                                   parent=parent_page)
        form = form_class(instance=page, parent_page=parent_page)
        edit_handler = edit_handler.bind_to_instance(instance=page,
                                                     form=form,
                                                     request=request)
        has_unsaved_changes = False

    return render(
        request, 'wagtailadmin/custom_add_footer.html', {
            'content_type': content_type,
            'page_class': page_class,
            'parent_page': parent_page,
            'edit_handler': edit_handler,
            'preview_modes': page.preview_modes,
            'form': form,
            'next': next_url,
            'has_unsaved_changes': has_unsaved_changes,
        })
Пример #11
0
 def form_invalid(self, form):
     messages.validation_error(self.request, self.get_error_message(), form)
     return self.render_to_response(self.get_context_data(form=form))
Пример #12
0
 def form_invalid(self, form):
     messages.validation_error(
         self.request, self.get_error_message(), form
     )
     return self.render_to_response(self.get_context_data())
Пример #13
0
 def form_invalid(self, form):
     # TODO: This override is only required for Wagtail<2.1
     messages.validation_error(
         self.request, self.get_error_message(), form
     )
     return self.render_to_response(self.get_context_data())
Пример #14
0
 def form_invalid(self, form):
     # TODO: This override is only required for Wagtail<2.1
     messages.validation_error(self.request, self.get_error_message(), form)
     return self.render_to_response(self.get_context_data())
Пример #15
0
def create(request, app_label, model_name):
    model = get_snippet_model_from_url_params(app_label, model_name)

    permission = get_permission_name('add', model)
    if not request.user.has_perm(permission):
        raise PermissionDenied

    for fn in hooks.get_hooks('before_create_snippet'):
        result = fn(request, model)
        if hasattr(result, 'status_code'):
            return result

    instance = model()

    # Set locale of the new instance
    if issubclass(model, TranslatableMixin):
        selected_locale = request.GET.get('locale')
        if selected_locale:
            instance.locale = get_object_or_404(Locale,
                                                language_code=selected_locale)
        else:
            instance.locale = Locale.get_default()

    # Make edit handler
    edit_handler = get_snippet_edit_handler(model)
    edit_handler = edit_handler.bind_to(request=request)
    form_class = edit_handler.get_form_class()

    if request.method == 'POST':
        form = form_class(request.POST, request.FILES, instance=instance)

        if form.is_valid():
            form.save()

            messages.success(
                request,
                _("%(snippet_type)s '%(instance)s' created.") % {
                    'snippet_type': capfirst(model._meta.verbose_name),
                    'instance': instance
                },
                buttons=[
                    messages.button(
                        reverse('wagtailsnippets:edit',
                                args=(app_label, model_name,
                                      quote(instance.pk))), _('Edit'))
                ])

            for fn in hooks.get_hooks('after_create_snippet'):
                result = fn(request, instance)
                if hasattr(result, 'status_code'):
                    return result

            urlquery = ''
            if isinstance(instance, TranslatableMixin
                          ) and instance.locale is not Locale.get_default():
                urlquery = '?locale=' + instance.locale.language_code

            return redirect(
                reverse('wagtailsnippets:list', args=[app_label, model_name]) +
                urlquery)
        else:
            messages.validation_error(
                request, _("The snippet could not be created due to errors."),
                form)
    else:
        form = form_class(instance=instance)

    edit_handler = edit_handler.bind_to(instance=instance, form=form)

    context = {
        'model_opts': model._meta,
        'edit_handler': edit_handler,
        'form': form,
        'action_menu': SnippetActionMenu(request, view='create', model=model),
        'locale': None,
        'translations': [],
    }

    if getattr(settings, 'WAGTAIL_I18N_ENABLED', False) and issubclass(
            model, TranslatableMixin):
        context.update({
            'locale':
            instance.locale,
            'translations': [{
                'locale':
                locale,
                'url':
                reverse('wagtailsnippets:add', args=[app_label, model_name]) +
                '?locale=' + locale.language_code
            } for locale in Locale.objects.all().exclude(id=instance.locale.id)
                             ],
        })

    return TemplateResponse(request, 'wagtailsnippets/snippets/create.html',
                            context)
Пример #16
0
def edit(request, app_name, model_name, pk):
    model = get_model_from_url_params(app_name, model_name)

    if not user_can_edit_setting_type(request.user, model):
        raise PermissionDenied

    setting_type_name = model._meta.verbose_name
    edit_handler = get_setting_edit_handler(model)
    form_class = edit_handler.get_form_class()
    site: Optional[Site] = None
    site_switcher = None
    form_id: int = None

    if issubclass(model, BaseSiteSetting):
        site = get_object_or_404(Site, pk=pk)
        form_id = site.pk
        instance = model.for_site(site)

        if request.method == "POST":
            form = form_class(
                request.POST, request.FILES, instance=instance, for_user=request.user
            )

            if form.is_valid():
                with transaction.atomic():
                    form.save()
                    log(instance, "wagtail.edit")

                messages.success(
                    request,
                    _("%(setting_type)s updated.")
                    % {
                        "setting_type": capfirst(setting_type_name),
                        "instance": instance,
                    },
                )
                return redirect("wagtailsettings:edit", app_name, model_name, site.pk)
            else:
                messages.validation_error(
                    request, _("The setting could not be saved due to errors."), form
                )
        else:
            form = form_class(instance=instance, for_user=request.user)

        edit_handler = edit_handler.get_bound_panel(
            instance=instance, request=request, form=form
        )

        media = form.media + edit_handler.media

        # Show a site switcher form if there are multiple sites
        if Site.objects.count() > 1:
            site_switcher = SiteSwitchForm(site, model)
            media += site_switcher.media

    elif issubclass(model, BaseGenericSetting):
        queryset = model.base_queryset()

        # Create the instance if we haven't already.
        if queryset.count() == 0:
            model.objects.create()

        instance = get_object_or_404(model, pk=pk)
        form_id = instance.pk

        if request.method == "POST":
            form = form_class(
                request.POST, request.FILES, instance=instance, for_user=request.user
            )

            if form.is_valid():
                with transaction.atomic():
                    form.save()
                    log(instance, "wagtail.edit")

                messages.success(
                    request,
                    _("%(setting_type)s updated.")
                    % {
                        "setting_type": capfirst(setting_type_name),
                        "instance": instance,
                    },
                )
                return redirect("wagtailsettings:edit", app_name, model_name)
            else:
                messages.validation_error(
                    request, _("The setting could not be saved due to errors."), form
                )
        else:
            form = form_class(instance=instance, for_user=request.user)

        edit_handler = edit_handler.get_bound_panel(
            instance=instance, request=request, form=form
        )

        media = form.media + edit_handler.media

    else:
        raise NotImplementedError

    return TemplateResponse(
        request,
        "wagtailsettings/edit.html",
        {
            "opts": model._meta,
            "setting_type_name": setting_type_name,
            "instance": instance,
            "edit_handler": edit_handler,
            "form": form,
            "site": site,
            "site_switcher": site_switcher,
            "tabbed": isinstance(edit_handler.panel, TabbedInterface),
            "media": media,
            "form_id": form_id,
        },
    )
Пример #17
0
def create(request, content_type_app_name, content_type_model_name, parent_page_id):
    parent_page = get_object_or_404(Page, id=parent_page_id).specific
    parent_page_perms = parent_page.permissions_for_user(request.user)
    if not parent_page_perms.can_add_subpage():
        raise PermissionDenied

    try:
        content_type = ContentType.objects.get_by_natural_key(content_type_app_name, content_type_model_name)
    except ContentType.DoesNotExist:
        raise Http404

    # Get class
    page_class = content_type.model_class()

    # Make sure the class is a descendant of Page
    if not issubclass(page_class, Page):
        raise Http404

    # page must be in the list of allowed subpage types for this parent ID
    if page_class not in parent_page.creatable_subpage_models():
        raise PermissionDenied

    if not page_class.can_create_at(parent_page):
        raise PermissionDenied

    for fn in hooks.get_hooks('before_create_page'):
        result = fn(request, parent_page, page_class)
        if hasattr(result, 'status_code'):
            return result

    page = page_class(owner=request.user)
    edit_handler = page_class.get_edit_handler()
    form_class = edit_handler.get_form_class()

    next_url = get_valid_next_url_from_request(request)

    if request.method == 'POST':
        form = form_class(request.POST, request.FILES, instance=page,
                          parent_page=parent_page)

        if form.is_valid():
            page = form.save(commit=False)

            is_publishing = bool(request.POST.get('action-publish')) and parent_page_perms.can_publish_subpage()
            is_submitting = bool(request.POST.get('action-submit'))

            if not is_publishing:
                page.live = False

            # Save page
            parent_page.add_child(instance=page)

            # Save revision
            revision = page.save_revision(
                user=request.user,
                submitted_for_moderation=is_submitting,
            )

            # Publish
            if is_publishing:
                revision.publish()

            # Notifications
            if is_publishing:
                if page.go_live_at and page.go_live_at > timezone.now():
                    messages.success(request, _("Page '{0}' created and scheduled for publishing.").format(page.get_admin_display_title()), buttons=[
                        messages.button(reverse('wagtailadmin_pages:edit', args=(page.id,)), _('Edit'))
                    ])
                else:
                    buttons = []
                    if page.url is not None:
                        buttons.append(messages.button(page.url, _('View live'), new_window=True))
                    buttons.append(messages.button(reverse('wagtailadmin_pages:edit', args=(page.id,)), _('Edit')))
                    messages.success(request, _("Page '{0}' created and published.").format(page.get_admin_display_title()), buttons=buttons)
            elif is_submitting:
                messages.success(
                    request,
                    _("Page '{0}' created and submitted for moderation.").format(page.get_admin_display_title()),
                    buttons=[
                        messages.button(
                            reverse('wagtailadmin_pages:view_draft', args=(page.id,)),
                            _('View draft'),
                            new_window=True
                        ),
                        messages.button(
                            reverse('wagtailadmin_pages:edit', args=(page.id,)),
                            _('Edit')
                        )
                    ]
                )
                if not send_notification(page.get_latest_revision().id, 'submitted', request.user.pk):
                    messages.error(request, _("Failed to send notifications to moderators"))
            else:
                messages.success(request, _("Page '{0}' created.").format(page.get_admin_display_title()))

            for fn in hooks.get_hooks('after_create_page'):
                result = fn(request, page)
                if hasattr(result, 'status_code'):
                    return result

            if is_publishing or is_submitting:
                # we're done here
                if next_url:
                    # redirect back to 'next' url if present
                    return redirect(next_url)
                # redirect back to the explorer
                return redirect('wagtailadmin_explore', page.get_parent().id)
            else:
                # Just saving - remain on edit page for further edits
                target_url = reverse('wagtailadmin_pages:edit', args=[page.id])
                if next_url:
                    # Ensure the 'next' url is passed through again if present
                    target_url += '?next=%s' % urlquote(next_url)
                return redirect(target_url)
        else:
            messages.validation_error(
                request, _("The page could not be created due to validation errors"), form
            )
            edit_handler = edit_handler.bind_to_instance(instance=page,
                                                         form=form,
                                                         request=request)
            has_unsaved_changes = True
    else:
        signals.init_new_page.send(sender=create, page=page, parent=parent_page)
        form = form_class(instance=page, parent_page=parent_page)
        edit_handler = edit_handler.bind_to_instance(instance=page, form=form, request=request)
        has_unsaved_changes = False

    return render(request, 'wagtailadmin/pages/create.html', {
        'content_type': content_type,
        'page_class': page_class,
        'parent_page': parent_page,
        'edit_handler': edit_handler,
        'preview_modes': page.preview_modes,
        'form': form,
        'next': next_url,
        'has_unsaved_changes': has_unsaved_changes,
    })
Пример #18
0
def edit(request, page_id):
    real_page_record = get_object_or_404(Page, id=page_id)
    latest_revision = real_page_record.get_latest_revision()
    page = real_page_record.get_latest_revision_as_page()
    parent = page.get_parent()

    content_type = ContentType.objects.get_for_model(page)
    page_class = content_type.model_class()

    page_perms = page.permissions_for_user(request.user)
    if not page_perms.can_edit():
        raise PermissionDenied

    for fn in hooks.get_hooks('before_edit_page'):
        result = fn(request, page)
        if hasattr(result, 'status_code'):
            return result

    edit_handler = page_class.get_edit_handler()
    form_class = edit_handler.get_form_class()

    next_url = get_valid_next_url_from_request(request)

    errors_debug = None

    if request.method == 'POST':
        form = form_class(request.POST, request.FILES, instance=page,
                          parent_page=parent)

        if form.is_valid() and not page.locked:
            page = form.save(commit=False)

            is_publishing = bool(request.POST.get('action-publish')) and page_perms.can_publish()
            is_submitting = bool(request.POST.get('action-submit'))
            is_reverting = bool(request.POST.get('revision'))

            # If a revision ID was passed in the form, get that revision so its
            # date can be referenced in notification messages
            if is_reverting:
                previous_revision = get_object_or_404(page.revisions, id=request.POST.get('revision'))

            # Save revision
            revision = page.save_revision(
                user=request.user,
                submitted_for_moderation=is_submitting,
            )
            # store submitted go_live_at for messaging below
            go_live_at = page.go_live_at

            # Publish
            if is_publishing:
                revision.publish()
                # Need to reload the page because the URL may have changed, and we
                # need the up-to-date URL for the "View Live" button.
                page = page.specific_class.objects.get(pk=page.pk)

            # Notifications
            if is_publishing:
                if go_live_at and go_live_at > timezone.now():
                    # Page has been scheduled for publishing in the future

                    if is_reverting:
                        message = _(
                            "Revision from {0} of page '{1}' has been scheduled for publishing."
                        ).format(
                            previous_revision.created_at.strftime("%d %b %Y %H:%M"),
                            page.get_admin_display_title()
                        )
                    else:
                        if page.live:
                            message = _(
                                "Page '{0}' is live and this revision has been scheduled for publishing."
                            ).format(
                                page.get_admin_display_title()
                            )
                        else:
                            message = _(
                                "Page '{0}' has been scheduled for publishing."
                            ).format(
                                page.get_admin_display_title()
                            )

                    messages.success(request, message, buttons=[
                        messages.button(
                            reverse('wagtailadmin_pages:edit', args=(page.id,)),
                            _('Edit')
                        )
                    ])

                else:
                    # Page is being published now

                    if is_reverting:
                        message = _(
                            "Revision from {0} of page '{1}' has been published."
                        ).format(
                            previous_revision.created_at.strftime("%d %b %Y %H:%M"),
                            page.get_admin_display_title()
                        )
                    else:
                        message = _(
                            "Page '{0}' has been published."
                        ).format(
                            page.get_admin_display_title()
                        )

                    buttons = []
                    if page.url is not None:
                        buttons.append(messages.button(page.url, _('View live'), new_window=True))
                    buttons.append(messages.button(reverse('wagtailadmin_pages:edit', args=(page_id,)), _('Edit')))
                    messages.success(request, message, buttons=buttons)

            elif is_submitting:

                message = _(
                    "Page '{0}' has been submitted for moderation."
                ).format(
                    page.get_admin_display_title()
                )

                messages.success(request, message, buttons=[
                    messages.button(
                        reverse('wagtailadmin_pages:view_draft', args=(page_id,)),
                        _('View draft'),
                        new_window=True
                    ),
                    messages.button(
                        reverse('wagtailadmin_pages:edit', args=(page_id,)),
                        _('Edit')
                    )
                ])

                if not send_notification(page.get_latest_revision().id, 'submitted', request.user.pk):
                    messages.error(request, _("Failed to send notifications to moderators"))

            else:  # Saving

                if is_reverting:
                    message = _(
                        "Page '{0}' has been replaced with revision from {1}."
                    ).format(
                        page.get_admin_display_title(),
                        previous_revision.created_at.strftime("%d %b %Y %H:%M")
                    )
                else:
                    message = _(
                        "Page '{0}' has been updated."
                    ).format(
                        page.get_admin_display_title()
                    )

                messages.success(request, message)

            for fn in hooks.get_hooks('after_edit_page'):
                result = fn(request, page)
                if hasattr(result, 'status_code'):
                    return result

            if is_publishing or is_submitting:
                # we're done here - redirect back to the explorer
                if next_url:
                    # redirect back to 'next' url if present
                    return redirect(next_url)
                # redirect back to the explorer
                return redirect('wagtailadmin_explore', page.get_parent().id)
            else:
                # Just saving - remain on edit page for further edits
                target_url = reverse('wagtailadmin_pages:edit', args=[page.id])
                if next_url:
                    # Ensure the 'next' url is passed through again if present
                    target_url += '?next=%s' % urlquote(next_url)
                return redirect(target_url)
        else:
            if page.locked:
                messages.error(request, _("The page could not be saved as it is locked"))
            else:
                messages.validation_error(
                    request, _("The page could not be saved due to validation errors"), form
                )

            edit_handler = edit_handler.bind_to_instance(instance=page,
                                                         form=form,
                                                         request=request)
            errors_debug = (
                repr(edit_handler.form.errors) +
                repr([
                    (name, formset.errors)
                    for (name, formset) in edit_handler.form.formsets.items()
                    if formset.errors
                ])
            )
            has_unsaved_changes = True
    else:
        form = form_class(instance=page, parent_page=parent)
        edit_handler = edit_handler.bind_to_instance(instance=page, form=form, request=request)
        has_unsaved_changes = False

    # Check for revisions still undergoing moderation and warn
    if latest_revision and latest_revision.submitted_for_moderation:
        buttons = []

        if page.live:
            buttons.append(messages.button(
                reverse('wagtailadmin_pages:revisions_compare', args=(page.id, 'live', latest_revision.id)),
                _('Compare with live version')
            ))

        messages.warning(request, _("This page is currently awaiting moderation"), buttons=buttons)

    if page.live and page.has_unpublished_changes:
        # Page status needs to present the version of the page containing the correct live URL
        page_for_status = real_page_record.specific
    else:
        page_for_status = page

    return render(request, 'wagtailadmin/pages/edit.html', {
        'page': page,
        'page_for_status': page_for_status,
        'content_type': content_type,
        'edit_handler': edit_handler,
        'errors_debug': errors_debug,
        'preview_modes': page.preview_modes,
        'form': form,
        'next': next_url,
        'has_unsaved_changes': has_unsaved_changes,
    })
Пример #19
0
 def form_invalid(self, form):
     self.form = form
     error_message = self.get_error_message()
     if error_message is not None:
         messages.validation_error(self.request, error_message, form)
     return super().form_invalid(form)
Пример #20
0
def create(request, app_label, model_name):
    model = get_snippet_model_from_url_params(app_label, model_name)

    permission = get_permission_name("add", model)
    if not request.user.has_perm(permission):
        raise PermissionDenied

    for fn in hooks.get_hooks("before_create_snippet"):
        result = fn(request, model)
        if hasattr(result, "status_code"):
            return result

    instance = model()

    # Set locale of the new instance
    if issubclass(model, TranslatableMixin):
        selected_locale = request.GET.get("locale")
        if selected_locale:
            instance.locale = get_object_or_404(Locale,
                                                language_code=selected_locale)
        else:
            instance.locale = Locale.get_default()

    # Make edit handler
    edit_handler = get_snippet_edit_handler(model)
    edit_handler = edit_handler.bind_to(request=request)
    form_class = edit_handler.get_form_class()

    if request.method == "POST":
        form = form_class(request.POST, request.FILES, instance=instance)

        if form.is_valid():
            with transaction.atomic():
                form.save()
                log(instance=instance, action="wagtail.create")

            messages.success(
                request,
                _("%(snippet_type)s '%(instance)s' created.") % {
                    "snippet_type": capfirst(model._meta.verbose_name),
                    "instance": instance,
                },
                buttons=[
                    messages.button(
                        reverse(
                            "wagtailsnippets:edit",
                            args=(app_label, model_name, quote(instance.pk)),
                        ),
                        _("Edit"),
                    )
                ],
            )

            for fn in hooks.get_hooks("after_create_snippet"):
                result = fn(request, instance)
                if hasattr(result, "status_code"):
                    return result

            urlquery = ""
            if (isinstance(instance, TranslatableMixin)
                    and instance.locale is not Locale.get_default()):
                urlquery = "?locale=" + instance.locale.language_code

            return redirect(
                reverse("wagtailsnippets:list", args=[app_label, model_name]) +
                urlquery)
        else:
            messages.validation_error(
                request, _("The snippet could not be created due to errors."),
                form)
    else:
        form = form_class(instance=instance)

    edit_handler = edit_handler.bind_to(instance=instance, form=form)

    context = {
        "model_opts": model._meta,
        "edit_handler": edit_handler,
        "form": form,
        "action_menu": SnippetActionMenu(request, view="create", model=model),
        "locale": None,
        "translations": [],
    }

    if getattr(settings, "WAGTAIL_I18N_ENABLED", False) and issubclass(
            model, TranslatableMixin):
        context.update({
            "locale":
            instance.locale,
            "translations": [{
                "locale":
                locale,
                "url":
                reverse("wagtailsnippets:add", args=[app_label, model_name]) +
                "?locale=" + locale.language_code,
            } for locale in Locale.objects.all().exclude(id=instance.locale.id)
                             ],
        })

    return TemplateResponse(request, "wagtailsnippets/snippets/create.html",
                            context)
Пример #21
0
def edit(request, app_label, model_name, pk):
    model = get_snippet_model_from_url_params(app_label, model_name)

    permission = get_permission_name("change", model)
    if not request.user.has_perm(permission):
        raise PermissionDenied

    instance = get_object_or_404(model, pk=unquote(pk))

    for fn in hooks.get_hooks("before_edit_snippet"):
        result = fn(request, instance)
        if hasattr(result, "status_code"):
            return result

    edit_handler = get_snippet_edit_handler(model)
    edit_handler = edit_handler.bind_to(instance=instance, request=request)
    form_class = edit_handler.get_form_class()

    if request.method == "POST":
        form = form_class(request.POST, request.FILES, instance=instance)

        if form.is_valid():
            with transaction.atomic():
                form.save()
                log(instance=instance, action="wagtail.edit")

            messages.success(
                request,
                _("%(snippet_type)s '%(instance)s' updated.") % {
                    "snippet_type": capfirst(model._meta.verbose_name),
                    "instance": instance,
                },
                buttons=[
                    messages.button(
                        reverse(
                            "wagtailsnippets:edit",
                            args=(app_label, model_name, quote(instance.pk)),
                        ),
                        _("Edit"),
                    )
                ],
            )

            for fn in hooks.get_hooks("after_edit_snippet"):
                result = fn(request, instance)
                if hasattr(result, "status_code"):
                    return result

            return redirect("wagtailsnippets:list", app_label, model_name)
        else:
            messages.validation_error(
                request, _("The snippet could not be saved due to errors."),
                form)
    else:
        form = form_class(instance=instance)

    edit_handler = edit_handler.bind_to(form=form)
    latest_log_entry = log_registry.get_logs_for_instance(instance).first()

    context = {
        "model_opts": model._meta,
        "instance": instance,
        "edit_handler": edit_handler,
        "form": form,
        "action_menu": SnippetActionMenu(request,
                                         view="edit",
                                         instance=instance),
        "locale": None,
        "translations": [],
        "latest_log_entry": latest_log_entry,
    }

    if getattr(settings, "WAGTAIL_I18N_ENABLED", False) and issubclass(
            model, TranslatableMixin):
        context.update({
            "locale":
            instance.locale,
            "translations": [{
                "locale":
                translation.locale,
                "url":
                reverse(
                    "wagtailsnippets:edit",
                    args=[app_label, model_name,
                          quote(translation.pk)],
                ),
            } for translation in instance.get_translations().select_related(
                "locale")],
        })

    return TemplateResponse(request, "wagtailsnippets/snippets/edit.html",
                            context)
Пример #22
0
def edit(request, app_label, model_name, pk):
    model = get_snippet_model_from_url_params(app_label, model_name)

    permission = get_permission_name('change', model)
    if not request.user.has_perm(permission):
        raise PermissionDenied

    instance = get_object_or_404(model, pk=unquote(pk))

    for fn in hooks.get_hooks('before_edit_snippet'):
        result = fn(request, instance)
        if hasattr(result, 'status_code'):
            return result

    edit_handler = get_snippet_edit_handler(model)
    edit_handler = edit_handler.bind_to(instance=instance, request=request)
    form_class = edit_handler.get_form_class()

    if request.method == 'POST':
        form = form_class(request.POST, request.FILES, instance=instance)

        if form.is_valid():
            form.save()

            messages.success(
                request,
                _("%(snippet_type)s '%(instance)s' updated.") % {
                    'snippet_type': capfirst(model._meta.verbose_name),
                    'instance': instance
                },
                buttons=[
                    messages.button(
                        reverse('wagtailsnippets:edit',
                                args=(app_label, model_name,
                                      quote(instance.pk))), _('Edit'))
                ])

            for fn in hooks.get_hooks('after_edit_snippet'):
                result = fn(request, instance)
                if hasattr(result, 'status_code'):
                    return result

            return redirect('wagtailsnippets:list', app_label, model_name)
        else:
            messages.validation_error(
                request, _("The snippet could not be saved due to errors."),
                form)
    else:
        form = form_class(instance=instance)

    edit_handler = edit_handler.bind_to(form=form)

    context = {
        'model_opts': model._meta,
        'instance': instance,
        'edit_handler': edit_handler,
        'form': form,
        'action_menu': SnippetActionMenu(request,
                                         view='edit',
                                         instance=instance),
        'locale': None,
        'translations': [],
    }

    if getattr(settings, 'WAGTAIL_I18N_ENABLED', False) and issubclass(
            model, TranslatableMixin):
        context.update({
            'locale':
            instance.locale,
            'translations': [{
                'locale':
                translation.locale,
                'url':
                reverse('wagtailsnippets:edit',
                        args=[app_label, model_name,
                              quote(translation.pk)])
            } for translation in instance.get_translations().select_related(
                'locale')],
        })

    return TemplateResponse(request, 'wagtailsnippets/snippets/edit.html',
                            context)
Пример #23
0
def edit(request, page_id):
    real_page_record = get_object_or_404(Page, id=page_id)
    latest_revision = real_page_record.get_latest_revision()
    content_type = real_page_record.cached_content_type
    page_class = real_page_record.specific_class

    if page_class is None:
        raise PageClassNotFoundError(
            f"The page '{real_page_record}' cannot be edited because the "
            f"model class used to create it ({content_type.app_label}."
            f"{content_type.model}) can no longer be found in the codebase. "
            "This usually happens as a result of switching between git "
            "branches without running migrations to trigger the removal of "
            "unused ContentTypes. To edit the page, you will need to switch "
            "back to a branch where the model class is still present."
        )

    page = real_page_record.get_latest_revision_as_page()
    parent = page.get_parent()

    page_perms = page.permissions_for_user(request.user)

    if not page_perms.can_edit():
        raise PermissionDenied

    next_url = get_valid_next_url_from_request(request)

    for fn in hooks.get_hooks('before_edit_page'):
        result = fn(request, page)
        if hasattr(result, 'status_code'):
            return result

    edit_handler = page_class.get_edit_handler()
    edit_handler = edit_handler.bind_to(instance=page, request=request)
    form_class = edit_handler.get_form_class()

    if request.method == 'GET':
        if page_perms.user_has_lock():
            if page.locked_at:
                lock_message = format_html(_("<b>Page '{}' was locked</b> by <b>you</b> on <b>{}</b>."), page.get_admin_display_title(), page.locked_at.strftime("%d %b %Y %H:%M"))
            else:
                lock_message = format_html(_("<b>Page '{}' is locked</b> by <b>you</b>."), page.get_admin_display_title())

            lock_message += format_html(
                '<span class="buttons"><button class="button button-small button-secondary" data-locking-action="{}">{}</button></span>',
                reverse('wagtailadmin_pages:unlock', args=(page.id,)),
                _("Unlock")
            )
            messages.warning(request, lock_message, extra_tags='lock')

        elif page.locked and page_perms.page_locked():
            # the page can also be locked at a permissions level if in a workflow, on a task the user is not a reviewer for
            # this should be indicated separately
            if page.locked_by and page.locked_at:
                lock_message = format_html(_("<b>Page '{}' was locked</b> by <b>{}</b> on <b>{}</b>."), page.get_admin_display_title(), str(page.locked_by), page.locked_at.strftime("%d %b %Y %H:%M"))
            else:
                # Page was probably locked with an old version of Wagtail, or a script
                lock_message = format_html(_("<b>Page '{}' is locked</b>."), page.get_admin_display_title())

            if page_perms.can_unlock():
                lock_message += format_html(
                    '<span class="buttons"><button class="button button-small button-secondary" data-locking-action="{}">{}</button></span>',
                    reverse('wagtailadmin_pages:unlock', args=(page.id,)),
                    _("Unlock")
                )
            messages.error(request, lock_message, extra_tags='lock')

        if page.current_workflow_state:
            workflow_state = page.current_workflow_state
            workflow = workflow_state.workflow
            workflow_tasks = workflow_state.all_tasks_with_status()
            task = workflow_state.current_task_state.task
            if (
                workflow_state.status != WorkflowState.STATUS_NEEDS_CHANGES
                and task.specific.page_locked_for_user(page, request.user)
            ):
                # Check for revisions still undergoing moderation and warn
                if len(workflow_tasks) == 1:
                    # If only one task in workflow, show simple message
                    workflow_info = _("This page is currently awaiting moderation.")
                else:
                    workflow_info = format_html(
                        _("This page is awaiting <b>'{}'</b> in the <b>'{}'</b> workflow."),
                        task.name, workflow.name
                    )
                messages.error(request, mark_safe(workflow_info + " " + _("Only reviewers for this task can edit the page.")),
                               extra_tags="lock")
    # Check for revisions still undergoing moderation and warn - this is for the old moderation system
    if latest_revision and latest_revision.submitted_for_moderation:
        buttons = []

        if page.live:
            buttons.append(messages.button(
                reverse('wagtailadmin_pages:revisions_compare', args=(page.id, 'live', latest_revision.id)),
                _('Compare with live version')
            ))

        messages.warning(request, _("This page is currently awaiting moderation"), buttons=buttons)

    # Show current workflow state if set, default to last workflow state
    workflow_state = page.current_workflow_state or page.workflow_states.order_by('created_at').last()
    if workflow_state:
        workflow_tasks = workflow_state.all_tasks_with_status()
    else:
        workflow_tasks = []

    errors_debug = None

    if request.method == 'POST':
        form = form_class(request.POST, request.FILES, instance=page,
                          parent_page=parent)

        is_publishing = False
        is_submitting = False
        is_restarting_workflow = False
        is_reverting = False
        is_saving = False
        is_cancelling_workflow = bool(request.POST.get('action-cancel-workflow')) and workflow_state and workflow_state.user_can_cancel(request.user)
        if is_cancelling_workflow:
            workflow_state.cancel(user=request.user)
            # do this here so even if the page is locked due to not having permissions, the original submitter can still cancel the workflow

        if form.is_valid() and not page_perms.page_locked():
            page = form.save(commit=False)

            is_publishing = bool(request.POST.get('action-publish')) and page_perms.can_publish()
            is_submitting = bool(request.POST.get('action-submit')) and page_perms.can_submit_for_moderation()
            is_restarting_workflow = bool(request.POST.get('action-restart-workflow')) and page_perms.can_submit_for_moderation() and workflow_state and workflow_state.user_can_cancel(request.user)
            is_reverting = bool(request.POST.get('revision'))

            is_performing_workflow_action = bool(request.POST.get('action-workflow-action'))
            if is_performing_workflow_action:
                workflow_action = request.POST['workflow-action-name']
                available_actions = page.current_workflow_task.get_actions(page, request.user)
                available_action_names = [name for name, verbose_name, modal in available_actions]
                if workflow_action not in available_action_names:
                    # prevent this action
                    is_performing_workflow_action = False

            is_saving = True
            has_content_changes = form.has_changed()

            if is_restarting_workflow:
                workflow_state.cancel(user=request.user)

            # If a revision ID was passed in the form, get that revision so its
            # date can be referenced in notification messages
            if is_reverting:
                previous_revision = get_object_or_404(page.revisions, id=request.POST.get('revision'))

            if is_performing_workflow_action and not has_content_changes:
                # don't save a new revision, as we're just going to update the page's
                # workflow state with no content changes
                revision = latest_revision
            else:
                # Save revision
                revision = page.save_revision(
                    user=request.user,
                    log_action=True,  # Always log the new revision on edit
                    previous_revision=(previous_revision if is_reverting else None)
                )

            # store submitted go_live_at for messaging below
            go_live_at = page.go_live_at

            # Publish
            if is_publishing:
                for fn in hooks.get_hooks('before_publish_page'):
                    result = fn(request, page)
                    if hasattr(result, 'status_code'):
                        return result

                revision.publish(
                    user=request.user,
                    changed=has_content_changes,
                    previous_revision=(previous_revision if is_reverting else None)
                )

                # Need to reload the page because the URL may have changed, and we
                # need the up-to-date URL for the "View Live" button.
                page = page.specific_class.objects.get(pk=page.pk)

                for fn in hooks.get_hooks('after_publish_page'):
                    result = fn(request, page)
                    if hasattr(result, 'status_code'):
                        return result

            # Submit
            if is_submitting or is_restarting_workflow:
                if workflow_state and workflow_state.status == WorkflowState.STATUS_NEEDS_CHANGES:
                    # If the workflow was in the needs changes state, resume the existing workflow on submission
                    workflow_state.resume(request.user)
                else:
                    # Otherwise start a new workflow
                    workflow = page.get_workflow()
                    workflow.start(page, request.user)

            if is_performing_workflow_action:
                extra_workflow_data_json = request.POST.get('workflow-action-extra-data', '{}')
                extra_workflow_data = json.loads(extra_workflow_data_json)
                page.current_workflow_task.on_action(page.current_workflow_task_state, request.user, workflow_action, **extra_workflow_data)

        # Notifications
        if is_publishing:
            if go_live_at and go_live_at > timezone.now():
                # Page has been scheduled for publishing in the future

                if is_reverting:
                    message = _(
                        "Version from {0} of page '{1}' has been scheduled for publishing."
                    ).format(
                        previous_revision.created_at.strftime("%d %b %Y %H:%M"),
                        page.get_admin_display_title()
                    )
                else:
                    if page.live:
                        message = _(
                            "Page '{0}' is live and this version has been scheduled for publishing."
                        ).format(
                            page.get_admin_display_title()
                        )

                    else:
                        message = _(
                            "Page '{0}' has been scheduled for publishing."
                        ).format(
                            page.get_admin_display_title()
                        )

                messages.success(request, message, buttons=[
                    messages.button(
                        reverse('wagtailadmin_pages:edit', args=(page.id,)),
                        _('Edit')
                    )
                ])

            else:
                # Page is being published now

                if is_reverting:
                    message = _(
                        "Version from {0} of page '{1}' has been published."
                    ).format(
                        previous_revision.created_at.strftime("%d %b %Y %H:%M"),
                        page.get_admin_display_title()
                    )
                else:
                    message = _(
                        "Page '{0}' has been published."
                    ).format(
                        page.get_admin_display_title()
                    )

                buttons = []
                if page.url is not None:
                    buttons.append(messages.button(page.url, _('View live'), new_window=True))
                buttons.append(messages.button(reverse('wagtailadmin_pages:edit', args=(page_id,)), _('Edit')))
                messages.success(request, message, buttons=buttons)

        elif is_submitting:

            message = _(
                "Page '{0}' has been submitted for moderation."
            ).format(
                page.get_admin_display_title()
            )

            messages.success(request, message, buttons=[
                messages.button(
                    reverse('wagtailadmin_pages:view_draft', args=(page_id,)),
                    _('View draft'),
                    new_window=True
                ),
                messages.button(
                    reverse('wagtailadmin_pages:edit', args=(page_id,)),
                    _('Edit')
                )
            ])

        elif is_cancelling_workflow:
            message = _(
                "Workflow on page '{0}' has been cancelled."
            ).format(
                page.get_admin_display_title()
            )

            messages.success(request, message, buttons=[
                messages.button(
                    reverse('wagtailadmin_pages:view_draft', args=(page_id,)),
                    _('View draft'),
                    new_window=True
                ),
                messages.button(
                    reverse('wagtailadmin_pages:edit', args=(page_id,)),
                    ('Edit')
                )
            ])

        elif is_restarting_workflow:

            message = _(
                "Workflow on page '{0}' has been restarted."
            ).format(
                page.get_admin_display_title()
            )

            messages.success(request, message, buttons=[
                messages.button(
                    reverse('wagtailadmin_pages:view_draft', args=(page_id,)),
                    _('View draft'),
                    new_window=True
                ),
                messages.button(
                    reverse('wagtailadmin_pages:edit', args=(page_id,)),
                    _('Edit')
                )
            ])

        elif is_reverting:
            message = _(
                "Page '{0}' has been replaced with version from {1}."
            ).format(
                page.get_admin_display_title(),
                previous_revision.created_at.strftime("%d %b %Y %H:%M")
            )

            messages.success(request, message)
        elif is_saving:
            message = _(
                "Page '{0}' has been updated."
            ).format(
                page.get_admin_display_title()
            )

            messages.success(request, message)

        if is_saving:
            for fn in hooks.get_hooks('after_edit_page'):
                result = fn(request, page)
                if hasattr(result, 'status_code'):
                    return result

            if is_publishing or is_submitting or is_restarting_workflow or is_performing_workflow_action:
                # we're done here - redirect back to the explorer
                if next_url:
                    # redirect back to 'next' url if present
                    return redirect(next_url)
                # redirect back to the explorer
                return redirect('wagtailadmin_explore', page.get_parent().id)
            else:
                # Just saving - remain on edit page for further edits
                target_url = reverse('wagtailadmin_pages:edit', args=[page.id])
                if next_url:
                    # Ensure the 'next' url is passed through again if present
                    target_url += '?next=%s' % urlquote(next_url)
                return redirect(target_url)
        else:
            if page_perms.page_locked():
                messages.error(request, _("The page could not be saved as it is locked"))
            else:
                messages.validation_error(
                    request, _("The page could not be saved due to validation errors"), form
                )
            errors_debug = (
                repr(form.errors)
                + repr([
                    (name, formset.errors)
                    for (name, formset) in form.formsets.items()
                    if formset.errors
                ])
            )
            has_unsaved_changes = True
    else:
        form = form_class(instance=page, parent_page=parent)
        has_unsaved_changes = False

    edit_handler = edit_handler.bind_to(form=form)

    # Check for revisions still undergoing moderation and warn
    if latest_revision and latest_revision.submitted_for_moderation:
        buttons = []

        if page.live:
            buttons.append(messages.button(
                reverse('wagtailadmin_pages:revisions_compare', args=(page.id, 'live', latest_revision.id)),
                _('Compare with live version')
            ))

        messages.warning(request, _("This page is currently awaiting moderation"), buttons=buttons)

    if page.live and page.has_unpublished_changes:
        # Page status needs to present the version of the page containing the correct live URL
        page_for_status = real_page_record.specific
    else:
        page_for_status = page

    return TemplateResponse(request, 'wagtailadmin/pages/edit.html', {
        'page': page,
        'page_for_status': page_for_status,
        'content_type': content_type,
        'edit_handler': edit_handler,
        'errors_debug': errors_debug,
        'action_menu': PageActionMenu(request, view='edit', page=page),
        'preview_modes': page.preview_modes,
        'form': form,
        'next': next_url,
        'has_unsaved_changes': has_unsaved_changes,
        'page_locked': page_perms.page_locked(),
        'workflow_state': workflow_state if workflow_state and workflow_state.is_active else None,
        'current_task_state': page.current_workflow_task_state,
        'publishing_will_cancel_workflow': workflow_tasks and getattr(settings, 'WAGTAIL_WORKFLOW_CANCEL_ON_PUBLISH', True)
    })