Exemplo n.º 1
0
def revisions_unschedule(request, page_id, revision_id):
    page = get_object_or_404(Page, id=page_id).specific

    user_perms = UserPagePermissionsProxy(request.user)
    if not user_perms.for_page(page).can_unschedule():
        raise PermissionDenied

    revision = get_object_or_404(page.revisions, id=revision_id)

    next_url = get_valid_next_url_from_request(request)

    subtitle = _('revision {0} of "{1}"').format(revision.id, page.get_admin_display_title())

    if request.method == 'POST':
        revision.approved_go_live_at = None
        revision.save(user=request.user, update_fields=['approved_go_live_at'])

        messages.success(request, _('Version {0} of "{1}" unscheduled.').format(revision.id, page.get_admin_display_title()), buttons=[
            messages.button(reverse('wagtailadmin_pages:edit', args=(page.id,)), _('Edit'))
        ])

        if next_url:
            return redirect(next_url)
        return redirect('wagtailadmin_pages:history', page.id)

    return TemplateResponse(request, 'wagtailadmin/pages/revisions/confirm_unschedule.html', {
        'page': page,
        'revision': revision,
        'next': next_url,
        'subtitle': subtitle
    })
Exemplo n.º 2
0
def delete(request, document_id):
    Document = get_document_model()
    doc = get_object_or_404(Document, id=document_id)

    if not permission_policy.user_has_permission_for_instance(
            request.user, "delete", doc):
        raise PermissionDenied

    next_url = get_valid_next_url_from_request(request)

    if request.method == "POST":
        doc.delete()
        messages.success(request,
                         _("Document '{0}' deleted.").format(doc.title))
        return redirect(next_url) if next_url else redirect(
            "wagtaildocs:index")

    return TemplateResponse(
        request,
        "wagtaildocs/documents/confirm_delete.html",
        {
            "document": doc,
            "next": next_url,
        },
    )
Exemplo n.º 3
0
def add_subpage(request, parent_page_id):
    parent_page = get_object_or_404(Page, id=parent_page_id).specific
    if not parent_page.permissions_for_user(request.user).can_add_subpage():
        raise PermissionDenied

    page_types = [(
        model.get_verbose_name(),
        model._meta.app_label,
        model._meta.model_name,
        model.get_page_description(),
    ) for model in type(parent_page).creatable_subpage_models()
                  if model.can_create_at(parent_page)]
    # sort by lower-cased version of verbose name
    page_types.sort(key=lambda page_type: page_type[0].lower())

    if len(page_types) == 1:
        # Only one page type is available - redirect straight to the create form rather than
        # making the user choose
        verbose_name, app_label, model_name, description = page_types[0]
        return redirect("wagtailadmin_pages:add", app_label, model_name,
                        parent_page.id)

    return TemplateResponse(
        request,
        "wagtailadmin/pages/add_subpage.html",
        {
            "parent_page": parent_page,
            "page_types": page_types,
            "next": get_valid_next_url_from_request(request),
        },
    )
Exemplo n.º 4
0
def delete(request, page_id):
    page = get_object_or_404(Page, id=page_id).specific
    if not page.permissions_for_user(request.user).can_delete():
        raise PermissionDenied

    with transaction.atomic():
        for fn in hooks.get_hooks('before_delete_page'):
            result = fn(request, page)
            if hasattr(result, 'status_code'):
                return result

        next_url = get_valid_next_url_from_request(request)

        if request.method == 'POST':
            parent_id = page.get_parent().id
            action = DeletePageAction(page, user=request.user)
            # Permission checks are done above, so skip them in execute.
            action.execute(skip_permission_checks=True)

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

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

            if next_url:
                return redirect(next_url)
            return redirect('wagtailadmin_explore', parent_id)

    return TemplateResponse(request, 'wagtailadmin/pages/confirm_delete.html', {
        'page': page,
        'descendant_count': page.get_descendant_count(),
        'next': next_url,
    })
Exemplo n.º 5
0
def convert_alias(request, page_id):
    page = get_object_or_404(Page, id=page_id,
                             alias_of_id__isnull=False).specific
    if not page.permissions_for_user(request.user).can_edit():
        raise PermissionDenied

    with transaction.atomic():
        for fn in hooks.get_hooks('before_convert_alias_page'):
            result = fn(request, page)
            if hasattr(result, 'status_code'):
                return result

        next_url = get_valid_next_url_from_request(request)

        if request.method == 'POST':
            page.alias_of_id = None
            page.save(update_fields=['alias_of_id'], clean=False)

            # Create an initial revision
            revision = page.save_revision(user=request.user,
                                          changed=False,
                                          clean=False)

            if page.live:
                page.live_revision = revision
                page.save(update_fields=['live_revision'], clean=False)

            # Log
            PageLogEntry.objects.log_action(
                instance=page,
                revision=revision,
                action='wagtail.convert_alias',
                user=request.user,
                data={
                    'page': {
                        'id': page.id,
                        'title': page.get_admin_display_title()
                    },
                },
            )

            messages.success(
                request,
                _("Page '{0}' has been converted into an ordinary page.").
                format(page.get_admin_display_title()))

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

            if next_url:
                return redirect(next_url)
            return redirect('wagtailadmin_pages:edit', page.id)

    return TemplateResponse(request,
                            'wagtailadmin/pages/confirm_convert_alias.html', {
                                'page': page,
                                'next': next_url,
                            })
Exemplo n.º 6
0
    def dispatch(
        self, request, content_type_app_name, content_type_model_name, parent_page_id
    ):
        self.parent_page = get_object_or_404(Page, id=parent_page_id).specific
        self.parent_page_perms = self.parent_page.permissions_for_user(
            self.request.user
        )
        if not self.parent_page_perms.can_add_subpage():
            raise PermissionDenied

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

        # Get class
        self.page_class = self.page_content_type.model_class()

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

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

        if not self.page_class.can_create_at(self.parent_page):
            raise PermissionDenied

        response = self.run_hook(
            "before_create_page", self.request, self.parent_page, self.page_class
        )
        if response:
            return response

        self.locale = self.parent_page.locale

        # If the parent page is the root page. The user may specify any locale they like
        if self.parent_page.is_root():
            selected_locale = request.GET.get("locale", None) or request.POST.get(
                "locale", None
            )
            if selected_locale:
                self.locale = get_object_or_404(Locale, language_code=selected_locale)

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

        # Note: Comment notifications should be enabled by default for pages that a user creates
        self.subscription = PageSubscription(
            page=self.page, user=self.request.user, comment_notifications=True
        )

        self.next_url = get_valid_next_url_from_request(self.request)

        return super().dispatch(request)
Exemplo n.º 7
0
    def dispatch(self, request, page_id):
        self.real_page_record = get_object_or_404(Page, id=page_id)
        self.latest_revision = self.real_page_record.get_latest_revision()
        self.page_content_type = self.real_page_record.cached_content_type
        self.page_class = self.real_page_record.specific_class

        if self.page_class is None:
            raise PageClassNotFoundError(
                f"The page '{self.real_page_record}' cannot be edited because the "
                f"model class used to create it ({self.page_content_type.app_label}."
                f"{self.page_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.")

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

        self.page_perms = self.page.permissions_for_user(self.request.user)

        if not self.page_perms.can_edit():
            raise PermissionDenied

        self.next_url = get_valid_next_url_from_request(self.request)

        response = self.run_hook("before_edit_page", self.request, self.page)
        if response:
            return response

        try:
            self.subscription = PageSubscription.objects.get(
                page=self.page, user=self.request.user)
        except PageSubscription.DoesNotExist:
            self.subscription = PageSubscription(page=self.page,
                                                 user=self.request.user,
                                                 comment_notifications=False)

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

        if getattr(settings, "WAGTAIL_WORKFLOW_ENABLED", True):
            # Retrieve current workflow state if set, default to last workflow state
            self.workflow_state = (
                self.page.current_workflow_state
                or self.page.workflow_states.order_by("created_at").last())
        else:
            self.workflow_state = None

        if self.workflow_state:
            self.workflow_tasks = self.workflow_state.all_tasks_with_status()
        else:
            self.workflow_tasks = []

        self.errors_debug = None

        return super().dispatch(request)
Exemplo n.º 8
0
def bulk_action_choices(context, app_label, model_name):

    bulk_actions_list = list(
        bulk_action_registry.get_bulk_actions_for_model(app_label, model_name)
    )
    bulk_actions_list.sort(key=lambda x: x.action_priority)

    bulk_action_more_list = []
    if len(bulk_actions_list) > 4:
        bulk_action_more_list = bulk_actions_list[4:]
        bulk_actions_list = bulk_actions_list[:4]

    next_url = get_valid_next_url_from_request(context["request"])
    if not next_url:
        next_url = context["request"].path

    bulk_action_buttons = [
        PageListingButton(
            action.display_name,
            reverse(
                "wagtail_bulk_action", args=[app_label, model_name, action.action_type]
            )
            + "?"
            + urlencode({"next": next_url}),
            attrs={"aria-label": action.aria_label},
            priority=action.action_priority,
            classes=action.classes | {"bulk-action-btn"},
        )
        for action in bulk_actions_list
    ]

    if bulk_action_more_list:
        more_button = ButtonWithDropdown(
            label=_("More"),
            attrs={"title": _("View more bulk actions")},
            classes={"bulk-actions-more", "dropup"},
            button_classes={"button", "button-small"},
            buttons_data=[
                {
                    "label": action.display_name,
                    "url": reverse(
                        "wagtail_bulk_action",
                        args=[app_label, model_name, action.action_type],
                    )
                    + "?"
                    + urlencode({"next": next_url}),
                    "attrs": {"aria-label": action.aria_label},
                    "priority": action.action_priority,
                    "classes": {"bulk-action-btn"},
                }
                for action in bulk_action_more_list
            ],
        )
        more_button.is_parent = True
        bulk_action_buttons.append(more_button)

    return {"buttons": bulk_action_buttons}
def delete_related_variants(request, page):
    if (not isinstance(page, models.PersonalisablePageMixin)
            or not page.personalisation_metadata.is_canonical):
        return
    # Get a list of related personalisation metadata for all the related
    # variants.
    variants_metadata = page.personalisation_metadata.variants_metadata.select_related(
        "variant")
    next_url = get_valid_next_url_from_request(request)

    if request.method == "POST":
        parent_id = page.get_parent().id
        with transaction.atomic():
            # To ensure variants are deleted for all descendants, start with
            # the deepest ones, and explicitly delete variants and metadata
            # for all of them, including the page itself. Otherwise protected
            # foreign key constraints are violated. Only consider canonical
            # pages.
            for metadata in PersonalisablePageMetadata.objects.filter(
                    canonical_page__in=page.get_descendants(inclusive=True),
                    variant=F("canonical_page"),
            ).order_by("-canonical_page__depth"):
                for variant_metadata in metadata.variants_metadata.select_related(
                        "variant"):
                    # Call delete() on objects to trigger any signals or hooks.
                    variant_metadata.variant.delete()
                metadata.delete()
                metadata.canonical_page.delete()

        msg = _("Page '{0}' and its variants deleted.")
        messages.success(request, msg.format(page.get_admin_display_title()))

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

        if next_url:
            return redirect(next_url)
        return redirect("wagtailadmin_explore", parent_id)

    return render(
        request,
        "wagtailadmin/pages/wagtail_personalisation/confirm_delete.html",
        {
            "page":
            page,
            "descendant_count":
            page.get_descendant_count(),
            "next":
            next_url,
            "variants":
            Page.objects.filter(
                pk__in=variants_metadata.values_list("variant_id")),
        },
    )
Exemplo n.º 10
0
def ion_unpublish(request, page_id):
    page = get_object_or_404(Page, id=page_id).specific

    # TODO permission handling postponed
    # user_perms = UserPagePermissionsProxy(request.user)
    # if not user_perms.for_page(page).can_unpublish():
    #     raise PermissionDenied

    next_url = get_valid_next_url_from_request(request)

    if request.method == 'POST':
        include_descendants = True

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

        page.unpublish(user=request.user)

        if include_descendants:
            live_descendant_pages = page.get_descendants().live().specific()
            for live_descendant_page in live_descendant_pages:
                # if user_perms.for_page(live_descendant_page).can_unpublish():
                live_descendant_page.unpublish()

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

        messages.success(request,
                         _("Page '{0}' unpublished.").format(
                             page.get_admin_display_title()),
                         buttons=[
                             messages.button(
                                 reverse('wagtailadmin_pages:edit',
                                         args=(page.id, )), _('Edit'))
                         ])

        if next_url:
            return redirect(next_url)
        return redirect('wagtailadmin_explore', page.get_parent().id)

    return TemplateResponse(
        request,
        'wagtailadmin/pages/confirm_unpublish.html',
        {
            'page': page,
            'next': next_url,
            # 'live_descendant_count': page.get_descendants().live().count(),
        })
Exemplo n.º 11
0
 def __init__(self, request, model):
     self.request = request
     next_url = get_valid_next_url_from_request(request)
     if not next_url:
         next_url = request.path
     self.next_url = next_url
     self.num_parent_objects = self.num_child_objects = 0
     if model in self.models:
         self.model = model
     else:
         raise Exception(
             "model {} is not among the specified list of models".format(
                 model.__class__.__name__))
Exemplo n.º 12
0
def unpublish(request, page_id):
    page = get_object_or_404(Page, id=page_id).specific

    user_perms = UserPagePermissionsProxy(request.user)
    if not user_perms.for_page(page).can_unpublish():
        raise PermissionDenied

    next_url = get_valid_next_url_from_request(request)

    if request.method == "POST":
        include_descendants = request.POST.get("include_descendants", False)

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

        action = UnpublishPageAction(page,
                                     user=request.user,
                                     include_descendants=include_descendants)
        action.execute(skip_permission_checks=True)

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

        messages.success(
            request,
            _("Page '{0}' unpublished.").format(
                page.get_admin_display_title()),
            buttons=[
                messages.button(
                    reverse("wagtailadmin_pages:edit", args=(page.id, )),
                    _("Edit"))
            ],
        )

        if next_url:
            return redirect(next_url)
        return redirect("wagtailadmin_explore", page.get_parent().id)

    return TemplateResponse(
        request,
        "wagtailadmin/pages/confirm_unpublish.html",
        {
            "page": page,
            "next": next_url,
            "live_descendant_count": page.get_descendants().live().count(),
        },
    )
Exemplo n.º 13
0
def bulk_action_choices(context, app_label, model_name):

    bulk_actions_list = list(
        bulk_action_registry.get_bulk_actions_for_model(app_label, model_name))
    bulk_actions_list.sort(key=lambda x: x.action_priority)

    bulk_action_more_list = []
    if len(bulk_actions_list) > 4:
        bulk_action_more_list = bulk_actions_list[4:]
        bulk_actions_list = bulk_actions_list[:4]

    next_url = get_valid_next_url_from_request(context['request'])
    if not next_url:
        next_url = context['request'].path

    bulk_action_buttons = [
        PageListingButton(
            action.display_name,
            reverse('wagtail_bulk_action',
                    args=[app_label, model_name, action.action_type]) + '?' +
            urlencode({'next': next_url}),
            attrs={'aria-label': action.aria_label},
            priority=action.action_priority,
            classes=action.classes | {'bulk-action-btn'},
        ) for action in bulk_actions_list
    ]

    if bulk_action_more_list:
        more_button = ButtonWithDropdown(
            label=_("More"),
            attrs={'title': _("View more bulk actions")},
            classes={'bulk-actions-more', 'dropup'},
            button_classes={'button', 'button-small'},
            buttons_data=[{
                'label':
                action.display_name,
                'url':
                reverse('wagtail_bulk_action',
                        args=[app_label, model_name, action.action_type]) +
                '?' + urlencode({'next': next_url}),
                'attrs': {
                    'aria-label': action.aria_label
                },
                'priority':
                action.action_priority,
                'classes': {'bulk-action-btn'},
            } for action in bulk_action_more_list])
        more_button.is_parent = True
        bulk_action_buttons.append(more_button)

    return {'buttons': bulk_action_buttons}
Exemplo n.º 14
0
def ion_publish_with_children(request, page_id):
    page = get_object_or_404(Page, id=page_id)
    page_perms = page.permissions_for_user(request.user)

    if not page_perms.can_publish():
        raise PermissionDenied

    revision = page.get_latest_revision()
    unpublished_descendant_pages = page.get_descendants().not_live()
    has_unpublished_alias_pages = unpublished_descendant_pages.filter(
        alias_of__isnull=False).exists()

    if has_unpublished_alias_pages:
        messages.error(
            request,
            "The page has unpublished alias subpages. Please publish the original page(s) first."
        )

    next_url = get_valid_next_url_from_request(request)

    if request.method == 'POST':
        if has_unpublished_alias_pages:
            return redirect(next_url) if next_url else redirect(
                'wagtailadmin_explore',
                page.get_parent().id)

        revision.publish()

        for unpublished_descendant_page in unpublished_descendant_pages:
            unpublished_descendant_revision = unpublished_descendant_page.get_latest_revision(
            )
            unpublished_descendant_revision.publish()

        messages.success(request, _("Publishing successful."))

        if next_url:
            return redirect(next_url)
        return redirect('wagtailadmin_explore', page.get_parent().id)

    return TemplateResponse(
        request, 'wagtailadmin/pages/publish_with_children.html', {
            'page': page,
            'next': next_url,
            'unpublished_descendants': unpublished_descendant_pages,
            'unpublished_descendant_count':
            unpublished_descendant_pages.count(),
            'has_unpublished_alias_pages': has_unpublished_alias_pages,
        })
Exemplo n.º 15
0
def upload_pofile(request, translation_id):
    translation = get_object_or_404(Translation, id=translation_id)

    instance = translation.get_target_instance()
    if not user_can_edit_instance(request.user, instance):
        raise PermissionDenied

    do_import = True

    with tempfile.NamedTemporaryFile() as f:
        # Note: polib.pofile accepts either a filename or contents. We cannot pass the
        # contents directly into polib.pofile or users could upload a file containing
        # a filename and this will be read by polib!
        f.write(request.FILES["file"].read())
        f.flush()

        try:
            po = polib.pofile(f.name)

        except (OSError, UnicodeDecodeError):
            # Annoyingly, POLib uses OSError for parser exceptions...
            messages.error(request, _("Please upload a valid PO file."))
            do_import = False

    if do_import:
        translation_id = po.metadata["X-WagtailLocalize-TranslationID"]
        if translation_id != str(translation.uuid):
            messages.error(
                request,
                _(
                    "Cannot import PO file that was created for a different translation."
                ),
            )
            do_import = False

    if do_import:
        translation.import_po(po, user=request.user, tool_name="PO File")

        messages.success(request, _("Successfully imported translations from PO File."))

    # Work out where to redirect to
    next_url = get_valid_next_url_from_request(request)
    if not next_url:
        # Note: You should always provide a next URL when using this view!
        next_url = reverse("wagtailadmin_home")

    return redirect(next_url)
Exemplo n.º 16
0
def stop_translation(request, translation_id):
    translation = get_object_or_404(Translation, id=translation_id)

    instance = translation.get_target_instance()
    if not user_can_edit_instance(request.user, instance):
        raise PermissionDenied

    translation.enabled = False
    translation.save(update_fields=['enabled'])

    next_url = get_valid_next_url_from_request(request)
    if not next_url:
        # Note: You should always provide a next URL when using this view!
        next_url = reverse('wagtailadmin_home')

    messages.success(request, _("Translation has been stopped."))

    return redirect(next_url)
Exemplo n.º 17
0
def revisions_unschedule(request, page_id, revision_id):
    page = get_object_or_404(Page, id=page_id).specific

    user_perms = UserPagePermissionsProxy(request.user)
    if not user_perms.for_page(page).can_unschedule():
        raise PermissionDenied

    revision = get_object_or_404(page.revisions, id=revision_id)

    next_url = get_valid_next_url_from_request(request)

    subtitle = _('revision {0} of "{1}"').format(
        revision.id, page.get_admin_display_title())

    if request.method == "POST":
        revision.approved_go_live_at = None
        revision.save(user=request.user, update_fields=["approved_go_live_at"])

        messages.success(
            request,
            _('Version {0} of "{1}" unscheduled.').format(
                revision.id, page.get_admin_display_title()),
            buttons=[
                messages.button(
                    reverse("wagtailadmin_pages:edit", args=(page.id, )),
                    _("Edit"))
            ],
        )

        if next_url:
            return redirect(next_url)
        return redirect("wagtailadmin_pages:history", page.id)

    return TemplateResponse(
        request,
        "wagtailadmin/pages/revisions/confirm_unschedule.html",
        {
            "page": page,
            "revision": revision,
            "next": next_url,
            "subtitle": subtitle
        },
    )
Exemplo n.º 18
0
    def dispatch(self, request, content_type_app_name, content_type_model_name,
                 parent_page_id):
        self.parent_page = get_object_or_404(Page, id=parent_page_id).specific
        self.parent_page_perms = self.parent_page.permissions_for_user(
            self.request.user)
        if not self.parent_page_perms.can_add_subpage():
            raise PermissionDenied

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

        # Get class
        self.page_class = self.page_content_type.model_class()

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

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

        if not self.page_class.can_create_at(self.parent_page):
            raise PermissionDenied

        response = self.run_hook('before_create_page', self.request,
                                 self.parent_page, self.page_class)
        if response:
            return response

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

        self.next_url = get_valid_next_url_from_request(self.request)

        return super().dispatch(request)
Exemplo n.º 19
0
def convert_alias(request, page_id):
    page = get_object_or_404(Page, id=page_id,
                             alias_of_id__isnull=False).specific
    if not page.permissions_for_user(request.user).can_edit():
        raise PermissionDenied

    with transaction.atomic():
        for fn in hooks.get_hooks("before_convert_alias_page"):
            result = fn(request, page)
            if hasattr(result, "status_code"):
                return result

        next_url = get_valid_next_url_from_request(request)

        if request.method == "POST":
            action = ConvertAliasPageAction(page, user=request.user)
            action.execute(skip_permission_checks=True)

            messages.success(
                request,
                _("Page '{0}' has been converted into an ordinary page.").
                format(page.get_admin_display_title()),
            )

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

            if next_url:
                return redirect(next_url)
            return redirect("wagtailadmin_pages:edit", page.id)

    return TemplateResponse(
        request,
        "wagtailadmin/pages/confirm_convert_alias.html",
        {
            "page": page,
            "next": next_url,
        },
    )
Exemplo n.º 20
0
def edit_translatable_alias_page(request, page):
    return render(
        request,
        "wagtail_localize/admin/edit_translatable_alias.html",
        {
            "page": page,
            "page_for_status": page,
            "content_type": page.cached_content_type,
            "next": get_valid_next_url_from_request(request),
            "locale": page.locale,
            "translations": [
                {
                    "locale": translation.locale,
                    "url": reverse("wagtailadmin_pages:edit", args=[translation.id]),
                }
                for translation in page.get_translations()
                .only("id", "locale")
                .select_related("locale")
            ],
        },
    )
Exemplo n.º 21
0
def delete(request, image_id):
    image = get_object_or_404(get_image_model(), id=image_id)

    if not permission_policy.user_has_permission_for_instance(
            request.user, 'delete', image):
        raise PermissionDenied

    next_url = get_valid_next_url_from_request(request)

    if request.method == 'POST':
        image.delete()
        messages.success(request,
                         _("Image '{0}' deleted.").format(image.title))
        return redirect(next_url) if next_url else redirect(
            'wagtailimages:index')

    return TemplateResponse(request,
                            "wagtailimages/images/confirm_delete.html", {
                                'image': image,
                                'next': next_url,
                            })
Exemplo n.º 22
0
def edit_translatable_alias_page(request, page):
    return render(
        request, 'wagtail_localize/admin/edit_translatable_alias.html', {
            'page':
            page,
            'page_for_status':
            page,
            'content_type':
            page.cached_content_type,
            'next':
            get_valid_next_url_from_request(request),
            'locale':
            page.locale,
            'translations': [{
                'locale':
                translation.locale,
                'url':
                reverse('wagtailadmin_pages:edit', args=[translation.id]),
            }
                             for translation in page.get_translations().only(
                                 'id', 'locale').select_related('locale')],
        })
Exemplo n.º 23
0
def before_copy_page(request, page):
    parent_page = page.get_parent()
    can_publish = parent_page.permissions_for_user(
        request.user).can_publish_subpage()
    form = PatchedCopyForm(request.POST or None,
                           user=request.user,
                           page=page,
                           can_publish=can_publish)
    next_url = get_valid_next_url_from_request(request)

    if request.method == 'POST':
        # Prefill parent_page in case the form is invalid (as prepopulated value for the form field,
        # because ModelChoiceField seems to not fall back to the user given value)
        parent_page = Page.objects.get(id=request.POST['new_parent_page'])

        if form.is_valid():
            # Receive the parent page (this should never be empty)
            if form.cleaned_data['new_parent_page']:
                parent_page = form.cleaned_data['new_parent_page']

            if not page.permissions_for_user(request.user).can_copy_to(
                    parent_page, form.cleaned_data.get('copy_subpages')):
                raise PermissionDenied

            # Re-check if the user has permission to publish subpages on the new parent
            can_publish = parent_page.permissions_for_user(
                request.user).can_publish_subpage()

            update_attrs = {}
            for code, name in settings.LANGUAGES:
                if wmt_settings.TRANSLATE_SLUGS:
                    slug = build_localized_fieldname('slug', code)
                else:
                    slug = 'slug'
                title = build_localized_fieldname('title', code)
                update_attrs[slug] = form.cleaned_data["new_{}".format(slug)]
                update_attrs[title] = form.cleaned_data["new_{}".format(title)]

            # Copy the page
            new_page = page.copy(
                recursive=form.cleaned_data.get('copy_subpages'),
                to=parent_page,
                update_attrs=update_attrs,
                keep_live=(can_publish
                           and form.cleaned_data.get('publish_copies')),
                user=request.user,
            )

            # Give a success message back to the user
            if form.cleaned_data.get('copy_subpages'):
                messages.success(
                    request,
                    _("Page '{0}' and {1} subpages copied.").format(
                        page.get_admin_display_title(),
                        new_page.get_descendants().count()))
            else:
                messages.success(
                    request,
                    _("Page '{0}' copied.").format(
                        page.get_admin_display_title()))

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

            # Redirect to explore of parent page
            if next_url:
                return redirect(next_url)
            return redirect('wagtailadmin_explore', parent_page.id)

    return render(request, 'modeltranslation_copy.html', {
        'page': page,
        'form': form,
        'next': next_url
    })
Exemplo n.º 24
0
def copy(request, app_label, model_name, id):
    # Validate snippet has been registered and title_field is set.
    meta = snippet_copy_registry.get(app_label, model_name)
    if meta is None:
        raise Exception("This snippet isn't registered as copyable")

    try:
        model = apps.get_model(app_label, model_name)
    except LookupError:
        raise Http404

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

    snippet = get_object_or_404(model, id=id)

    # Create the form
    form = meta['copy_form_class'](request.POST or None,
                                   snippet=snippet,
                                   title_field_name=meta['title_field_name'])

    next_url = get_valid_next_url_from_request(request)

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

    # Check if user is submitting
    if request.method == 'POST':

        if form.is_valid():

            # Copy the snippet
            new_snippet = form.copy()

            # Give a success message back to the user
            messages.success(
                request,
                _(f"{snippet.get_snippet_verbose_name()} '{snippet}' has been copied."
                  ).format(snippet))

            for fn in hooks.get_hooks('after_copy_snippet'):
                result = fn(request, snippet, new_snippet)
                if hasattr(result, 'status_code'):
                    return result

            if next_url:
                return redirect(next_url)

            if 'wagtail.contrib.modeladmin' in settings.INSTALLED_APPS:
                url_helper = AdminURLHelper(new_snippet)
                return redirect(
                    url_helper.get_action_url('edit', quote(new_snippet.pk)))

            return redirect('wagtailsnippets:edit', app_label, model_name,
                            new_snippet.id)

    return render(
        request, 'wagtailsnippetscopy/copy.html', {
            'snippet': snippet,
            'app_label': app_label,
            'model_name': model_name,
            'form': form,
            'next': next_url,
        })
Exemplo n.º 25
0
def edit(request, document_id):
    Document = get_document_model()
    DocumentForm = get_document_form(Document)

    doc = get_object_or_404(Document, id=document_id)

    if not permission_policy.user_has_permission_for_instance(
            request.user, "change", doc):
        raise PermissionDenied

    next_url = get_valid_next_url_from_request(request)

    if request.method == "POST":
        original_file = doc.file
        form = DocumentForm(request.POST,
                            request.FILES,
                            instance=doc,
                            user=request.user)
        if form.is_valid():
            if "file" in form.changed_data:
                doc = form.save(commit=False)
                doc.file_size = doc.file.size

                # Set new document file hash
                doc.file.seek(0)
                doc._set_file_hash(doc.file.read())
                doc.file.seek(0)
                doc.save()
                form.save_m2m()

                # If providing a new document file, delete the old one.
                # NB Doing this via original_file.delete() clears the file field,
                # which definitely isn't what we want...
                original_file.storage.delete(original_file.name)
            else:
                doc = form.save()

            # Reindex the document to make sure all tags are indexed
            search_index.insert_or_update_object(doc)

            edit_url = reverse("wagtaildocs:edit", args=(doc.id, ))
            redirect_url = "wagtaildocs:index"
            if next_url:
                edit_url = f"{edit_url}?{urlencode({'next': next_url})}"
                redirect_url = next_url

            messages.success(
                request,
                _("Document '{0}' updated").format(doc.title),
                buttons=[messages.button(edit_url, _("Edit"))],
            )
            return redirect(redirect_url)
        else:
            messages.error(request,
                           _("The document could not be saved due to errors."))
    else:
        form = DocumentForm(instance=doc, user=request.user)

    try:
        local_path = doc.file.path
    except NotImplementedError:
        # Document is hosted externally (eg, S3)
        local_path = None

    if local_path:
        # Give error if document file doesn't exist
        if not os.path.isfile(local_path):
            messages.error(
                request,
                _("The file could not be found. Please change the source or delete the document"
                  ),
                buttons=[
                    messages.button(
                        reverse("wagtaildocs:delete", args=(doc.id, )),
                        _("Delete"))
                ],
            )

    return TemplateResponse(
        request,
        "wagtaildocs/documents/edit.html",
        {
            "document":
            doc,
            "filesize":
            doc.get_file_size(),
            "form":
            form,
            "user_can_delete":
            permission_policy.user_has_permission_for_instance(
                request.user, "delete", doc),
            "next":
            next_url,
        },
    )
Exemplo n.º 26
0
def edit(request, image_id):
    Image = get_image_model()
    ImageForm = get_image_form(Image)

    image = get_object_or_404(Image, id=image_id)

    if not permission_policy.user_has_permission_for_instance(
            request.user, "change", image):
        raise PermissionDenied

    next_url = get_valid_next_url_from_request(request)

    if request.method == "POST":
        original_file = image.file
        form = ImageForm(request.POST,
                         request.FILES,
                         instance=image,
                         user=request.user)
        if form.is_valid():
            if "file" in form.changed_data:
                # Set new image file size
                image.file_size = image.file.size

                # Set new image file hash
                image.file.seek(0)
                image._set_file_hash(image.file.read())
                image.file.seek(0)

            form.save()

            if "file" in form.changed_data:
                # if providing a new image file, delete the old one and all renditions.
                # NB Doing this via original_file.delete() clears the file field,
                # which definitely isn't what we want...
                original_file.storage.delete(original_file.name)
                image.renditions.all().delete()

            # Reindex the image to make sure all tags are indexed
            search_index.insert_or_update_object(image)

            edit_url = reverse("wagtailimages:edit", args=(image.id, ))
            redirect_url = "wagtailimages:index"
            if next_url:
                edit_url = f"{edit_url}?{urlencode({'next': next_url})}"
                redirect_url = next_url

            messages.success(
                request,
                _("Image '{0}' updated.").format(image.title),
                buttons=[messages.button(edit_url, _("Edit again"))],
            )
            return redirect(redirect_url)
        else:
            messages.error(request,
                           _("The image could not be saved due to errors."))
    else:
        form = ImageForm(instance=image, user=request.user)

    # Check if we should enable the frontend url generator
    try:
        reverse("wagtailimages_serve", args=("foo", "1", "bar"))
        url_generator_enabled = True
    except NoReverseMatch:
        url_generator_enabled = False

    if image.is_stored_locally():
        # Give error if image file doesn't exist
        if not os.path.isfile(image.file.path):
            messages.error(
                request,
                _("The source image file could not be found. Please change the source or delete the image."
                  ).format(image.title),
                buttons=[
                    messages.button(
                        reverse("wagtailimages:delete", args=(image.id, )),
                        _("Delete"))
                ],
            )

    try:
        filesize = image.get_file_size()
    except SourceImageIOError:
        filesize = None

    return TemplateResponse(
        request,
        "wagtailimages/images/edit.html",
        {
            "image":
            image,
            "form":
            form,
            "url_generator_enabled":
            url_generator_enabled,
            "filesize":
            filesize,
            "user_can_delete":
            permission_policy.user_has_permission_for_instance(
                request.user, "delete", image),
            "next":
            next_url,
        },
    )
Exemplo n.º 27
0
def delete(request, page_id):
    page = get_object_or_404(Page, id=page_id).specific
    if not page.permissions_for_user(request.user).can_delete():
        raise PermissionDenied

    wagtail_site_name = getattr(settings, "WAGTAIL_SITE_NAME", "wagtail")
    with transaction.atomic():
        for fn in hooks.get_hooks("before_delete_page"):
            result = fn(request, page)
            if hasattr(result, "status_code"):
                return result

        next_url = get_valid_next_url_from_request(request)

        pages_to_delete = {page}

        # The `construct_translated_pages_to_cascade_actions` hook returns translation and
        # alias pages when the action is set to "delete"
        if getattr(settings, "WAGTAIL_I18N_ENABLED", False):
            for fn in hooks.get_hooks(
                    "construct_translated_pages_to_cascade_actions"):
                fn_pages = fn([page], "delete")
                if fn_pages and isinstance(fn_pages, dict):
                    for additional_pages in fn_pages.values():
                        pages_to_delete.update(additional_pages)

        pages_to_delete = list(pages_to_delete)

        if request.method == "POST":
            continue_deleting = True
            if (request.POST.get("confirm_site_name")
                    and request.POST.get("confirm_site_name") !=
                    wagtail_site_name):
                messages.error(
                    request, f"Please type '{wagtail_site_name}' to confirm.")
                continue_deleting = False
            if continue_deleting:
                parent_id = page.get_parent().id
                # Delete the source page.
                action = DeletePageAction(page, user=request.user)
                # Permission checks are done above, so skip them in execute.
                action.execute(skip_permission_checks=True)

                # Delete translation and alias pages if they have the same parent page.
                if getattr(settings, "WAGTAIL_I18N_ENABLED", False):
                    parent_page_translations = page.get_parent(
                    ).get_translations()
                    for page_or_alias in pages_to_delete:
                        if page_or_alias.get_parent(
                        ) in parent_page_translations:
                            action = DeletePageAction(page_or_alias,
                                                      user=request.user)
                            # Permission checks are done above, so skip them in execute.
                            action.execute(skip_permission_checks=True)

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

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

                if next_url:
                    return redirect(next_url)
                return redirect("wagtailadmin_explore", parent_id)

    descendant_count = page.get_descendant_count()
    return TemplateResponse(
        request,
        "wagtailadmin/pages/confirm_delete.html",
        {
            "page":
            page,
            "descendant_count":
            descendant_count,
            "next":
            next_url,
            # if the number of pages ( child pages + current page) exceeds this limit, then confirm before delete.
            "confirm_before_delete": (descendant_count + 1) >= getattr(
                settings, "WAGTAILADMIN_UNSAFE_PAGE_DELETION_LIMIT", 10),
            "wagtail_site_name":
            wagtail_site_name,
            # note that while pages_to_delete may contain a mix of translated pages
            # and aliases, we count the "translations" only, as aliases are similar
            # to symlinks, so they should just follow the source
            "translation_count":
            len([
                translation.id for translation in pages_to_delete
                if not translation.alias_of_id and translation.id != page.id
            ]),
            "translation_descendant_count":
            sum([
                translation.get_descendants().filter(
                    alias_of__isnull=True).count()
                for translation in pages_to_delete
            ]),
        },
    )
Exemplo n.º 28
0
def custom_admin_round_copy_view(request, page):
    # Custom view to handle copied Round pages.
    # https://github.com/wagtail/wagtail/blob/124827911463f0cb959edbb9d8d5685578540bd3/wagtail/admin/views/pages.py#L824

    # Parent page defaults to parent of source page
    parent_page = page.get_parent()

    # Check if the user has permission to publish subpages on the parent
    can_publish = parent_page.permissions_for_user(request.user).can_publish_subpage()

    form = CopyForm(request.POST or None, user=request.user, page=page, can_publish=can_publish)

    next_url = get_valid_next_url_from_request(request)

    # Prefill parent_page in case the form is invalid (as prepopulated value for the form field,
    # because ModelChoiceField seems to not fall back to the user given value)
    parent_page = Page.objects.get(id=request.POST['new_parent_page'])

    if form.is_valid():
        # Receive the parent page (this should never be empty)
        if form.cleaned_data['new_parent_page']:
            parent_page = form.cleaned_data['new_parent_page']

        if not page.permissions_for_user(request.user).can_copy_to(parent_page,
                                                                   form.cleaned_data.get('copy_subpages')):
            raise PermissionDenied

        # Re-check if the user has permission to publish subpages on the new parent
        can_publish = parent_page.permissions_for_user(request.user).can_publish_subpage()

        # Copy the page
        new_page = page.copy(
            recursive=form.cleaned_data.get('copy_subpages'),
            to=parent_page,
            update_attrs={
                'title': form.cleaned_data['new_title'],
                'slug': form.cleaned_data['new_slug'],
                'start_date': None,
                'end_date': None,
            },
            keep_live=(can_publish and form.cleaned_data.get('publish_copies')),
            user=request.user,
        )

        messages.info(request, _((
            "Please select the date in the copied page. "
            "Newly copied pages have NONE value for the start and end date"
        )))

        # Give a success message back to the user
        if form.cleaned_data.get('copy_subpages'):
            messages.success(
                request, _("Page '{0}' and {1} subpages copied.").format(
                    page.get_admin_display_title(), new_page.get_descendants().count()
                )
            )
        else:
            messages.success(request, _("Page '{0}' copied.").format(page.get_admin_display_title()))

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

        # Redirect to explore of parent page
        if next_url:
            return redirect(next_url)
        return redirect('wagtailadmin_explore', parent_page.id)
 def get_success_url(self):
     return get_valid_next_url_from_request(self.request)
Exemplo n.º 30
0
def machine_translate(request, translation_id):
    translation = get_object_or_404(Translation, id=translation_id)

    instance = translation.get_target_instance()
    if not user_can_edit_instance(request.user, instance):
        raise PermissionDenied

    translator = get_machine_translator()
    if translator is None:
        raise Http404

    if not translator.can_translate(translation.source.locale,
                                    translation.target_locale):
        raise Http404

    # Get segments
    segments = defaultdict(list)
    for string_segment in translation.source.stringsegment_set.all(
    ).select_related("context", "string"):
        segment = StringSegmentValue(
            string_segment.context.path,
            string_segment.string.as_value()).with_order(string_segment.order)
        if string_segment.attrs:
            segment.attrs = json.loads(string_segment.attrs)

        # Don't translate if there already is a translation
        if StringTranslation.objects.filter(
                translation_of_id=string_segment.string_id,
                locale=translation.target_locale,
                context_id=string_segment.context_id,
        ).exists():
            continue

        segments[segment.string].append(
            (string_segment.string_id, string_segment.context_id))

    if segments:
        translations = translator.translate(translation.source.locale,
                                            translation.target_locale,
                                            segments.keys())

        with transaction.atomic():
            for string, contexts in segments.items():
                for string_id, context_id in contexts:
                    StringTranslation.objects.get_or_create(
                        translation_of_id=string_id,
                        locale=translation.target_locale,
                        context_id=context_id,
                        defaults={
                            'data': translations[string].data,
                            'translation_type':
                            StringTranslation.TRANSLATION_TYPE_MACHINE,
                            'tool_name': translator.display_name,
                            'last_translated_by': request.user,
                            'has_error': False,
                            'field_error': "",
                        })

        messages.success(
            request,
            _("Successfully translated with {}.").format(
                translator.display_name))

    else:
        messages.warning(request, _("There isn't anything left to translate."))

    # Work out where to redirect to
    next_url = get_valid_next_url_from_request(request)
    if not next_url:
        # Note: You should always provide a next URL when using this view!
        next_url = reverse('wagtailadmin_home')

    return redirect(next_url)