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
@@ -19,15 +19,17 @@ def user_can_edit_snippet_type(user, model):
19
19
  return False
20
20
 
21
21
 
22
- def user_can_edit_snippets(user):
22
+ def user_can_access_snippets(user):
23
23
  """
24
- true if user has 'add', 'change' or 'delete' permission
24
+ true if user has 'add', 'change', 'delete', or 'view' permission
25
25
  on any model registered as a snippet type
26
26
  """
27
27
  snippet_models = get_snippet_models()
28
28
 
29
29
  for model in snippet_models:
30
- if user_can_edit_snippet_type(user, model):
30
+ if model.snippet_viewset.permission_policy.user_has_any_permission(
31
+ user, {"add", "change", "delete", "view"}
32
+ ):
31
33
  return True
32
34
 
33
35
  return False
@@ -1 +1 @@
1
- (()=>{"use strict";var e,r={8039:(e,r,t)=>{var o=t(2614),a=t(9465);class n extends o.ZZ{getURLParams(e){const r=super.getURLParams(e);return wagtailConfig.ACTIVE_CONTENT_LOCALE&&(r.locale=wagtailConfig.ACTIVE_CONTENT_LOCALE),r}}class i extends a.y{titleStateKey="string";chooserModalClass=n}class l extends a._{widgetClass=i;chooserModalClass=n}window.telepath.register("wagtail.snippets.widgets.SnippetChooser",l)},1669:e=>{e.exports=jQuery}},t={};function o(e){var a=t[e];if(void 0!==a)return a.exports;var n=t[e]={id:e,loaded:!1,exports:{}};return r[e].call(n.exports,n,n.exports,o),n.loaded=!0,n.exports}o.m=r,e=[],o.O=(r,t,a,n)=>{if(!t){var i=1/0;for(u=0;u<e.length;u++){for(var[t,a,n]=e[u],l=!0,s=0;s<t.length;s++)(!1&n||i>=n)&&Object.keys(o.O).every((e=>o.O[e](t[s])))?t.splice(s--,1):(l=!1,n<i&&(i=n));if(l){e.splice(u--,1);var d=a();void 0!==d&&(r=d)}}return r}n=n||0;for(var u=e.length;u>0&&e[u-1][2]>n;u--)e[u]=e[u-1];e[u]=[t,a,n]},o.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return o.d(r,{a:r}),r},o.d=(e,r)=>{for(var t in r)o.o(r,t)&&!o.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},o.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),o.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),o.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),o.j=474,(()=>{var e={474:0};o.O.j=r=>0===e[r];var r=(r,t)=>{var a,n,[i,l,s]=t,d=0;if(i.some((r=>0!==e[r]))){for(a in l)o.o(l,a)&&(o.m[a]=l[a]);if(s)var u=s(o)}for(r&&r(t);d<i.length;d++)n=i[d],o.o(e,n)&&e[n]&&e[n][0](),e[n]=0;return o.O(u)},t=globalThis.webpackChunkwagtail=globalThis.webpackChunkwagtail||[];t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})();var a=o.O(void 0,[321],(()=>o(8039)));a=o.O(a)})();
1
+ (()=>{"use strict";var e,r={8039:(e,r,t)=>{var o=t(2614),a=t(9465);class n extends o.ZZ{getURLParams(e){const r=super.getURLParams(e);return wagtailConfig.ACTIVE_CONTENT_LOCALE&&(r.locale=wagtailConfig.ACTIVE_CONTENT_LOCALE),r}}class i extends a.y{titleStateKey="string";chooserModalClass=n}class s extends a._{widgetClass=i;chooserModalClass=n}window.telepath.register("wagtail.snippets.widgets.SnippetChooser",s)},1669:e=>{e.exports=jQuery}},t={};function o(e){var a=t[e];if(void 0!==a)return a.exports;var n=t[e]={exports:{}};return r[e](n,n.exports,o),n.exports}o.m=r,e=[],o.O=(r,t,a,n)=>{if(!t){var i=1/0;for(d=0;d<e.length;d++){for(var[t,a,n]=e[d],s=!0,l=0;l<t.length;l++)(!1&n||i>=n)&&Object.keys(o.O).every((e=>o.O[e](t[l])))?t.splice(l--,1):(s=!1,n<i&&(i=n));if(s){e.splice(d--,1);var u=a();void 0!==u&&(r=u)}}return r}n=n||0;for(var d=e.length;d>0&&e[d-1][2]>n;d--)e[d]=e[d-1];e[d]=[t,a,n]},o.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return o.d(r,{a:r}),r},o.d=(e,r)=>{for(var t in r)o.o(r,t)&&!o.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},o.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),o.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),o.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.j=474,(()=>{var e={474:0};o.O.j=r=>0===e[r];var r=(r,t)=>{var a,n,[i,s,l]=t,u=0;if(i.some((r=>0!==e[r]))){for(a in s)o.o(s,a)&&(o.m[a]=s[a]);if(l)var d=l(o)}for(r&&r(t);u<i.length;u++)n=i[u],o.o(e,n)&&e[n]&&e[n][0](),e[n]=0;return o.O(d)},t=globalThis.webpackChunkwagtail=globalThis.webpackChunkwagtail||[];t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})();var a=o.O(void 0,[321],(()=>o(8039)));a=o.O(a)})();
@@ -1 +1 @@
1
- (()=>{"use strict";var e,r={9987:(e,r,t)=>{var o=t(2614),a=t(9465);class n extends o.ZZ{getURLParams(e){const r=super.getURLParams(e);return wagtailConfig.ACTIVE_CONTENT_LOCALE&&(r.locale=wagtailConfig.ACTIVE_CONTENT_LOCALE),r}}class i extends a.y{titleStateKey="string";chooserModalClass=n}window.SnippetChooser=i},1669:e=>{e.exports=jQuery}},t={};function o(e){var a=t[e];if(void 0!==a)return a.exports;var n=t[e]={id:e,loaded:!1,exports:{}};return r[e].call(n.exports,n,n.exports,o),n.loaded=!0,n.exports}o.m=r,e=[],o.O=(r,t,a,n)=>{if(!t){var i=1/0;for(u=0;u<e.length;u++){for(var[t,a,n]=e[u],l=!0,s=0;s<t.length;s++)(!1&n||i>=n)&&Object.keys(o.O).every((e=>o.O[e](t[s])))?t.splice(s--,1):(l=!1,n<i&&(i=n));if(l){e.splice(u--,1);var d=a();void 0!==d&&(r=d)}}return r}n=n||0;for(var u=e.length;u>0&&e[u-1][2]>n;u--)e[u]=e[u-1];e[u]=[t,a,n]},o.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return o.d(r,{a:r}),r},o.d=(e,r)=>{for(var t in r)o.o(r,t)&&!o.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},o.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),o.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),o.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),o.j=686,(()=>{var e={686:0};o.O.j=r=>0===e[r];var r=(r,t)=>{var a,n,[i,l,s]=t,d=0;if(i.some((r=>0!==e[r]))){for(a in l)o.o(l,a)&&(o.m[a]=l[a]);if(s)var u=s(o)}for(r&&r(t);d<i.length;d++)n=i[d],o.o(e,n)&&e[n]&&e[n][0](),e[n]=0;return o.O(u)},t=globalThis.webpackChunkwagtail=globalThis.webpackChunkwagtail||[];t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})();var a=o.O(void 0,[321],(()=>o(9987)));a=o.O(a)})();
1
+ (()=>{"use strict";var e,r={9987:(e,r,t)=>{var o=t(2614),a=t(9465);class n extends o.ZZ{getURLParams(e){const r=super.getURLParams(e);return wagtailConfig.ACTIVE_CONTENT_LOCALE&&(r.locale=wagtailConfig.ACTIVE_CONTENT_LOCALE),r}}class i extends a.y{titleStateKey="string";chooserModalClass=n}window.SnippetChooser=i},1669:e=>{e.exports=jQuery}},t={};function o(e){var a=t[e];if(void 0!==a)return a.exports;var n=t[e]={exports:{}};return r[e](n,n.exports,o),n.exports}o.m=r,e=[],o.O=(r,t,a,n)=>{if(!t){var i=1/0;for(f=0;f<e.length;f++){for(var[t,a,n]=e[f],l=!0,s=0;s<t.length;s++)(!1&n||i>=n)&&Object.keys(o.O).every((e=>o.O[e](t[s])))?t.splice(s--,1):(l=!1,n<i&&(i=n));if(l){e.splice(f--,1);var u=a();void 0!==u&&(r=u)}}return r}n=n||0;for(var f=e.length;f>0&&e[f-1][2]>n;f--)e[f]=e[f-1];e[f]=[t,a,n]},o.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return o.d(r,{a:r}),r},o.d=(e,r)=>{for(var t in r)o.o(r,t)&&!o.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},o.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),o.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),o.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.j=686,(()=>{var e={686:0};o.O.j=r=>0===e[r];var r=(r,t)=>{var a,n,[i,l,s]=t,u=0;if(i.some((r=>0!==e[r]))){for(a in l)o.o(l,a)&&(o.m[a]=l[a]);if(s)var f=s(o)}for(r&&r(t);u<i.length;u++)n=i[u],o.o(e,n)&&e[n]&&e[n][0](),e[n]=0;return o.O(f)},t=globalThis.webpackChunkwagtail=globalThis.webpackChunkwagtail||[];t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})();var a=o.O(void 0,[321],(()=>o(9987)));a=o.O(a)})();
@@ -1,7 +1,7 @@
1
1
  {% load wagtailadmin_tags %}
2
2
 
3
3
  {% if show_menu %}
4
- {% dropdown_button button=default_menu_item toggle_icon="arrow-up" %}
4
+ {% dropdown_button button=default_menu_item toggle_icon="arrow-up" keep_mounted=True %}
5
5
  {% for item in rendered_menu_items %}
6
6
  {{ item }}
7
7
  {% endfor %}
@@ -24,9 +24,11 @@ from taggit.models import Tag
24
24
  from wagtail import hooks
25
25
  from wagtail.admin.admin_url_finder import AdminURLFinder
26
26
  from wagtail.admin.forms import WagtailAdminModelForm
27
+ from wagtail.admin.menu import admin_menu
27
28
  from wagtail.admin.panels import FieldPanel, ObjectList, get_edit_handler
28
29
  from wagtail.admin.widgets.button import ButtonWithDropdown
29
30
  from wagtail.blocks.field_block import FieldBlockAdapter
31
+ from wagtail.coreutils import get_dummy_request
30
32
  from wagtail.models import Locale, ModelLogEntry, Revision
31
33
  from wagtail.signals import published, unpublished
32
34
  from wagtail.snippets.action_menu import (
@@ -95,6 +97,26 @@ class TestSnippetIndexView(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
95
97
  response = self.get()
96
98
  self.assertEqual(response.status_code, 302)
97
99
 
100
+ def test_get_with_only_view_permissions(self):
101
+ self.user.is_superuser = False
102
+ self.user.user_permissions.add(
103
+ Permission.objects.get(
104
+ content_type__app_label="wagtailadmin", codename="access_admin"
105
+ ),
106
+ Permission.objects.get(
107
+ content_type__app_label="tests", codename="view_advert"
108
+ ),
109
+ )
110
+ self.user.save()
111
+
112
+ response = self.get()
113
+ self.assertEqual(response.status_code, 200)
114
+ self.assertTemplateUsed(response, "wagtailadmin/generic/listing.html")
115
+ soup = self.get_soup(response.content)
116
+ link = soup.select_one("tr td a")
117
+ self.assertEqual(link["href"], reverse("wagtailsnippets_tests_advert:list"))
118
+ self.assertEqual(link.text.strip(), "Adverts")
119
+
98
120
  def test_simple(self):
99
121
  response = self.get()
100
122
  self.assertEqual(response.status_code, 200)
@@ -110,6 +132,29 @@ class TestSnippetIndexView(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
110
132
  def test_displays_snippet(self):
111
133
  self.assertContains(self.get(), "Adverts")
112
134
 
135
+ def test_snippets_menu_item_shown_with_only_view_permission(self):
136
+ self.user.is_superuser = False
137
+ self.user.user_permissions.add(
138
+ Permission.objects.get(
139
+ content_type__app_label="wagtailadmin", codename="access_admin"
140
+ ),
141
+ Permission.objects.get(
142
+ content_type__app_label="tests", codename="view_advert"
143
+ ),
144
+ )
145
+ self.user.save()
146
+
147
+ request = get_dummy_request()
148
+ request.user = self.user
149
+ menu_items = admin_menu.menu_items_for_request(request)
150
+ snippets = [item for item in menu_items if item.name == "snippets"]
151
+ self.assertEqual(len(snippets), 1)
152
+ item = snippets[0]
153
+ self.assertEqual(item.name, "snippets")
154
+ self.assertEqual(item.label, "Snippets")
155
+ self.assertEqual(item.icon_name, "snippet")
156
+ self.assertEqual(item.url, reverse("wagtailsnippets:index"))
157
+
113
158
 
114
159
  class TestSnippetListView(WagtailTestUtils, TestCase):
115
160
  def setUp(self):
@@ -319,6 +364,23 @@ class TestSnippetListView(WagtailTestUtils, TestCase):
319
364
  self.assertEqual(response.status_code, 200)
320
365
  self.assertTemplateUsed(response, "wagtailadmin/shared/buttons.html")
321
366
 
367
+ def test_dropdown_not_rendered_when_no_child_buttons_exist(self):
368
+ Advert.objects.create(text="My Lovely advert")
369
+
370
+ def remove_all_buttons(buttons, snippet, user):
371
+ buttons[:] = []
372
+ self.assertEqual(len(buttons), 0)
373
+
374
+ with hooks.register_temporarily(
375
+ "construct_snippet_listing_buttons",
376
+ remove_all_buttons,
377
+ ):
378
+ response = self.get()
379
+
380
+ soup = self.get_soup(response.content)
381
+ actions = soup.select_one("tbody tr td ul.actions")
382
+ self.assertIsNone(actions)
383
+
322
384
  def test_use_latest_draft_as_title(self):
323
385
  snippet = DraftStateModel.objects.create(text="Draft-enabled Foo, Published")
324
386
  snippet.save_revision().publish()
@@ -1124,12 +1186,14 @@ class TestCreateDraftStateSnippet(WagtailTestUtils, TestCase):
1124
1186
  allow_extra_attrs=True,
1125
1187
  )
1126
1188
  # Should show the dialog template pointing to the [data-edit-form] selector as the root
1127
- self.assertTagInHTML(
1128
- '<template data-controller="w-teleport" data-w-teleport-target-value="[data-edit-form]">',
1129
- html,
1130
- count=1,
1131
- allow_extra_attrs=True,
1132
- )
1189
+ soup = self.get_soup(html)
1190
+ dialog = soup.select_one(
1191
+ """
1192
+ template[data-controller="w-teleport"][data-w-teleport-target-value="[data-edit-form]"]
1193
+ #schedule-publishing-dialog
1194
+ """
1195
+ )
1196
+ self.assertIsNotNone(dialog)
1133
1197
  # Should render the main form with data-edit-form attribute
1134
1198
  self.assertTagInHTML(
1135
1199
  f'<form action="{add_url}" method="POST" data-edit-form>',
@@ -1524,12 +1588,14 @@ class BaseTestSnippetEditView(WagtailTestUtils, TestCase):
1524
1588
  allow_extra_attrs=True,
1525
1589
  )
1526
1590
  # Should show the dialog template pointing to the [data-edit-form] selector as the root
1527
- self.assertTagInHTML(
1528
- '<template data-controller="w-teleport" data-w-teleport-target-value="[data-edit-form]">',
1529
- html,
1530
- count=1,
1531
- allow_extra_attrs=True,
1532
- )
1591
+ soup = self.get_soup(html)
1592
+ dialog = soup.select_one(
1593
+ """
1594
+ template[data-controller="w-teleport"][data-w-teleport-target-value="[data-edit-form]"]
1595
+ #schedule-publishing-dialog
1596
+ """
1597
+ )
1598
+ self.assertIsNotNone(dialog)
1533
1599
  # Should render the main form with data-edit-form attribute
1534
1600
  self.assertTagInHTML(
1535
1601
  f'<form action="{self.get_edit_url()}" method="POST" data-edit-form>',
@@ -1607,3 +1607,25 @@ class TestCustomMethods(BaseSnippetViewSetTests):
1607
1607
  self.assertIsNotNone(template)
1608
1608
  links = template.find_all("a", attrs={"href": add_url})
1609
1609
  self.assertEqual(len(links), 1)
1610
+
1611
+
1612
+ class TestCustomPermissionPolicy(BaseSnippetViewSetTests):
1613
+ model = FullFeaturedSnippet
1614
+
1615
+ @classmethod
1616
+ def setUpTestData(cls):
1617
+ cls.object = cls.model.objects.create(text="Hello World")
1618
+
1619
+ def test_get_edit_view_not_allowed(self):
1620
+ response = self.client.get(self.get_url("edit", args=(quote(self.object.pk),)))
1621
+ self.assertEqual(response.status_code, 200)
1622
+
1623
+ # The custom permission policy disallows any user with [FORBIDDEN]
1624
+ # in their name, even if they are a superuser
1625
+ self.user.first_name = "[FORBIDDEN]"
1626
+ self.user.last_name = "Joe"
1627
+ self.user.save()
1628
+ self.assertTrue(self.user.is_superuser)
1629
+ self.assertEqual(self.user.get_full_name(), "[FORBIDDEN] Joe")
1630
+ response = self.client.get(self.get_url("edit", args=(quote(self.object.pk),)))
1631
+ self.assertRedirects(response, reverse("wagtailadmin_home"))
@@ -47,7 +47,6 @@ from wagtail.models import (
47
47
  from wagtail.permissions import ModelPermissionPolicy
48
48
  from wagtail.snippets.action_menu import SnippetActionMenu
49
49
  from wagtail.snippets.models import SnippetAdminURLFinder, get_snippet_models
50
- from wagtail.snippets.permissions import user_can_edit_snippet_type
51
50
  from wagtail.snippets.side_panels import SnippetStatusSidePanel
52
51
  from wagtail.snippets.views.chooser import SnippetChooserViewSet
53
52
  from wagtail.utils.deprecation import RemovedInWagtail70Warning
@@ -90,9 +89,10 @@ class ModelIndexView(generic.BaseListingView):
90
89
  "name": capfirst(model._meta.verbose_name_plural),
91
90
  "count": model._default_manager.all().count(),
92
91
  "model": model,
92
+ "url": url,
93
93
  }
94
94
  for model in get_snippet_models()
95
- if user_can_edit_snippet_type(self.request.user, model)
95
+ if (url := self.get_list_url(model))
96
96
  ]
97
97
 
98
98
  def dispatch(self, request, *args, **kwargs):
@@ -103,8 +103,12 @@ class ModelIndexView(generic.BaseListingView):
103
103
  def get_breadcrumbs_items(self):
104
104
  return self.breadcrumbs_items + [{"url": "", "label": _("Snippets")}]
105
105
 
106
- def get_list_url(self, type):
107
- return reverse(type["model"].snippet_viewset.get_url_name("list"))
106
+ def get_list_url(self, model):
107
+ if model.snippet_viewset.permission_policy.user_has_any_permission(
108
+ self.request.user,
109
+ {"add", "change", "delete", "view"},
110
+ ):
111
+ return reverse(model.snippet_viewset.get_url_name("list"))
108
112
 
109
113
  def get_queryset(self):
110
114
  return None
@@ -115,7 +119,7 @@ class ModelIndexView(generic.BaseListingView):
115
119
  TitleColumn(
116
120
  "name",
117
121
  label=_("Name"),
118
- get_url=self.get_list_url,
122
+ get_url=lambda type: type["url"],
119
123
  sort_key="name",
120
124
  ),
121
125
  Column(
@@ -206,16 +210,17 @@ class IndexView(generic.IndexViewOptionalFeaturesMixin, generic.IndexView):
206
210
  )
207
211
  hook(more_buttons, instance, self.request.user, {})
208
212
 
209
- list_buttons.append(
210
- ButtonWithDropdown(
211
- buttons=more_buttons,
212
- icon_name="dots-horizontal",
213
- attrs={
214
- "aria-label": _("More options for '%(title)s'")
215
- % {"title": str(instance)},
216
- },
213
+ if more_buttons:
214
+ list_buttons.append(
215
+ ButtonWithDropdown(
216
+ buttons=more_buttons,
217
+ icon_name="dots-horizontal",
218
+ attrs={
219
+ "aria-label": _("More options for '%(title)s'")
220
+ % {"title": str(instance)},
221
+ },
222
+ )
217
223
  )
218
- )
219
224
 
220
225
  return list_buttons
221
226
 
@@ -1,5 +1,3 @@
1
- from django.contrib.auth.models import Permission
2
- from django.contrib.contenttypes.models import ContentType
3
1
  from django.urls import include, path, reverse
4
2
  from django.utils.functional import cached_property
5
3
  from django.utils.translation import gettext_lazy as _
@@ -8,7 +6,7 @@ from wagtail import hooks
8
6
  from wagtail.admin.menu import MenuItem
9
7
  from wagtail.snippets.bulk_actions.delete import DeleteBulkAction
10
8
  from wagtail.snippets.models import get_snippet_models
11
- from wagtail.snippets.permissions import user_can_edit_snippets
9
+ from wagtail.snippets.permissions import user_can_access_snippets
12
10
  from wagtail.snippets.views import snippets as snippet_views
13
11
 
14
12
 
@@ -35,7 +33,7 @@ class SnippetsMenuItem(MenuItem):
35
33
  )
36
34
 
37
35
  def is_shown(self, request):
38
- return not self._all_have_menu_items and user_can_edit_snippets(request.user)
36
+ return not self._all_have_menu_items and user_can_access_snippets(request.user)
39
37
 
40
38
 
41
39
  @hooks.register("register_admin_menu_item")
@@ -49,10 +47,4 @@ def register_snippets_menu_item():
49
47
  )
50
48
 
51
49
 
52
- @hooks.register("register_permissions")
53
- def register_permissions():
54
- content_types = ContentType.objects.get_for_models(*get_snippet_models()).values()
55
- return Permission.objects.filter(content_type__in=content_types)
56
-
57
-
58
50
  hooks.register("register_bulk_action", DeleteBulkAction)
@@ -3,6 +3,7 @@ from django.shortcuts import resolve_url
3
3
  from django.template.defaulttags import token_kwargs
4
4
  from django.template.loader import render_to_string
5
5
  from django.utils.encoding import force_str
6
+ from django.utils.functional import Promise
6
7
  from django.utils.html import conditional_escape
7
8
 
8
9
  from wagtail import VERSION, __version__
@@ -120,6 +121,8 @@ def richtext(value):
120
121
  elif value is None:
121
122
  html = ""
122
123
  else:
124
+ if isinstance(value, Promise):
125
+ value = str(value)
123
126
  if isinstance(value, str):
124
127
  html = expand_db_html(value)
125
128
  else:
@@ -7,7 +7,7 @@
7
7
  # - File.size exceptions raise DummyExternalStorageError
8
8
  # - Storage._save() fails loudly if the content file's pointer is not at the start
9
9
 
10
- from django.core.files.base import File
10
+ from django.core.files import File
11
11
  from django.core.files.storage import FileSystemStorage, Storage
12
12
  from django.utils.deconstruct import deconstructible
13
13
 
@@ -0,0 +1,40 @@
1
+ # Generated by Django 5.0.6 on 2024-06-21 06:47
2
+
3
+ import django.db.models.deletion
4
+ from django.db import migrations, models
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ dependencies = [
10
+ ('i18n', '0002_clusterabletestmodel_clusterabletestmodelchild_clusterabletestmodeltranslatablechild'),
11
+ ('wagtailcore', '0094_alter_page_locale'),
12
+ ]
13
+
14
+ operations = [
15
+ migrations.AlterField(
16
+ model_name='clusterabletestmodel',
17
+ name='locale',
18
+ field=models.ForeignKey(editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale', verbose_name='locale'),
19
+ ),
20
+ migrations.AlterField(
21
+ model_name='clusterabletestmodeltranslatablechild',
22
+ name='locale',
23
+ field=models.ForeignKey(editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale', verbose_name='locale'),
24
+ ),
25
+ migrations.AlterField(
26
+ model_name='testchildobject',
27
+ name='locale',
28
+ field=models.ForeignKey(editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale', verbose_name='locale'),
29
+ ),
30
+ migrations.AlterField(
31
+ model_name='testmodel',
32
+ name='locale',
33
+ field=models.ForeignKey(editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale', verbose_name='locale'),
34
+ ),
35
+ migrations.AlterField(
36
+ model_name='testnonparentalchildobject',
37
+ name='locale',
38
+ field=models.ForeignKey(editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale', verbose_name='locale'),
39
+ ),
40
+ ]
@@ -62,6 +62,10 @@ class RoutablePageTest(RoutablePage):
62
62
  template="routablepagetests/routable_page_test_alternate.html",
63
63
  )
64
64
 
65
+ @route(r"^render-method-with-arg/(?P<slug>.+)/$")
66
+ def render_method_test_with_arg(self, request, slug):
67
+ return self.render(request)
68
+
65
69
  def get_route_paths(self):
66
70
  return [
67
71
  "/",
@@ -0,0 +1,20 @@
1
+ # Generated by Django 5.0.6 on 2024-06-21 06:47
2
+
3
+ import django.db.models.deletion
4
+ from django.db import migrations, models
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ dependencies = [
10
+ ('snippetstests', '0011_nonautocompletesearchablesnippet'),
11
+ ('wagtailcore', '0094_alter_page_locale'),
12
+ ]
13
+
14
+ operations = [
15
+ migrations.AlterField(
16
+ model_name='translatablesnippet',
17
+ name='locale',
18
+ field=models.ForeignKey(editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale', verbose_name='locale'),
19
+ ),
20
+ ]
@@ -0,0 +1,52 @@
1
+ # Generated by Django 4.2.13 on 2024-06-12 12:06
2
+
3
+ from django.db import migrations, models
4
+ import django.db.models.deletion
5
+ import modelcluster.fields
6
+ import wagtail.search.index
7
+
8
+
9
+ class Migration(migrations.Migration):
10
+
11
+ dependencies = [
12
+ ("tests", "0037_testpermissionedgenericsetting_and_more"),
13
+ ]
14
+
15
+ operations = [
16
+ migrations.CreateModel(
17
+ name="SocialLink",
18
+ fields=[
19
+ (
20
+ "id",
21
+ models.AutoField(
22
+ auto_created=True,
23
+ primary_key=True,
24
+ serialize=False,
25
+ verbose_name="ID",
26
+ ),
27
+ ),
28
+ ("url", models.URLField()),
29
+ (
30
+ "kind",
31
+ models.CharField(
32
+ choices=[("twitter", "Twitter"), ("facebook", "Facebook")],
33
+ max_length=30,
34
+ ),
35
+ ),
36
+ (
37
+ "person",
38
+ modelcluster.fields.ParentalKey(
39
+ on_delete=django.db.models.deletion.CASCADE,
40
+ related_name="social_links",
41
+ to="tests.personpage",
42
+ verbose_name="Person",
43
+ ),
44
+ ),
45
+ ],
46
+ options={
47
+ "verbose_name": "Social link",
48
+ "verbose_name_plural": "Social links",
49
+ },
50
+ bases=(wagtail.search.index.Indexed, models.Model),
51
+ ),
52
+ ]
@@ -0,0 +1,45 @@
1
+ # Generated by Django 5.0.6 on 2024-06-21 06:47
2
+
3
+ import django.db.models.deletion
4
+ from django.db import migrations, models
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ dependencies = [
10
+ ('tests', '0038_sociallink'),
11
+ ('wagtailcore', '0094_alter_page_locale'),
12
+ ]
13
+
14
+ operations = [
15
+ migrations.AlterField(
16
+ model_name='eventcategory',
17
+ name='locale',
18
+ field=models.ForeignKey(editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale', verbose_name='locale'),
19
+ ),
20
+ migrations.AlterField(
21
+ model_name='eventpagecarouselitem',
22
+ name='locale',
23
+ field=models.ForeignKey(editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale', verbose_name='locale'),
24
+ ),
25
+ migrations.AlterField(
26
+ model_name='eventpagerelatedlink',
27
+ name='locale',
28
+ field=models.ForeignKey(editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale', verbose_name='locale'),
29
+ ),
30
+ migrations.AlterField(
31
+ model_name='eventpagespeaker',
32
+ name='locale',
33
+ field=models.ForeignKey(editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale', verbose_name='locale'),
34
+ ),
35
+ migrations.AlterField(
36
+ model_name='eventpagespeakeraward',
37
+ name='locale',
38
+ field=models.ForeignKey(editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale', verbose_name='locale'),
39
+ ),
40
+ migrations.AlterField(
41
+ model_name='fullfeaturedsnippet',
42
+ name='locale',
43
+ field=models.ForeignKey(editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale', verbose_name='locale'),
44
+ ),
45
+ ]
@@ -2097,6 +2097,7 @@ class PersonPage(Page):
2097
2097
  "Person",
2098
2098
  ),
2099
2099
  InlinePanel("addresses", label="Address"),
2100
+ InlinePanel("social_links", label="Social links"),
2100
2101
  ]
2101
2102
 
2102
2103
  class Meta:
@@ -2133,6 +2134,29 @@ class AddressTag(TaggedItemBase):
2133
2134
  )
2134
2135
 
2135
2136
 
2137
+ class SocialLink(index.Indexed, ClusterableModel):
2138
+ url = models.URLField()
2139
+ kind = models.CharField(
2140
+ max_length=30,
2141
+ choices=[
2142
+ ("twitter", "Twitter"),
2143
+ ("facebook", "Facebook"),
2144
+ ],
2145
+ )
2146
+ person = ParentalKey(
2147
+ to="tests.PersonPage", related_name="social_links", verbose_name="Person"
2148
+ )
2149
+
2150
+ panels = [
2151
+ FieldPanel("url"),
2152
+ FieldPanel("kind"),
2153
+ ]
2154
+
2155
+ class Meta:
2156
+ verbose_name = "Social link"
2157
+ verbose_name_plural = "Social links"
2158
+
2159
+
2136
2160
  class RestaurantPage(Page):
2137
2161
  tags = ClusterTaggableManager(through="tests.TaggedRestaurant", blank=True)
2138
2162
 
@@ -278,6 +278,7 @@ class ToyViewSetGroup(ModelViewSetGroup):
278
278
  index_view_class=FeatureCompleteToyIndexView,
279
279
  list_display=["name", "strid", "release_date"],
280
280
  ordering=["strid"],
281
+ copy_view_enabled=False,
281
282
  ),
282
283
  )
283
284
 
@@ -21,6 +21,7 @@ from wagtail.admin.ui.tables import BooleanColumn, UpdatedAtColumn
21
21
  from wagtail.admin.utils import set_query_params
22
22
  from wagtail.admin.views.account import BaseSettingsPanel
23
23
  from wagtail.admin.widgets import Button
24
+ from wagtail.permission_policies.base import ModelPermissionPolicy
24
25
  from wagtail.snippets.bulk_actions.snippet_bulk_action import SnippetBulkAction
25
26
  from wagtail.snippets.models import register_snippet
26
27
  from wagtail.snippets.views.chooser import SnippetChooserViewSet
@@ -264,6 +265,13 @@ class FullFeaturedSnippetFilterSet(WagtailFilterSet):
264
265
  fields = ["country_code", "some_date"]
265
266
 
266
267
 
268
+ class FullFeaturedPermissionPolicy(ModelPermissionPolicy):
269
+ def user_has_permission(self, user, action):
270
+ if not user.is_anonymous and "[FORBIDDEN]" in user.get_full_name():
271
+ return False
272
+ return super().user_has_permission(user, action)
273
+
274
+
267
275
  class FullFeaturedSnippetChooserViewSet(SnippetChooserViewSet):
268
276
  form_fields = ["text", "country_code", "some_number"]
269
277
 
@@ -303,6 +311,7 @@ class FullFeaturedSnippetViewSet(SnippetViewSet):
303
311
  # Ensure that the menu item is placed last
304
312
  menu_order = 999999
305
313
  inspect_view_enabled = True
314
+ permission_policy = FullFeaturedPermissionPolicy(FullFeaturedSnippet)
306
315
 
307
316
  class IndexView(SnippetViewSet.index_view_class):
308
317
  def get_add_url(self):
@@ -2,5 +2,10 @@ from django.conf.urls.i18n import i18n_patterns
2
2
  from django.urls import include, path
3
3
 
4
4
  from wagtail import urls as wagtail_urls
5
+ from wagtail.admin import urls as wagtailadmin_urls
5
6
 
6
- urlpatterns = i18n_patterns(path("", include(wagtail_urls)))
7
+ urlpatterns = [
8
+ path("admin/", include(wagtailadmin_urls)),
9
+ ]
10
+
11
+ urlpatterns += i18n_patterns(path("", include(wagtail_urls)))
@@ -0,0 +1,11 @@
1
+ from django.conf.urls.i18n import i18n_patterns
2
+ from django.urls import include, path
3
+
4
+ from wagtail import urls as wagtail_urls
5
+ from wagtail.admin import urls as wagtailadmin_urls
6
+
7
+ urlpatterns = [
8
+ path("admin/", include(wagtailadmin_urls)),
9
+ ]
10
+
11
+ urlpatterns += i18n_patterns(path("site/", include(wagtail_urls)))