Example #1
0
    def check(self, skip_permission_checks=False):
        from wagtail.models import UserPagePermissionsProxy

        # Essential data model checks
        if self.page._state.adding:
            raise CopyPageIntegrityError(
                "Page.copy() called on an unsaved page")

        if (self.to and self.recursive
                and (self.to.id == self.page.id
                     or self.to.is_descendant_of(self.page))):
            raise CopyPageIntegrityError(
                "You cannot copy a tree branch recursively into itself")

        # Permission checks
        if self.user and not skip_permission_checks:
            to = self.to
            if to is None:
                to = self.page.get_parent()

            if not self.page.permissions_for_user(self.user).can_copy_to(
                    to, self.recursive):
                raise CopyPagePermissionError(
                    "You do not have permission to copy this page")

            if self.keep_live:
                destination_perms = UserPagePermissionsProxy(
                    self.user).for_page(self.to)

                if not destination_perms.can_publish_subpage():
                    raise CopyPagePermissionError(
                        "You do not have permission to publish a page at the destination"
                    )
Example #2
0
    def test_page_locked_for_unlocked_page(self):
        user = get_user_model().objects.get(email="*****@*****.**")
        christmas_page = EventPage.objects.get(
            url_path="/home/events/christmas/")

        perms = UserPagePermissionsProxy(user).for_page(christmas_page)

        self.assertFalse(perms.page_locked())
Example #3
0
    def is_active(self):
        # Hide the panel if the user can't edit or publish pages
        user_perms = UserPagePermissionsProxy(self.request.user)
        if not user_perms.can_edit_pages() and not user_perms.can_publish_pages():
            return False

        # Hide the panel if there are no notification preferences
        return self.get_form().fields
Example #4
0
 def __init__(self, *args, **kwargs):
     super().__init__(*args, **kwargs)
     user_perms = UserPagePermissionsProxy(self.instance.user)
     if not user_perms.can_publish_pages():
         del self.fields["submitted_notifications"]
     if not user_perms.can_edit_pages():
         del self.fields["approved_notifications"]
         del self.fields["rejected_notifications"]
         del self.fields["updated_comments_notifications"]
Example #5
0
    def __init__(self, request, **kwargs):
        self.request = request
        self.context = kwargs
        self.context["request"] = request
        page = self.context.get("page")
        user_page_permissions = UserPagePermissionsProxy(self.request.user)
        self.context["user_page_permissions"] = user_page_permissions
        if page:
            self.context[
                "user_page_permissions_tester"] = user_page_permissions.for_page(
                    page)

        self.menu_items = []

        if page:
            task = page.current_workflow_task
            current_workflow_state = page.current_workflow_state
            is_final_task = (current_workflow_state
                             and current_workflow_state.is_at_final_task)
            if task:
                actions = task.get_actions(page, request.user)
                workflow_menu_items = []
                for name, label, launch_modal in actions:
                    icon_name = "edit"
                    if name == "approve":
                        if is_final_task and not getattr(
                                settings,
                                "WAGTAIL_WORKFLOW_REQUIRE_REAPPROVAL_ON_EDIT",
                                False,
                        ):
                            label = _("%(label)s and Publish") % {
                                "label": label
                            }
                        icon_name = "success"

                    item = WorkflowMenuItem(name,
                                            label,
                                            launch_modal,
                                            icon_name=icon_name)

                    if item.is_shown(self.context):
                        workflow_menu_items.append(item)
                self.menu_items.extend(workflow_menu_items)

        for menu_item in _get_base_page_action_menu_items():
            if menu_item.is_shown(self.context):
                self.menu_items.append(menu_item)

        self.menu_items.sort(key=lambda item: item.order)

        for hook in hooks.get_hooks("construct_page_action_menu"):
            hook(self.menu_items, self.request, self.context)

        try:
            self.default_item = self.menu_items.pop(0)
        except IndexError:
            self.default_item = None
Example #6
0
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context.update({
            "page":
            self.page,
            "page_for_status":
            self.page_for_status,
            "content_type":
            self.page_content_type,
            "edit_handler":
            self.edit_handler,
            "errors_debug":
            self.errors_debug,
            "action_menu":
            PageActionMenu(self.request, view="edit", page=self.page),
            "preview_modes":
            self.page.preview_modes,
            "form":
            self.form,
            "next":
            self.next_url,
            "has_unsaved_changes":
            self.has_unsaved_changes,
            "page_locked":
            self.page_perms.page_locked(),
            "workflow_state":
            self.workflow_state
            if self.workflow_state and self.workflow_state.is_active else None,
            "current_task_state":
            self.page.current_workflow_task_state,
            "publishing_will_cancel_workflow":
            self.workflow_tasks
            and getattr(settings, "WAGTAIL_WORKFLOW_CANCEL_ON_PUBLISH", True),
            "locale":
            None,
            "translations": [],
        })

        if getattr(settings, "WAGTAIL_I18N_ENABLED", False):
            user_perms = UserPagePermissionsProxy(self.request.user)

            context.update({
                "locale":
                self.page.locale,
                "translations":
                [{
                    "locale":
                    translation.locale,
                    "url":
                    reverse("wagtailadmin_pages:edit", args=[translation.id]),
                } for translation in self.page.get_translations().only(
                    "id", "locale", "depth").select_related("locale")
                 if user_perms.for_page(translation).can_edit()],
            })

        return context
Example #7
0
    def test_lock_page_for_non_editing_user(self):
        user = get_user_model().objects.get(
            email="*****@*****.**")
        christmas_page = EventPage.objects.get(
            url_path="/home/events/christmas/")

        perms = UserPagePermissionsProxy(user).for_page(christmas_page)

        self.assertFalse(perms.can_lock())
        self.assertFalse(perms.can_unlock())
Example #8
0
File: home.py Project: tnir/wagtail
 def get_context_data(self, parent_context):
     request = parent_context["request"]
     context = super().get_context_data(parent_context)
     user_perms = UserPagePermissionsProxy(request.user)
     context["page_revisions_for_moderation"] = (
         user_perms.revisions_for_moderation().select_related(
             "user").order_by("-created_at"))
     context["request"] = request
     context["csrf_token"] = parent_context["csrf_token"]
     return context
Example #9
0
    def test_page_locked_in_workflow(self):
        workflow, task = self.create_workflow_and_task()
        editor = get_user_model().objects.get(email="*****@*****.**")
        moderator = get_user_model().objects.get(
            email="*****@*****.**")
        superuser = get_user_model().objects.get(email="*****@*****.**")
        christmas_page = EventPage.objects.get(
            url_path="/home/events/christmas/")
        christmas_page.save_revision()
        workflow.start(christmas_page, editor)

        moderator_perms = UserPagePermissionsProxy(moderator).for_page(
            christmas_page)

        # the moderator is in the group assigned to moderate the task, so the page should
        # not be locked for them
        self.assertFalse(moderator_perms.page_locked())

        superuser_perms = UserPagePermissionsProxy(superuser).for_page(
            christmas_page)

        # superusers can moderate any GroupApprovalTask, so the page should not be locked
        # for them
        self.assertFalse(superuser_perms.page_locked())

        editor_perms = UserPagePermissionsProxy(editor).for_page(
            christmas_page)

        # the editor is not in the group assigned to moderate the task, so the page should
        # be locked for them
        self.assertTrue(editor_perms.page_locked())
Example #10
0
    def get_context_data(self, parent_context):
        context = super().get_context_data(parent_context)
        user_perms = UserPagePermissionsProxy(self.request.user)
        page = self.object

        if page.id:
            context.update({
                "history_url":
                reverse("wagtailadmin_pages:history", args=(page.id, )),
                "lock_url":
                reverse("wagtailadmin_pages:lock", args=(page.id, )),
                "unlock_url":
                reverse("wagtailadmin_pages:unlock", args=(page.id, )),
                "user_can_lock":
                user_perms.for_page(page).can_lock(),
                "user_can_unlock":
                user_perms.for_page(page).can_unlock(),
                "locale":
                None,
                "translations": [],
            })
        else:
            context.update({
                "locale": None,
                "translations": [],
            })

        if getattr(settings, "WAGTAIL_I18N_ENABLED", False):
            url_name = "wagtailadmin_pages:edit"
            if self.in_explorer:
                url_name = "wagtailadmin_explore"

            context.update({
                "locale":
                page.locale,
                "translations":
                [{
                    "locale": translation.locale,
                    "url": reverse(url_name, args=[translation.id]),
                } for translation in page.get_translations().only(
                    "id", "locale", "depth").select_related("locale")
                 if user_perms.for_page(translation).can_edit()],
                # The sum of translated pages plus 1 to account for the current page
                "translations_total":
                page.get_translations().count() + 1,
            })

        context.update({
            "model_name": self.model.get_verbose_name(),
            "model_description": self.model.get_page_description(),
            "status_templates": self.get_status_templates(context),
        })

        return context
Example #11
0
    def test_lock_page_for_moderator_without_unlock_permission(self):
        user = get_user_model().objects.get(email="*****@*****.**")
        christmas_page = EventPage.objects.get(
            url_path="/home/events/christmas/")

        GroupPagePermission.objects.filter(group__name="Event moderators",
                                           permission_type="unlock").delete()

        perms = UserPagePermissionsProxy(user).for_page(christmas_page)

        self.assertTrue(perms.can_lock())
        self.assertFalse(perms.can_unlock())
Example #12
0
    def execute(self, skip_permission_checks=False):
        super().execute(skip_permission_checks)

        if self.include_descendants:
            from wagtail.models import UserPagePermissionsProxy

            user_perms = UserPagePermissionsProxy(self.user)
            for live_descendant_page in (self.object.get_descendants().live(
            ).defer_streamfields().specific().iterator()):
                action = UnpublishPageAction(live_descendant_page)
                if user_perms.for_page(live_descendant_page).can_unpublish():
                    action.execute(skip_permission_checks=True)
Example #13
0
def get_forms_for_user(user):
    """
    Return a queryset of form pages that this user is allowed to access the submissions for
    """
    editable_forms = UserPagePermissionsProxy(user).editable_pages()
    editable_forms = editable_forms.filter(content_type__in=get_form_types())

    # Apply hooks
    for fn in hooks.get_hooks("filter_form_submissions_for_user"):
        editable_forms = fn(user, editable_forms)

    return editable_forms
Example #14
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(),
        },
    )
Example #15
0
    def filter_queryset(self, request, queryset, view):
        if request.GET.get("for_explorer"):
            if not hasattr(queryset, "_filtered_by_child_of"):
                raise BadRequestError(
                    "filtering by for_explorer without child_of is not supported"
                )

            parent_page = queryset._filtered_by_child_of
            for hook in hooks.get_hooks("construct_explorer_page_queryset"):
                queryset = hook(parent_page, queryset, request)

            user_perms = UserPagePermissionsProxy(request.user)
            queryset = user_perms.explorable_pages() & queryset

        return queryset
Example #16
0
    def test_explorable_pages_with_permission_gap_in_hierarchy(self):
        corporate_editor = get_user_model().objects.get(
            email="*****@*****.**")
        user_perms = UserPagePermissionsProxy(corporate_editor)

        about_us_page = Page.objects.get(url_path="/home/about-us/")
        businessy_events = Page.objects.get(
            url_path="/home/events/businessy-events/")
        events_page = Page.objects.get(url_path="/home/events/")

        explorable_pages = user_perms.explorable_pages()

        self.assertTrue(explorable_pages.filter(id=about_us_page.id).exists())
        self.assertTrue(
            explorable_pages.filter(id=businessy_events.id).exists())
        self.assertTrue(explorable_pages.filter(id=events_page.id).exists())
Example #17
0
    def get_valid_parent_pages(self, user):
        """
        Identifies possible parent pages for the current user by first looking
        at allowed_parent_page_models() on self.model to limit options to the
        correct type of page, then checking permissions on those individual
        pages to make sure we have permission to add a subpage to it.
        """
        # Get queryset of pages where this page type can be added
        allowed_parent_page_content_types = list(
            ContentType.objects.get_for_models(
                *self.model.allowed_parent_page_models()).values())
        allowed_parent_pages = Page.objects.filter(
            content_type__in=allowed_parent_page_content_types)

        # Get queryset of pages where the user has permission to add subpages
        if user.is_superuser:
            pages_where_user_can_add = Page.objects.all()
        else:
            pages_where_user_can_add = Page.objects.none()
            user_perms = UserPagePermissionsProxy(user)

            for perm in user_perms.permissions.filter(permission_type="add"):
                # user has add permission on any subpage of perm.page
                # (including perm.page itself)
                pages_where_user_can_add |= Page.objects.descendant_of(
                    perm.page, inclusive=True)

        # Combine them
        return allowed_parent_pages & pages_where_user_can_add
Example #18
0
def usage(request, pk):
    workflow = get_object_or_404(Workflow, id=pk)

    perms = UserPagePermissionsProxy(request.user)

    pages = workflow.all_pages() & perms.editable_pages()
    paginator = Paginator(pages, per_page=10)
    pages = paginator.get_page(request.GET.get("p"))

    return render(
        request,
        "wagtailadmin/workflows/usage.html",
        {
            "workflow": workflow,
            "used_by": pages,
        },
    )
Example #19
0
def _get_user_page_permissions(context):
    # Create a UserPagePermissionsProxy object to represent the user's global permissions, and
    # cache it in the context for the duration of the page request, if one does not exist already
    if "user_page_permissions" not in context:
        context["user_page_permissions"] = UserPagePermissionsProxy(
            context["request"].user)

    return context["user_page_permissions"]
Example #20
0
    def test_lock_page_for_editor_with_lock_permission(self):
        user = get_user_model().objects.get(email="*****@*****.**")
        christmas_page = EventPage.objects.get(
            url_path="/home/events/christmas/")

        GroupPagePermission.objects.create(
            group=Group.objects.get(name="Event editors"),
            page=christmas_page,
            permission_type="lock",
        )

        perms = UserPagePermissionsProxy(user).for_page(christmas_page)

        self.assertTrue(perms.can_lock())

        # Still shouldn't have unlock permission
        self.assertFalse(perms.can_unlock())
Example #21
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
        },
    )
Example #22
0
    def test_lock_page_for_moderator_whole_locked_page_without_unlock_permission(
            self):
        user = get_user_model().objects.get(email="*****@*****.**")
        christmas_page = EventPage.objects.get(
            url_path="/home/events/christmas/")

        # Lock the page
        christmas_page.locked = True
        christmas_page.locked_by = user
        christmas_page.locked_at = timezone.now()
        christmas_page.save()

        GroupPagePermission.objects.filter(group__name="Event moderators",
                                           permission_type="unlock").delete()

        perms = UserPagePermissionsProxy(user).for_page(christmas_page)

        # Unlike in the previous test, the user can unlock this page as it was them who locked
        self.assertTrue(perms.can_lock())
        self.assertTrue(perms.can_unlock())
Example #23
0
    def execute(self, skip_permission_checks=False):
        self.check(skip_permission_checks=skip_permission_checks)

        self._unpublish_page(
            self.page,
            set_expired=self.set_expired,
            commit=self.commit,
            user=self.user,
            log_action=self.log_action,
        )

        if self.include_descendants:
            from wagtail.models import UserPagePermissionsProxy

            user_perms = UserPagePermissionsProxy(self.user)
            for live_descendant_page in (self.page.get_descendants().live().
                                         defer_streamfields().specific()):
                action = UnpublishPageAction(live_descendant_page)
                if user_perms.for_page(live_descendant_page).can_unpublish():
                    action.execute(skip_permission_checks=True)
Example #24
0
 def test_with_user_no_permission(self):
     homepage = Page.objects.get(url_path="/home/")
     # event editor does not have permissions on homepage
     event_editor = get_user_model().objects.get(
         email="*****@*****.**")
     permission_proxy = UserPagePermissionsProxy(event_editor)
     result = can_choose_page(homepage,
                              permission_proxy,
                              self.desired_classes,
                              user_perm="copy_to")
     self.assertFalse(result)
Example #25
0
    def get_queryset(self):
        latest_publishing_log = PageLogEntry.objects.filter(
            page=OuterRef("pk"), action__exact="wagtail.publish")
        self.queryset = (UserPagePermissionsProxy(
            self.request.user).publishable_pages().exclude(
                last_published_at__isnull=True).prefetch_workflow_states(
                ).select_related("content_type").annotate_approved_schedule().
                         order_by("last_published_at").annotate(
                             last_published_by=Subquery(
                                 latest_publishing_log.values("user")[:1])))

        return super().get_queryset()
Example #26
0
def workflow_history(request, page_id):
    page = get_object_or_404(Page, id=page_id)

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

    workflow_states = WorkflowState.objects.filter(
        page=page).order_by("-created_at")

    paginator = Paginator(workflow_states, per_page=20)
    workflow_states = paginator.get_page(request.GET.get("p"))

    return TemplateResponse(
        request,
        "wagtailadmin/pages/workflow_history/index.html",
        {
            "page": page,
            "workflow_states": workflow_states,
        },
    )
Example #27
0
    def test_editable_pages_for_non_editing_user(self):
        user = get_user_model().objects.get(
            email="*****@*****.**")
        homepage = Page.objects.get(url_path="/home/")
        christmas_page = EventPage.objects.get(
            url_path="/home/events/christmas/")
        unpublished_event_page = EventPage.objects.get(
            url_path="/home/events/tentative-unpublished-event/")
        someone_elses_event_page = EventPage.objects.get(
            url_path="/home/events/someone-elses-event/")

        user_perms = UserPagePermissionsProxy(user)
        editable_pages = user_perms.editable_pages()
        can_edit_pages = user_perms.can_edit_pages()
        publishable_pages = user_perms.publishable_pages()
        can_publish_pages = user_perms.can_publish_pages()

        self.assertFalse(editable_pages.filter(id=homepage.id).exists())
        self.assertFalse(editable_pages.filter(id=christmas_page.id).exists())
        self.assertFalse(
            editable_pages.filter(id=unpublished_event_page.id).exists())
        self.assertFalse(
            editable_pages.filter(id=someone_elses_event_page.id).exists())

        self.assertFalse(can_edit_pages)

        self.assertFalse(publishable_pages.filter(id=homepage.id).exists())
        self.assertFalse(
            publishable_pages.filter(id=christmas_page.id).exists())
        self.assertFalse(
            publishable_pages.filter(id=unpublished_event_page.id).exists())
        self.assertFalse(
            publishable_pages.filter(id=someone_elses_event_page.id).exists())

        self.assertFalse(can_publish_pages)
Example #28
0
    def get_context_data(self, parent_context):
        context = super().get_context_data(parent_context)
        user_perms = UserPagePermissionsProxy(self.request.user)

        if self.page.id:
            context.update({
                "lock_url":
                reverse("wagtailadmin_pages:lock", args=(self.page.id, )),
                "unlock_url":
                reverse("wagtailadmin_pages:unlock", args=(self.page.id, )),
                "user_can_lock":
                user_perms.for_page(self.page).can_lock(),
                "user_can_unlock":
                user_perms.for_page(self.page).can_unlock(),
                "locale":
                None,
                "translations": [],
            })
        else:
            context.update({
                "locale": None,
                "translations": [],
            })

        if getattr(settings, "WAGTAIL_I18N_ENABLED", False):
            context.update({
                "locale":
                self.page.locale,
                "translations":
                [{
                    "locale":
                    translation.locale,
                    "url":
                    reverse("wagtailadmin_pages:edit", args=[translation.id]),
                } for translation in self.page.get_translations().only(
                    "id", "locale", "depth").select_related("locale")
                 if user_perms.for_page(translation).can_edit()],
            })

        return context
Example #29
0
    def test_explorable_pages(self):
        event_editor = get_user_model().objects.get(
            email="*****@*****.**")
        christmas_page = EventPage.objects.get(
            url_path="/home/events/christmas/")
        unpublished_event_page = EventPage.objects.get(
            url_path="/home/events/tentative-unpublished-event/")
        someone_elses_event_page = EventPage.objects.get(
            url_path="/home/events/someone-elses-event/")
        about_us_page = Page.objects.get(url_path="/home/about-us/")

        user_perms = UserPagePermissionsProxy(event_editor)
        explorable_pages = user_perms.explorable_pages()

        # Verify all pages below /home/events/ are explorable
        self.assertTrue(explorable_pages.filter(id=christmas_page.id).exists())
        self.assertTrue(
            explorable_pages.filter(id=unpublished_event_page.id).exists())
        self.assertTrue(
            explorable_pages.filter(id=someone_elses_event_page.id).exists())

        # Verify page outside /events/ tree are not explorable
        self.assertFalse(explorable_pages.filter(id=about_us_page.id).exists())
Example #30
0
    def test_lock_page_for_superuser(self):
        user = get_user_model().objects.get(email="*****@*****.**")
        christmas_page = EventPage.objects.get(
            url_path="/home/events/christmas/")
        locked_page = Page.objects.get(url_path="/home/my-locked-page/")

        perms = UserPagePermissionsProxy(user).for_page(christmas_page)
        locked_perms = UserPagePermissionsProxy(user).for_page(locked_page)

        self.assertTrue(perms.can_lock())
        self.assertFalse(
            locked_perms.can_unpublish())  # locked pages can't be unpublished
        self.assertTrue(perms.can_unlock())