Repository: wagtail/wagtail

Issue:
"Sort menu order" button even with missing permissions
### Issue Summary

Currently, the "Sort menu order"-button in the "more buttons"-dropdown is shown to users, which aren't allowed to change the order. Normally that's not a big issue, because clicking the link, which appends `?ordering=ord`, doesn't allow the user to change the order (drag&drop). But it still triggers the adapted view where all pages are rendered in one listing, so that could be avoided.

**Possible fix:**
I think this line https://github.com/wagtail/wagtail/blob/d308d6930a728208281cbfa426fe066951ca6736/wagtail/admin/wagtail_hooks.py#L353

should be changed to `if is_parent and page_perms.can_reorder_children():`

### Steps to Reproduce

1. Start a new project with `wagtail start myproject`
2. Create a page structure with some subpages which could be sorted.
3. Create an user and assign him to the existing "Editors" group. This group is not allowed to re-order the pages, because they cannot publish pages.
4. Login with that user and find the "Sort menu order"-button


### Technical details

* Wagtail version: 2.16.2



Discussion:

Resolving patch:
diff --git a/wagtail/admin/wagtail_hooks.py b/wagtail/admin/wagtail_hooks.py
--- a/wagtail/admin/wagtail_hooks.py
+++ b/wagtail/admin/wagtail_hooks.py
@@ -350,7 +350,7 @@ def page_listing_more_buttons(page, page_perms, is_parent=False, next_url=None):
             priority=50,
         )
 
-    if is_parent:
+    if is_parent and page_perms.can_reorder_children():
         yield Button(
             _("Sort menu order"),
             "?ordering=ord",


Test patch:
diff --git a/wagtail/admin/tests/test_buttons_hooks.py b/wagtail/admin/tests/test_buttons_hooks.py
--- a/wagtail/admin/tests/test_buttons_hooks.py
+++ b/wagtail/admin/tests/test_buttons_hooks.py
@@ -9,7 +9,7 @@
 from wagtail.test.utils import WagtailTestUtils
 
 
-class PagePerms:
+class BasePagePerms:
     def can_move(self):
         return False
 
@@ -17,7 +17,7 @@ def can_copy(self):
         return False
 
     def can_delete(self):
-        return True
+        return False
 
     def can_unpublish(self):
         return False
@@ -25,6 +25,19 @@ def can_unpublish(self):
     def can_view_revisions(self):
         return False
 
+    def can_reorder_children(self):
+        return False
+
+
+class DeleteOnlyPagePerms(BasePagePerms):
+    def can_delete(self):
+        return True
+
+
+class ReorderOnlyPagePerms(BasePagePerms):
+    def can_reorder_children(self):
+        return True
+
 
 class TestButtonsHooks(TestCase, WagtailTestUtils):
     def setUp(self):
@@ -144,7 +157,7 @@ def page_header_buttons(page, page_perms, next_url=None):
         self.assertContains(response, "Another useless header button")
 
     def test_delete_button_next_url(self):
-        page_perms = PagePerms()
+        page_perms = DeleteOnlyPagePerms()
         page = self.root_page
         base_url = reverse("wagtailadmin_pages:delete", args=[page.id])
 
@@ -168,3 +181,19 @@ def test_delete_button_next_url(self):
         )
 
         self.assertEqual(delete_button.url, base_url)
+
+    def test_reorder_button_visibility(self):
+        page = self.root_page
+        page_perms = BasePagePerms()
+
+        # no button returned
+        buttons = page_listing_more_buttons(page, page_perms, is_parent=True)
+        self.assertEqual(len(list(buttons)), 0)
+
+        page_perms = ReorderOnlyPagePerms()
+        # page_listing_more_button generator yields only `Sort menu order button`
+        reorder_button = next(
+            page_listing_more_buttons(page, page_perms, is_parent=True)
+        )
+
+        self.assertEqual(reorder_button.url, "?ordering=ord")