wagtail 6.1.2__py3-none-any.whl → 6.2rc1__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 (644) hide show
  1. wagtail/__init__.py +1 -1
  2. wagtail/actions/copy_for_translation.py +15 -1
  3. wagtail/admin/checks.py +20 -30
  4. wagtail/admin/forms/pages.py +10 -0
  5. wagtail/admin/icons.py +43 -0
  6. wagtail/admin/locale/ar/LC_MESSAGES/django.po +2 -2
  7. wagtail/admin/locale/be/LC_MESSAGES/django.po +7 -7
  8. wagtail/admin/locale/be/LC_MESSAGES/djangojs.po +3 -3
  9. wagtail/admin/locale/ca/LC_MESSAGES/django.mo +0 -0
  10. wagtail/admin/locale/ca/LC_MESSAGES/django.po +51 -50
  11. wagtail/admin/locale/cs/LC_MESSAGES/django.po +10 -8
  12. wagtail/admin/locale/de/LC_MESSAGES/django.po +49 -47
  13. wagtail/admin/locale/dv/LC_MESSAGES/django.po +8 -8
  14. wagtail/admin/locale/el/LC_MESSAGES/django.po +4 -4
  15. wagtail/admin/locale/en/LC_MESSAGES/django.po +405 -295
  16. wagtail/admin/locale/en/LC_MESSAGES/djangojs.po +21 -3
  17. wagtail/admin/locale/es/LC_MESSAGES/django.po +40 -39
  18. wagtail/admin/locale/es_419/LC_MESSAGES/django.po +8 -8
  19. wagtail/admin/locale/et/LC_MESSAGES/django.po +14 -12
  20. wagtail/admin/locale/fa/LC_MESSAGES/django.mo +0 -0
  21. wagtail/admin/locale/fa/LC_MESSAGES/django.po +93 -19
  22. wagtail/admin/locale/fa/LC_MESSAGES/djangojs.mo +0 -0
  23. wagtail/admin/locale/fa/LC_MESSAGES/djangojs.po +5 -1
  24. wagtail/admin/locale/fi/LC_MESSAGES/django.po +18 -18
  25. wagtail/admin/locale/fr/LC_MESSAGES/django.mo +0 -0
  26. wagtail/admin/locale/fr/LC_MESSAGES/django.po +134 -46
  27. wagtail/admin/locale/gl/LC_MESSAGES/django.po +55 -54
  28. wagtail/admin/locale/hr_HR/LC_MESSAGES/django.po +13 -12
  29. wagtail/admin/locale/hr_HR/LC_MESSAGES/djangojs.po +2 -2
  30. wagtail/admin/locale/hu/LC_MESSAGES/django.po +45 -42
  31. wagtail/admin/locale/id_ID/LC_MESSAGES/django.po +6 -6
  32. wagtail/admin/locale/is_IS/LC_MESSAGES/django.po +53 -51
  33. wagtail/admin/locale/it/LC_MESSAGES/django.po +56 -55
  34. wagtail/admin/locale/ja/LC_MESSAGES/django.po +2 -2
  35. wagtail/admin/locale/ko/LC_MESSAGES/django.po +18 -17
  36. wagtail/admin/locale/lt/LC_MESSAGES/django.po +4 -4
  37. wagtail/admin/locale/nb/LC_MESSAGES/django.po +22 -22
  38. wagtail/admin/locale/nl/LC_MESSAGES/django.po +44 -41
  39. wagtail/admin/locale/pl/LC_MESSAGES/django.po +49 -47
  40. wagtail/admin/locale/pl/LC_MESSAGES/djangojs.po +3 -3
  41. wagtail/admin/locale/pt_BR/LC_MESSAGES/django.mo +0 -0
  42. wagtail/admin/locale/pt_BR/LC_MESSAGES/django.po +46 -26
  43. wagtail/admin/locale/pt_PT/LC_MESSAGES/django.po +21 -20
  44. wagtail/admin/locale/ro/LC_MESSAGES/django.po +51 -50
  45. wagtail/admin/locale/ru/LC_MESSAGES/django.po +60 -59
  46. wagtail/admin/locale/ru/LC_MESSAGES/djangojs.po +3 -3
  47. wagtail/admin/locale/sk_SK/LC_MESSAGES/django.mo +0 -0
  48. wagtail/admin/locale/sk_SK/LC_MESSAGES/django.po +15 -5
  49. wagtail/admin/locale/sl/LC_MESSAGES/django.mo +0 -0
  50. wagtail/admin/locale/sl/LC_MESSAGES/django.po +86 -39
  51. wagtail/admin/locale/sl/LC_MESSAGES/djangojs.po +2 -2
  52. wagtail/admin/locale/sv/LC_MESSAGES/django.mo +0 -0
  53. wagtail/admin/locale/sv/LC_MESSAGES/django.po +117 -41
  54. wagtail/admin/locale/sv/LC_MESSAGES/djangojs.mo +0 -0
  55. wagtail/admin/locale/sv/LC_MESSAGES/djangojs.po +5 -2
  56. wagtail/admin/locale/tet/LC_MESSAGES/django.po +2 -2
  57. wagtail/admin/locale/th/LC_MESSAGES/django.po +4 -4
  58. wagtail/admin/locale/tr/LC_MESSAGES/django.po +4 -4
  59. wagtail/admin/locale/tr_TR/LC_MESSAGES/django.po +4 -4
  60. wagtail/admin/locale/uk/LC_MESSAGES/django.po +11 -10
  61. wagtail/admin/locale/zh_Hans/LC_MESSAGES/django.mo +0 -0
  62. wagtail/admin/locale/zh_Hans/LC_MESSAGES/django.po +84 -13
  63. wagtail/admin/locale/zh_Hant/LC_MESSAGES/django.po +2 -2
  64. wagtail/admin/menu.py +2 -2
  65. wagtail/admin/migrations/0004_editingsession.py +57 -0
  66. wagtail/admin/migrations/0005_editingsession_is_editing.py +18 -0
  67. wagtail/admin/models.py +36 -3
  68. wagtail/admin/rich_text/editors/draftail/__init__.py +2 -20
  69. wagtail/admin/static/wagtailadmin/css/core.css +1 -1
  70. wagtail/admin/static/wagtailadmin/js/bulk-actions.js +1 -1
  71. wagtail/admin/static/wagtailadmin/js/chooser-modal.js +1 -1
  72. wagtail/admin/static/wagtailadmin/js/chooser-widget-telepath.js +1 -1
  73. wagtail/admin/static/wagtailadmin/js/chooser-widget.js +1 -1
  74. wagtail/admin/static/wagtailadmin/js/comments.js +1 -1
  75. wagtail/admin/static/wagtailadmin/js/core.js +1 -1
  76. wagtail/admin/static/wagtailadmin/js/date-time-chooser.js +1 -1
  77. wagtail/admin/static/wagtailadmin/js/draftail.js +1 -1
  78. wagtail/admin/static/wagtailadmin/js/expanding-formset.js +1 -1
  79. wagtail/admin/static/wagtailadmin/js/filtered-select.js +1 -1
  80. wagtail/admin/static/wagtailadmin/js/modal-workflow.js +1 -1
  81. wagtail/admin/static/wagtailadmin/js/page-chooser-modal.js +1 -1
  82. wagtail/admin/static/wagtailadmin/js/page-chooser-telepath.js +1 -1
  83. wagtail/admin/static/wagtailadmin/js/page-chooser.js +1 -1
  84. wagtail/admin/static/wagtailadmin/js/preview-panel.js +2 -1
  85. wagtail/admin/static/wagtailadmin/js/preview-panel.js.LICENSE.txt +11 -0
  86. wagtail/admin/static/wagtailadmin/js/privacy-switch.js +1 -1
  87. wagtail/admin/static/wagtailadmin/js/sidebar.js +1 -1
  88. wagtail/admin/static/wagtailadmin/js/task-chooser-modal.js +1 -1
  89. wagtail/admin/static/wagtailadmin/js/task-chooser.js +1 -1
  90. wagtail/admin/static/wagtailadmin/js/telepath/blocks.js +1 -1
  91. wagtail/admin/static/wagtailadmin/js/telepath/widgets.js +1 -1
  92. wagtail/admin/static/wagtailadmin/js/userbar.js +2 -1
  93. wagtail/admin/static/wagtailadmin/js/userbar.js.LICENSE.txt +11 -0
  94. wagtail/admin/static/wagtailadmin/js/vendor.js +1 -1
  95. wagtail/admin/static/wagtailadmin/js/vendor.js.LICENSE.txt +0 -12
  96. wagtail/admin/static/wagtailadmin/js/wagtailadmin.js +1 -1
  97. wagtail/admin/static/wagtailadmin/js/workflow-action.js +1 -1
  98. wagtail/admin/templates/wagtailadmin/collection_privacy/ancestor_privacy.html +2 -6
  99. wagtail/admin/templates/wagtailadmin/generic/index_results.html +1 -17
  100. wagtail/admin/templates/wagtailadmin/generic/listing_results.html +20 -1
  101. wagtail/admin/templates/wagtailadmin/home/workflow_objects_to_moderate.html +2 -11
  102. wagtail/admin/templates/wagtailadmin/page_privacy/ancestor_privacy.html +2 -6
  103. wagtail/admin/templates/wagtailadmin/page_privacy/no_privacy.html +2 -0
  104. wagtail/admin/templates/wagtailadmin/pages/_editor_js.html +0 -1
  105. wagtail/admin/templates/wagtailadmin/pages/action_menu/menu.html +1 -1
  106. wagtail/admin/templates/wagtailadmin/reports/aging_pages_results.html +54 -0
  107. wagtail/admin/templates/wagtailadmin/reports/base_page_report.html +1 -17
  108. wagtail/admin/templates/wagtailadmin/reports/base_page_report_results.html +10 -0
  109. wagtail/admin/templates/wagtailadmin/reports/base_report.html +1 -40
  110. wagtail/admin/templates/wagtailadmin/reports/base_report_results.html +1 -0
  111. wagtail/admin/templates/wagtailadmin/reports/listing/_list_page_report.html +21 -27
  112. wagtail/admin/templates/wagtailadmin/reports/listing/_list_page_types_usage.html +48 -54
  113. wagtail/admin/templates/wagtailadmin/reports/{locked_pages.html → locked_pages_results.html} +3 -3
  114. wagtail/admin/templates/wagtailadmin/reports/page_types_usage_results.html +10 -0
  115. wagtail/admin/templates/wagtailadmin/reports/site_history_results.html +53 -0
  116. wagtail/admin/templates/wagtailadmin/reports/workflow_results.html +74 -0
  117. wagtail/admin/templates/wagtailadmin/reports/workflow_tasks_results.html +56 -0
  118. wagtail/admin/templates/wagtailadmin/shared/_workflow_init.html +8 -44
  119. wagtail/admin/templates/wagtailadmin/shared/avatar.html +11 -1
  120. wagtail/admin/templates/wagtailadmin/shared/dialog/dialog.html +5 -4
  121. wagtail/admin/templates/wagtailadmin/shared/dropdown/dropdown_button.html +2 -1
  122. wagtail/admin/templates/wagtailadmin/shared/editing_sessions/list.html +132 -0
  123. wagtail/admin/templates/wagtailadmin/shared/editing_sessions/module.html +44 -0
  124. wagtail/admin/templates/wagtailadmin/shared/headers/slim_header.html +7 -1
  125. wagtail/admin/templates/wagtailadmin/shared/page_status_tag_new.html +1 -1
  126. wagtail/admin/templates/wagtailadmin/shared/side_panels/checks.html +32 -16
  127. wagtail/admin/templates/wagtailadmin/skeleton.html +1 -1
  128. wagtail/admin/templates/wagtailadmin/userbar/item_accessibility.html +9 -11
  129. wagtail/admin/templatetags/wagtailadmin_tags.py +13 -2
  130. wagtail/admin/tests/formats/en/__init__.py +0 -0
  131. wagtail/admin/tests/formats/en/formats.py +1 -0
  132. wagtail/admin/tests/pages/test_create_page.py +47 -0
  133. wagtail/admin/tests/pages/test_edit_page.py +10 -8
  134. wagtail/admin/tests/pages/test_parent_page_chooser_view.py +45 -1
  135. wagtail/admin/tests/test_checks.py +53 -3
  136. wagtail/admin/tests/test_collections_views.py +62 -1
  137. wagtail/admin/tests/test_edit_handlers.py +37 -0
  138. wagtail/admin/tests/test_editing_sessions.py +1336 -0
  139. wagtail/admin/tests/test_icon_sprite.py +12 -21
  140. wagtail/admin/tests/test_page_chooser.py +309 -7
  141. wagtail/admin/tests/test_privacy.py +82 -0
  142. wagtail/admin/tests/test_reports_views.py +464 -70
  143. wagtail/admin/tests/test_userbar.py +93 -6
  144. wagtail/admin/tests/test_workflows.py +223 -33
  145. wagtail/admin/tests/viewsets/test_model_viewset.py +151 -2
  146. wagtail/admin/ui/editing_sessions.py +57 -0
  147. wagtail/admin/urls/__init__.py +9 -15
  148. wagtail/admin/urls/editing_sessions.py +17 -0
  149. wagtail/admin/urls/reports.py +33 -1
  150. wagtail/admin/userbar.py +77 -20
  151. wagtail/admin/views/chooser.py +49 -22
  152. wagtail/admin/views/collections.py +0 -11
  153. wagtail/admin/views/editing_sessions.py +193 -0
  154. wagtail/admin/views/generic/__init__.py +1 -0
  155. wagtail/admin/views/generic/base.py +3 -2
  156. wagtail/admin/views/generic/history.py +9 -3
  157. wagtail/admin/views/generic/mixins.py +44 -3
  158. wagtail/admin/views/generic/models.py +46 -72
  159. wagtail/admin/views/generic/permissions.py +20 -10
  160. wagtail/admin/views/home.py +2 -31
  161. wagtail/admin/views/page_privacy.py +20 -5
  162. wagtail/admin/views/pages/choose_parent.py +62 -0
  163. wagtail/admin/views/pages/edit.py +28 -0
  164. wagtail/admin/views/reports/aging_pages.py +6 -10
  165. wagtail/admin/views/reports/audit_logging.py +13 -42
  166. wagtail/admin/views/reports/base.py +31 -4
  167. wagtail/admin/views/reports/locked_pages.py +5 -8
  168. wagtail/admin/views/reports/page_types_usage.py +6 -10
  169. wagtail/admin/views/reports/workflows.py +36 -12
  170. wagtail/admin/viewsets/base.py +8 -3
  171. wagtail/admin/viewsets/chooser.py +1 -1
  172. wagtail/admin/viewsets/model.py +26 -1
  173. wagtail/admin/wagtail_hooks.py +2 -1
  174. wagtail/api/v2/filters.py +6 -0
  175. wagtail/api/v2/tests/test_documents.py +1 -1
  176. wagtail/api/v2/tests/test_images.py +1 -1
  177. wagtail/api/v2/tests/test_pages.py +11 -1
  178. wagtail/api/v2/utils.py +2 -2
  179. wagtail/blocks/base.py +35 -12
  180. wagtail/blocks/definition_lookup.py +85 -0
  181. wagtail/blocks/list_block.py +12 -0
  182. wagtail/blocks/migrations/migrate_operation.py +2 -0
  183. wagtail/blocks/stream_block.py +19 -0
  184. wagtail/blocks/struct_block.py +19 -0
  185. wagtail/contrib/forms/locale/be/LC_MESSAGES/django.po +3 -3
  186. wagtail/contrib/forms/locale/en/LC_MESSAGES/django.po +1 -1
  187. wagtail/contrib/forms/locale/hr_HR/LC_MESSAGES/django.po +2 -2
  188. wagtail/contrib/forms/locale/pl/LC_MESSAGES/django.po +3 -3
  189. wagtail/contrib/forms/locale/pt_BR/LC_MESSAGES/django.mo +0 -0
  190. wagtail/contrib/forms/locale/pt_BR/LC_MESSAGES/django.po +2 -2
  191. wagtail/contrib/forms/locale/ru/LC_MESSAGES/django.po +3 -3
  192. wagtail/contrib/forms/locale/sl/LC_MESSAGES/django.po +2 -2
  193. wagtail/contrib/frontend_cache/backends/__init__.py +5 -0
  194. wagtail/contrib/frontend_cache/backends/azure.py +179 -0
  195. wagtail/contrib/frontend_cache/backends/base.py +28 -0
  196. wagtail/contrib/frontend_cache/backends/cloudflare.py +114 -0
  197. wagtail/contrib/frontend_cache/backends/cloudfront.py +99 -0
  198. wagtail/contrib/frontend_cache/backends/http.py +64 -0
  199. wagtail/contrib/frontend_cache/tests.py +59 -17
  200. wagtail/contrib/frontend_cache/utils.py +26 -8
  201. wagtail/contrib/redirects/filters.py +15 -1
  202. wagtail/contrib/redirects/locale/ar/LC_MESSAGES/django.po +4 -4
  203. wagtail/contrib/redirects/locale/be/LC_MESSAGES/django.po +3 -3
  204. wagtail/contrib/redirects/locale/bg/LC_MESSAGES/django.po +4 -4
  205. wagtail/contrib/redirects/locale/ca/LC_MESSAGES/django.po +4 -4
  206. wagtail/contrib/redirects/locale/cs/LC_MESSAGES/django.po +4 -4
  207. wagtail/contrib/redirects/locale/cy/LC_MESSAGES/django.po +6 -6
  208. wagtail/contrib/redirects/locale/de/LC_MESSAGES/django.po +5 -4
  209. wagtail/contrib/redirects/locale/el/LC_MESSAGES/django.po +7 -7
  210. wagtail/contrib/redirects/locale/en/LC_MESSAGES/django.po +37 -72
  211. wagtail/contrib/redirects/locale/es/LC_MESSAGES/django.po +6 -6
  212. wagtail/contrib/redirects/locale/et/LC_MESSAGES/django.po +4 -4
  213. wagtail/contrib/redirects/locale/fa/LC_MESSAGES/django.mo +0 -0
  214. wagtail/contrib/redirects/locale/fa/LC_MESSAGES/django.po +18 -5
  215. wagtail/contrib/redirects/locale/fi/LC_MESSAGES/django.po +6 -6
  216. wagtail/contrib/redirects/locale/fr/LC_MESSAGES/django.po +4 -4
  217. wagtail/contrib/redirects/locale/gl/LC_MESSAGES/django.po +4 -4
  218. wagtail/contrib/redirects/locale/hr_HR/LC_MESSAGES/django.po +8 -8
  219. wagtail/contrib/redirects/locale/hu/LC_MESSAGES/django.po +6 -6
  220. wagtail/contrib/redirects/locale/id_ID/LC_MESSAGES/django.po +4 -4
  221. wagtail/contrib/redirects/locale/is_IS/LC_MESSAGES/django.po +6 -6
  222. wagtail/contrib/redirects/locale/it/LC_MESSAGES/django.po +4 -4
  223. wagtail/contrib/redirects/locale/ja/LC_MESSAGES/django.po +2 -2
  224. wagtail/contrib/redirects/locale/ko/LC_MESSAGES/django.po +4 -4
  225. wagtail/contrib/redirects/locale/lt/LC_MESSAGES/django.po +4 -4
  226. wagtail/contrib/redirects/locale/mn/LC_MESSAGES/django.po +4 -4
  227. wagtail/contrib/redirects/locale/nb/LC_MESSAGES/django.po +4 -4
  228. wagtail/contrib/redirects/locale/nl/LC_MESSAGES/django.po +4 -4
  229. wagtail/contrib/redirects/locale/pl/LC_MESSAGES/django.po +9 -9
  230. wagtail/contrib/redirects/locale/pt_BR/LC_MESSAGES/django.po +5 -5
  231. wagtail/contrib/redirects/locale/pt_PT/LC_MESSAGES/django.po +4 -4
  232. wagtail/contrib/redirects/locale/ro/LC_MESSAGES/django.po +4 -4
  233. wagtail/contrib/redirects/locale/ru/LC_MESSAGES/django.po +7 -7
  234. wagtail/contrib/redirects/locale/sk_SK/LC_MESSAGES/django.po +4 -4
  235. wagtail/contrib/redirects/locale/sl/LC_MESSAGES/django.po +6 -6
  236. wagtail/contrib/redirects/locale/sr/LC_MESSAGES/django.po +2 -2
  237. wagtail/contrib/redirects/locale/sv/LC_MESSAGES/django.po +4 -4
  238. wagtail/contrib/redirects/locale/tet/LC_MESSAGES/django.po +4 -4
  239. wagtail/contrib/redirects/locale/th/LC_MESSAGES/django.po +4 -4
  240. wagtail/contrib/redirects/locale/tr/LC_MESSAGES/django.po +4 -4
  241. wagtail/contrib/redirects/locale/tr_TR/LC_MESSAGES/django.po +4 -4
  242. wagtail/contrib/redirects/locale/uk/LC_MESSAGES/django.po +4 -4
  243. wagtail/contrib/redirects/locale/zh/LC_MESSAGES/django.po +4 -4
  244. wagtail/contrib/redirects/locale/zh_Hans/LC_MESSAGES/django.po +4 -4
  245. wagtail/contrib/redirects/locale/zh_Hant/LC_MESSAGES/django.po +4 -4
  246. wagtail/contrib/redirects/models.py +6 -5
  247. wagtail/contrib/redirects/templates/wagtailredirects/edit.html +1 -38
  248. wagtail/contrib/redirects/tests/test_redirects.py +141 -1
  249. wagtail/contrib/redirects/urls.py +1 -2
  250. wagtail/contrib/redirects/views.py +39 -80
  251. wagtail/contrib/routable_page/models.py +6 -4
  252. wagtail/contrib/routable_page/tests.py +11 -0
  253. wagtail/contrib/search_promotions/locale/ar/LC_MESSAGES/django.po +4 -4
  254. wagtail/contrib/search_promotions/locale/be/LC_MESSAGES/django.po +7 -7
  255. wagtail/contrib/search_promotions/locale/ca/LC_MESSAGES/django.po +8 -8
  256. wagtail/contrib/search_promotions/locale/cs/LC_MESSAGES/django.po +2 -2
  257. wagtail/contrib/search_promotions/locale/cy/LC_MESSAGES/django.po +4 -4
  258. wagtail/contrib/search_promotions/locale/de/LC_MESSAGES/django.po +6 -6
  259. wagtail/contrib/search_promotions/locale/el/LC_MESSAGES/django.po +4 -4
  260. wagtail/contrib/search_promotions/locale/en/LC_MESSAGES/django.po +1 -1
  261. wagtail/contrib/search_promotions/locale/es/LC_MESSAGES/django.po +6 -6
  262. wagtail/contrib/search_promotions/locale/et/LC_MESSAGES/django.po +4 -4
  263. wagtail/contrib/search_promotions/locale/fa/LC_MESSAGES/django.po +4 -4
  264. wagtail/contrib/search_promotions/locale/fi/LC_MESSAGES/django.po +6 -6
  265. wagtail/contrib/search_promotions/locale/fr/LC_MESSAGES/django.mo +0 -0
  266. wagtail/contrib/search_promotions/locale/fr/LC_MESSAGES/django.po +9 -6
  267. wagtail/contrib/search_promotions/locale/gl/LC_MESSAGES/django.po +6 -6
  268. wagtail/contrib/search_promotions/locale/hr_HR/LC_MESSAGES/django.po +8 -8
  269. wagtail/contrib/search_promotions/locale/hu/LC_MESSAGES/django.po +4 -4
  270. wagtail/contrib/search_promotions/locale/id_ID/LC_MESSAGES/django.po +4 -4
  271. wagtail/contrib/search_promotions/locale/is_IS/LC_MESSAGES/django.po +8 -8
  272. wagtail/contrib/search_promotions/locale/it/LC_MESSAGES/django.po +6 -6
  273. wagtail/contrib/search_promotions/locale/ja/LC_MESSAGES/django.po +4 -4
  274. wagtail/contrib/search_promotions/locale/ko/LC_MESSAGES/django.po +4 -4
  275. wagtail/contrib/search_promotions/locale/lt/LC_MESSAGES/django.po +6 -6
  276. wagtail/contrib/search_promotions/locale/nb/LC_MESSAGES/django.po +4 -4
  277. wagtail/contrib/search_promotions/locale/nl/LC_MESSAGES/django.po +6 -6
  278. wagtail/contrib/search_promotions/locale/pl/LC_MESSAGES/django.po +9 -9
  279. wagtail/contrib/search_promotions/locale/pt_BR/LC_MESSAGES/django.po +4 -4
  280. wagtail/contrib/search_promotions/locale/pt_PT/LC_MESSAGES/django.po +4 -4
  281. wagtail/contrib/search_promotions/locale/ro/LC_MESSAGES/django.po +4 -4
  282. wagtail/contrib/search_promotions/locale/ru/LC_MESSAGES/django.po +9 -9
  283. wagtail/contrib/search_promotions/locale/sk_SK/LC_MESSAGES/django.po +4 -4
  284. wagtail/contrib/search_promotions/locale/sl/LC_MESSAGES/django.mo +0 -0
  285. wagtail/contrib/search_promotions/locale/sl/LC_MESSAGES/django.po +62 -8
  286. wagtail/contrib/search_promotions/locale/sr/LC_MESSAGES/django.po +2 -2
  287. wagtail/contrib/search_promotions/locale/sv/LC_MESSAGES/django.mo +0 -0
  288. wagtail/contrib/search_promotions/locale/sv/LC_MESSAGES/django.po +9 -6
  289. wagtail/contrib/search_promotions/locale/th/LC_MESSAGES/django.po +4 -4
  290. wagtail/contrib/search_promotions/locale/tr/LC_MESSAGES/django.po +4 -4
  291. wagtail/contrib/search_promotions/locale/tr_TR/LC_MESSAGES/django.po +4 -4
  292. wagtail/contrib/search_promotions/locale/uk/LC_MESSAGES/django.po +4 -4
  293. wagtail/contrib/search_promotions/locale/zh_Hans/LC_MESSAGES/django.po +2 -2
  294. wagtail/contrib/search_promotions/locale/zh_Hant/LC_MESSAGES/django.po +2 -2
  295. wagtail/contrib/settings/locale/be/LC_MESSAGES/django.po +3 -3
  296. wagtail/contrib/settings/locale/en/LC_MESSAGES/django.po +4 -4
  297. wagtail/contrib/settings/locale/hr_HR/LC_MESSAGES/django.po +2 -2
  298. wagtail/contrib/settings/locale/pl/LC_MESSAGES/django.po +3 -3
  299. wagtail/contrib/settings/locale/pt_BR/LC_MESSAGES/django.po +1 -1
  300. wagtail/contrib/settings/locale/ru/LC_MESSAGES/django.po +3 -3
  301. wagtail/contrib/settings/locale/sk_SK/LC_MESSAGES/django.mo +0 -0
  302. wagtail/contrib/settings/locale/sk_SK/LC_MESSAGES/django.po +10 -1
  303. wagtail/contrib/settings/locale/sl/LC_MESSAGES/django.po +2 -2
  304. wagtail/contrib/settings/locale/sr/LC_MESSAGES/django.po +2 -2
  305. wagtail/contrib/simple_translation/locale/be/LC_MESSAGES/django.po +3 -3
  306. wagtail/contrib/simple_translation/locale/en/LC_MESSAGES/django.po +5 -1
  307. wagtail/contrib/simple_translation/locale/hr_HR/LC_MESSAGES/django.po +2 -2
  308. wagtail/contrib/simple_translation/locale/pl/LC_MESSAGES/django.po +3 -3
  309. wagtail/contrib/simple_translation/locale/pt_BR/LC_MESSAGES/django.po +1 -1
  310. wagtail/contrib/simple_translation/locale/ru/LC_MESSAGES/django.po +3 -3
  311. wagtail/contrib/simple_translation/locale/sl/LC_MESSAGES/django.po +2 -2
  312. wagtail/contrib/simple_translation/models.py +2 -1
  313. wagtail/contrib/styleguide/locale/be/LC_MESSAGES/django.po +3 -3
  314. wagtail/contrib/styleguide/locale/en/LC_MESSAGES/django.po +7 -7
  315. wagtail/contrib/styleguide/locale/hr_HR/LC_MESSAGES/django.po +2 -2
  316. wagtail/contrib/styleguide/locale/pl/LC_MESSAGES/django.po +3 -3
  317. wagtail/contrib/styleguide/locale/ru/LC_MESSAGES/django.po +3 -3
  318. wagtail/contrib/styleguide/locale/sk_SK/LC_MESSAGES/django.mo +0 -0
  319. wagtail/contrib/styleguide/locale/sk_SK/LC_MESSAGES/django.po +5 -1
  320. wagtail/contrib/styleguide/locale/sl/LC_MESSAGES/django.po +2 -2
  321. wagtail/contrib/styleguide/locale/zh_Hans/LC_MESSAGES/django.mo +0 -0
  322. wagtail/contrib/styleguide/locale/zh_Hans/LC_MESSAGES/django.po +3 -0
  323. wagtail/contrib/table_block/locale/be/LC_MESSAGES/django.po +3 -3
  324. wagtail/contrib/table_block/locale/en/LC_MESSAGES/django.po +1 -1
  325. wagtail/contrib/table_block/locale/fr/LC_MESSAGES/django.mo +0 -0
  326. wagtail/contrib/table_block/locale/fr/LC_MESSAGES/django.po +27 -1
  327. wagtail/contrib/table_block/locale/hr_HR/LC_MESSAGES/django.po +2 -2
  328. wagtail/contrib/table_block/locale/pl/LC_MESSAGES/django.po +3 -3
  329. wagtail/contrib/table_block/locale/ru/LC_MESSAGES/django.po +3 -3
  330. wagtail/contrib/table_block/locale/sl/LC_MESSAGES/django.mo +0 -0
  331. wagtail/contrib/table_block/locale/sl/LC_MESSAGES/django.po +29 -3
  332. wagtail/contrib/table_block/static/table_block/js/table.js +1 -1
  333. wagtail/contrib/typed_table_block/blocks.py +19 -0
  334. wagtail/contrib/typed_table_block/locale/be/LC_MESSAGES/django.po +3 -3
  335. wagtail/contrib/typed_table_block/locale/en/LC_MESSAGES/django.po +10 -10
  336. wagtail/contrib/typed_table_block/locale/fr/LC_MESSAGES/django.mo +0 -0
  337. wagtail/contrib/typed_table_block/locale/fr/LC_MESSAGES/django.po +12 -1
  338. wagtail/contrib/typed_table_block/locale/pl/LC_MESSAGES/django.po +3 -3
  339. wagtail/contrib/typed_table_block/locale/pt_BR/LC_MESSAGES/django.po +1 -1
  340. wagtail/contrib/typed_table_block/locale/ru/LC_MESSAGES/django.po +3 -3
  341. wagtail/contrib/typed_table_block/locale/sl/LC_MESSAGES/django.mo +0 -0
  342. wagtail/contrib/typed_table_block/locale/sl/LC_MESSAGES/django.po +14 -4
  343. wagtail/contrib/typed_table_block/static/typed_table_block/js/typed_table_block.js +1 -1
  344. wagtail/contrib/typed_table_block/tests.py +38 -0
  345. wagtail/coreutils.py +1 -1
  346. wagtail/documents/__init__.py +1 -1
  347. wagtail/documents/locale/ar/LC_MESSAGES/django.po +8 -8
  348. wagtail/documents/locale/be/LC_MESSAGES/django.po +11 -11
  349. wagtail/documents/locale/bg/LC_MESSAGES/django.po +4 -4
  350. wagtail/documents/locale/ca/LC_MESSAGES/django.mo +0 -0
  351. wagtail/documents/locale/ca/LC_MESSAGES/django.po +12 -11
  352. wagtail/documents/locale/cs/LC_MESSAGES/django.po +6 -6
  353. wagtail/documents/locale/de/LC_MESSAGES/django.po +10 -8
  354. wagtail/documents/locale/el/LC_MESSAGES/django.po +8 -8
  355. wagtail/documents/locale/en/LC_MESSAGES/django.po +8 -8
  356. wagtail/documents/locale/es/LC_MESSAGES/django.po +8 -8
  357. wagtail/documents/locale/et/LC_MESSAGES/django.po +6 -6
  358. wagtail/documents/locale/fa/LC_MESSAGES/django.mo +0 -0
  359. wagtail/documents/locale/fa/LC_MESSAGES/django.po +17 -8
  360. wagtail/documents/locale/fi/LC_MESSAGES/django.po +10 -10
  361. wagtail/documents/locale/fr/LC_MESSAGES/django.po +6 -6
  362. wagtail/documents/locale/gl/LC_MESSAGES/django.po +8 -8
  363. wagtail/documents/locale/hr_HR/LC_MESSAGES/django.po +14 -14
  364. wagtail/documents/locale/hu/LC_MESSAGES/django.po +12 -12
  365. wagtail/documents/locale/id_ID/LC_MESSAGES/django.po +6 -6
  366. wagtail/documents/locale/is_IS/LC_MESSAGES/django.po +8 -8
  367. wagtail/documents/locale/it/LC_MESSAGES/django.po +8 -8
  368. wagtail/documents/locale/ja/LC_MESSAGES/django.po +8 -8
  369. wagtail/documents/locale/ko/LC_MESSAGES/django.po +8 -8
  370. wagtail/documents/locale/lt/LC_MESSAGES/django.po +8 -8
  371. wagtail/documents/locale/mi/LC_MESSAGES/django.po +10 -10
  372. wagtail/documents/locale/mn/LC_MESSAGES/django.po +5 -4
  373. wagtail/documents/locale/nb/LC_MESSAGES/django.po +6 -6
  374. wagtail/documents/locale/nl/LC_MESSAGES/django.po +8 -8
  375. wagtail/documents/locale/pl/LC_MESSAGES/django.po +11 -11
  376. wagtail/documents/locale/pt_BR/LC_MESSAGES/django.po +8 -8
  377. wagtail/documents/locale/pt_PT/LC_MESSAGES/django.po +8 -8
  378. wagtail/documents/locale/ro/LC_MESSAGES/django.po +8 -8
  379. wagtail/documents/locale/ru/LC_MESSAGES/django.po +9 -9
  380. wagtail/documents/locale/sk_SK/LC_MESSAGES/django.mo +0 -0
  381. wagtail/documents/locale/sk_SK/LC_MESSAGES/django.po +55 -12
  382. wagtail/documents/locale/sl/LC_MESSAGES/django.mo +0 -0
  383. wagtail/documents/locale/sl/LC_MESSAGES/django.po +30 -10
  384. wagtail/documents/locale/sr/LC_MESSAGES/django.po +2 -2
  385. wagtail/documents/locale/sv/LC_MESSAGES/django.po +6 -6
  386. wagtail/documents/locale/th/LC_MESSAGES/django.po +8 -8
  387. wagtail/documents/locale/tr/LC_MESSAGES/django.po +8 -8
  388. wagtail/documents/locale/tr_TR/LC_MESSAGES/django.po +8 -8
  389. wagtail/documents/locale/uk/LC_MESSAGES/django.po +8 -8
  390. wagtail/documents/locale/zh/LC_MESSAGES/django.po +2 -2
  391. wagtail/documents/locale/zh_Hans/LC_MESSAGES/django.mo +0 -0
  392. wagtail/documents/locale/zh_Hans/LC_MESSAGES/django.po +11 -5
  393. wagtail/documents/locale/zh_Hant/LC_MESSAGES/django.po +4 -4
  394. wagtail/documents/models.py +5 -1
  395. wagtail/documents/static/wagtaildocs/js/document-chooser-modal.js +1 -1
  396. wagtail/documents/static/wagtaildocs/js/document-chooser-telepath.js +1 -1
  397. wagtail/documents/static/wagtaildocs/js/document-chooser.js +1 -1
  398. wagtail/documents/tests/test_models.py +5 -1
  399. wagtail/embeds/apps.py +2 -0
  400. wagtail/embeds/embeds.py +12 -14
  401. wagtail/embeds/finders/__init__.py +2 -0
  402. wagtail/embeds/finders/facebook.py +17 -33
  403. wagtail/embeds/finders/instagram.py +19 -16
  404. wagtail/embeds/locale/be/LC_MESSAGES/django.po +3 -3
  405. wagtail/embeds/locale/en/LC_MESSAGES/django.po +1 -1
  406. wagtail/embeds/locale/hr_HR/LC_MESSAGES/django.po +2 -2
  407. wagtail/embeds/locale/pl/LC_MESSAGES/django.po +3 -3
  408. wagtail/embeds/locale/ru/LC_MESSAGES/django.po +3 -3
  409. wagtail/embeds/locale/sl/LC_MESSAGES/django.po +2 -2
  410. wagtail/embeds/signal_handlers.py +13 -0
  411. wagtail/embeds/tests/test_embeds.py +7 -7
  412. wagtail/fields.py +58 -14
  413. wagtail/images/__init__.py +1 -1
  414. wagtail/images/locale/ar/LC_MESSAGES/django.po +6 -6
  415. wagtail/images/locale/be/LC_MESSAGES/django.po +3 -3
  416. wagtail/images/locale/ca/LC_MESSAGES/django.po +8 -8
  417. wagtail/images/locale/cs/LC_MESSAGES/django.po +8 -8
  418. wagtail/images/locale/cy/LC_MESSAGES/django.po +8 -8
  419. wagtail/images/locale/de/LC_MESSAGES/django.po +6 -6
  420. wagtail/images/locale/el/LC_MESSAGES/django.po +8 -8
  421. wagtail/images/locale/en/LC_MESSAGES/django.po +34 -34
  422. wagtail/images/locale/es/LC_MESSAGES/django.po +10 -10
  423. wagtail/images/locale/et/LC_MESSAGES/django.po +8 -8
  424. wagtail/images/locale/fa/LC_MESSAGES/django.mo +0 -0
  425. wagtail/images/locale/fa/LC_MESSAGES/django.po +28 -9
  426. wagtail/images/locale/fi/LC_MESSAGES/django.po +8 -8
  427. wagtail/images/locale/fr/LC_MESSAGES/django.po +6 -6
  428. wagtail/images/locale/gl/LC_MESSAGES/django.po +8 -8
  429. wagtail/images/locale/hr_HR/LC_MESSAGES/django.po +8 -8
  430. wagtail/images/locale/hu/LC_MESSAGES/django.po +8 -8
  431. wagtail/images/locale/id_ID/LC_MESSAGES/django.po +6 -6
  432. wagtail/images/locale/is_IS/LC_MESSAGES/django.po +8 -8
  433. wagtail/images/locale/it/LC_MESSAGES/django.po +8 -8
  434. wagtail/images/locale/ja/LC_MESSAGES/django.po +8 -8
  435. wagtail/images/locale/ko/LC_MESSAGES/django.po +6 -6
  436. wagtail/images/locale/lt/LC_MESSAGES/django.po +8 -8
  437. wagtail/images/locale/nb/LC_MESSAGES/django.po +8 -8
  438. wagtail/images/locale/nl/LC_MESSAGES/django.po +8 -8
  439. wagtail/images/locale/pl/LC_MESSAGES/django.po +11 -11
  440. wagtail/images/locale/pt_BR/LC_MESSAGES/django.po +8 -8
  441. wagtail/images/locale/pt_PT/LC_MESSAGES/django.po +8 -8
  442. wagtail/images/locale/ro/LC_MESSAGES/django.po +8 -8
  443. wagtail/images/locale/ru/LC_MESSAGES/django.po +11 -11
  444. wagtail/images/locale/sk_SK/LC_MESSAGES/django.mo +0 -0
  445. wagtail/images/locale/sk_SK/LC_MESSAGES/django.po +23 -8
  446. wagtail/images/locale/sl/LC_MESSAGES/django.mo +0 -0
  447. wagtail/images/locale/sl/LC_MESSAGES/django.po +44 -12
  448. wagtail/images/locale/sv/LC_MESSAGES/django.mo +0 -0
  449. wagtail/images/locale/sv/LC_MESSAGES/django.po +20 -8
  450. wagtail/images/locale/tet/LC_MESSAGES/django.po +4 -4
  451. wagtail/images/locale/th/LC_MESSAGES/django.po +8 -8
  452. wagtail/images/locale/tr/LC_MESSAGES/django.po +6 -6
  453. wagtail/images/locale/tr_TR/LC_MESSAGES/django.po +6 -6
  454. wagtail/images/locale/uk/LC_MESSAGES/django.po +8 -8
  455. wagtail/images/locale/zh_Hans/LC_MESSAGES/django.mo +0 -0
  456. wagtail/images/locale/zh_Hans/LC_MESSAGES/django.po +49 -5
  457. wagtail/images/locale/zh_Hant/LC_MESSAGES/django.po +4 -4
  458. wagtail/images/models.py +3 -0
  459. wagtail/images/static/wagtailimages/js/image-chooser-modal.js +1 -1
  460. wagtail/images/static/wagtailimages/js/image-chooser-telepath.js +1 -1
  461. wagtail/images/static/wagtailimages/js/image-chooser.js +1 -1
  462. wagtail/images/templates/wagtailimages/images/edit.html +4 -4
  463. wagtail/images/tests/test_admin_views.py +58 -2
  464. wagtail/images/tests/test_image_operations.py +12 -0
  465. wagtail/images/tests/tests.py +27 -2
  466. wagtail/images/views/chooser.py +6 -1
  467. wagtail/images/views/images.py +7 -3
  468. wagtail/images/views/serve.py +1 -0
  469. wagtail/locale/be/LC_MESSAGES/django.po +3 -3
  470. wagtail/locale/en/LC_MESSAGES/django.po +84 -80
  471. wagtail/locale/fa/LC_MESSAGES/django.mo +0 -0
  472. wagtail/locale/fa/LC_MESSAGES/django.po +3 -0
  473. wagtail/locale/fr/LC_MESSAGES/django.mo +0 -0
  474. wagtail/locale/fr/LC_MESSAGES/django.po +23 -4
  475. wagtail/locale/hr_HR/LC_MESSAGES/django.po +2 -2
  476. wagtail/locale/pl/LC_MESSAGES/django.po +3 -3
  477. wagtail/locale/pt_BR/LC_MESSAGES/django.po +1 -1
  478. wagtail/locale/ru/LC_MESSAGES/django.po +3 -3
  479. wagtail/locale/sl/LC_MESSAGES/django.po +2 -2
  480. wagtail/locale/sv/LC_MESSAGES/django.mo +0 -0
  481. wagtail/locale/sv/LC_MESSAGES/django.po +11 -2
  482. wagtail/locales/locale/be/LC_MESSAGES/django.po +3 -3
  483. wagtail/locales/locale/en/LC_MESSAGES/django.po +2 -2
  484. wagtail/locales/locale/hr_HR/LC_MESSAGES/django.po +2 -2
  485. wagtail/locales/locale/pl/LC_MESSAGES/django.po +3 -3
  486. wagtail/locales/locale/ru/LC_MESSAGES/django.po +3 -3
  487. wagtail/locales/locale/sl/LC_MESSAGES/django.po +2 -2
  488. wagtail/locales/tests.py +16 -0
  489. wagtail/locales/wagtail_hooks.py +0 -9
  490. wagtail/migrations/0094_alter_page_locale.py +19 -0
  491. wagtail/models/__init__.py +11 -5
  492. wagtail/models/i18n.py +6 -1
  493. wagtail/project_template/requirements.txt +1 -1
  494. wagtail/search/locale/be/LC_MESSAGES/django.po +3 -3
  495. wagtail/search/locale/en/LC_MESSAGES/django.po +1 -1
  496. wagtail/search/locale/fa/LC_MESSAGES/django.mo +0 -0
  497. wagtail/search/locale/fa/LC_MESSAGES/django.po +24 -0
  498. wagtail/search/locale/hr_HR/LC_MESSAGES/django.po +2 -2
  499. wagtail/search/locale/pl/LC_MESSAGES/django.po +3 -3
  500. wagtail/search/locale/pt_BR/LC_MESSAGES/django.mo +0 -0
  501. wagtail/search/locale/pt_BR/LC_MESSAGES/django.po +2 -2
  502. wagtail/search/locale/ru/LC_MESSAGES/django.po +3 -3
  503. wagtail/search/locale/sl/LC_MESSAGES/django.po +2 -2
  504. wagtail/search/tests/test_queries.py +24 -0
  505. wagtail/search/utils.py +6 -12
  506. wagtail/signals.py +4 -0
  507. wagtail/sites/locale/be/LC_MESSAGES/django.po +3 -3
  508. wagtail/sites/locale/en/LC_MESSAGES/django.po +2 -2
  509. wagtail/sites/locale/hr_HR/LC_MESSAGES/django.po +2 -2
  510. wagtail/sites/locale/pl/LC_MESSAGES/django.po +3 -3
  511. wagtail/sites/locale/ru/LC_MESSAGES/django.po +3 -3
  512. wagtail/sites/locale/sl/LC_MESSAGES/django.po +2 -2
  513. wagtail/sites/locale/sr/LC_MESSAGES/django.po +2 -2
  514. wagtail/sites/tests.py +15 -0
  515. wagtail/sites/wagtail_hooks.py +0 -9
  516. wagtail/snippets/locale/be/LC_MESSAGES/django.po +3 -3
  517. wagtail/snippets/locale/ca/LC_MESSAGES/django.po +6 -6
  518. wagtail/snippets/locale/de/LC_MESSAGES/django.po +5 -5
  519. wagtail/snippets/locale/en/LC_MESSAGES/django.po +9 -9
  520. wagtail/snippets/locale/es/LC_MESSAGES/django.po +6 -6
  521. wagtail/snippets/locale/fa/LC_MESSAGES/django.mo +0 -0
  522. wagtail/snippets/locale/fa/LC_MESSAGES/django.po +17 -1
  523. wagtail/snippets/locale/fr/LC_MESSAGES/django.po +5 -5
  524. wagtail/snippets/locale/gl/LC_MESSAGES/django.po +6 -6
  525. wagtail/snippets/locale/hr_HR/LC_MESSAGES/django.po +8 -8
  526. wagtail/snippets/locale/hu/LC_MESSAGES/django.po +7 -7
  527. wagtail/snippets/locale/is_IS/LC_MESSAGES/django.po +5 -5
  528. wagtail/snippets/locale/it/LC_MESSAGES/django.po +5 -5
  529. wagtail/snippets/locale/ko/LC_MESSAGES/django.po +6 -6
  530. wagtail/snippets/locale/nb/LC_MESSAGES/django.po +6 -6
  531. wagtail/snippets/locale/nl/LC_MESSAGES/django.po +8 -8
  532. wagtail/snippets/locale/pl/LC_MESSAGES/django.po +9 -9
  533. wagtail/snippets/locale/pt_BR/LC_MESSAGES/django.po +1 -1
  534. wagtail/snippets/locale/ro/LC_MESSAGES/django.po +6 -6
  535. wagtail/snippets/locale/ru/LC_MESSAGES/django.po +8 -8
  536. wagtail/snippets/locale/sk_SK/LC_MESSAGES/django.mo +0 -0
  537. wagtail/snippets/locale/sk_SK/LC_MESSAGES/django.po +3 -0
  538. wagtail/snippets/locale/sl/LC_MESSAGES/django.po +8 -8
  539. wagtail/snippets/locale/sr/LC_MESSAGES/django.po +2 -2
  540. wagtail/snippets/locale/sv/LC_MESSAGES/django.po +6 -6
  541. wagtail/snippets/locale/zh_Hans/LC_MESSAGES/django.mo +0 -0
  542. wagtail/snippets/locale/zh_Hans/LC_MESSAGES/django.po +40 -1
  543. wagtail/snippets/permissions.py +5 -3
  544. wagtail/snippets/static/wagtailsnippets/js/snippet-chooser-telepath.js +1 -1
  545. wagtail/snippets/static/wagtailsnippets/js/snippet-chooser.js +1 -1
  546. wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/menu.html +1 -1
  547. wagtail/snippets/tests/test_snippets.py +78 -12
  548. wagtail/snippets/tests/test_viewset.py +22 -0
  549. wagtail/snippets/views/snippets.py +19 -14
  550. wagtail/snippets/wagtail_hooks.py +2 -10
  551. wagtail/templatetags/wagtailcore_tags.py +3 -0
  552. wagtail/test/dummy_external_storage.py +1 -1
  553. wagtail/test/i18n/migrations/0003_alter_clusterabletestmodel_locale_and_more.py +40 -0
  554. wagtail/test/routablepage/models.py +4 -0
  555. wagtail/test/snippets/migrations/0012_alter_translatablesnippet_locale.py +20 -0
  556. wagtail/test/testapp/migrations/0038_sociallink.py +52 -0
  557. wagtail/test/testapp/migrations/0039_alter_eventcategory_locale_and_more.py +45 -0
  558. wagtail/test/testapp/models.py +24 -0
  559. wagtail/test/testapp/views.py +1 -0
  560. wagtail/test/testapp/wagtail_hooks.py +9 -0
  561. wagtail/test/urls_multilang.py +6 -1
  562. wagtail/test/urls_multilang_non_root.py +11 -0
  563. wagtail/tests/streamfield_migrations/test_migrations.py +53 -12
  564. wagtail/tests/test_audit_log.py +72 -2
  565. wagtail/tests/test_blocks.py +103 -0
  566. wagtail/tests/test_signals.py +49 -2
  567. wagtail/tests/test_streamfield.py +153 -0
  568. wagtail/tests/test_utils.py +42 -1
  569. wagtail/tests/tests.py +5 -0
  570. wagtail/users/apps.py +1 -0
  571. wagtail/users/forms.py +7 -0
  572. wagtail/users/locale/ar/LC_MESSAGES/django.po +4 -4
  573. wagtail/users/locale/be/LC_MESSAGES/django.po +9 -9
  574. wagtail/users/locale/ca/LC_MESSAGES/django.po +8 -8
  575. wagtail/users/locale/cs/LC_MESSAGES/django.po +6 -6
  576. wagtail/users/locale/cy/LC_MESSAGES/django.po +8 -8
  577. wagtail/users/locale/de/LC_MESSAGES/django.po +8 -8
  578. wagtail/users/locale/el/LC_MESSAGES/django.po +4 -4
  579. wagtail/users/locale/en/LC_MESSAGES/django.po +55 -50
  580. wagtail/users/locale/es/LC_MESSAGES/django.po +8 -8
  581. wagtail/users/locale/et/LC_MESSAGES/django.po +8 -8
  582. wagtail/users/locale/fa/LC_MESSAGES/django.mo +0 -0
  583. wagtail/users/locale/fa/LC_MESSAGES/django.po +69 -7
  584. wagtail/users/locale/fi/LC_MESSAGES/django.po +8 -8
  585. wagtail/users/locale/fr/LC_MESSAGES/django.mo +0 -0
  586. wagtail/users/locale/fr/LC_MESSAGES/django.po +52 -11
  587. wagtail/users/locale/gl/LC_MESSAGES/django.po +8 -8
  588. wagtail/users/locale/hr_HR/LC_MESSAGES/django.po +10 -10
  589. wagtail/users/locale/hu/LC_MESSAGES/django.po +8 -8
  590. wagtail/users/locale/id_ID/LC_MESSAGES/django.po +4 -4
  591. wagtail/users/locale/is_IS/LC_MESSAGES/django.po +8 -8
  592. wagtail/users/locale/it/LC_MESSAGES/django.po +8 -8
  593. wagtail/users/locale/ja/LC_MESSAGES/django.po +4 -4
  594. wagtail/users/locale/ko/LC_MESSAGES/django.po +4 -4
  595. wagtail/users/locale/lt/LC_MESSAGES/django.po +4 -4
  596. wagtail/users/locale/lv/LC_MESSAGES/django.po +4 -4
  597. wagtail/users/locale/mn/LC_MESSAGES/django.po +5 -4
  598. wagtail/users/locale/nb/LC_MESSAGES/django.po +8 -8
  599. wagtail/users/locale/nl/LC_MESSAGES/django.po +6 -6
  600. wagtail/users/locale/pl/LC_MESSAGES/django.po +9 -9
  601. wagtail/users/locale/pt_BR/LC_MESSAGES/django.po +9 -9
  602. wagtail/users/locale/pt_PT/LC_MESSAGES/django.po +8 -8
  603. wagtail/users/locale/ro/LC_MESSAGES/django.po +8 -8
  604. wagtail/users/locale/ru/LC_MESSAGES/django.po +11 -11
  605. wagtail/users/locale/sk_SK/LC_MESSAGES/django.mo +0 -0
  606. wagtail/users/locale/sk_SK/LC_MESSAGES/django.po +12 -5
  607. wagtail/users/locale/sl/LC_MESSAGES/django.mo +0 -0
  608. wagtail/users/locale/sl/LC_MESSAGES/django.po +56 -12
  609. wagtail/users/locale/sv/LC_MESSAGES/django.mo +0 -0
  610. wagtail/users/locale/sv/LC_MESSAGES/django.po +49 -10
  611. wagtail/users/locale/tet/LC_MESSAGES/django.po +4 -4
  612. wagtail/users/locale/th/LC_MESSAGES/django.po +4 -4
  613. wagtail/users/locale/tr/LC_MESSAGES/django.po +4 -4
  614. wagtail/users/locale/tr_TR/LC_MESSAGES/django.po +4 -4
  615. wagtail/users/locale/uk/LC_MESSAGES/django.po +8 -8
  616. wagtail/users/locale/zh_Hans/LC_MESSAGES/django.mo +0 -0
  617. wagtail/users/locale/zh_Hans/LC_MESSAGES/django.po +49 -5
  618. wagtail/users/locale/zh_Hant/LC_MESSAGES/django.po +2 -2
  619. wagtail/users/models.py +1 -0
  620. wagtail/users/templates/wagtailusers/groups/includes/formatted_permissions.html +3 -2
  621. wagtail/users/templatetags/wagtailusers_tags.py +9 -0
  622. wagtail/users/tests/__init__.py +7 -1
  623. wagtail/users/tests/test_admin_views.py +117 -32
  624. wagtail/users/views/groups.py +4 -0
  625. wagtail/users/views/users.py +58 -14
  626. wagtail/users/wagtail_hooks.py +7 -123
  627. wagtail/utils/utils.py +27 -0
  628. wagtail/utils/version.py +5 -2
  629. wagtail-6.2rc1.dist-info/METADATA +78 -0
  630. {wagtail-6.1.2.dist-info → wagtail-6.2rc1.dist-info}/RECORD +634 -607
  631. {wagtail-6.1.2.dist-info → wagtail-6.2rc1.dist-info}/WHEEL +1 -1
  632. wagtail/admin/templates/wagtailadmin/reports/aging_pages.html +0 -58
  633. wagtail/admin/templates/wagtailadmin/reports/page_types_usage.html +0 -18
  634. wagtail/admin/templates/wagtailadmin/reports/site_history.html +0 -57
  635. wagtail/admin/templates/wagtailadmin/reports/workflow.html +0 -81
  636. wagtail/admin/templates/wagtailadmin/reports/workflow_tasks.html +0 -63
  637. wagtail/contrib/frontend_cache/backends.py +0 -400
  638. wagtail/contrib/redirects/templates/wagtailredirects/list.html +0 -43
  639. wagtail/contrib/redirects/templates/wagtailredirects/reports/redirects_report.html +0 -14
  640. wagtail/contrib/redirects/tests/test_reports_view.py +0 -82
  641. wagtail-6.1.2.dist-info/METADATA +0 -78
  642. {wagtail-6.1.2.dist-info → wagtail-6.2rc1.dist-info}/LICENSE +0 -0
  643. {wagtail-6.1.2.dist-info → wagtail-6.2rc1.dist-info}/entry_points.txt +0 -0
  644. {wagtail-6.1.2.dist-info → wagtail-6.2rc1.dist-info}/top_level.txt +0 -0
@@ -17,6 +17,7 @@
17
17
  # Vincent Zhao <zhaopu2008@gmail.com>, 2017
18
18
  # yi huang <yi.codeplayer@gmail.com>, 2018
19
19
  # Yin Guanhao <sopium@mysterious.site>, 2021
20
+ # Yu Cheng, 2024
20
21
  # 祝沙军 <zhushajun@gmail.com>, 2017
21
22
  # 汇民 王 <whuim@qq.com>, 2017,2019-2021
22
23
  # 祝沙军 <zhushajun@gmail.com>, 2016
@@ -27,7 +28,7 @@ msgstr ""
27
28
  "Report-Msgid-Bugs-To: \n"
28
29
  "POT-Creation-Date: 2024-05-02 10:04+0100\n"
29
30
  "PO-Revision-Date: 2014-02-19 11:54+0000\n"
30
- "Last-Translator: Ford Guo <agile.guo@gmail.com>, 2023\n"
31
+ "Last-Translator: Yu Cheng, 2024\n"
31
32
  "Language-Team: Chinese (China) (http://app.transifex.com/torchbox/wagtail/"
32
33
  "language/zh_CN/)\n"
33
34
  "MIME-Version: 1.0\n"
@@ -122,6 +123,15 @@ msgstr "选择你所在时区"
122
123
  msgid "profile picture"
123
124
  msgstr "配置图片"
124
125
 
126
+ msgid "System default"
127
+ msgstr "系统默认"
128
+
129
+ msgid "Light"
130
+ msgstr "浅色"
131
+
132
+ msgid "Dark"
133
+ msgstr "深色"
134
+
125
135
  msgid "Default"
126
136
  msgstr "默认"
127
137
 
@@ -173,6 +183,11 @@ msgstr "确认删除"
173
183
  msgid "No, don't delete"
174
184
  msgstr "否,不删除"
175
185
 
186
+ #, python-format
187
+ msgid "Change active state for 1 user"
188
+ msgid_plural "Change active state for %(counter)s users"
189
+ msgstr[0] "更改 %(counter)s 个用户的活动状态"
190
+
176
191
  msgid "Set active state"
177
192
  msgstr "设置活动状态"
178
193
 
@@ -188,6 +203,13 @@ msgstr "是的,更改状态"
188
203
  msgid "No, don't change state"
189
204
  msgstr "否,不更改状态"
190
205
 
206
+ #, python-format
207
+ msgid ""
208
+ "The group '%(group_name)s' has <strong>%(group_user_count)s</strong> member."
209
+ msgid_plural ""
210
+ "The group '%(group_name)s' has <strong>%(group_user_count)s</strong> members."
211
+ msgstr[0] "“%(group_name)s”组有 <strong>%(group_user_count)s</strong> 个成员。"
212
+
191
213
  msgid ""
192
214
  "Deleting this group will revoke this group's permissions from all member "
193
215
  "users."
@@ -229,6 +251,12 @@ msgstr "解锁"
229
251
  msgid "Custom permissions"
230
252
  msgstr "定制权限"
231
253
 
254
+ msgid "Toggle all"
255
+ msgstr "全部切换"
256
+
257
+ msgid "Toggle all add permissions"
258
+ msgstr "切换所有添加权限"
259
+
232
260
  msgid "Other permissions"
233
261
  msgstr "其他权限"
234
262
 
@@ -247,8 +275,8 @@ msgstr "对不起,没有符合“%(query)s”的组"
247
275
 
248
276
  #, python-format
249
277
  msgid ""
250
- "There are no groups configured. Why not <a href="
251
- "\"%(wagtailusers_create_group_url)s\">add some</a>?"
278
+ "There are no groups configured. Why not <a "
279
+ "href=\"%(wagtailusers_create_group_url)s\">add some</a>?"
252
280
  msgstr ""
253
281
  "目前还没有组。<a href=\"%(wagtailusers_create_group_url)s\">添加</a>一个?"
254
282
 
@@ -270,10 +298,13 @@ msgstr "删除用户"
270
298
  msgid "Select all users in listing"
271
299
  msgstr "选择列表中的所有用户"
272
300
 
301
+ msgid "Sorry, no users match your query"
302
+ msgstr "抱歉,没有用户符合您的查询"
303
+
273
304
  #, python-format
274
305
  msgid ""
275
- "There are no users configured. Why not <a href=\"%(wagtailusers_add_url)s"
276
- "\">add some</a>?"
306
+ "There are no users configured. Why not <a "
307
+ "href=\"%(wagtailusers_add_url)s\">add some</a>?"
277
308
  msgstr ""
278
309
  "目前还没有用户。为何不<a href=\"%(wagtailusers_add_url)s\">添加一些用户</a>?"
279
310
 
@@ -303,6 +334,9 @@ msgstr "有效"
303
334
  msgid "Inactive"
304
335
  msgstr "无效"
305
336
 
337
+ msgid "Mark as active"
338
+ msgstr "标记为活动状态"
339
+
306
340
  msgid "Change the active state for selected users"
307
341
  msgstr "更改所选用户的活动状态"
308
342
 
@@ -343,6 +377,9 @@ msgstr "查看此组中的用户"
343
377
  msgid "Group '%(object)s' deleted."
344
378
  msgstr "组 '%(object)s' 已删除。"
345
379
 
380
+ msgid "Last login"
381
+ msgstr "上次登录"
382
+
346
383
  msgid "Group"
347
384
  msgstr "组"
348
385
 
@@ -358,9 +395,16 @@ msgstr "用户名"
358
395
  msgid "Admin"
359
396
  msgstr "管理"
360
397
 
398
+ msgid "Access level"
399
+ msgstr "访问权限"
400
+
361
401
  msgid "Status"
362
402
  msgstr "状态"
363
403
 
404
+ #, python-format
405
+ msgid "More options for '%(title)s'"
406
+ msgstr "“%(title)s”的更多选项"
407
+
364
408
  #, python-format
365
409
  msgid "User '%(object)s' created."
366
410
  msgstr "用户 '%(object)s' 已创建."
@@ -175,8 +175,8 @@ msgstr "對不起,沒有符合“%(query)s”的群組"
175
175
 
176
176
  #, python-format
177
177
  msgid ""
178
- "There are no groups configured. Why not <a href="
179
- "\"%(wagtailusers_create_group_url)s\">add some</a>?"
178
+ "There are no groups configured. Why not <a "
179
+ "href=\"%(wagtailusers_create_group_url)s\">add some</a>?"
180
180
  msgstr ""
181
181
  "目前還沒有群組。<a href=\"%(wagtailusers_create_group_url)s\">新增</a>一個?"
182
182
 
wagtail/users/models.py CHANGED
@@ -89,6 +89,7 @@ class UserProfile(models.Model):
89
89
  SNUG = "snug", _("Snug")
90
90
 
91
91
  density = models.CharField(
92
+ # Translators: "Density" is the term used to describe the amount of space between elements in the user interface
92
93
  verbose_name=_("density"),
93
94
  choices=AdminDensityThemes.choices,
94
95
  default=AdminDensityThemes.DEFAULT,
@@ -96,7 +96,8 @@
96
96
  <fieldset class="w-p-0">
97
97
  <legend class="w-sr-only">{% trans "Custom permissions" %}</legend>
98
98
  {% for custom_perm in content_perms_dict.custom %}
99
- {% include "wagtailadmin/shared/forms/single_checkbox.html" with name="permissions" value=custom_perm.perm.id checked=custom_perm.selected text=custom_perm.name attrs=custom_perm.attrs %}
99
+ {% trans custom_perm.name as custom_perm_label %}
100
+ {% include "wagtailadmin/shared/forms/single_checkbox.html" with name="permissions" value=custom_perm.perm.id checked=custom_perm.selected text=custom_perm_label attrs=custom_perm.attrs %}
100
101
  {% endfor %}
101
102
  </fieldset>
102
103
  {% endif %}
@@ -170,7 +171,7 @@
170
171
  <tbody>
171
172
  {% for perm_tuple in other_perms %}
172
173
  <tr>
173
- <td class="title"><label for="{{ perm_tuple.1.id_for_label }}" class="w-label-3">{{ perm_tuple.0.name }}</label></td>
174
+ <td class="title"><label for="{{ perm_tuple.1.id_for_label }}" class="w-label-3">{% trans perm_tuple.0.name %}</label></td>
174
175
  <td>
175
176
  {{ perm_tuple.1.tag }}
176
177
  </td>
@@ -6,6 +6,7 @@ from django.contrib.auth import get_permission_codename
6
6
  from django.contrib.auth.models import Permission
7
7
  from django.contrib.contenttypes.models import ContentType
8
8
  from django.utils.text import camel_case_to_spaces
9
+ from django.utils.translation import gettext_noop
9
10
 
10
11
  from wagtail import hooks
11
12
  from wagtail.admin.models import Admin
@@ -55,6 +56,14 @@ def normalize_permission_label(permission: Permission):
55
56
  return label
56
57
 
57
58
 
59
+ # normalize_permission_label will return "Can view" for Django's standard "Can view X" permission.
60
+ # formatted_permissions.html passes these labels through {% trans %} - since this is a variable
61
+ # within the template it will not be picked up by makemessages, so we define a translation here
62
+ # instead.
63
+
64
+ VIEW_PERMISSION_LABEL = gettext_noop("Can view")
65
+
66
+
58
67
  @register.inclusion_tag("wagtailusers/groups/includes/formatted_permissions.html")
59
68
  def format_permissions(permission_bound_field):
60
69
  """
@@ -2,6 +2,12 @@ from .test_admin_views import (
2
2
  CustomGroupViewSet,
3
3
  CustomUserCreationForm,
4
4
  CustomUserEditForm,
5
+ CustomUserViewSet,
5
6
  )
6
7
 
7
- __all__ = ["CustomGroupViewSet", "CustomUserCreationForm", "CustomUserEditForm"]
8
+ __all__ = [
9
+ "CustomGroupViewSet",
10
+ "CustomUserViewSet",
11
+ "CustomUserCreationForm",
12
+ "CustomUserEditForm",
13
+ ]
@@ -33,12 +33,16 @@ from wagtail.models import (
33
33
  )
34
34
  from wagtail.test.utils import WagtailTestUtils
35
35
  from wagtail.test.utils.template_tests import AdminTemplateTestUtils
36
- from wagtail.users.forms import UserCreationForm, UserEditForm
36
+ from wagtail.users.forms import GroupForm, UserCreationForm, UserEditForm
37
37
  from wagtail.users.models import UserProfile
38
38
  from wagtail.users.permission_order import register as register_permission_order
39
39
  from wagtail.users.views.groups import GroupViewSet
40
- from wagtail.users.views.users import get_user_creation_form, get_user_edit_form
41
- from wagtail.users.wagtail_hooks import get_group_viewset_cls
40
+ from wagtail.users.views.users import (
41
+ UserViewSet,
42
+ get_user_creation_form,
43
+ get_user_edit_form,
44
+ )
45
+ from wagtail.users.wagtail_hooks import get_viewset_cls
42
46
  from wagtail.users.widgets import UserListingButton
43
47
  from wagtail.utils.deprecation import RemovedInWagtail70Warning
44
48
 
@@ -53,6 +57,10 @@ def test_avatar_provider(user, default, size=50):
53
57
  return "/nonexistent/path/to/avatar.png"
54
58
 
55
59
 
60
+ class CustomGroupForm(GroupForm):
61
+ pass
62
+
63
+
56
64
  class CustomUserCreationForm(UserCreationForm):
57
65
  country = forms.CharField(required=True, label="Country")
58
66
  attachment = forms.FileField(required=True, label="Attachment")
@@ -66,6 +74,18 @@ class CustomUserEditForm(UserEditForm):
66
74
  class CustomGroupViewSet(GroupViewSet):
67
75
  icon = "custom-icon"
68
76
 
77
+ def get_form_class(self, for_update=False):
78
+ return CustomGroupForm
79
+
80
+
81
+ class CustomUserViewSet(UserViewSet):
82
+ icon = "custom-icon"
83
+
84
+ def get_form_class(self, for_update=False):
85
+ if for_update:
86
+ return CustomUserEditForm
87
+ return CustomUserCreationForm
88
+
69
89
 
70
90
  class TestUserFormHelpers(TestCase):
71
91
  def test_get_user_edit_form_with_default_form(self):
@@ -80,25 +100,45 @@ class TestUserFormHelpers(TestCase):
80
100
  WAGTAIL_USER_CREATION_FORM="wagtail.users.tests.CustomUserCreationForm"
81
101
  )
82
102
  def test_get_user_creation_form_with_custom_form(self):
83
- user_form = get_user_creation_form()
103
+ with self.assertWarnsMessage(
104
+ RemovedInWagtail70Warning,
105
+ "The `WAGTAIL_USER_CREATION_FORM` setting is deprecated. Use a custom "
106
+ "`UserViewSet` subclass and override `get_form_class()` instead.",
107
+ ):
108
+ user_form = get_user_creation_form()
84
109
  self.assertIs(user_form, CustomUserCreationForm)
85
110
 
86
111
  @override_settings(WAGTAIL_USER_EDIT_FORM="wagtail.users.tests.CustomUserEditForm")
87
112
  def test_get_user_edit_form_with_custom_form(self):
88
- user_form = get_user_edit_form()
113
+ with self.assertWarnsMessage(
114
+ RemovedInWagtail70Warning,
115
+ "The `WAGTAIL_USER_EDIT_FORM` setting is deprecated. Use a custom "
116
+ "`UserViewSet` subclass and override `get_form_class()` instead.",
117
+ ):
118
+ user_form = get_user_edit_form()
89
119
  self.assertIs(user_form, CustomUserEditForm)
90
120
 
91
121
  @override_settings(
92
122
  WAGTAIL_USER_CREATION_FORM="wagtail.users.tests.CustomUserCreationFormDoesNotExist"
93
123
  )
94
124
  def test_get_user_creation_form_with_invalid_form(self):
95
- self.assertRaises(ImproperlyConfigured, get_user_creation_form)
125
+ with self.assertWarnsMessage(
126
+ RemovedInWagtail70Warning,
127
+ "The `WAGTAIL_USER_CREATION_FORM` setting is deprecated. Use a custom "
128
+ "`UserViewSet` subclass and override `get_form_class()` instead.",
129
+ ):
130
+ self.assertRaises(ImproperlyConfigured, get_user_creation_form)
96
131
 
97
132
  @override_settings(
98
133
  WAGTAIL_USER_EDIT_FORM="wagtail.users.tests.CustomUserEditFormDoesNotExist"
99
134
  )
100
135
  def test_get_user_edit_form_with_invalid_form(self):
101
- self.assertRaises(ImproperlyConfigured, get_user_edit_form)
136
+ with self.assertWarnsMessage(
137
+ RemovedInWagtail70Warning,
138
+ "The `WAGTAIL_USER_EDIT_FORM` setting is deprecated. Use a custom "
139
+ "`UserViewSet` subclass and override `get_form_class()` instead.",
140
+ ):
141
+ self.assertRaises(ImproperlyConfigured, get_user_edit_form)
102
142
 
103
143
 
104
144
  class TestGroupUsersView(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
@@ -466,7 +506,6 @@ class TestUserCreateView(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
466
506
  )
467
507
  @override_settings(
468
508
  WAGTAIL_USER_CREATION_FORM="wagtail.users.tests.CustomUserCreationForm",
469
- WAGTAIL_USER_CUSTOM_FIELDS=["country", "document"],
470
509
  )
471
510
  def test_create_with_custom_form(self):
472
511
  response = self.post(
@@ -1625,7 +1664,7 @@ class TestGroupIndexView(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
1625
1664
  self.assertEqual(names, ["Editors", "Moderators", "Photographers"])
1626
1665
 
1627
1666
 
1628
- class TestGroupIndexResultsView(WagtailTestUtils, TestCase):
1667
+ class TestGroupIndexResultsView(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
1629
1668
  def setUp(self):
1630
1669
  self.login()
1631
1670
 
@@ -1637,7 +1676,7 @@ class TestGroupIndexResultsView(WagtailTestUtils, TestCase):
1637
1676
  self.assertEqual(response.status_code, 200)
1638
1677
  self.assertTemplateUsed(response, "wagtailadmin/generic/listing_results.html")
1639
1678
  # response should not contain page furniture
1640
- self.assertNotContains(response, "Add a group")
1679
+ self.assertBreadcrumbsNotRendered(response.content)
1641
1680
 
1642
1681
  def test_search(self):
1643
1682
  response = self.get({"q": "Hello"})
@@ -2397,7 +2436,7 @@ class TestGroupEditView(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
2397
2436
 
2398
2437
  def test_is_custom_permission_checked(self):
2399
2438
  # Add a permission from the 'custom permission' column to the user's group
2400
- custom_permission = Permission.objects.get(codename="view_fancysnippet")
2439
+ custom_permission = Permission.objects.get(codename="view_fullfeaturedsnippet")
2401
2440
  self.test_group.permissions.add(custom_permission)
2402
2441
 
2403
2442
  response = self.get()
@@ -2566,44 +2605,76 @@ class TestGroupHistoryView(WagtailTestUtils, TestCase):
2566
2605
 
2567
2606
 
2568
2607
  class TestGroupViewSet(TestCase):
2608
+ app_config_attr = "group_viewset"
2609
+ default_viewset_cls = GroupViewSet
2610
+ custom_viewset_cls = CustomGroupViewSet
2611
+ create_form_cls = CustomGroupForm
2612
+ edit_form_cls = CustomGroupForm
2613
+
2569
2614
  def setUp(self):
2570
2615
  self.app_config = apps.get_app_config("wagtailusers")
2571
2616
 
2572
- def test_get_group_viewset_cls(self):
2573
- self.assertIs(get_group_viewset_cls(self.app_config), GroupViewSet)
2617
+ def test_get_viewset_cls(self):
2618
+ self.assertIs(
2619
+ get_viewset_cls(self.app_config, self.app_config_attr),
2620
+ self.default_viewset_cls,
2621
+ )
2574
2622
 
2575
- def test_get_group_viewset_cls_with_custom_form(self):
2623
+ def test_get_viewset_cls_with_custom_form(self):
2576
2624
  with unittest.mock.patch.object(
2577
2625
  self.app_config,
2578
- "group_viewset",
2579
- new="wagtail.users.tests.CustomGroupViewSet",
2626
+ self.app_config_attr,
2627
+ new=f"wagtail.users.tests.{self.custom_viewset_cls.__name__}",
2580
2628
  ):
2581
- group_viewset = get_group_viewset_cls(self.app_config)
2582
- self.assertIs(group_viewset, CustomGroupViewSet)
2629
+ group_viewset = get_viewset_cls(self.app_config, self.app_config_attr)
2630
+ self.assertIs(group_viewset, self.custom_viewset_cls)
2583
2631
  self.assertEqual(group_viewset.icon, "custom-icon")
2632
+ viewset = group_viewset()
2633
+ self.assertIs(viewset.get_form_class(for_update=False), self.create_form_cls)
2634
+ self.assertIs(viewset.get_form_class(for_update=True), self.edit_form_cls)
2584
2635
 
2585
- def test_get_group_viewset_cls_custom_form_invalid_value(self):
2636
+ def test_get_viewset_cls_custom_form_invalid_value(self):
2586
2637
  with unittest.mock.patch.object(
2587
- self.app_config, "group_viewset", new="asdfasdf"
2638
+ self.app_config, self.app_config_attr, new="asdfasdf"
2588
2639
  ):
2589
- with self.assertRaises(ImproperlyConfigured) as exc_info:
2590
- get_group_viewset_cls(self.app_config)
2591
- self.assertIn(
2592
- "asdfasdf doesn't look like a module path", str(exc_info.exception)
2593
- )
2640
+ with self.assertRaisesMessage(
2641
+ ImproperlyConfigured,
2642
+ f"Invalid setting for WagtailUsersAppConfig.{self.app_config_attr}: "
2643
+ "asdfasdf doesn't look like a module path",
2644
+ ):
2645
+ get_viewset_cls(self.app_config, self.app_config_attr)
2594
2646
 
2595
- def test_get_group_viewset_cls_custom_form_does_not_exist(self):
2647
+ def test_get_viewset_cls_custom_form_does_not_exist(self):
2596
2648
  with unittest.mock.patch.object(
2597
2649
  self.app_config,
2598
- "group_viewset",
2650
+ self.app_config_attr,
2599
2651
  new="wagtail.users.tests.CustomClassDoesNotExist",
2600
2652
  ):
2601
- with self.assertRaises(ImproperlyConfigured) as exc_info:
2602
- get_group_viewset_cls(self.app_config)
2603
- self.assertIn(
2653
+ with self.assertRaisesMessage(
2654
+ ImproperlyConfigured,
2655
+ f"Invalid setting for WagtailUsersAppConfig.{self.app_config_attr}: "
2604
2656
  'Module "wagtail.users.tests" does not define a "CustomClassDoesNotExist" attribute/class',
2605
- str(exc_info.exception),
2606
- )
2657
+ ):
2658
+ get_viewset_cls(self.app_config, self.app_config_attr)
2659
+
2660
+
2661
+ class TestUserViewSet(TestGroupViewSet):
2662
+ app_config_attr = "user_viewset"
2663
+ default_viewset_cls = UserViewSet
2664
+ custom_viewset_cls = CustomUserViewSet
2665
+ create_form_cls = CustomUserCreationForm
2666
+ edit_form_cls = CustomUserEditForm
2667
+
2668
+ def test_registered_permissions(self):
2669
+ group_ct = ContentType.objects.get_for_model(Group)
2670
+ qs = Permission.objects.none()
2671
+ for fn in hooks.get_hooks("register_permissions"):
2672
+ qs |= fn()
2673
+ registered_user_permissions = qs.filter(content_type=group_ct)
2674
+ self.assertEqual(
2675
+ set(registered_user_permissions.values_list("codename", flat=True)),
2676
+ {"add_group", "change_group", "delete_group"},
2677
+ )
2607
2678
 
2608
2679
 
2609
2680
  class TestAuthorisationIndexView(WagtailTestUtils, TestCase):
@@ -2957,3 +3028,17 @@ class TestTemplateTags(WagtailTestUtils, TestCase):
2957
3028
  top_level_custom_button.text.strip(),
2958
3029
  "Show profile",
2959
3030
  )
3031
+
3032
+
3033
+ class TestAdminPermissions(WagtailTestUtils, TestCase):
3034
+ def test_registered_user_permissions(self):
3035
+ user_ct = ContentType.objects.get_for_model(User)
3036
+ model_name = User._meta.model_name
3037
+ qs = Permission.objects.none()
3038
+ for fn in hooks.get_hooks("register_permissions"):
3039
+ qs |= fn()
3040
+ registered_user_permissions = qs.filter(content_type=user_ct)
3041
+ self.assertEqual(
3042
+ set(registered_user_permissions.values_list("codename", flat=True)),
3043
+ {f"add_{model_name}", f"change_{model_name}", f"delete_{model_name}"},
3044
+ )
@@ -149,6 +149,10 @@ class GroupViewSet(ModelViewSet):
149
149
  model = Group
150
150
  ordering = ["name"]
151
151
  add_to_reference_index = False
152
+ menu_name = "groups"
153
+ menu_label = _("Groups")
154
+ menu_order = 601
155
+ add_to_settings_menu = True
152
156
 
153
157
  index_view_class = IndexView
154
158
  add_view_class = CreateView
@@ -2,7 +2,10 @@ from warnings import warn
2
2
 
3
3
  import django_filters
4
4
  from django.conf import settings
5
- from django.contrib.auth import get_user_model, update_session_auth_hash
5
+ from django.contrib.auth import (
6
+ get_user_model,
7
+ update_session_auth_hash,
8
+ )
6
9
  from django.contrib.auth.models import Group
7
10
  from django.core.exceptions import FieldDoesNotExist, PermissionDenied
8
11
  from django.db.models import Q
@@ -14,6 +17,7 @@ from django.utils.translation import gettext_lazy
14
17
 
15
18
  from wagtail import hooks
16
19
  from wagtail.admin.filters import DateRangePickerWidget, WagtailFilterSet
20
+ from wagtail.admin.search import SearchArea
17
21
  from wagtail.admin.ui.tables import (
18
22
  BulkActionsCheckboxColumn,
19
23
  Column,
@@ -22,8 +26,7 @@ from wagtail.admin.ui.tables import (
22
26
  TitleColumn,
23
27
  )
24
28
  from wagtail.admin.utils import get_user_display_name
25
- from wagtail.admin.views.generic import CreateView, DeleteView, EditView, IndexView
26
- from wagtail.admin.views.generic.history import HistoryView
29
+ from wagtail.admin.views import generic
27
30
  from wagtail.admin.viewsets.model import ModelViewSet
28
31
  from wagtail.admin.widgets.boolean_radio_select import BooleanRadioSelect
29
32
  from wagtail.admin.widgets.button import (
@@ -41,7 +44,8 @@ User = get_user_model()
41
44
 
42
45
  # Typically we would check the permission 'auth.change_user' (and 'auth.add_user' /
43
46
  # 'auth.delete_user') for user management actions, but this may vary according to
44
- # the AUTH_USER_MODEL setting
47
+ # the AUTH_USER_MODEL setting. These are no longer used in the codebase in favour
48
+ # of ModelPermissionPolicy, but are kept here for backwards compatibility.
45
49
  add_user_perm = f"{AUTH_USER_APP_LABEL}.add_{AUTH_USER_MODEL_NAME.lower()}"
46
50
  change_user_perm = "{}.change_{}".format(
47
51
  AUTH_USER_APP_LABEL, AUTH_USER_MODEL_NAME.lower()
@@ -54,6 +58,11 @@ delete_user_perm = "{}.delete_{}".format(
54
58
  def get_user_creation_form():
55
59
  form_setting = "WAGTAIL_USER_CREATION_FORM"
56
60
  if hasattr(settings, form_setting):
61
+ warn(
62
+ "The `WAGTAIL_USER_CREATION_FORM` setting is deprecated. Use a custom "
63
+ "`UserViewSet` subclass and override `get_form_class()` instead.",
64
+ RemovedInWagtail70Warning,
65
+ )
57
66
  return get_custom_form(form_setting)
58
67
  else:
59
68
  return UserCreationForm
@@ -62,6 +71,11 @@ def get_user_creation_form():
62
71
  def get_user_edit_form():
63
72
  form_setting = "WAGTAIL_USER_EDIT_FORM"
64
73
  if hasattr(settings, form_setting):
74
+ warn(
75
+ "The `WAGTAIL_USER_EDIT_FORM` setting is deprecated. Use a custom "
76
+ "`UserViewSet` subclass and override `get_form_class()` instead.",
77
+ RemovedInWagtail70Warning,
78
+ )
65
79
  return get_custom_form(form_setting)
66
80
  else:
67
81
  return UserEditForm
@@ -125,7 +139,7 @@ class UserFilterSet(WagtailFilterSet):
125
139
  fields = []
126
140
 
127
141
 
128
- class Index(IndexView):
142
+ class IndexView(generic.IndexView):
129
143
  """
130
144
  Lists the users for management within the admin.
131
145
  """
@@ -257,7 +271,7 @@ class Index(IndexView):
257
271
  return queryset
258
272
 
259
273
 
260
- class Create(CreateView):
274
+ class CreateView(generic.CreateView):
261
275
  """
262
276
  Provide the ability to create a user within the admin.
263
277
  """
@@ -279,7 +293,7 @@ class Create(CreateView):
279
293
  )
280
294
 
281
295
 
282
- class Edit(EditView):
296
+ class EditView(generic.EditView):
283
297
  """
284
298
  Provide the ability to edit a user within the admin.
285
299
  """
@@ -333,7 +347,7 @@ class Edit(EditView):
333
347
  return context
334
348
 
335
349
 
336
- class Delete(DeleteView):
350
+ class DeleteView(generic.DeleteView):
337
351
  """
338
352
  Provide the ability to delete a user within the admin.
339
353
  """
@@ -363,7 +377,7 @@ class Delete(DeleteView):
363
377
  )
364
378
 
365
379
 
366
- class History(HistoryView):
380
+ class HistoryView(generic.HistoryView):
367
381
  def get_page_subtitle(self):
368
382
  return get_user_display_name(self.object)
369
383
 
@@ -374,12 +388,16 @@ class UserViewSet(ModelViewSet):
374
388
  ordering = "name"
375
389
  add_to_reference_index = False
376
390
  filterset_class = UserFilterSet
391
+ menu_name = "users"
392
+ menu_label = gettext_lazy("Users")
393
+ menu_order = 600
394
+ add_to_settings_menu = True
377
395
 
378
- index_view_class = Index
379
- add_view_class = Create
380
- edit_view_class = Edit
381
- delete_view_class = Delete
382
- history_view_class = History
396
+ index_view_class = IndexView
397
+ add_view_class = CreateView
398
+ edit_view_class = EditView
399
+ delete_view_class = DeleteView
400
+ history_view_class = HistoryView
383
401
 
384
402
  template_prefix = "wagtailusers/users/"
385
403
 
@@ -395,3 +413,29 @@ class UserViewSet(ModelViewSet):
395
413
  if for_update:
396
414
  return get_user_edit_form()
397
415
  return get_user_creation_form()
416
+
417
+ @cached_property
418
+ def search_area_class(self):
419
+ class UsersSearchArea(SearchArea):
420
+ def is_shown(search_area, request):
421
+ return self.permission_policy.user_has_any_permission(
422
+ request.user, {"add", "change", "delete"}
423
+ )
424
+
425
+ return UsersSearchArea
426
+
427
+ def get_search_area(self):
428
+ return self.search_area_class(
429
+ gettext_lazy("Users"),
430
+ self.get_url_name("index"),
431
+ name="users",
432
+ icon_name="user",
433
+ order=600,
434
+ )
435
+
436
+ def register_search_area(self):
437
+ hooks.register("register_admin_search_area", self.get_search_area)
438
+
439
+ def on_register(self):
440
+ super().on_register()
441
+ self.register_search_area()