def register_unplanned_events(request, events): permissions = UserPagePermissionsProxy(request.user) # Only get the last revision of never published and unplanned pages queryset = ( PageRevision.objects.filter( page__first_published_at__isnull=True).order_by( 'page', '-created_at') # .distinct('page') # Doesn't work with sqlite ) pages = [] ids = set() for page in queryset: page = page.as_page_object() if page.go_live_at is not None: continue if page.pk in ids: continue # Avoid duplicated event ids.add(page.pk) pages.append({ 'id': page.pk, 'title': page.title, 'url': page.full_url, 'editable': permissions.for_page(page).can_publish(), 'color': '#e9b04d', 'stick': True, 'data': get_page_event_data(page), }) return events + pages
def test_editable_pages_for_non_editing_user(self): user = get_user_model().objects.get(username='******') 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)
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) page.unpublish() 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() messages.success(request, _("Page '{0}' unpublished.").format(page.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 render(request, 'wagtailadmin/pages/confirm_unpublish.html', { 'page': page, 'next': next_url, 'live_descendant_count': page.get_descendants().live().count(), })
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) page.unpublish() 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() 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 render( request, "wagtailadmin/pages/confirm_unpublish.html", {"page": page, "next": next_url, "live_descendant_count": page.get_descendants().live().count()}, )
def test_editable_pages_for_user_with_edit_permission(self): event_moderator = get_user_model().objects.get(username="******") 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(event_moderator) 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.assertTrue(editable_pages.filter(id=christmas_page.id).exists()) self.assertTrue(editable_pages.filter(id=unpublished_event_page.id).exists()) self.assertTrue(editable_pages.filter(id=someone_elses_event_page.id).exists()) self.assertTrue(can_edit_pages) self.assertFalse(publishable_pages.filter(id=homepage.id).exists()) self.assertTrue(publishable_pages.filter(id=christmas_page.id).exists()) self.assertTrue(publishable_pages.filter(id=unpublished_event_page.id).exists()) self.assertTrue(publishable_pages.filter(id=someone_elses_event_page.id).exists()) self.assertTrue(can_publish_pages)
def test_lock_page_for_moderator(self): user = get_user_model().objects.get(username='******') christmas_page = EventPage.objects.get(url_path='/home/events/christmas/') perms = UserPagePermissionsProxy(user).for_page(christmas_page) self.assertTrue(perms.can_lock())
def test_lock_page_for_non_editing_user(self): user = get_user_model().objects.get(username='******') christmas_page = EventPage.objects.get(url_path='/home/events/christmas/') perms = UserPagePermissionsProxy(user).for_page(christmas_page) self.assertFalse(perms.can_lock())
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) page.unpublish() 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() 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 render(request, 'wagtailadmin/pages/confirm_unpublish.html', { 'page': page, 'next': next_url, 'live_descendant_count': page.get_descendants().live().count(), })
def account(request): user_perms = UserPagePermissionsProxy(request.user) show_notification_preferences = user_perms.can_edit_pages() or user_perms.can_publish_pages() return render(request, 'wagtailadmin/account/account.html', { 'show_change_password': getattr(settings, 'WAGTAIL_PASSWORD_MANAGEMENT_ENABLED', True) and request.user.has_usable_password(), 'show_notification_preferences': show_notification_preferences })
def __init__(self, *args, **kwargs): super(NotificationPreferencesForm, self).__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']
def account(request): user_perms = UserPagePermissionsProxy(request.user) show_notification_preferences = user_perms.can_edit_pages() or user_perms.can_publish_pages() return render(request, 'wagtailadmin/account/account.html', { 'show_change_password': password_management_enabled() and request.user.has_usable_password(), 'show_notification_preferences': show_notification_preferences })
def test_lock_page_for_non_editing_user(self): user = get_user_model().objects.get(username='******') christmas_page = EventPage.objects.get( url_path='/home/events/christmas/') perms = UserPagePermissionsProxy(user).for_page(christmas_page) self.assertFalse(perms.can_lock())
def test_lock_page_for_moderator(self): user = get_user_model().objects.get(username='******') christmas_page = EventPage.objects.get( url_path='/home/events/christmas/') perms = UserPagePermissionsProxy(user).for_page(christmas_page) self.assertTrue(perms.can_lock())
def find_rca_now_index_page(user): """Look for the RCA Now index page: a page of type RcaNowIndex where this user can add pages""" user_perms = UserPagePermissionsProxy(user) for page in RcaNowIndex.objects.all(): if user_perms.for_page(page).can_add_subpage(): return page raise Exception('No usable RCA Now section found (using the RcaNowIndex page type and with add permission for students)')
def find_student_index_page(user): """Look for the student index page: a page of type StandardIndex with slug "students" where this user can add pages""" user_perms = UserPagePermissionsProxy(user) for page in StandardIndex.objects.filter(slug='students'): if user_perms.for_page(page).can_add_subpage(): return page raise Exception('No usable student index found (using the StandardIndex page type and with add permission for students)')
def test_lock_page_for_superuser(self): user = get_user_model().objects.get(username='******') 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
def find_rca_now_index_page(user): """Look for the RCA Now index page: a page of type RcaNowIndex where this user can add pages""" user_perms = UserPagePermissionsProxy(user) for page in RcaNowIndex.objects.all(): if user_perms.for_page(page).can_add_subpage(): return page raise Exception( 'No usable RCA Now section found (using the RcaNowIndex page type and with add permission for students)' )
def find_student_index_page(user): """Look for the student index page: a page of type StandardIndex with slug "students" where this user can add pages""" user_perms = UserPagePermissionsProxy(user) for page in StandardIndex.objects.filter(slug='students'): if user_perms.for_page(page).can_add_subpage(): return page raise Exception( 'No usable student index found (using the StandardIndex page type and with add permission for students)' )
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
def test_editable_pages_for_superuser(self): user = User.objects.get(username='******') 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/') editable_pages = UserPagePermissionsProxy(user).editable_pages() self.assertTrue(editable_pages.filter(id=homepage.id).exists()) self.assertTrue(editable_pages.filter(id=christmas_page.id).exists()) self.assertTrue(editable_pages.filter(id=unpublished_event_page.id).exists()) self.assertTrue(editable_pages.filter(id=someone_elses_event_page.id).exists())
def __init__(self, request): super(MultitenantPagesForModerationPanel, self).__init__(request) # Restrict the list to Pages on the current Site. self.page_revisions_for_moderation = (UserPagePermissionsProxy( request.user).revisions_for_moderation().select_related( 'page', 'user').filter(page__in=Page.objects.in_site( request.site)).order_by('-created_at'))
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
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(username='******') permission_proxy = UserPagePermissionsProxy(event_editor) result = can_choose_page(homepage, permission_proxy, self.desired_classes, user_perm='copy_to') self.assertFalse(result)
def register_published_events(request, start, end, events): permissions = UserPagePermissionsProxy(request.user) queryset = Page.objects.filter(first_published_at__isnull=False) if start is not None: queryset = queryset.filter(first_published_at__gte=start) if end is not None: queryset = queryset.filter(first_published_at__lte=end) queryset = queryset.specific() return events + [{ 'id': page.pk, 'title': page.title, 'start': page.first_published_at.isoformat(), 'url': page.full_url, 'editable': permissions.for_page(page).can_unpublish(), 'color': '#333', 'data': get_page_event_data(page), } for page in queryset]
def register_planned_events(request, start, end, events): permissions = UserPagePermissionsProxy(request.user) # Only get the last revision of never published and planned pages queryset = ( PageRevision.objects.filter( page__first_published_at__isnull=True).order_by( 'page', '-created_at') # .distinct('page') # Doesn't work with sqlite ) if start is not None: start = parse_datetime(start) if end is not None: end = parse_datetime(end) pages = [] ids = set() for page in queryset: page = page.as_page_object() if page.go_live_at is None: continue if start is not None and start > page.go_live_at: continue if end is not None and end < page.go_live_at: continue if page.pk in ids: continue # Avoid duplicated event # Determine event color color = '#e9b04d' if page.expired: color = '#f37e77' elif page.approved_schedule: color = '#358c8b' ids.add(page.pk) pages.append({ 'id': page.pk, 'title': page.title, 'start': page.go_live_at.isoformat(), 'url': page.get_url(request), 'editable': permissions.for_page(page).can_publish(), 'color': color, 'data': get_page_event_data(page), }) return events + pages
def push_to_intranet(request, page_id): # Get page page = get_object_or_404(Page, id=page_id) # User must have publish permission user_perms = UserPagePermissionsProxy(request.user) page_perms = user_perms.for_page(page) if not page_perms.can_publish(): raise PermissionDenied if request.method == "POST": # Perform request url = settings.INTRANET_PUSH_URL.format( type=page._meta.app_label + '.' + page.__class__.__name__, id=page.id, ) response = requests.post(url) if response.status_code == 200: intranet_url = response.json()['public_url'] # Success message message = "Successfully pushed '{0}' to the intranet.".format( page.title) messages.success(request, message, buttons=[ messages.button(intranet_url, 'View on intranet'), ]) else: # Error message message = "Error received while pushing '{0}' to the intranet. (status code: {1})".format( page.title, request.status_code) messages.error(request, message) return redirect('wagtailadmin_explore', page.get_parent().id) return render(request, 'rca/admin/push_to_intranet.html', { 'page': page, })
def test_editable_pages_for_non_editing_user(self): user = get_user_model().objects.get(username='******') 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)
def test_editable_pages_for_user_with_edit_permission(self): event_moderator = User.objects.get(username='******') 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(event_moderator) 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.assertTrue(editable_pages.filter(id=christmas_page.id).exists()) self.assertTrue( editable_pages.filter(id=unpublished_event_page.id).exists()) self.assertTrue( editable_pages.filter(id=someone_elses_event_page.id).exists()) self.assertTrue(can_edit_pages) self.assertFalse(publishable_pages.filter(id=homepage.id).exists()) self.assertTrue( publishable_pages.filter(id=christmas_page.id).exists()) self.assertTrue( publishable_pages.filter(id=unpublished_event_page.id).exists()) self.assertTrue( publishable_pages.filter(id=someone_elses_event_page.id).exists()) self.assertTrue(can_publish_pages)
def push_to_intranet(request, page_id): # Get page page = get_object_or_404(Page, id=page_id) # User must have publish permission user_perms = UserPagePermissionsProxy(request.user) page_perms = user_perms.for_page(page) if not page_perms.can_publish(): raise PermissionDenied if request.method == "POST": # Perform request url = settings.INTRANET_PUSH_URL.format( type=page._meta.app_label + '.' + page.__class__.__name__, id=page.id, ) response = requests.post(url) if response.status_code == 200: intranet_url = response.json()['public_url'] # Success message message = "Successfully pushed '{0}' to the intranet.".format(page.title) messages.success(request, message, buttons=[ messages.button( intranet_url, 'View on intranet' ), ]) else: # Error message message = "Error received while pushing '{0}' to the intranet. (status code: {1})".format(page.title, request.status_code) messages.error(request, message) return redirect('wagtailadmin_explore', page.get_parent().id) return render(request, 'rca/admin/push_to_intranet.html', { 'page': page, })
def page_permissions(context, page): """ Usage: {% page_permissions page as page_perms %} Sets the variable 'page_perms' to a PagePermissionTester object that can be queried to find out what actions the current logged-in user can perform on the given page. """ # 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) # Now retrieve a PagePermissionTester from it, specific to the given page return context['user_page_permissions'].for_page(page)
def test_lock_page_for_superuser(self): user = get_user_model().objects.get(username='******') 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
def test_editable_pages_for_superuser(self): user = User.objects.get(username='******') 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/') editable_pages = UserPagePermissionsProxy(user).editable_pages() self.assertTrue(editable_pages.filter(id=homepage.id).exists()) self.assertTrue(editable_pages.filter(id=christmas_page.id).exists()) self.assertTrue( editable_pages.filter(id=unpublished_event_page.id).exists()) self.assertTrue( editable_pages.filter(id=someone_elses_event_page.id).exists())
def get_forms_for_user(user): """ Return a queryset of form pages that this user is allowed to access the submissions for """ editable_pages = UserPagePermissionsProxy(user).editable_pages() return editable_pages.filter(content_type__in=get_form_types())
def __init__(self, request): self.request = request user_perms = UserPagePermissionsProxy(request.user) self.page_revisions_for_moderation = ( user_perms.revisions_for_moderation().select_related("page", "user").order_by("-created_at") )
def setUp(self): self.user = self.login() self.permission_proxy = UserPagePermissionsProxy(self.user) self.desired_classes = (Page, )
def browse(request, parent_page_id=None): # A missing or empty page_type parameter indicates 'all page types' # (i.e. descendants of wagtailcore.page) page_type_string = request.GET.get('page_type') or 'wagtailcore.page' user_perm = request.GET.get('user_perms', False) try: desired_classes = page_models_from_string(page_type_string) except (ValueError, LookupError): raise Http404 # Find parent page if parent_page_id: parent_page = get_object_or_404(Page, id=parent_page_id) elif desired_classes == (Page,): # Just use the root page parent_page = Page.get_first_root_node() else: # Find the highest common ancestor for the specific classes passed in # In many cases, such as selecting an EventPage under an EventIndex, # this will help the administrator find their page quicker. all_desired_pages = filter_page_type(Page.objects.all(), desired_classes) parent_page = all_desired_pages.first_common_ancestor() # Get children of parent page pages = parent_page.get_children().specific() # allow hooks to modify the queryset for hook in hooks.get_hooks('construct_page_chooser_queryset'): pages = hook(pages, request) # Filter them by page type if desired_classes != (Page,): # restrict the page listing to just those pages that: # - are of the given content type (taking into account class inheritance) # - or can be navigated into (i.e. have children) choosable_pages = filter_page_type(pages, desired_classes) descendable_pages = pages.filter(numchild__gt=0) pages = choosable_pages | descendable_pages can_choose_root = request.GET.get('can_choose_root', False) # Do permission lookups for this user now, instead of for every page. permission_proxy = UserPagePermissionsProxy(request.user) # Parent page can be chosen if it is a instance of desired_classes parent_page.can_choose = can_choose_page( parent_page, permission_proxy, desired_classes, can_choose_root, user_perm) # Pagination # We apply pagination first so we don't need to walk the entire list # in the block below paginator, pages = paginate(request, pages, per_page=25) # Annotate each page with can_choose/can_decend flags for page in pages: page.can_choose = can_choose_page(page, permission_proxy, desired_classes, can_choose_root, user_perm) page.can_descend = page.get_children_count() # Render return render_modal_workflow( request, 'wagtailadmin/chooser/browse.html', 'wagtailadmin/chooser/browse.js', shared_context(request, { 'parent_page': parent_page, 'parent_page_id': parent_page.pk, 'pages': pages, 'search_form': SearchForm(), 'page_type_string': page_type_string, 'page_type_names': [desired_class.get_verbose_name() for desired_class in desired_classes], 'page_types_restricted': (page_type_string != 'wagtailcore.page') }) )
def get_forms_for_user(user): """Return a queryset of form pages that this user is allowed to access the submissions for""" editable_pages = UserPagePermissionsProxy(user).editable_pages() return editable_pages.filter(content_type__in=get_form_types())
def __init__(self, request): self.request = request user_perms = UserPagePermissionsProxy(request.user) self.page_revisions_for_moderation = (user_perms.revisions_for_moderation() .select_related('page', 'user').order_by('-created_at'))
def __init__(self, request): self.request = request user_perms = UserPagePermissionsProxy(request.user) self.page_revisions_for_moderation = user_perms.revisions_for_moderation().select_related('page', 'user').order_by('-created_at')