wagtail 6.2.2__py3-none-any.whl → 6.3rc2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (386) hide show
  1. wagtail/__init__.py +1 -1
  2. wagtail/actions/copy_for_translation.py +6 -0
  3. wagtail/actions/publish_revision.py +3 -3
  4. wagtail/admin/action_menu.py +5 -3
  5. wagtail/admin/forms/account.py +1 -1
  6. wagtail/admin/icons.py +2 -6
  7. wagtail/admin/locale/cy/LC_MESSAGES/django.mo +0 -0
  8. wagtail/admin/locale/cy/LC_MESSAGES/django.po +32 -0
  9. wagtail/admin/locale/dv/LC_MESSAGES/django.mo +0 -0
  10. wagtail/admin/locale/dv/LC_MESSAGES/django.po +28 -0
  11. wagtail/admin/locale/en/LC_MESSAGES/django.po +451 -485
  12. wagtail/admin/locale/en/LC_MESSAGES/djangojs.po +7 -7
  13. wagtail/admin/locale/sl/LC_MESSAGES/django.mo +0 -0
  14. wagtail/admin/locale/sl/LC_MESSAGES/django.po +150 -0
  15. wagtail/admin/locale/sl/LC_MESSAGES/djangojs.mo +0 -0
  16. wagtail/admin/locale/sl/LC_MESSAGES/djangojs.po +9 -2
  17. wagtail/admin/locale/ug/LC_MESSAGES/django.mo +0 -0
  18. wagtail/admin/locale/ug/LC_MESSAGES/django.po +3250 -196
  19. wagtail/admin/localization.py +12 -2
  20. wagtail/admin/panels/model_utils.py +1 -1
  21. wagtail/admin/site_summary.py +0 -2
  22. wagtail/admin/static/wagtailadmin/css/core.css +1 -1
  23. wagtail/admin/static/wagtailadmin/css/panels/draftail.css +1 -1
  24. wagtail/admin/static/wagtailadmin/images/email-header.jpg +0 -0
  25. wagtail/admin/static/wagtailadmin/js/bulk-actions.js +1 -1
  26. wagtail/admin/static/wagtailadmin/js/core.js +1 -1
  27. wagtail/admin/static/wagtailadmin/js/core.js.LICENSE.txt +12 -0
  28. wagtail/admin/static/wagtailadmin/js/draftail.js +1 -1
  29. wagtail/admin/static/wagtailadmin/js/sidebar.js +1 -1
  30. wagtail/admin/static/wagtailadmin/js/telepath/telepath.js +1 -1
  31. wagtail/admin/static/wagtailadmin/js/telepath/widgets.js +1 -1
  32. wagtail/admin/static/wagtailadmin/js/userbar.js +1 -1
  33. wagtail/admin/static/wagtailadmin/js/userbar.js.LICENSE.txt +1 -1
  34. wagtail/admin/static/wagtailadmin/js/vendor.js +1 -1
  35. wagtail/admin/static/wagtailadmin/js/wagtailadmin.js +1 -1
  36. wagtail/admin/static/wagtailadmin/js/workflow-action.js +1 -1
  37. wagtail/admin/staticfiles.py +6 -4
  38. wagtail/admin/templates/wagtailadmin/account/account.html +42 -59
  39. wagtail/admin/templates/wagtailadmin/admin_base.html +0 -28
  40. wagtail/admin/templates/wagtailadmin/bulk_actions/footer.html +1 -1
  41. wagtail/admin/templates/wagtailadmin/chooser/_search_results.html +7 -5
  42. wagtail/admin/templates/wagtailadmin/chooser/tables/page_navigate_to_children_cell.html +1 -1
  43. wagtail/admin/templates/wagtailadmin/generic/chooser/results.html +7 -5
  44. wagtail/admin/templates/wagtailadmin/generic/edit.html +0 -8
  45. wagtail/admin/templates/wagtailadmin/generic/form.html +60 -17
  46. wagtail/admin/templates/wagtailadmin/generic/index.html +17 -0
  47. wagtail/admin/templates/wagtailadmin/generic/index_results.html +9 -35
  48. wagtail/admin/templates/wagtailadmin/generic/inspect.html +2 -21
  49. wagtail/admin/templates/wagtailadmin/generic/listing.html +11 -17
  50. wagtail/admin/templates/wagtailadmin/generic/listing_results.html +19 -1
  51. wagtail/admin/templates/wagtailadmin/home/account_summary.html +26 -0
  52. wagtail/admin/templates/wagtailadmin/home/locked_pages.html +28 -18
  53. wagtail/admin/templates/wagtailadmin/home/recent_edits.html +28 -17
  54. wagtail/admin/templates/wagtailadmin/home/site_summary_pages.html +2 -2
  55. wagtail/admin/templates/wagtailadmin/home/upgrade_notification.html +35 -13
  56. wagtail/admin/templates/wagtailadmin/home/user_objects_in_workflow_moderation.html +28 -18
  57. wagtail/admin/templates/wagtailadmin/home/workflow_objects_to_moderate.html +43 -32
  58. wagtail/admin/templates/wagtailadmin/home.html +22 -5
  59. wagtail/admin/templates/wagtailadmin/pages/_editor_js.html +0 -1
  60. wagtail/admin/templates/wagtailadmin/pages/action_menu/menu.html +1 -11
  61. wagtail/admin/templates/wagtailadmin/pages/action_menu/menu_item.html +1 -6
  62. wagtail/admin/templates/wagtailadmin/pages/action_menu/page_locked.html +1 -1
  63. wagtail/admin/templates/wagtailadmin/pages/action_menu/publish.html +1 -1
  64. wagtail/admin/templates/wagtailadmin/pages/action_menu/save_draft.html +1 -1
  65. wagtail/admin/templates/wagtailadmin/pages/bulk_actions/confirm_bulk_delete.html +12 -6
  66. wagtail/admin/templates/wagtailadmin/pages/bulk_actions/confirm_bulk_move.html +12 -7
  67. wagtail/admin/templates/wagtailadmin/pages/bulk_actions/confirm_bulk_publish.html +17 -11
  68. wagtail/admin/templates/wagtailadmin/pages/bulk_actions/confirm_bulk_unpublish.html +15 -9
  69. wagtail/admin/templates/wagtailadmin/pages/confirm_delete.html +9 -9
  70. wagtail/admin/templates/wagtailadmin/pages/confirm_move.html +2 -2
  71. wagtail/admin/templates/wagtailadmin/pages/confirm_unpublish.html +4 -4
  72. wagtail/admin/templates/wagtailadmin/pages/create.html +15 -34
  73. wagtail/admin/templates/wagtailadmin/pages/edit.html +15 -30
  74. wagtail/admin/templates/wagtailadmin/pages/explorable_index.html +6 -0
  75. wagtail/admin/templates/wagtailadmin/pages/explorable_index_results.html +60 -0
  76. wagtail/admin/templates/wagtailadmin/pages/index.html +1 -36
  77. wagtail/admin/templates/wagtailadmin/pages/index_results.html +2 -50
  78. wagtail/admin/templates/wagtailadmin/pages/listing/_locked_indicator.html +1 -1
  79. wagtail/admin/templates/wagtailadmin/pages/listing/_ordering_cell.html +1 -1
  80. wagtail/admin/templates/wagtailadmin/pages/listing/_page_header_buttons.html +1 -1
  81. wagtail/admin/templates/wagtailadmin/pages/listing/_page_title_column_header.html +3 -3
  82. wagtail/admin/templates/wagtailadmin/pages/listing/_pagination.html +1 -1
  83. wagtail/admin/templates/wagtailadmin/pages/listing.html +24 -0
  84. wagtail/admin/templates/wagtailadmin/pages/search.html +1 -20
  85. wagtail/admin/templates/wagtailadmin/pages/search_results.html +27 -25
  86. wagtail/admin/templates/wagtailadmin/permissions/includes/collection_member_permissions_formset.html +0 -1
  87. wagtail/admin/templates/wagtailadmin/reports/listing/_list_page_report.html +2 -2
  88. wagtail/admin/templates/wagtailadmin/reports/listing/_list_page_types_usage.html +6 -6
  89. wagtail/admin/templates/wagtailadmin/reports/workflow_tasks_results.html +1 -1
  90. wagtail/admin/templates/wagtailadmin/shared/action_menu/menu.html +14 -0
  91. wagtail/admin/templates/wagtailadmin/shared/action_menu/menu_item.html +6 -0
  92. wagtail/admin/templates/wagtailadmin/shared/avatar.html +13 -3
  93. wagtail/admin/templates/wagtailadmin/shared/header.html +0 -5
  94. wagtail/admin/templates/wagtailadmin/shared/headers/slim_header.html +1 -1
  95. wagtail/admin/templates/wagtailadmin/shared/page_status_tag_new.html +4 -1
  96. wagtail/admin/templates/wagtailadmin/shared/pagination_nav.html +1 -1
  97. wagtail/admin/templates/wagtailadmin/shared/side_panel_toggle.html +1 -1
  98. wagtail/admin/templates/wagtailadmin/shared/side_panels/includes/status/locale.html +1 -1
  99. wagtail/admin/templates/wagtailadmin/shared/side_panels/includes/status/usage.html +2 -2
  100. wagtail/admin/templates/wagtailadmin/shared/side_panels/preview.html +94 -52
  101. wagtail/admin/templates/wagtailadmin/{pages/_unsaved_changes_warning.html → shared/unsaved_changes_warning.html} +4 -4
  102. wagtail/admin/templates/wagtailadmin/shared/usage_summary.html +2 -2
  103. wagtail/admin/templates/wagtailadmin/shared/workflow_history/detail.html +1 -7
  104. wagtail/admin/templates/wagtailadmin/shared/workflow_history/listing.html +1 -0
  105. wagtail/admin/templates/wagtailadmin/shared/workflow_history/{list.html → listing_results.html} +33 -35
  106. wagtail/admin/templates/wagtailadmin/tables/references_cell.html +1 -1
  107. wagtail/admin/templates/wagtailadmin/workflows/create.html +11 -36
  108. wagtail/admin/templates/wagtailadmin/workflows/create_task.html +0 -38
  109. wagtail/admin/templates/wagtailadmin/workflows/edit.html +44 -74
  110. wagtail/admin/templates/wagtailadmin/workflows/edit_task.html +27 -66
  111. wagtail/admin/templates/wagtailadmin/workflows/includes/task_usage_cell.html +4 -2
  112. wagtail/admin/templates/wagtailadmin/workflows/includes/workflow_tasks_cell.html +4 -4
  113. wagtail/admin/templates/wagtailadmin/workflows/includes/workflow_used_by_cell.html +15 -11
  114. wagtail/admin/templates/wagtailadmin/workflows/task_chooser/includes/results.html +7 -5
  115. wagtail/admin/templatetags/wagtailadmin_tags.py +51 -22
  116. wagtail/admin/tests/pages/test_content_type_use_view.py +82 -2
  117. wagtail/admin/tests/pages/test_edit_page.py +70 -0
  118. wagtail/admin/tests/pages/test_explorer_view.py +65 -4
  119. wagtail/admin/tests/pages/test_page_search.py +8 -7
  120. wagtail/admin/tests/pages/test_page_usage.py +3 -1
  121. wagtail/admin/tests/pages/test_preview.py +208 -63
  122. wagtail/admin/tests/pages/test_reorder_page.py +91 -1
  123. wagtail/admin/tests/pages/test_view_draft.py +32 -1
  124. wagtail/admin/tests/pages/test_workflow_history.py +288 -7
  125. wagtail/admin/tests/test_account_management.py +23 -3
  126. wagtail/admin/tests/test_audit_log.py +24 -2
  127. wagtail/admin/tests/test_collections_views.py +17 -5
  128. wagtail/admin/tests/test_dashboard.py +1 -1
  129. wagtail/admin/tests/test_edit_handlers.py +3 -2
  130. wagtail/admin/tests/test_icon_sprite.py +4 -0
  131. wagtail/admin/tests/test_privacy.py +5 -19
  132. wagtail/admin/tests/test_reports_views.py +1 -1
  133. wagtail/admin/tests/test_site_summary.py +3 -3
  134. wagtail/admin/tests/test_templatetags.py +27 -3
  135. wagtail/admin/tests/test_upgrade_notification.py +71 -18
  136. wagtail/admin/tests/test_views.py +2 -2
  137. wagtail/admin/tests/test_views_generic.py +13 -0
  138. wagtail/admin/tests/test_widgets.py +3 -3
  139. wagtail/admin/tests/test_workflows.py +172 -27
  140. wagtail/admin/tests/tests.py +1 -1
  141. wagtail/admin/tests/viewsets/test_model_viewset.py +55 -3
  142. wagtail/admin/ui/side_panels.py +19 -0
  143. wagtail/admin/ui/sidebar.py +4 -3
  144. wagtail/admin/ui/tables/__init__.py +14 -1
  145. wagtail/admin/ui/tables/pages.py +6 -1
  146. wagtail/admin/urls/pages.py +10 -1
  147. wagtail/admin/urls/workflows.py +6 -1
  148. wagtail/admin/views/account.py +5 -1
  149. wagtail/admin/views/collections.py +0 -2
  150. wagtail/admin/views/generic/base.py +118 -1
  151. wagtail/admin/views/generic/history.py +158 -26
  152. wagtail/admin/views/generic/models.py +113 -99
  153. wagtail/admin/views/home.py +24 -9
  154. wagtail/admin/views/page_privacy.py +54 -30
  155. wagtail/admin/views/pages/history.py +11 -4
  156. wagtail/admin/views/pages/listing.py +76 -89
  157. wagtail/admin/views/pages/preview.py +1 -1
  158. wagtail/admin/views/pages/search.py +27 -71
  159. wagtail/admin/views/pages/usage.py +63 -24
  160. wagtail/admin/views/pages/utils.py +4 -3
  161. wagtail/admin/views/reports/base.py +0 -6
  162. wagtail/admin/views/workflows.py +67 -25
  163. wagtail/admin/viewsets/model.py +4 -3
  164. wagtail/admin/widgets/chooser.py +2 -1
  165. wagtail/api/v2/tests/test_pages.py +15 -2
  166. wagtail/blocks/field_block.py +15 -3
  167. wagtail/blocks/static_block.py +3 -0
  168. wagtail/contrib/forms/locale/cy/LC_MESSAGES/django.mo +0 -0
  169. wagtail/contrib/forms/locale/cy/LC_MESSAGES/django.po +29 -1
  170. wagtail/contrib/forms/locale/en/LC_MESSAGES/django.po +15 -11
  171. wagtail/contrib/forms/templates/wagtailforms/confirm_delete.html +1 -0
  172. wagtail/contrib/forms/templates/wagtailforms/index.html +1 -1
  173. wagtail/contrib/forms/templates/wagtailforms/index_results.html +1 -1
  174. wagtail/contrib/forms/templates/wagtailforms/list_submissions.html +2 -1
  175. wagtail/contrib/forms/templates/wagtailforms/panels/form_responses_panel.html +2 -2
  176. wagtail/contrib/forms/tests/test_views.py +234 -35
  177. wagtail/contrib/forms/utils.py +8 -14
  178. wagtail/contrib/forms/views.py +72 -27
  179. wagtail/contrib/frontend_cache/backends/azure.py +1 -1
  180. wagtail/contrib/frontend_cache/backends/cloudfront.py +2 -2
  181. wagtail/contrib/frontend_cache/backends/dummy.py +11 -0
  182. wagtail/contrib/frontend_cache/tests.py +31 -37
  183. wagtail/contrib/frontend_cache/utils.py +12 -5
  184. wagtail/contrib/redirects/locale/cy/LC_MESSAGES/django.mo +0 -0
  185. wagtail/contrib/redirects/locale/cy/LC_MESSAGES/django.po +16 -1
  186. wagtail/contrib/redirects/locale/en/LC_MESSAGES/django.po +20 -24
  187. wagtail/contrib/redirects/models.py +16 -1
  188. wagtail/contrib/redirects/signal_handlers.py +18 -3
  189. wagtail/contrib/redirects/templates/wagtailredirects/add.html +5 -16
  190. wagtail/contrib/redirects/templates/wagtailredirects/import_summary.html +1 -1
  191. wagtail/contrib/redirects/tests/test_redirects.py +49 -6
  192. wagtail/contrib/redirects/tests/test_signal_handlers.py +42 -1
  193. wagtail/contrib/redirects/views.py +27 -3
  194. wagtail/contrib/search_promotions/locale/cy/LC_MESSAGES/django.mo +0 -0
  195. wagtail/contrib/search_promotions/locale/cy/LC_MESSAGES/django.po +60 -1
  196. wagtail/contrib/search_promotions/locale/en/LC_MESSAGES/django.po +12 -18
  197. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/add.html +5 -8
  198. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/edit.html +15 -10
  199. wagtail/contrib/search_promotions/tests.py +13 -2
  200. wagtail/contrib/search_promotions/views.py +15 -3
  201. wagtail/contrib/settings/locale/cy/LC_MESSAGES/django.mo +0 -0
  202. wagtail/contrib/settings/locale/cy/LC_MESSAGES/django.po +6 -1
  203. wagtail/contrib/settings/locale/en/LC_MESSAGES/django.po +2 -10
  204. wagtail/contrib/settings/templates/wagtailsettings/edit.html +12 -45
  205. wagtail/contrib/simple_translation/locale/cy/LC_MESSAGES/django.mo +0 -0
  206. wagtail/contrib/simple_translation/locale/cy/LC_MESSAGES/django.po +13 -1
  207. wagtail/contrib/simple_translation/locale/dv/LC_MESSAGES/django.mo +0 -0
  208. wagtail/contrib/simple_translation/locale/dv/LC_MESSAGES/django.po +3 -0
  209. wagtail/contrib/simple_translation/locale/en/LC_MESSAGES/django.po +4 -4
  210. wagtail/contrib/simple_translation/locale/sl/LC_MESSAGES/django.mo +0 -0
  211. wagtail/contrib/simple_translation/locale/sl/LC_MESSAGES/django.po +5 -2
  212. wagtail/contrib/simple_translation/tests/test_views.py +51 -0
  213. wagtail/contrib/simple_translation/wagtail_hooks.py +16 -11
  214. wagtail/contrib/styleguide/locale/cy/LC_MESSAGES/django.mo +0 -0
  215. wagtail/contrib/styleguide/locale/cy/LC_MESSAGES/django.po +5 -1
  216. wagtail/contrib/styleguide/locale/en/LC_MESSAGES/django.po +1 -1
  217. wagtail/contrib/table_block/locale/cy/LC_MESSAGES/django.mo +0 -0
  218. wagtail/contrib/table_block/locale/cy/LC_MESSAGES/django.po +27 -1
  219. wagtail/contrib/table_block/locale/en/LC_MESSAGES/django.po +1 -1
  220. wagtail/contrib/typed_table_block/blocks.py +25 -0
  221. wagtail/contrib/typed_table_block/locale/cy/LC_MESSAGES/django.mo +0 -0
  222. wagtail/contrib/typed_table_block/locale/cy/LC_MESSAGES/django.po +12 -1
  223. wagtail/contrib/typed_table_block/locale/en/LC_MESSAGES/django.po +10 -10
  224. wagtail/contrib/typed_table_block/tests.py +24 -1
  225. wagtail/coreutils.py +5 -11
  226. wagtail/documents/admin_urls.py +2 -2
  227. wagtail/documents/locale/cy/LC_MESSAGES/django.mo +0 -0
  228. wagtail/documents/locale/cy/LC_MESSAGES/django.po +10 -0
  229. wagtail/documents/locale/en/LC_MESSAGES/django.po +61 -76
  230. wagtail/documents/migrations/0014_alter_document_file_size.py +18 -0
  231. wagtail/documents/models.py +1 -1
  232. wagtail/documents/rich_text/__init__.py +1 -3
  233. wagtail/documents/static/wagtaildocs/js/add-multiple.js +1 -1
  234. wagtail/documents/templates/wagtaildocs/bulk_actions/confirm_bulk_add_tags.html +5 -1
  235. wagtail/documents/templates/wagtaildocs/bulk_actions/confirm_bulk_add_to_collection.html +5 -1
  236. wagtail/documents/templates/wagtaildocs/bulk_actions/confirm_bulk_delete.html +11 -5
  237. wagtail/documents/templates/wagtaildocs/documents/add.html +13 -41
  238. wagtail/documents/templates/wagtaildocs/documents/edit.html +28 -56
  239. wagtail/documents/templates/wagtaildocs/documents/index.html +1 -4
  240. wagtail/documents/templates/wagtaildocs/homepage/site_summary_documents.html +2 -2
  241. wagtail/documents/templates/wagtaildocs/multiple/add.html +36 -41
  242. wagtail/documents/tests/test_admin_views.py +64 -6
  243. wagtail/documents/tests/test_site_summary.py +3 -3
  244. wagtail/documents/views/documents.py +103 -113
  245. wagtail/documents/views/multiple.py +19 -1
  246. wagtail/embeds/locale/en/LC_MESSAGES/django.po +1 -1
  247. wagtail/embeds/oembed_providers.py +9 -19
  248. wagtail/fields.py +43 -27
  249. wagtail/images/admin_urls.py +2 -2
  250. wagtail/images/blocks.py +230 -2
  251. wagtail/images/fields.py +17 -29
  252. wagtail/images/image_operations.py +1 -1
  253. wagtail/images/locale/cy/LC_MESSAGES/django.mo +0 -0
  254. wagtail/images/locale/cy/LC_MESSAGES/django.po +128 -1
  255. wagtail/images/locale/en/LC_MESSAGES/django.po +119 -129
  256. wagtail/images/migrations/0025_alter_image_file_alter_rendition_file.py +36 -43
  257. wagtail/images/migrations/0027_image_description.py +20 -0
  258. wagtail/images/models.py +120 -45
  259. wagtail/images/rich_text/__init__.py +1 -3
  260. wagtail/images/static/wagtailimages/js/add-multiple.js +1 -1
  261. wagtail/images/static/wagtailimages/js/image-block.js +1 -0
  262. wagtail/images/templates/wagtailimages/bulk_actions/confirm_bulk_add_tags.html +5 -1
  263. wagtail/images/templates/wagtailimages/bulk_actions/confirm_bulk_add_to_collection.html +5 -1
  264. wagtail/images/templates/wagtailimages/bulk_actions/confirm_bulk_delete.html +11 -5
  265. wagtail/images/templates/wagtailimages/chooser/results.html +2 -2
  266. wagtail/images/templates/wagtailimages/homepage/site_summary_images.html +2 -2
  267. wagtail/images/templates/wagtailimages/images/_file_field.html +2 -2
  268. wagtail/images/templates/wagtailimages/images/add.html +13 -31
  269. wagtail/images/templates/wagtailimages/images/edit.html +53 -82
  270. wagtail/images/templates/wagtailimages/images/index.html +1 -4
  271. wagtail/images/templates/wagtailimages/images/url_generator.html +1 -1
  272. wagtail/images/templates/wagtailimages/multiple/add.html +40 -47
  273. wagtail/images/templates/wagtailimages/widgets/image.html +5 -0
  274. wagtail/images/templates/wagtailimages/widgets/image_chooser.html +1 -1
  275. wagtail/images/tests/test_admin_views.py +70 -10
  276. wagtail/images/tests/test_blocks.py +367 -1
  277. wagtail/images/tests/test_image_operations.py +23 -0
  278. wagtail/images/tests/test_models.py +20 -0
  279. wagtail/images/tests/test_signal_handlers.py +99 -95
  280. wagtail/images/tests/test_site_summary.py +3 -3
  281. wagtail/images/tests/test_templatetags.py +11 -7
  282. wagtail/images/tests/tests.py +4 -0
  283. wagtail/images/views/images.py +103 -104
  284. wagtail/images/views/multiple.py +17 -1
  285. wagtail/locale/cy/LC_MESSAGES/django.mo +0 -0
  286. wagtail/locale/cy/LC_MESSAGES/django.po +3 -0
  287. wagtail/locale/en/LC_MESSAGES/django.po +137 -125
  288. wagtail/locale/sl/LC_MESSAGES/django.mo +0 -0
  289. wagtail/locale/sl/LC_MESSAGES/django.po +3 -0
  290. wagtail/locales/locale/en/LC_MESSAGES/django.po +8 -8
  291. wagtail/locales/views.py +4 -1
  292. wagtail/migrations/0089_log_entry_data_json_null_to_object.py +1 -7
  293. wagtail/models/__init__.py +122 -14
  294. wagtail/models/audit_log.py +1 -3
  295. wagtail/models/i18n.py +1 -2
  296. wagtail/project_template/Dockerfile +3 -3
  297. wagtail/project_template/requirements.txt +2 -2
  298. wagtail/query.py +17 -4
  299. wagtail/rich_text/__init__.py +2 -3
  300. wagtail/rich_text/pages.py +2 -4
  301. wagtail/rich_text/rewriters.py +2 -2
  302. wagtail/search/backends/database/mysql/query.py +3 -3
  303. wagtail/search/backends/database/sqlite/query.py +6 -6
  304. wagtail/search/locale/en/LC_MESSAGES/django.po +1 -1
  305. wagtail/sites/locale/en/LC_MESSAGES/django.po +6 -6
  306. wagtail/sites/views.py +0 -1
  307. wagtail/snippets/action_menu.py +14 -4
  308. wagtail/snippets/locale/cy/LC_MESSAGES/django.mo +0 -0
  309. wagtail/snippets/locale/cy/LC_MESSAGES/django.po +73 -1
  310. wagtail/snippets/locale/en/LC_MESSAGES/django.po +27 -33
  311. wagtail/snippets/static/wagtailsnippets/js/snippet-chooser-telepath.js +1 -1
  312. wagtail/snippets/static/wagtailsnippets/js/snippet-chooser.js +1 -1
  313. wagtail/snippets/templates/wagtailsnippets/bulk_actions/confirm_bulk_delete.html +5 -3
  314. wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/locked.html +1 -1
  315. wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/menu.html +1 -11
  316. wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/menu_item.html +1 -6
  317. wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/publish.html +1 -1
  318. wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/save.html +1 -1
  319. wagtail/snippets/templates/wagtailsnippets/snippets/create.html +1 -18
  320. wagtail/snippets/templates/wagtailsnippets/snippets/edit.html +1 -14
  321. wagtail/snippets/templates/wagtailsnippets/snippets/index.html +2 -5
  322. wagtail/snippets/tests/test_preview.py +193 -61
  323. wagtail/snippets/tests/test_snippets.py +247 -38
  324. wagtail/snippets/tests/test_usage.py +5 -0
  325. wagtail/snippets/tests/test_viewset.py +25 -9
  326. wagtail/snippets/tests/test_workflows.py +232 -19
  327. wagtail/snippets/views/snippets.py +1 -10
  328. wagtail/test/numberformat.py +104 -0
  329. wagtail/test/settings.py +10 -0
  330. wagtail/test/settings_ui.py +2 -0
  331. wagtail/test/testapp/migrations/0010_alter_customimage_file_and_more.py +71 -78
  332. wagtail/test/testapp/migrations/0040_nocreatablesubpagetypespage_nosubpagetypespage.py +54 -0
  333. wagtail/test/testapp/migrations/0041_alter_jsonstreammodel_options.py +17 -0
  334. wagtail/test/testapp/migrations/0042_alter_customdocument_file_size_and_more.py +28 -0
  335. wagtail/test/testapp/migrations/0043_customimage_description.py +41 -0
  336. wagtail/test/testapp/migrations/0044_custompreviewsizesmodel_custompreviewsizespage.py +52 -0
  337. wagtail/test/testapp/migrations/0045_alter_streampage_body.py +52 -0
  338. wagtail/test/testapp/models.py +62 -4
  339. wagtail/test/testapp/rich_text.py +2 -2
  340. wagtail/test/testapp/templates/tests/form_page_landing.html +2 -1
  341. wagtail/test/testapp/urls.py +5 -0
  342. wagtail/test/testapp/views.py +5 -0
  343. wagtail/test/utils/page_tests.py +5 -5
  344. wagtail/test/utils/template_tests.py +2 -2
  345. wagtail/tests/test_blocks.py +15 -0
  346. wagtail/tests/test_page_permissions.py +109 -0
  347. wagtail/tests/test_revision_model.py +27 -0
  348. wagtail/tests/test_signals.py +21 -2
  349. wagtail/tests/test_tests.py +30 -0
  350. wagtail/users/locale/cy/LC_MESSAGES/django.mo +0 -0
  351. wagtail/users/locale/cy/LC_MESSAGES/django.po +118 -1
  352. wagtail/users/locale/dv/LC_MESSAGES/django.mo +0 -0
  353. wagtail/users/locale/dv/LC_MESSAGES/django.po +3 -0
  354. wagtail/users/locale/en/LC_MESSAGES/django.po +89 -113
  355. wagtail/users/locale/sl/LC_MESSAGES/django.mo +0 -0
  356. wagtail/users/locale/sl/LC_MESSAGES/django.po +3 -0
  357. wagtail/users/migrations/0014_userprofile_contrast.py +23 -0
  358. wagtail/users/models.py +11 -0
  359. wagtail/users/templates/wagtailusers/bulk_actions/confirm_bulk_assign_role.html +5 -1
  360. wagtail/users/templates/wagtailusers/bulk_actions/confirm_bulk_delete.html +5 -1
  361. wagtail/users/templates/wagtailusers/bulk_actions/confirm_bulk_set_active_state.html +5 -1
  362. wagtail/users/templates/wagtailusers/groups/create.html +19 -17
  363. wagtail/users/templates/wagtailusers/groups/edit.html +2 -40
  364. wagtail/users/templates/wagtailusers/groups/includes/formatted_permissions.html +1 -62
  365. wagtail/users/templates/wagtailusers/groups/includes/page_permissions_formset.html +0 -1
  366. wagtail/users/templates/wagtailusers/users/create.html +46 -50
  367. wagtail/users/templates/wagtailusers/users/edit.html +45 -62
  368. wagtail/users/templates/wagtailusers/users/index.html +1 -4
  369. wagtail/users/templatetags/wagtailusers_tags.py +1 -5
  370. wagtail/users/tests/test_admin_views.py +85 -66
  371. wagtail/users/views/groups.py +4 -1
  372. wagtail/users/views/users.py +2 -0
  373. {wagtail-6.2.2.dist-info → wagtail-6.3rc2.dist-info}/METADATA +6 -6
  374. {wagtail-6.2.2.dist-info → wagtail-6.3rc2.dist-info}/RECORD +378 -367
  375. wagtail/admin/static/wagtailadmin/js/preview-panel.js +0 -2
  376. wagtail/admin/static/wagtailadmin/js/preview-panel.js.LICENSE.txt +0 -11
  377. wagtail/admin/templates/wagtailadmin/generic/history_results.html +0 -1
  378. wagtail/admin/templates/wagtailadmin/page_privacy/ancestor_privacy.html +0 -3
  379. wagtail/admin/templates/wagtailadmin/pages/usage_results.html +0 -6
  380. wagtail/admin/templates/wagtailadmin/shared/workflow_history/index.html +0 -17
  381. wagtail/admin/templates/wagtailadmin/shared/workflow_history/results.html +0 -17
  382. wagtail/admin/templates/wagtailadmin/workflows/usage.html +0 -44
  383. {wagtail-6.2.2.dist-info → wagtail-6.3rc2.dist-info}/LICENSE +0 -0
  384. {wagtail-6.2.2.dist-info → wagtail-6.3rc2.dist-info}/WHEEL +0 -0
  385. {wagtail-6.2.2.dist-info → wagtail-6.3rc2.dist-info}/entry_points.txt +0 -0
  386. {wagtail-6.2.2.dist-info → wagtail-6.3rc2.dist-info}/top_level.txt +0 -0
@@ -11,15 +11,6 @@
11
11
  <col width="10%" />
12
12
  <col width="10%" />
13
13
  <col width="10%" />
14
- {% if extra_perms_exist.publish %}
15
- <col width="10%" />
16
- {% endif %}
17
- {% if extra_perms_exist.lock %}
18
- <col width="10%" />
19
- {% endif %}
20
- {% if extra_perms_exist.unlock %}
21
- <col width="10%" />
22
- {% endif %}
23
14
  {% if extra_perms_exist.custom %}
24
15
  <col width="25%" />
25
16
  {% endif %}
@@ -30,15 +21,6 @@
30
21
  <th>{% trans "Add" %}</th>
31
22
  <th>{% trans "Change" %}</th>
32
23
  <th>{% trans "Delete" %}</th>
33
- {% if extra_perms_exist.publish %}
34
- <th>{% trans "Publish" %}</th>
35
- {% endif %}
36
- {% if extra_perms_exist.lock %}
37
- <th>{% trans "Lock" %}</th>
38
- {% endif %}
39
- {% if extra_perms_exist.unlock %}
40
- <th>{% trans "Unlock" %}</th>
41
- {% endif %}
42
24
  {% if extra_perms_exist.custom %}
43
25
  <th>{% trans "Custom permissions" %}</th>
44
26
  {% endif %}
@@ -66,34 +48,10 @@
66
48
  {{ content_perms_dict.delete.checkbox.tag }}
67
49
  {% endif %}
68
50
  </td>
69
- {% if extra_perms_exist.publish %}
70
- <td>
71
- {% if content_perms_dict.publish %}
72
- <label for="{{ content_perms_dict.publish.checkbox.id_for_label }}" class="w-sr-only">{{ content_perms_dict.publish.perm.name }}</label>
73
- {{ content_perms_dict.publish.checkbox.tag }}
74
- {% endif %}
75
- </td>
76
- {% endif %}
77
- {% if extra_perms_exist.lock %}
78
- <td>
79
- {% if content_perms_dict.lock %}
80
- <label for="{{ content_perms_dict.lock.checkbox.id_for_label }}" class="w-sr-only">{{ content_perms_dict.lock.perm.name }}</label>
81
- {{ content_perms_dict.lock.checkbox.tag }}
82
- {% endif %}
83
- </td>
84
- {% endif %}
85
- {% if extra_perms_exist.unlock %}
86
- <td>
87
- {% if content_perms_dict.unlock %}
88
- <label for="{{ content_perms_dict.unlock.checkbox.id_for_label }}" class="w-sr-only">{{ content_perms_dict.unlock.perm.name }}</label>
89
- {{ content_perms_dict.unlock.checkbox.tag }}
90
- {% endif %}
91
- </td>
92
- {% endif %}
93
51
  {% if extra_perms_exist.custom %}
94
52
  <td>
95
53
  {% if content_perms_dict.custom %}
96
- <fieldset class="w-p-0">
54
+ <fieldset class="w-p-0 w-flex w-flex-col w-gap-1">
97
55
  <legend class="w-sr-only">{% trans "Custom permissions" %}</legend>
98
56
  {% for custom_perm in content_perms_dict.custom %}
99
57
  {% trans custom_perm.name as custom_perm_label %}
@@ -124,24 +82,6 @@
124
82
  <label for="toggle-all-delete" class="visuallyhidden">{% trans "Toggle all delete permissions" %}</label>
125
83
  <input id="toggle-all-delete" type="checkbox" data-action="w-bulk#toggleAll" data-w-bulk-target="all" data-w-bulk-group-param="delete">
126
84
  </td>
127
- {% if extra_perms_exist.publish %}
128
- <td>
129
- <label for="toggle-all-publish" class="visuallyhidden">{% trans "Toggle all publish permissions" %}</label>
130
- <input id="toggle-all-publish" type="checkbox" data-action="w-bulk#toggleAll" data-w-bulk-target="all" data-w-bulk-group-param="publish">
131
- </td>
132
- {% endif %}
133
- {% if extra_perms_exist.lock %}
134
- <td>
135
- <label for="toggle-all-lock" class="visuallyhidden">{% trans "Toggle all lock permissions" %}</label>
136
- <input id="toggle-all-lock" type="checkbox" data-action="w-bulk#toggleAll" data-w-bulk-target="all" data-w-bulk-group-param="lock">
137
- </td>
138
- {% endif %}
139
- {% if extra_perms_exist.unlock %}
140
- <td>
141
- <label for="toggle-all-unlock" class="visuallyhidden">{% trans "Toggle all unlock permissions" %}</label>
142
- <input id="toggle-all-unlock" type="checkbox" data-action="w-bulk#toggleAll" data-w-bulk-target="all" data-w-bulk-group-param="unlock">
143
- </td>
144
- {% endif %}
145
85
  {% if extra_perms_exist.custom %}
146
86
  <td>
147
87
  <label for="toggle-all-custom" class="visuallyhidden">{% trans "Toggle all custom permissions" %}</label>
@@ -165,7 +105,6 @@
165
105
  <thead>
166
106
  <tr>
167
107
  <th>{% trans "Name" %}</th>
168
- <th></th>
169
108
  </tr>
170
109
  </thead>
171
110
  <tbody>
@@ -25,7 +25,6 @@
25
25
  {% for identifier, short_label, long_label in formset.permission_types %}
26
26
  <th title="{{ long_label }}">{{ short_label }}</th>
27
27
  {% endfor %}
28
- <th></th>
29
28
  </tr>
30
29
  </thead>
31
30
  <tbody id="id_{{ formset.prefix }}-FORMS">
@@ -2,7 +2,7 @@
2
2
  {% load wagtailadmin_tags wagtailimages_tags %}
3
3
  {% load i18n %}
4
4
 
5
- {% block main_content %}
5
+ {% block form_content %}
6
6
  <div class="w-tabs" data-tabs>
7
7
  <div class="w-tabs__wrapper">
8
8
  <div role="tablist" class="w-tabs__list">
@@ -13,55 +13,51 @@
13
13
  </div>
14
14
  </div>
15
15
 
16
- <form action="{% url 'wagtailusers_users:add' %}" method="POST" novalidate{% if form.is_multipart %} enctype="multipart/form-data"{% endif %}>
17
- <div class="tab-content">
18
- {% csrf_token %}
19
- <section
20
- id="tab-account"
21
- class="w-tabs__panel"
22
- role="tabpanel"
23
- hidden
24
- aria-labelledby="tab-label-account"
25
- >
26
- <ul class="fields">
27
- {% block fields %}
28
- {% if form.separate_username_field %}
29
- <li>{% formattedfield form.username_field %}</li>
30
- {% endif %}
31
- <li>{% formattedfield form.email %}</li>
32
- <li>{% formattedfield form.first_name %}</li>
33
- <li>{% formattedfield form.last_name %}</li>
34
- {% block extra_fields %}{% endblock extra_fields %}
35
- {% if form.password1 %}
36
- <li>{% formattedfield form.password1 %}</li>
37
- {% endif %}
38
- {% if form.password2 %}
39
- <li>{% formattedfield form.password2 %}</li>
40
- {% endif %}
41
- {% endblock fields %}
16
+ <div class="tab-content">
17
+ <section
18
+ id="tab-account"
19
+ class="w-tabs__panel"
20
+ role="tabpanel"
21
+ hidden
22
+ aria-labelledby="tab-label-account"
23
+ >
24
+ <ul class="fields">
25
+ {% block fields %}
26
+ {% if form.separate_username_field %}
27
+ <li>{% formattedfield form.username_field %}</li>
28
+ {% endif %}
29
+ <li>{% formattedfield form.email %}</li>
30
+ <li>{% formattedfield form.first_name %}</li>
31
+ <li>{% formattedfield form.last_name %}</li>
32
+ {% block extra_fields %}{% endblock extra_fields %}
33
+ {% if form.password1 %}
34
+ <li>{% formattedfield form.password1 %}</li>
35
+ {% endif %}
36
+ {% if form.password2 %}
37
+ <li>{% formattedfield form.password2 %}</li>
38
+ {% endif %}
39
+ {% endblock fields %}
42
40
 
43
- <li>
44
- <a href="#tab-roles" data-tab-trigger class="button">
45
- {% trans "Roles" %}
46
- {% icon name="arrow-right" classname="default" %}
47
- </a>
48
- </li>
49
- </ul>
50
- </section>
51
- <section
52
- id="tab-roles"
53
- class="w-tabs__panel"
54
- role="tabpanel"
55
- hidden
56
- aria-labelledby="tab-label-roles"
57
- >
58
- <ul class="fields">
59
- <li>{% formattedfield form.is_superuser %}</li>
60
- <li>{% formattedfield form.groups %}</li>
61
- <li><button class="button">{% trans "Add user" %}</button></li>
62
- </ul>
63
- </section>
64
- </div>
65
- </form>
41
+ <li>
42
+ <a href="#tab-roles" data-tab-trigger class="button w-flex w-items-center w-w-fit w-mb-8">
43
+ {% trans "Roles" %}
44
+ {% icon name="arrow-right" classname="default" %}
45
+ </a>
46
+ </li>
47
+ </ul>
48
+ </section>
49
+ <section
50
+ id="tab-roles"
51
+ class="w-tabs__panel"
52
+ role="tabpanel"
53
+ hidden
54
+ aria-labelledby="tab-label-roles"
55
+ >
56
+ <ul class="fields">
57
+ <li>{% formattedfield form.is_superuser %}</li>
58
+ <li>{% formattedfield form.groups %}</li>
59
+ </ul>
60
+ </section>
61
+ </div>
66
62
  </div>
67
63
  {% endblock %}
@@ -1,8 +1,8 @@
1
- {% extends "wagtailadmin/generic/form.html" %}
1
+ {% extends "wagtailadmin/generic/edit.html" %}
2
2
  {% load wagtailimages_tags wagtailadmin_tags %}
3
3
  {% load i18n %}
4
4
 
5
- {% block main_content %}
5
+ {% block form_content %}
6
6
  <div class="w-tabs" data-tabs>
7
7
  <div class="w-tabs__wrapper">
8
8
  <div role="tablist" class="w-tabs__list">
@@ -13,67 +13,50 @@
13
13
  </div>
14
14
  </div>
15
15
 
16
- <form action="{% url 'wagtailusers_users:edit' user.pk %}" method="POST" novalidate{% if form.is_multipart %} enctype="multipart/form-data"{% endif %}>
17
- <div class="tab-content">
18
- {% csrf_token %}
19
-
20
- <section
21
- id="tab-account"
22
- class="w-tabs__panel"
23
- role="tabpanel"
24
- hidden
25
- aria-labelledby="tab-label-account"
26
- >
27
- <ul class="fields">
28
- {% block fields %}
29
- {% if form.separate_username_field %}
30
- <li>{% formattedfield form.username_field %}</li>
31
- {% endif %}
32
- <li>{% formattedfield form.email %}</li>
33
- <li>{% formattedfield form.first_name %}</li>
34
- <li>{% formattedfield form.last_name %}</li>
35
- {% block extra_fields %}{% endblock extra_fields %}
36
- {% if form.password1 %}
37
- <li>{% formattedfield form.password1 %}</li>
38
- {% endif %}
39
- {% if form.password2 %}
40
- <li>{% formattedfield form.password2 %}</li>
41
- {% endif %}
42
- {% if form.is_active %}
43
- <li>{% formattedfield form.is_active %}</li>
44
- {% endif %}
45
-
46
- {% endblock fields %}
47
- <li>
48
- <input type="submit" value="{% trans 'Save' %}" class="button"/>
49
- {% if can_delete %}
50
- <a href="{% url 'wagtailusers_users:delete' user.pk %}" class="button no">{% trans "Delete user" %}</a>
51
- {% endif %}
52
- </li>
53
- </ul>
54
- </section>
55
- <section
56
- id="tab-roles"
57
- class="w-tabs__panel"
58
- role="tabpanel"
59
- hidden
60
- aria-labelledby="tab-label-roles"
61
- >
62
- <ul class="fields">
63
- {% if form.is_superuser %}
64
- <li>{% formattedfield form.is_superuser %}</li>
16
+ <div class="tab-content">
17
+ <section
18
+ id="tab-account"
19
+ class="w-tabs__panel"
20
+ role="tabpanel"
21
+ hidden
22
+ aria-labelledby="tab-label-account"
23
+ >
24
+ <ul class="fields">
25
+ {% block fields %}
26
+ {% if form.separate_username_field %}
27
+ <li>{% formattedfield form.username_field %}</li>
28
+ {% endif %}
29
+ <li>{% formattedfield form.email %}</li>
30
+ <li>{% formattedfield form.first_name %}</li>
31
+ <li>{% formattedfield form.last_name %}</li>
32
+ {% block extra_fields %}{% endblock extra_fields %}
33
+ {% if form.password1 %}
34
+ <li>{% formattedfield form.password1 %}</li>
35
+ {% endif %}
36
+ {% if form.password2 %}
37
+ <li>{% formattedfield form.password2 %}</li>
38
+ {% endif %}
39
+ {% if form.is_active %}
40
+ <li>{% formattedfield form.is_active %}</li>
65
41
  {% endif %}
66
42
 
67
- <li>{% formattedfield form.groups %}</li>
68
- <li>
69
- <input type="submit" value="{% trans 'Save' %}" class="button"/>
70
- {% if can_delete %}
71
- <a href="{% url 'wagtailusers_users:delete' user.pk %}" class="button no">{% trans "Delete user" %}</a>
72
- {% endif %}
73
- </li>
74
- </ul>
75
- </section>
76
- </div>
77
- </form>
43
+ {% endblock fields %}
44
+ </ul>
45
+ </section>
46
+ <section
47
+ id="tab-roles"
48
+ class="w-tabs__panel"
49
+ role="tabpanel"
50
+ hidden
51
+ aria-labelledby="tab-label-roles"
52
+ >
53
+ <ul class="fields">
54
+ {% if form.is_superuser %}
55
+ <li>{% formattedfield form.is_superuser %}</li>
56
+ {% endif %}
57
+ <li>{% formattedfield form.groups %}</li>
58
+ </ul>
59
+ </section>
60
+ </div>
78
61
  </div>
79
62
  {% endblock %}
@@ -2,13 +2,10 @@
2
2
  {% load i18n wagtailadmin_tags %}
3
3
  {% block extra_js %}
4
4
  {{ block.super }}
5
- <script>
6
- window.wagtailConfig.BULK_ACTION_ITEM_TYPE = 'USER';
7
- </script>
8
5
  <script defer src="{% versioned_static 'wagtailadmin/js/bulk-actions.js' %}"></script>
9
6
  {% endblock %}
10
7
 
11
8
  {% block bulk_actions %}
12
9
  {% trans "Select all users in listing" as select_all_text %}
13
- {% include 'wagtailadmin/bulk_actions/footer.html' with select_all_obj_text=select_all_text app_label=model_opts.app_label model_name=model_opts.model_name objects=page_obj %}
10
+ {% include 'wagtailadmin/bulk_actions/footer.html' with select_all_obj_text=select_all_text app_label=model_opts.app_label model_name=model_opts.model_name objects=page_obj item_type="USER" %}
14
11
  {% endblock %}
@@ -76,7 +76,6 @@ def format_permissions(permission_bound_field):
76
76
  'add': checkbox,
77
77
  'change': checkbox,
78
78
  'delete': checkbox,
79
- 'publish': checkbox, # only if the model extends DraftStateMixin
80
79
  'custom': list_of_checkboxes_for_custom_permissions
81
80
  },
82
81
  ]
@@ -112,13 +111,10 @@ def format_permissions(permission_bound_field):
112
111
 
113
112
  # Permissions that are known by Wagtail, to be shown under their own columns.
114
113
  # Other permissions will be shown under the "custom permissions" column.
115
- main_permission_names = ["add", "change", "delete", "publish", "lock", "unlock"]
114
+ main_permission_names = ["add", "change", "delete"]
116
115
 
117
116
  # Only show the columns for these permissions if any of the model has them.
118
117
  extra_perms_exist = {
119
- "publish": False,
120
- "lock": False,
121
- "unlock": False,
122
118
  "custom": False,
123
119
  }
124
120
  # Batch the permission query for all content types, then group by content type
@@ -27,8 +27,10 @@ from wagtail.coreutils import get_dummy_request
27
27
  from wagtail.log_actions import log
28
28
  from wagtail.models import (
29
29
  Collection,
30
+ DraftStateMixin,
30
31
  GroupCollectionPermission,
31
32
  GroupPagePermission,
33
+ LockableMixin,
32
34
  Page,
33
35
  )
34
36
  from wagtail.test.utils import WagtailTestUtils
@@ -205,7 +207,7 @@ class TestUserIndexView(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
205
207
  # response should contain page furniture, including the "Add a user" button
206
208
  self.assertContains(response, "Add a user")
207
209
  self.assertBreadcrumbsItemsRendered(
208
- [{"url": "", "label": capfirst(User._meta.verbose_name_plural)}],
210
+ [{"url": "", "label": "Users"}],
209
211
  response.content,
210
212
  )
211
213
 
@@ -244,12 +246,10 @@ class TestUserIndexView(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
244
246
  self.assertIn(self.test_user, results)
245
247
 
246
248
  def test_pagination(self):
247
- # page numbers in range should be accepted
248
- response = self.get({"p": 1})
249
- self.assertEqual(response.status_code, 200)
250
- # page numbers out of range should return 404
251
- response = self.get({"p": 9999})
252
- self.assertEqual(response.status_code, 404)
249
+ pages = ["0", "1", "-1", "9999", "Not a page"]
250
+ for page in pages:
251
+ response = self.get({"p": page})
252
+ self.assertEqual(response.status_code, 200)
253
253
 
254
254
  def test_ordering(self):
255
255
  # checking that only valid ordering used, in case of `IndexView` the valid
@@ -1854,7 +1854,6 @@ class TestGroupCreateView(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
1854
1854
  Q(codename__startswith="add")
1855
1855
  | Q(codename__startswith="change")
1856
1856
  | Q(codename__startswith="delete")
1857
- | Q(codename__startswith="publish")
1858
1857
  ).delete()
1859
1858
 
1860
1859
  # A custom permission that happens to also start with "change"
@@ -1873,36 +1872,46 @@ class TestGroupCreateView(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
1873
1872
 
1874
1873
  self.assertInHTML("Custom permissions", response.content.decode())
1875
1874
 
1876
- def test_show_publish_permissions(self):
1877
- response = self.get()
1878
- html = response.content.decode()
1879
-
1880
- # Should show the Publish column
1881
- self.assertInHTML("<th>Publish</th>", html)
1882
-
1883
- # Should show inputs for publish permissions on models with DraftStateMixin
1884
- self.assertInHTML("Can publish draft state model", html)
1885
- self.assertInHTML("Can publish draft state custom primary key model", html)
1886
-
1887
- # Should not show inputs for publish permissions on models without DraftStateMixin
1888
- self.assertNotInHTML("Can publish advert", html)
1889
-
1890
- def test_hide_publish_permissions(self):
1891
- # Remove all `publish` permissions
1892
- Permission.objects.filter(codename__startswith="publish").delete()
1893
-
1875
+ def test_show_mixin_permissions(self):
1894
1876
  response = self.get()
1895
- html = response.content.decode()
1896
-
1897
- # Should not show the Publish column
1898
- self.assertNotInHTML("<th>Publish</th>", html)
1899
-
1900
- # Should not show inputs for publish permissions even on models with DraftStateMixin
1901
- self.assertNotInHTML("Can publish draft state model", html)
1902
- self.assertNotInHTML("Can publish draft state custom primary key model", html)
1903
-
1904
- # Should not show inputs for publish permissions on models without DraftStateMixin
1905
- self.assertNotInHTML("Can publish advert", html)
1877
+ soup = self.get_soup(response.content)
1878
+ object_permissions = soup.select_one("#object-permissions-section")
1879
+ self.assertIsNotNone(object_permissions)
1880
+
1881
+ # Should not show separate Publish, Lock, or Unlock columns
1882
+ # (i.e. the checkboxes should be in the "Custom permissions" column)
1883
+ self.assertFalse(
1884
+ {th.text.strip() for th in object_permissions.select("th")}
1885
+ & {"Publish", "Lock", "Unlock"}
1886
+ )
1887
+
1888
+ mixin_permissions = (
1889
+ ("publish", DraftStateMixin),
1890
+ ("lock", LockableMixin),
1891
+ ("unlock", LockableMixin),
1892
+ )
1893
+ for action, mixin in mixin_permissions:
1894
+ with self.subTest(action=action):
1895
+ permissions = Permission.objects.filter(
1896
+ codename__startswith=action,
1897
+ content_type__app_label="tests",
1898
+ ).select_related("content_type")
1899
+ self.assertGreater(len(permissions), 0)
1900
+
1901
+ for permission in permissions:
1902
+ # Should show a checkbox for each permission in the
1903
+ # "Custom permissions" column (thus inside a fieldset), with a
1904
+ # simple "Can {action}" label (without the model name)
1905
+ checkbox = object_permissions.select_one(
1906
+ f'td > fieldset input[value="{permission.pk}"]'
1907
+ )
1908
+ self.assertIsNotNone(checkbox)
1909
+ label = checkbox.parent
1910
+ self.assertEqual(label.name, "label")
1911
+ self.assertEqual(label.text.strip(), f"Can {action}")
1912
+ # Should only show the permission for models with the mixin applied
1913
+ content_type = permission.content_type
1914
+ self.assertTrue(issubclass(content_type.model_class(), mixin))
1906
1915
 
1907
1916
  def test_strip_model_name_from_custom_permissions(self):
1908
1917
  """
@@ -2462,36 +2471,46 @@ class TestGroupEditView(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
2462
2471
 
2463
2472
  self.assertEqual(len(checkbox), 1)
2464
2473
 
2465
- def test_show_publish_permissions(self):
2474
+ def test_show_mixin_permissions(self):
2466
2475
  response = self.get()
2467
- html = response.content.decode()
2468
-
2469
- # Should show the Publish column
2470
- self.assertInHTML("<th>Publish</th>", html)
2471
-
2472
- # Should show inputs for publish permissions on models with DraftStateMixin
2473
- self.assertInHTML("Can publish draft state model", html)
2474
- self.assertInHTML("Can publish draft state custom primary key model", html)
2475
-
2476
- # Should not show inputs for publish permissions on models without DraftStateMixin
2477
- self.assertNotInHTML("Can publish advert", html)
2478
-
2479
- def test_hide_publish_permissions(self):
2480
- # Remove all `publish` permissions
2481
- Permission.objects.filter(codename__startswith="publish").delete()
2482
-
2483
- response = self.get()
2484
- html = response.content.decode()
2485
-
2486
- # Should not show the Publish column
2487
- self.assertNotInHTML("<th>Publish</th>", html)
2488
-
2489
- # Should not show inputs for publish permissions even on models with DraftStateMixin
2490
- self.assertNotInHTML("Can publish draft state model", html)
2491
- self.assertNotInHTML("Can publish draft state custom primary key model", html)
2492
-
2493
- # Should not show inputs for publish permissions on models without DraftStateMixin
2494
- self.assertNotInHTML("Can publish advert", html)
2476
+ soup = self.get_soup(response.content)
2477
+ object_permissions = soup.select_one("#object-permissions-section")
2478
+ self.assertIsNotNone(object_permissions)
2479
+
2480
+ # Should not show separate Publish, Lock, or Unlock columns
2481
+ # (i.e. the checkboxes should be in the "Custom permissions" column)
2482
+ self.assertFalse(
2483
+ {th.text.strip() for th in object_permissions.select("th")}
2484
+ & {"Publish", "Lock", "Unlock"}
2485
+ )
2486
+
2487
+ mixin_permissions = (
2488
+ ("publish", DraftStateMixin),
2489
+ ("lock", LockableMixin),
2490
+ ("unlock", LockableMixin),
2491
+ )
2492
+ for action, mixin in mixin_permissions:
2493
+ with self.subTest(action=action):
2494
+ permissions = Permission.objects.filter(
2495
+ codename__startswith=action,
2496
+ content_type__app_label="tests",
2497
+ ).select_related("content_type")
2498
+ self.assertGreater(len(permissions), 0)
2499
+
2500
+ for permission in permissions:
2501
+ # Should show a checkbox for each permission in the
2502
+ # "Custom permissions" column (thus inside a fieldset), with a
2503
+ # simple "Can {action}" label (without the model name)
2504
+ checkbox = object_permissions.select_one(
2505
+ f'td > fieldset input[value="{permission.pk}"]'
2506
+ )
2507
+ self.assertIsNotNone(checkbox)
2508
+ label = checkbox.parent
2509
+ self.assertEqual(label.name, "label")
2510
+ self.assertEqual(label.text.strip(), f"Can {action}")
2511
+ # Should only show the permission for models with the mixin applied
2512
+ content_type = permission.content_type
2513
+ self.assertTrue(issubclass(content_type.model_class(), mixin))
2495
2514
 
2496
2515
  def test_group_edit_loads_with_django_permissions_in_order(self):
2497
2516
  # ensure objects are ordered as registered, followed by the default ordering
@@ -113,7 +113,6 @@ class CreateView(PermissionPanelFormsMixin, generic.CreateView):
113
113
  class EditView(PermissionPanelFormsMixin, generic.EditView):
114
114
  success_message = _("Group '%(object)s' updated.")
115
115
  error_message = _("The group could not be saved due to errors.")
116
- delete_item_label = _("Delete group")
117
116
  context_object_name = "group"
118
117
 
119
118
  @cached_property
@@ -159,6 +158,10 @@ class GroupViewSet(ModelViewSet):
159
158
  edit_view_class = EditView
160
159
  delete_view_class = DeleteView
161
160
 
161
+ # Copying requires prepopulating the formsets with copies of the existing
162
+ # permissions, which is not currently supported.
163
+ copy_view_enabled = False
164
+
162
165
  template_prefix = "wagtailusers/groups/"
163
166
 
164
167
  @property
@@ -149,6 +149,8 @@ class IndexView(generic.IndexView):
149
149
  results_template_name = "wagtailusers/users/index_results.html"
150
150
  add_item_label = gettext_lazy("Add a user")
151
151
  context_object_name = "users"
152
+ # We don't set search_fields and the model may not be indexed, but we override
153
+ # search_queryset, so we set is_searchable to True to enable search
152
154
  is_searchable = True
153
155
  page_title = gettext_lazy("Users")
154
156
  show_other_searches = True