Ejemplo n.º 1
0
def move_confirm(request, page_to_move_id, destination_id):
    page_to_move = get_object_or_404(Page, id=page_to_move_id).specific
    # Needs .specific_deferred because the .get_admin_display_title method is called in template
    destination = get_object_or_404(Page, id=destination_id).specific_deferred

    if not Page._slug_is_available(
            page_to_move.slug, destination, page=page_to_move):
        messages.error(
            request,
            _("The slug '{0}' is already in use at the selected parent page. Make sure the slug is unique and try again"
              ).format(page_to_move.slug),
        )
        return redirect(
            "wagtailadmin_pages:move_choose_destination",
            page_to_move.id,
            destination.id,
        )

    for fn in hooks.get_hooks("before_move_page"):
        result = fn(request, page_to_move, destination)
        if hasattr(result, "status_code"):
            return result

    if request.method == "POST":
        # any invalid moves *should* be caught by the permission check in the action class,
        # so don't bother to catch InvalidMoveToDescendant
        action = MovePageAction(page_to_move,
                                destination,
                                pos="last-child",
                                user=request.user)
        action.execute()

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

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

        return redirect("wagtailadmin_explore", destination.id)

    return TemplateResponse(
        request,
        "wagtailadmin/pages/confirm_move.html",
        {
            "page_to_move": page_to_move,
            "destination": destination,
        },
    )
Ejemplo n.º 2
0
def delete(request, user_id):
    user = get_object_or_404(User, pk=user_id)

    if not user_can_delete_user(request.user, user):
        raise PermissionDenied

    for fn in hooks.get_hooks("before_delete_user"):
        result = fn(request, user)
        if hasattr(result, "status_code"):
            return result
    if request.method == "POST":
        with transaction.atomic():
            log(user, "wagtail.delete")
            user.delete()
        messages.success(request, _("User '{0}' deleted.").format(user))
        for fn in hooks.get_hooks("after_delete_user"):
            result = fn(request, user)
            if hasattr(result, "status_code"):
                return result
        return redirect("wagtailusers_users:index")

    return TemplateResponse(
        request,
        "wagtailusers/users/confirm_delete.html",
        {
            "user": user,
        },
    )
Ejemplo n.º 3
0
def edit(request, user_id):
    user = get_object_or_404(User, pk=user_id)
    can_delete = user_can_delete_user(request.user, user)
    editing_self = request.user == user

    for fn in hooks.get_hooks("before_edit_user"):
        result = fn(request, user)
        if hasattr(result, "status_code"):
            return result
    if request.method == "POST":
        form = get_user_edit_form()(request.POST,
                                    request.FILES,
                                    instance=user,
                                    editing_self=editing_self)
        if form.is_valid():
            with transaction.atomic():
                user = form.save()
                log(user, "wagtail.edit")

            if user == request.user and "password1" in form.changed_data:
                # User is changing their own password; need to update their session hash
                update_session_auth_hash(request, user)

            messages.success(
                request,
                _("User '{0}' updated.").format(user),
                buttons=[
                    messages.button(
                        reverse("wagtailusers_users:edit", args=(user.pk, )),
                        _("Edit"))
                ],
            )
            for fn in hooks.get_hooks("after_edit_user"):
                result = fn(request, user)
                if hasattr(result, "status_code"):
                    return result
            return redirect("wagtailusers_users:index")
        else:
            messages.error(request,
                           _("The user could not be saved due to errors."))
    else:
        form = get_user_edit_form()(instance=user, editing_self=editing_self)

    return TemplateResponse(
        request,
        "wagtailusers/users/edit.html",
        {
            "user": user,
            "form": form,
            "can_delete": can_delete,
        },
    )
Ejemplo n.º 4
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(),
        },
    )
Ejemplo n.º 5
0
def page_listing_buttons(context, page, page_perms, is_parent=False):
    next_url = context.request.path
    button_hooks = hooks.get_hooks("register_page_listing_buttons")

    buttons = []
    for hook in button_hooks:
        buttons.extend(hook(page, page_perms, is_parent, next_url))

    buttons.sort()

    for hook in hooks.get_hooks("construct_page_listing_buttons"):
        hook(buttons, page, page_perms, is_parent, context)

    return {"page": page, "buttons": buttons}
Ejemplo n.º 6
0
def snippet_listing_buttons(context, snippet):
    next_url = context["request"].path
    button_hooks = hooks.get_hooks("register_snippet_listing_buttons")

    buttons = []
    for hook in button_hooks:
        buttons.extend(hook(snippet, context["request"].user, next_url))

    buttons.sort()

    for hook in hooks.get_hooks("construct_snippet_listing_buttons"):
        hook(buttons, snippet, context["request"].user, context)

    return {"snippet": snippet, "buttons": buttons}
Ejemplo n.º 7
0
def _get_base_page_action_menu_items():
    """
    Retrieve the global list of menu items for the page action menu,
    which may then be customised on a per-request basis
    """
    global BASE_PAGE_ACTION_MENU_ITEMS

    if BASE_PAGE_ACTION_MENU_ITEMS is None:
        BASE_PAGE_ACTION_MENU_ITEMS = [
            SaveDraftMenuItem(order=0),
            DeleteMenuItem(order=10),
            LockMenuItem(order=15),
            UnlockMenuItem(order=15),
            UnpublishMenuItem(order=20),
            PublishMenuItem(order=30),
            CancelWorkflowMenuItem(order=40),
            RestartWorkflowMenuItem(order=50),
            SubmitForModerationMenuItem(order=60),
            PageLockedMenuItem(order=10000),
        ]
        for hook in hooks.get_hooks("register_page_action_menu_item"):
            action_menu_item = hook()
            if action_menu_item:
                BASE_PAGE_ACTION_MENU_ITEMS.append(action_menu_item)

    return BASE_PAGE_ACTION_MENU_ITEMS
Ejemplo n.º 8
0
def for_moderation(request, revision_id):
    items = [
        EditPageItem(
            Revision.page_revisions.get(id=revision_id).content_object),
        AddPageItem(
            Revision.page_revisions.get(id=revision_id).content_object),
        ApproveModerationEditPageItem(
            Revision.page_revisions.get(id=revision_id)),
        RejectModerationEditPageItem(
            Revision.page_revisions.get(id=revision_id)),
    ]

    for fn in hooks.get_hooks("construct_wagtail_userbar"):
        fn(request, items)

    # Render the items
    rendered_items = [item.render(request) for item in items]

    # Remove any unrendered items
    rendered_items = [item for item in rendered_items if item]

    # Render the edit bird
    return TemplateResponse(
        request,
        "wagtailadmin/userbar/base.html",
        {
            "items": rendered_items,
        },
    )
Ejemplo n.º 9
0
def page_header_buttons(context, page, page_perms):
    next_url = context.request.path
    button_hooks = hooks.get_hooks("register_page_header_buttons")

    buttons = []
    for hook in button_hooks:
        buttons.extend(hook(page, page_perms, next_url))

    buttons.sort()
    return {
        "page": page,
        "buttons": buttons,
        "title": _("Actions"),
        "icon_name": "ellipsis-v",
        "classes": [
            "w-flex",
            "w-justify-center",
            "w-items-center",
            "w-h-full",
            "w-ml-1",
        ],
        "button_classes": [
            "w-p-0",
            "w-w-12",
            "w-h-12",
            "w-text-primary",
            "w-bg-transparent",
            "hover:w-scale-110",
            "w-transition",
            "w-outline-offset-inside",
            "w-relative",
            "w-z-30",
        ],
        "hide_title": True,
    }
Ejemplo n.º 10
0
    def test_after_hook(self):
        def after_hook():
            pass

        with self.register_hook("test_hook_name", after_hook, order=1):
            hook_fns = hooks.get_hooks("test_hook_name")
            self.assertEqual(hook_fns, [test_hook, after_hook])
Ejemplo n.º 11
0
    def get(self, request):
        self.image_model = get_image_model()

        images = permission_policy.instances_user_has_any_permission_for(
            request.user, ["choose"]).order_by("-created_at")

        # allow hooks to modify the queryset
        for hook in hooks.get_hooks("construct_image_chooser_queryset"):
            images = hook(images, request)

        collection_id = request.GET.get("collection_id")
        if collection_id:
            images = images.filter(collection=collection_id)

        self.is_searching = False
        self.q = None

        if "q" in request.GET:
            self.search_form = SearchForm(request.GET)
            if self.search_form.is_valid():
                self.q = self.search_form.cleaned_data["q"]
                self.is_searching = True
                images = images.search(self.q)
        else:
            self.search_form = SearchForm()

        if not self.is_searching:
            tag_name = request.GET.get("tag")
            if tag_name:
                images = images.filter(tags__name=tag_name)

        # Pagination
        paginator = Paginator(images, per_page=CHOOSER_PAGE_SIZE)
        self.images = paginator.get_page(request.GET.get("p"))
        return self.render_to_response()
Ejemplo n.º 12
0
    def test_before_hook(self):
        def before_hook():
            pass

        with self.register_hook("test_hook_name", before_hook, order=-1):
            hook_fns = hooks.get_hooks("test_hook_name")
            self.assertEqual(hook_fns, [before_hook, test_hook])
Ejemplo n.º 13
0
    def __init__(self, request, **kwargs):
        self.request = request
        self.context = kwargs
        self.context["request"] = request

        if "instance" in self.context:
            self.context["model"] = self.context["instance"].__class__

        self.context["draftstate_enabled"] = issubclass(
            self.context["model"], DraftStateMixin)

        self.menu_items = [
            menu_item for menu_item in get_base_snippet_action_menu_items(
                self.context["model"]) if menu_item.is_shown(self.context)
        ]

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

        for hook in hooks.get_hooks("construct_snippet_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
Ejemplo n.º 14
0
def home(request):

    panels = [
        SiteSummaryPanel(request),
        UpgradeNotificationPanel(),
        WorkflowPagesToModeratePanel(),
        PagesForModerationPanel(),
        UserPagesInWorkflowModerationPanel(),
        RecentEditsPanel(),
        LockedPagesPanel(),
    ]

    for fn in hooks.get_hooks("construct_homepage_panels"):
        fn(request, panels)

    media = Media()

    for panel in panels:
        media += panel.media

    site_details = get_site_for_user(request.user)

    return TemplateResponse(
        request,
        "wagtailadmin/home.html",
        {
            "root_page": site_details["root_page"],
            "root_site": site_details["root_site"],
            "site_name": site_details["site_name"],
            "panels": sorted(panels, key=lambda p: p.order),
            "user": request.user,
            "media": media,
        },
    )
Ejemplo n.º 15
0
 def __init__(self, request):
     self.request = request
     summary_items = []
     for fn in hooks.get_hooks("construct_homepage_summary_items"):
         fn(request, summary_items)
     self.summary_items = [s for s in summary_items if s.is_shown()]
     self.summary_items.sort(key=lambda p: p.order)
Ejemplo n.º 16
0
 def __init__(self, *args, **kwargs):
     super().__init__(*args, **kwargs)
     self.registered_permissions = Permission.objects.none()
     for fn in hooks.get_hooks("register_permissions"):
         self.registered_permissions = self.registered_permissions | fn()
     self.fields[
         "permissions"].queryset = self.registered_permissions.select_related(
             "content_type")
Ejemplo n.º 17
0
 def test_page_tree_sync_off(self):
     with hooks.register_temporarily(
             "construct_translated_pages_to_cascade_actions",
             self.unpublish_hook):
         for fn in hooks.get_hooks(
                 "construct_translated_pages_to_cascade_actions"):
             response = fn([self.en_homepage], "unpublish")
             self.assertIsNone(response)
Ejemplo n.º 18
0
    def get_object_list(self):
        documents = self.permission_policy.instances_user_has_any_permission_for(
            self.request.user, ["choose"])
        # allow hooks to modify the queryset
        for hook in hooks.get_hooks("construct_document_chooser_queryset"):
            documents = hook(documents, self.request)

        return documents
Ejemplo n.º 19
0
def get_permission_panel_classes():
    global _permission_panel_classes
    if _permission_panel_classes is None:
        _permission_panel_classes = [GroupPagePermissionFormSet]
        for fn in hooks.get_hooks("register_group_permission_panel"):
            _permission_panel_classes.append(fn())

    return _permission_panel_classes
Ejemplo n.º 20
0
    def _scan_for_serializers(self):
        serializers = dict(self.BASE_SERIALIZERS_BY_MODEL_CLASS)

        for fn in hooks.get_hooks('register_custom_serializers'):
            serializers.update(fn())

        self.serializers_by_model_class = serializers
        self._scanned_for_serializers = True
Ejemplo n.º 21
0
 def populate(self):
     for fn in hooks.get_hooks("register_admin_viewset"):
         viewset = fn()
         if isinstance(viewset, (list, tuple)):
             for vs in viewset:
                 self.register(vs)
         else:
             self.register(viewset)
Ejemplo n.º 22
0
    def _scan_for_adapters(self):
        adapters = dict(self.BASE_ADAPTERS_BY_FIELD_CLASS)

        for fn in hooks.get_hooks('register_field_adapters'):
            adapters.update(fn())

        self.adapters_by_field_class = adapters
        self._scanned_for_adapters = True
Ejemplo n.º 23
0
 def test_missing_hook_action(self):
     with hooks.register_temporarily(
             "construct_translated_pages_to_cascade_actions",
             self.missing_hook_action):
         for fn in hooks.get_hooks(
                 "construct_translated_pages_to_cascade_actions"):
             response = fn([self.en_homepage], "")
             if response is not None:
                 self.assertIsInstance(response, dict)
Ejemplo n.º 24
0
 def test_registered_permission(self):
     permission = Permission.objects.get_by_natural_key(
         app_label="tests", model="testsetting", codename="change_testsetting"
     )
     for fn in hooks.get_hooks("register_permissions"):
         if permission in fn():
             break
     else:
         self.fail("Change permission for tests.TestSetting not registered")
Ejemplo n.º 25
0
 def run_hook(self, hook_name, *args, **kwargs):
     """
     Run the named hook, passing args and kwargs to each function registered under that hook name.
     If any return an HttpResponse, stop processing and return that response
     """
     for fn in hooks.get_hooks(hook_name):
         result = fn(*args, **kwargs)
         if hasattr(result, "status_code"):
             return result
Ejemplo n.º 26
0
    def dropdown_buttons(self):
        button_hooks = hooks.get_hooks(self.hook_name)

        buttons = []
        for hook in button_hooks:
            buttons.extend(hook(self.page, self.page_perms, self.next_url))

        buttons.sort()
        return buttons
Ejemplo n.º 27
0
    def filter_object_list(self, objects):
        if self.construct_queryset_hook_name:
            # allow hooks to modify the queryset
            for hook in hooks.get_hooks(self.construct_queryset_hook_name):
                objects = hook(objects, self.request)

        if self.filter_form.is_valid():
            objects = self.filter_form.filter(objects)
        return objects
Ejemplo n.º 28
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
Ejemplo n.º 29
0
def hook_output(hook_name):
    """
    Example: {% hook_output 'insert_editor_css' %}
    Whenever we have a hook whose functions take no parameters and return a string, this tag can be used
    to output the concatenation of all of those return values onto the page.
    Note that the output is not escaped - it is the hook function's responsibility to escape unsafe content.
    """
    snippets = [fn() for fn in hooks.get_hooks(hook_name)]
    return mark_safe("".join(snippets))
Ejemplo n.º 30
0
    def filter_queryset(self, request, queryset, view):
        if not hasattr(queryset, '_filtered_by_child_of'):
            raise BadRequestError(
                "filtering 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)

        return queryset