Reputation: 332
I'm creating a wagtail site where users may signup, login to the wagtail admin and write article pages to publish. Is there a hook or possible way to intercept and filter data in the wagtail admin so that users see only the article pages they themselves created?
So far I've set up user registration with django-allauth and users are able to successfully login. Once registered the user_signed_up receiver fires and the user is assigned to the 'Author' role. In the admin, author's only have access to add articles. Articles is an app with an article index page and article page (basically a blog and blog index page). Once they login the only thing they see is the Pages tab on the left, clicking on that takes them to the 'Articles' list. This is where they are able to add an 'Article' page and view their articles created so far.
It's also where my problem is. From the Articles list page, the users are able to see all the articles created by all users on the site. They are only able to edit their own which is great, but eventually there will be hundreds of articles from others users. Is there a way to intercept the 'Articles' data before its displayed and filter it by the current user?
The result of intercepting this data would then keep each user that is logged in to the wagtail admin aware of only the article pages that they have created.
Much thanks, it's my first time using Wagtail and I'm enjoying it so far.
Upvotes: 4
Views: 2934
Reputation: 123
Thanks to both @Pahikua and @Igor Margitich. I was able to combine their answers into a beautiful arrangement which was exactly what I wanted.
from wagtail.core import hooks
from django.core.exceptions import PermissionDenied
from django.views.defaults import permission_denied
from .models import Article
@hooks.register('before_edit_page')
def before_edit_page(request, page):
# user_group = request.user.groups.filter(name='Author').exists() # I did not use user_group
if not (request.user.is_superuser or page.owner == request.user):
return permission_denied(request, PermissionDenied("You do not have permission to edit this page."))
@hooks.register('before_delete_page')
def before_delete_page(request, page):
if not (request.user.is_superuser or page.owner == request.user):
return permission_denied(request,PermissionDenied("You do not have permission to delete this page."))
@hooks.register('before_create_page')
def before_create_page(request, parent_page, page_class):
if not (request.user.is_superuser or page_class == Article):
return permission_denied(request, PermissionDenied("You do not have permission to add this page."))
Upvotes: 0
Reputation: 53
@Pahikua be aware that method 2 just hides the pages from the list and does not protect pages from editing and deleting. In your case it means that Author1 can open url like pages/id/edit/ where id is id of the page owned by Author2 and edit it.
To avoid this you have to add before_edit_page and before_delete_page hooks. Something like this:
@hooks.register('before_edit_page')
def before_edit_page(request, page):
user_group = request.user.groups.filter(name='Author').exists()
if user_group and page.owner != request.user:
raise PermissionDenied
Upvotes: 0
Reputation: 332
I discovered two different solutions to this question.
I'll go over how I handled each of the above methods. Both worked, it's a matter of deciding whether I prefer to use Wagtails built in page explorer or not.
Method 1: ModelAdmin
The use of ModelAdmin.get_queryset() and other helpful methods were found in the Wagtail Docs here.
As per this page in the Wagtail docs I added ModelAdmin to INSTALLED_APPS:
# base.py settings
INSTALLED_APPS = [
...
'wagtail.contrib.modeladmin',
]
Then I created a file named wagtail_hooks.py in my 'article' app. In that file I added the code to create my article listing page in the admin:
# wagtail_hooks.py
from wagtail.contrib.modeladmin.options import (ModelAdmin, modeladmin_register)
from .models import Article
class ArticleAdmin(ModelAdmin):
model = Article
menu_label = 'Articles'
menu_icon = 'doc-full-inverse'
menu_order = 000
add_to_settings_menu = False
exclude_from_explorer = False
list_display = ('title', 'owner')
search_fields = ('title', 'owner')
def get_queryset(self, request):
qs = super().get_queryset(request)
#only show articles from the current user
return qs.filter(owner=request.user)
modeladmin_register(ArticleAdmin)
They key here was to implement ModelAdmin.get_queryset() which let me filter the articles owner.
You'll also likely want to remove the Page explorer menu item as it's a bit redundant. I also recommend implementing Method 2 below as well. Even if you remove the Page explorer menu item the user could possibly get there by entering the URL directly in the browser. If they do, implementing Method 2 will ensure the do not see content authored by other users.
Method 2: construct_explorer_page_queryset @hooks
The hook information in Wagtail's documentation - construct_explorer_page_queryset Also referenced this Google Groups article - https://groups.google.com/forum/#!topic/wagtail/10tcq8PB8io
In the same wagtail_hooks.py file I created above I added this code:
@hooks.register('construct_explorer_page_queryset')
def show_authors_only_their_articles(parent_page, pages, request):
user_group = request.user.groups.filter(name='Author').exists()
if user_group:
pages = pages.filter(owner=request.user)
return pages
That's it for the second method.
Upvotes: 5