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
@@ -1,7 +1,8 @@
1
1
  import datetime
2
2
  import json
3
3
 
4
- from django.db.models import F, JSONField
4
+ from django.db import connection
5
+ from django.db.models import F, JSONField, TextField
5
6
  from django.db.models.functions import Cast
6
7
  from django.test import TestCase
7
8
  from django.utils import timezone
@@ -24,8 +25,8 @@ class BaseMigrationTest(TestCase, MigrationTestMixin):
24
25
  ]
25
26
  app_name = None
26
27
 
27
- def setUp(self):
28
- instances = [
28
+ def _get_test_instances(self):
29
+ return [
29
30
  self.factory(
30
31
  content__0__char1="Test char 1",
31
32
  content__1__char1="Test char 2",
@@ -44,6 +45,9 @@ class BaseMigrationTest(TestCase, MigrationTestMixin):
44
45
  ),
45
46
  ]
46
47
 
48
+ def setUp(self):
49
+ instances = self._get_test_instances()
50
+
47
51
  self.original_raw_data = {}
48
52
  self.original_revisions = {}
49
53
 
@@ -102,9 +106,7 @@ class BaseMigrationTest(TestCase, MigrationTestMixin):
102
106
 
103
107
  self.apply_migration()
104
108
 
105
- instances = self.model.objects.all().annotate(
106
- raw_content=Cast(F("content"), JSONField())
107
- )
109
+ instances = self.model.objects.all()
108
110
 
109
111
  for instance in instances:
110
112
  old_revisions = self.original_revisions[instance.id]
@@ -128,9 +130,7 @@ class BaseMigrationTest(TestCase, MigrationTestMixin):
128
130
  revisions_from = timezone.now() + datetime.timedelta(days=2)
129
131
  self.apply_migration(revisions_from=revisions_from)
130
132
 
131
- instances = self.model.objects.all().annotate(
132
- raw_content=Cast(F("content"), JSONField())
133
- )
133
+ instances = self.model.objects.all()
134
134
 
135
135
  for instance in instances:
136
136
  old_revisions = self.original_revisions[instance.id]
@@ -159,9 +159,7 @@ class BaseMigrationTest(TestCase, MigrationTestMixin):
159
159
  revisions_from = timezone.now() - datetime.timedelta(days=2)
160
160
  self.apply_migration(revisions_from=revisions_from)
161
161
 
162
- instances = self.model.objects.all().annotate(
163
- raw_content=Cast(F("content"), JSONField())
164
- )
162
+ instances = self.model.objects.all()
165
163
 
166
164
  for instance in instances:
167
165
  old_revisions = self.original_revisions[instance.id]
@@ -209,3 +207,46 @@ class TestPage(BaseMigrationTest):
209
207
 
210
208
  def test_migrate_revisions_from_date(self):
211
209
  self._test_migrate_revisions_from_date()
210
+
211
+
212
+ class TestNullStreamField(BaseMigrationTest):
213
+ """
214
+ Migrations are processed if the underlying JSON is null.
215
+
216
+ This might occur if we're operating on a StreamField that was added to a model that
217
+ had existing records.
218
+ """
219
+
220
+ model = models.SamplePage
221
+ factory = factories.SamplePageFactory
222
+ has_revisions = True
223
+ app_name = "streamfield_migration_tests"
224
+
225
+ def _get_test_instances(self):
226
+ return self.factory.create_batch(1, content=None)
227
+
228
+ def setUp(self):
229
+ super().setUp()
230
+
231
+ # Bypass StreamField/StreamBlock processing that cast a None stream field value
232
+ # to the empty StreamValue, and set the underlying JSON to null.
233
+ with connection.cursor() as cursor:
234
+ cursor.execute(f"UPDATE {self.model._meta.db_table} SET content = 'null'")
235
+
236
+ def assert_null_content(self):
237
+ """
238
+ The raw JSON of all instances for this test is null.
239
+ """
240
+
241
+ instances = self.model.objects.all().annotate(
242
+ raw_content=Cast(F("content"), TextField())
243
+ )
244
+
245
+ for instance in instances:
246
+ with self.subTest(instance=instance):
247
+ self.assertEqual(instance.raw_content, "null")
248
+
249
+ def test_migrate_stream_data(self):
250
+ self.assert_null_content()
251
+ self.apply_migration()
252
+ self.assert_null_content()
@@ -3,6 +3,7 @@ import json
3
3
 
4
4
  from django.conf import settings
5
5
  from django.contrib.auth import get_user_model
6
+ from django.contrib.contenttypes.models import ContentType
6
7
  from django.core.exceptions import ValidationError
7
8
  from django.core.serializers.json import DjangoJSONEncoder
8
9
  from django.test import TestCase
@@ -10,6 +11,7 @@ from django.utils import timezone
10
11
  from freezegun import freeze_time
11
12
 
12
13
  from wagtail.log_actions import LogActionRegistry
14
+ from wagtail.log_actions import registry as log_registry
13
15
  from wagtail.models import (
14
16
  Page,
15
17
  PageLogEntry,
@@ -36,8 +38,13 @@ class TestAuditLogManager(WagtailTestUtils, TestCase):
36
38
  title="Simple page", slug="simple", content="Hello", owner=self.user
37
39
  )
38
40
  )
41
+ self.snippet_1 = FullFeaturedSnippet.objects.create(text="snippet 1")
42
+ self.snippet_2 = FullFeaturedSnippet.objects.create(text="snippet 2")
43
+ self.snippet_content_type = ContentType.objects.get_for_model(
44
+ FullFeaturedSnippet
45
+ )
39
46
 
40
- def test_log_action(self):
47
+ def test_log_action_for_page(self):
41
48
  now = timezone.now()
42
49
 
43
50
  with freeze_time(now):
@@ -49,7 +56,19 @@ class TestAuditLogManager(WagtailTestUtils, TestCase):
49
56
  self.assertEqual(entry.user, self.user)
50
57
  self.assertEqual(entry.timestamp, now)
51
58
 
52
- def test_get_for_model(self):
59
+ def test_log_action_for_snippet(self):
60
+ now = timezone.now()
61
+
62
+ with freeze_time(now):
63
+ entry = ModelLogEntry.objects.log_action(
64
+ self.snippet_1, "wagtail.edit", user=self.user
65
+ )
66
+
67
+ self.assertEqual(entry.content_type, self.snippet_content_type)
68
+ self.assertEqual(entry.user, self.user)
69
+ self.assertEqual(entry.timestamp, now)
70
+
71
+ def test_get_for_page_model(self):
53
72
  PageLogEntry.objects.log_action(self.page, "wagtail.edit")
54
73
  PageLogEntry.objects.log_action(self.simple_page, "wagtail.edit")
55
74
 
@@ -59,11 +78,62 @@ class TestAuditLogManager(WagtailTestUtils, TestCase):
59
78
  list(entries), list(PageLogEntry.objects.filter(page=self.simple_page))
60
79
  )
61
80
 
81
+ def test_get_for_snippet_model(self):
82
+ ModelLogEntry.objects.log_action(self.snippet_1, "wagtail.edit")
83
+ ModelLogEntry.objects.log_action(self.snippet_2, "wagtail.edit")
84
+
85
+ entries = ModelLogEntry.objects.get_for_model(FullFeaturedSnippet)
86
+ self.assertEqual(entries.count(), 2)
87
+ self.assertListEqual(
88
+ list(entries),
89
+ list(ModelLogEntry.objects.filter(content_type=self.snippet_content_type)),
90
+ )
91
+
62
92
  def test_get_for_user(self):
63
93
  self.assertEqual(
64
94
  PageLogEntry.objects.get_for_user(self.user).count(), 1
65
95
  ) # the create from setUp
66
96
 
97
+ def test_get_for_page_instance(self):
98
+ PageLogEntry.objects.log_action(self.page, "wagtail.edit")
99
+ PageLogEntry.objects.log_action(self.simple_page, "wagtail.edit")
100
+ other_simple_page = self.page.add_child(
101
+ instance=SimplePage(
102
+ title="Simple page 2", slug="simple2", content="Hello", owner=self.user
103
+ )
104
+ )
105
+ PageLogEntry.objects.log_action(other_simple_page, "wagtail.edit")
106
+
107
+ entries = PageLogEntry.objects.for_instance(self.simple_page)
108
+ expected_entries = list(PageLogEntry.objects.filter(page=self.simple_page))
109
+ self.assertEqual(entries.count(), 2)
110
+ self.assertListEqual(list(entries), expected_entries)
111
+
112
+ # should also be able to retrieve entries via the log registry, which
113
+ # eliminates the need to know that PageLogEntry is the log entry model
114
+ entries = log_registry.get_logs_for_instance(self.simple_page)
115
+ self.assertEqual(entries.count(), 2)
116
+ self.assertListEqual(list(entries), expected_entries)
117
+
118
+ def test_get_for_snippet_instance(self):
119
+ ModelLogEntry.objects.log_action(self.snippet_1, "wagtail.edit")
120
+ ModelLogEntry.objects.log_action(self.snippet_2, "wagtail.edit")
121
+
122
+ entries = ModelLogEntry.objects.for_instance(self.snippet_1)
123
+ expected_entries = list(
124
+ ModelLogEntry.objects.filter(
125
+ content_type=self.snippet_content_type, object_id=self.snippet_1.pk
126
+ )
127
+ )
128
+ self.assertEqual(entries.count(), 1)
129
+ self.assertListEqual(list(entries), expected_entries)
130
+
131
+ # should also be able to retrieve entries via the log registry, which
132
+ # eliminates the need to know that ModelLogEntry is the log entry model
133
+ entries = log_registry.get_logs_for_instance(self.snippet_1)
134
+ self.assertEqual(entries.count(), 1)
135
+ self.assertListEqual(list(entries), expected_entries)
136
+
67
137
 
68
138
  class TestAuditLog(TestCase):
69
139
  def setUp(self):
@@ -17,6 +17,7 @@ from django.utils.translation import gettext_lazy as _
17
17
 
18
18
  from wagtail import blocks
19
19
  from wagtail.blocks.base import get_error_json_data
20
+ from wagtail.blocks.definition_lookup import BlockDefinitionLookup
20
21
  from wagtail.blocks.field_block import FieldBlockAdapter
21
22
  from wagtail.blocks.list_block import ListBlockAdapter, ListBlockValidationError
22
23
  from wagtail.blocks.static_block import StaticBlockAdapter
@@ -5882,3 +5883,105 @@ class TestValidationErrorAsJsonData(TestCase):
5882
5883
  ],
5883
5884
  },
5884
5885
  )
5886
+
5887
+
5888
+ class TestBlockDefinitionLookup(TestCase):
5889
+ def test_simple_lookup(self):
5890
+ lookup = BlockDefinitionLookup(
5891
+ {
5892
+ 0: ("wagtail.blocks.CharBlock", [], {"required": True}),
5893
+ 1: ("wagtail.blocks.RichTextBlock", [], {}),
5894
+ }
5895
+ )
5896
+ char_block = lookup.get_block(0)
5897
+ char_block.set_name("title")
5898
+ self.assertIsInstance(char_block, blocks.CharBlock)
5899
+ self.assertTrue(char_block.required)
5900
+
5901
+ rich_text_block = lookup.get_block(1)
5902
+ self.assertIsInstance(rich_text_block, blocks.RichTextBlock)
5903
+
5904
+ # A subsequent call to get_block with the same index should return a new instance;
5905
+ # this ensures that state changes such as set_name are independent of other blocks
5906
+ char_block_2 = lookup.get_block(0)
5907
+ char_block_2.set_name("subtitle")
5908
+ self.assertIsInstance(char_block, blocks.CharBlock)
5909
+ self.assertTrue(char_block.required)
5910
+ self.assertIsNot(char_block, char_block_2)
5911
+ self.assertEqual(char_block.name, "title")
5912
+ self.assertEqual(char_block_2.name, "subtitle")
5913
+
5914
+ def test_structblock_lookup(self):
5915
+ lookup = BlockDefinitionLookup(
5916
+ {
5917
+ 0: ("wagtail.blocks.CharBlock", [], {"required": True}),
5918
+ 1: ("wagtail.blocks.RichTextBlock", [], {}),
5919
+ 2: (
5920
+ "wagtail.blocks.StructBlock",
5921
+ [
5922
+ [
5923
+ ("title", 0),
5924
+ ("description", 1),
5925
+ ],
5926
+ ],
5927
+ {},
5928
+ ),
5929
+ }
5930
+ )
5931
+ struct_block = lookup.get_block(2)
5932
+ self.assertIsInstance(struct_block, blocks.StructBlock)
5933
+ title_block = struct_block.child_blocks["title"]
5934
+ self.assertIsInstance(title_block, blocks.CharBlock)
5935
+ self.assertTrue(title_block.required)
5936
+ description_block = struct_block.child_blocks["description"]
5937
+ self.assertIsInstance(description_block, blocks.RichTextBlock)
5938
+
5939
+ def test_streamblock_lookup(self):
5940
+ lookup = BlockDefinitionLookup(
5941
+ {
5942
+ 0: ("wagtail.blocks.CharBlock", [], {"required": True}),
5943
+ 1: ("wagtail.blocks.RichTextBlock", [], {}),
5944
+ 2: (
5945
+ "wagtail.blocks.StreamBlock",
5946
+ [
5947
+ [
5948
+ ("heading", 0),
5949
+ ("paragraph", 1),
5950
+ ],
5951
+ ],
5952
+ {},
5953
+ ),
5954
+ }
5955
+ )
5956
+ stream_block = lookup.get_block(2)
5957
+ self.assertIsInstance(stream_block, blocks.StreamBlock)
5958
+ title_block = stream_block.child_blocks["heading"]
5959
+ self.assertIsInstance(title_block, blocks.CharBlock)
5960
+ self.assertTrue(title_block.required)
5961
+ description_block = stream_block.child_blocks["paragraph"]
5962
+ self.assertIsInstance(description_block, blocks.RichTextBlock)
5963
+
5964
+ def test_listblock_lookup(self):
5965
+ lookup = BlockDefinitionLookup(
5966
+ {
5967
+ 0: ("wagtail.blocks.CharBlock", [], {"required": True}),
5968
+ 1: ("wagtail.blocks.ListBlock", [0], {}),
5969
+ }
5970
+ )
5971
+ list_block = lookup.get_block(1)
5972
+ self.assertIsInstance(list_block, blocks.ListBlock)
5973
+ list_item_block = list_block.child_block
5974
+ self.assertIsInstance(list_item_block, blocks.CharBlock)
5975
+ self.assertTrue(list_item_block.required)
5976
+
5977
+ # Passing a class as the child block is still valid; this is not converted
5978
+ # to a reference
5979
+ lookup = BlockDefinitionLookup(
5980
+ {
5981
+ 0: ("wagtail.blocks.ListBlock", [blocks.CharBlock], {}),
5982
+ }
5983
+ )
5984
+ list_block = lookup.get_block(0)
5985
+ self.assertIsInstance(list_block, blocks.ListBlock)
5986
+ list_item_block = list_block.child_block
5987
+ self.assertIsInstance(list_item_block, blocks.CharBlock)
@@ -1,9 +1,10 @@
1
1
  from unittest import mock
2
2
 
3
+ from django.conf import settings
3
4
  from django.test import TestCase
4
5
 
5
- from wagtail.models import Site
6
- from wagtail.signals import page_slug_changed
6
+ from wagtail.models import Locale, Site
7
+ from wagtail.signals import copy_for_translation_done, page_slug_changed
7
8
  from wagtail.test.testapp.models import SimplePage
8
9
  from wagtail.test.utils import WagtailTestUtils
9
10
 
@@ -97,3 +98,49 @@ class TestPageSlugChangedSignal(WagtailTestUtils, TestCase):
97
98
 
98
99
  # Check the signal was NOT fired
99
100
  self.assertEqual(handler.call_count, 0)
101
+
102
+
103
+ class TestCopyForTranslationDoneSignal(WagtailTestUtils, TestCase):
104
+ """
105
+ Tests for the `wagtail.signals.copy_for_translation_done` signal
106
+ """
107
+
108
+ def setUp(self):
109
+ # Find root page
110
+ site = Site.objects.select_related("root_page").get(is_default_site=True)
111
+ root_page = site.root_page
112
+
113
+ # Create a subpage
114
+ self.subpage = SimplePage(
115
+ title="Subpage in english", slug="subpage-in-english", content="hello"
116
+ )
117
+ root_page.add_child(instance=self.subpage)
118
+
119
+ # Get the languages and create locales
120
+ language_codes = dict(settings.LANGUAGES).keys()
121
+
122
+ for language_code in language_codes:
123
+ Locale.objects.get_or_create(language_code=language_code)
124
+
125
+ # Get the locales needed
126
+ self.locale = Locale.objects.get(language_code="en")
127
+ self.another_locale = Locale.objects.get(language_code="fr")
128
+
129
+ root_page.copy_for_translation(self.another_locale)
130
+
131
+ def test_signal_emitted_on_copy_for_translation_done(self):
132
+ # Connect a mock signal handler to the signal
133
+ handler = mock.MagicMock()
134
+ copy_for_translation_done.connect(handler)
135
+
136
+ page_to_translate = SimplePage.objects.get(id=self.subpage.id)
137
+
138
+ try:
139
+ with self.captureOnCommitCallbacks(execute=True):
140
+ page_to_translate.copy_for_translation(self.another_locale)
141
+ finally:
142
+ # Disconnect mock handler to prevent cross-test pollution
143
+ copy_for_translation_done.disconnect(handler)
144
+
145
+ # Check the signal was fired
146
+ self.assertEqual(handler.call_count, 1)
@@ -721,3 +721,156 @@ class TestGetBlockByContentPath(TestCase):
721
721
  self.assertEqual(bound_block.value, "Barnaby Rudge")
722
722
  bound_block = field.get_block_by_content_path(self.page.body, ["456", "999"])
723
723
  self.assertIsNone(bound_block)
724
+
725
+
726
+ class TestConstructStreamFieldFromLookup(TestCase):
727
+ def test_construct_block_list_from_lookup(self):
728
+ field = StreamField(
729
+ [
730
+ ("heading", 0),
731
+ ("paragraph", 1),
732
+ ("button", 3),
733
+ ],
734
+ block_lookup={
735
+ 0: ("wagtail.blocks.CharBlock", [], {"required": True}),
736
+ 1: ("wagtail.blocks.RichTextBlock", [], {}),
737
+ 2: ("wagtail.blocks.PageChooserBlock", [], {}),
738
+ 3: (
739
+ "wagtail.blocks.StructBlock",
740
+ [
741
+ [
742
+ ("page", 2),
743
+ ("link_text", 0),
744
+ ]
745
+ ],
746
+ {},
747
+ ),
748
+ },
749
+ )
750
+ stream_block = field.stream_block
751
+ self.assertIsInstance(stream_block, blocks.StreamBlock)
752
+ self.assertEqual(len(stream_block.child_blocks), 3)
753
+
754
+ heading_block = stream_block.child_blocks["heading"]
755
+ self.assertIsInstance(heading_block, blocks.CharBlock)
756
+ self.assertTrue(heading_block.required)
757
+ self.assertEqual(heading_block.name, "heading")
758
+
759
+ paragraph_block = stream_block.child_blocks["paragraph"]
760
+ self.assertIsInstance(paragraph_block, blocks.RichTextBlock)
761
+ self.assertEqual(paragraph_block.name, "paragraph")
762
+
763
+ button_block = stream_block.child_blocks["button"]
764
+ self.assertIsInstance(button_block, blocks.StructBlock)
765
+ self.assertEqual(button_block.name, "button")
766
+ self.assertEqual(len(button_block.child_blocks), 2)
767
+ page_block = button_block.child_blocks["page"]
768
+ self.assertIsInstance(page_block, blocks.PageChooserBlock)
769
+ link_text_block = button_block.child_blocks["link_text"]
770
+ self.assertIsInstance(link_text_block, blocks.CharBlock)
771
+ self.assertEqual(link_text_block.name, "link_text")
772
+
773
+ def test_construct_top_level_block_from_lookup(self):
774
+ field = StreamField(
775
+ 4,
776
+ block_lookup={
777
+ 0: ("wagtail.blocks.CharBlock", [], {"required": True}),
778
+ 1: ("wagtail.blocks.RichTextBlock", [], {}),
779
+ 2: ("wagtail.blocks.PageChooserBlock", [], {}),
780
+ 3: (
781
+ "wagtail.blocks.StructBlock",
782
+ [
783
+ [
784
+ ("page", 2),
785
+ ("link_text", 0),
786
+ ]
787
+ ],
788
+ {},
789
+ ),
790
+ 4: (
791
+ "wagtail.blocks.StreamBlock",
792
+ [
793
+ [
794
+ ("heading", 0),
795
+ ("paragraph", 1),
796
+ ("button", 3),
797
+ ]
798
+ ],
799
+ {},
800
+ ),
801
+ },
802
+ )
803
+ stream_block = field.stream_block
804
+ self.assertIsInstance(stream_block, blocks.StreamBlock)
805
+ self.assertEqual(len(stream_block.child_blocks), 3)
806
+
807
+ heading_block = stream_block.child_blocks["heading"]
808
+ self.assertIsInstance(heading_block, blocks.CharBlock)
809
+ self.assertTrue(heading_block.required)
810
+ self.assertEqual(heading_block.name, "heading")
811
+
812
+ paragraph_block = stream_block.child_blocks["paragraph"]
813
+ self.assertIsInstance(paragraph_block, blocks.RichTextBlock)
814
+ self.assertEqual(paragraph_block.name, "paragraph")
815
+
816
+ button_block = stream_block.child_blocks["button"]
817
+ self.assertIsInstance(button_block, blocks.StructBlock)
818
+ self.assertEqual(button_block.name, "button")
819
+ self.assertEqual(len(button_block.child_blocks), 2)
820
+ page_block = button_block.child_blocks["page"]
821
+ self.assertIsInstance(page_block, blocks.PageChooserBlock)
822
+ link_text_block = button_block.child_blocks["link_text"]
823
+ self.assertIsInstance(link_text_block, blocks.CharBlock)
824
+ self.assertEqual(link_text_block.name, "link_text")
825
+
826
+
827
+ class TestDeconstructStreamFieldWithLookup(TestCase):
828
+ def test_deconstruct(self):
829
+ class ButtonBlock(blocks.StructBlock):
830
+ page = blocks.PageChooserBlock()
831
+ link_text = blocks.CharBlock(required=True)
832
+
833
+ field = StreamField(
834
+ [
835
+ ("heading", blocks.CharBlock(required=True)),
836
+ ("paragraph", blocks.RichTextBlock()),
837
+ ("button", ButtonBlock()),
838
+ ],
839
+ blank=True,
840
+ )
841
+ field.set_attributes_from_name("body")
842
+
843
+ name, path, args, kwargs = field.deconstruct()
844
+ self.assertEqual(name, "body")
845
+ self.assertEqual(path, "wagtail.fields.StreamField")
846
+ self.assertEqual(
847
+ args,
848
+ [
849
+ [
850
+ ("heading", 0),
851
+ ("paragraph", 1),
852
+ ("button", 3),
853
+ ]
854
+ ],
855
+ )
856
+ self.assertEqual(
857
+ kwargs,
858
+ {
859
+ "blank": True,
860
+ "block_lookup": {
861
+ 0: ("wagtail.blocks.CharBlock", (), {"required": True}),
862
+ 1: ("wagtail.blocks.RichTextBlock", (), {}),
863
+ 2: ("wagtail.blocks.PageChooserBlock", (), {}),
864
+ 3: (
865
+ "wagtail.blocks.StructBlock",
866
+ [
867
+ [
868
+ ("page", 2),
869
+ ("link_text", 0),
870
+ ]
871
+ ],
872
+ {},
873
+ ),
874
+ },
875
+ },
876
+ )
@@ -28,7 +28,8 @@ from wagtail.coreutils import (
28
28
  )
29
29
  from wagtail.models import Page, Site
30
30
  from wagtail.utils.file import hash_filelike
31
- from wagtail.utils.utils import deep_update
31
+ from wagtail.utils.utils import deep_update, flatten_choices
32
+ from wagtail.utils.version import get_main_version
32
33
 
33
34
 
34
35
  class TestCamelCaseToUnderscore(TestCase):
@@ -575,3 +576,43 @@ class HashFileLikeTestCase(SimpleTestCase):
575
576
  hash_filelike(FakeLargeFile()),
576
577
  "bd36f0c5a02cd6e9e34202ea3ff8db07b533e025",
577
578
  )
579
+
580
+
581
+ class TestVersion(SimpleTestCase):
582
+ def test_get_main_version(self):
583
+ cases = [
584
+ ((6, 2, 0, "final", 0), False, "6.2"),
585
+ ((6, 2, 1, "final", 0), False, "6.2"),
586
+ ((6, 2, 0, "final", 0), True, "6.2"),
587
+ ((6, 2, 1, "final", 0), True, "6.2.1"),
588
+ ]
589
+ for version, include_patch, expected in cases:
590
+ with self.subTest(version=version, include_patch=include_patch):
591
+ self.assertEqual(get_main_version(version, include_patch), expected)
592
+
593
+
594
+ class TestFlattenChoices(SimpleTestCase):
595
+ def test_tuple_choices(self):
596
+ choices = [(1, "1st"), (2, "2nd")]
597
+ self.assertEqual(flatten_choices(choices), {"1": "1st", "2": "2nd"})
598
+
599
+ def test_grouped_tuple_choices(self):
600
+ choices = [("Group", [(1, "1st"), (2, "2nd")])]
601
+ self.assertEqual(flatten_choices(choices), {"1": "1st", "2": "2nd"})
602
+
603
+ def test_dictionary_choices(self):
604
+ choices = {
605
+ "Martial Arts": {"judo": "Judo", "karate": "Karate"},
606
+ "Racket": {"badminton": "Badminton", "tennis": "Tennis"},
607
+ "unknown": "Unknown",
608
+ }
609
+ self.assertEqual(
610
+ flatten_choices(choices),
611
+ {
612
+ "judo": "Judo",
613
+ "karate": "Karate",
614
+ "badminton": "Badminton",
615
+ "tennis": "Tennis",
616
+ "unknown": "Unknown",
617
+ },
618
+ )
wagtail/tests/tests.py CHANGED
@@ -9,6 +9,7 @@ from django.test import TestCase
9
9
  from django.test.utils import override_settings
10
10
  from django.urls.exceptions import NoReverseMatch
11
11
  from django.utils.safestring import SafeString
12
+ from django.utils.translation import gettext_lazy
12
13
 
13
14
  from wagtail.coreutils import (
14
15
  get_dummy_request,
@@ -536,6 +537,10 @@ class TestRichtextTag(TestCase):
536
537
  self.assertEqual(result, "Hello world!")
537
538
  self.assertIsInstance(result, SafeString)
538
539
 
540
+ def test_call_with_lazy(self):
541
+ result = richtext(gettext_lazy("test"))
542
+ self.assertEqual(result, "test")
543
+
539
544
  def test_call_with_none(self):
540
545
  result = richtext(None)
541
546
  self.assertEqual(result, "")
wagtail/users/apps.py CHANGED
@@ -8,3 +8,4 @@ class WagtailUsersAppConfig(AppConfig):
8
8
  verbose_name = _("Wagtail users")
9
9
  default_auto_field = "django.db.models.AutoField"
10
10
  group_viewset = "wagtail.users.views.groups.GroupViewSet"
11
+ user_viewset = "wagtail.users.views.users.UserViewSet"
wagtail/users/forms.py CHANGED
@@ -1,4 +1,5 @@
1
1
  from itertools import groupby
2
+ from warnings import warn
2
3
 
3
4
  from django import forms
4
5
  from django.conf import settings
@@ -21,6 +22,7 @@ from wagtail.models import (
21
22
  GroupPagePermission,
22
23
  Page,
23
24
  )
25
+ from wagtail.utils.deprecation import RemovedInWagtail70Warning
24
26
 
25
27
  User = get_user_model()
26
28
 
@@ -29,6 +31,11 @@ standard_fields = {"email", "first_name", "last_name", "is_superuser", "groups"}
29
31
  # Custom fields
30
32
  if hasattr(settings, "WAGTAIL_USER_CUSTOM_FIELDS"):
31
33
  custom_fields = set(settings.WAGTAIL_USER_CUSTOM_FIELDS)
34
+ warn(
35
+ "The `WAGTAIL_USER_CUSTOM_FIELDS` setting is deprecated. Use a custom "
36
+ "`UserViewSet` subclass and override `get_form_class()` instead.",
37
+ RemovedInWagtail70Warning,
38
+ )
32
39
  else:
33
40
  custom_fields = set()
34
41
 
@@ -177,11 +177,11 @@ msgstr "عذرًا ، لا توجد مجموعات تطابق \"%(query)s\""
177
177
 
178
178
  #, python-format
179
179
  msgid ""
180
- "There are no groups configured. Why not <a href="
181
- "\"%(wagtailusers_create_group_url)s\">add some</a>?"
180
+ "There are no groups configured. Why not <a "
181
+ "href=\"%(wagtailusers_create_group_url)s\">add some</a>?"
182
182
  msgstr ""
183
- "لا توجد مجموعات تم تكوينها. لماذا لا <a href="
184
- "\"%(wagtailusers_create_group_url)s\">تضيف بعض</a>؟"
183
+ "لا توجد مجموعات تم تكوينها. لماذا لا <a "
184
+ "href=\"%(wagtailusers_create_group_url)s\">تضيف بعض</a>؟"
185
185
 
186
186
  msgid "Are you sure you want to delete this user?"
187
187
  msgstr "هل أنت متأكد من حذف هذا المستخدم؟ "