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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (386) hide show
  1. wagtail/__init__.py +1 -1
  2. wagtail/actions/copy_for_translation.py +6 -0
  3. wagtail/actions/publish_revision.py +3 -3
  4. wagtail/admin/action_menu.py +5 -3
  5. wagtail/admin/forms/account.py +1 -1
  6. wagtail/admin/icons.py +2 -6
  7. wagtail/admin/locale/cy/LC_MESSAGES/django.mo +0 -0
  8. wagtail/admin/locale/cy/LC_MESSAGES/django.po +32 -0
  9. wagtail/admin/locale/dv/LC_MESSAGES/django.mo +0 -0
  10. wagtail/admin/locale/dv/LC_MESSAGES/django.po +28 -0
  11. wagtail/admin/locale/en/LC_MESSAGES/django.po +451 -485
  12. wagtail/admin/locale/en/LC_MESSAGES/djangojs.po +7 -7
  13. wagtail/admin/locale/sl/LC_MESSAGES/django.mo +0 -0
  14. wagtail/admin/locale/sl/LC_MESSAGES/django.po +150 -0
  15. wagtail/admin/locale/sl/LC_MESSAGES/djangojs.mo +0 -0
  16. wagtail/admin/locale/sl/LC_MESSAGES/djangojs.po +9 -2
  17. wagtail/admin/locale/ug/LC_MESSAGES/django.mo +0 -0
  18. wagtail/admin/locale/ug/LC_MESSAGES/django.po +3250 -196
  19. wagtail/admin/localization.py +12 -2
  20. wagtail/admin/panels/model_utils.py +1 -1
  21. wagtail/admin/site_summary.py +0 -2
  22. wagtail/admin/static/wagtailadmin/css/core.css +1 -1
  23. wagtail/admin/static/wagtailadmin/css/panels/draftail.css +1 -1
  24. wagtail/admin/static/wagtailadmin/images/email-header.jpg +0 -0
  25. wagtail/admin/static/wagtailadmin/js/bulk-actions.js +1 -1
  26. wagtail/admin/static/wagtailadmin/js/core.js +1 -1
  27. wagtail/admin/static/wagtailadmin/js/core.js.LICENSE.txt +12 -0
  28. wagtail/admin/static/wagtailadmin/js/draftail.js +1 -1
  29. wagtail/admin/static/wagtailadmin/js/sidebar.js +1 -1
  30. wagtail/admin/static/wagtailadmin/js/telepath/telepath.js +1 -1
  31. wagtail/admin/static/wagtailadmin/js/telepath/widgets.js +1 -1
  32. wagtail/admin/static/wagtailadmin/js/userbar.js +1 -1
  33. wagtail/admin/static/wagtailadmin/js/userbar.js.LICENSE.txt +1 -1
  34. wagtail/admin/static/wagtailadmin/js/vendor.js +1 -1
  35. wagtail/admin/static/wagtailadmin/js/wagtailadmin.js +1 -1
  36. wagtail/admin/static/wagtailadmin/js/workflow-action.js +1 -1
  37. wagtail/admin/staticfiles.py +6 -4
  38. wagtail/admin/templates/wagtailadmin/account/account.html +42 -59
  39. wagtail/admin/templates/wagtailadmin/admin_base.html +0 -28
  40. wagtail/admin/templates/wagtailadmin/bulk_actions/footer.html +1 -1
  41. wagtail/admin/templates/wagtailadmin/chooser/_search_results.html +7 -5
  42. wagtail/admin/templates/wagtailadmin/chooser/tables/page_navigate_to_children_cell.html +1 -1
  43. wagtail/admin/templates/wagtailadmin/generic/chooser/results.html +7 -5
  44. wagtail/admin/templates/wagtailadmin/generic/edit.html +0 -8
  45. wagtail/admin/templates/wagtailadmin/generic/form.html +60 -17
  46. wagtail/admin/templates/wagtailadmin/generic/index.html +17 -0
  47. wagtail/admin/templates/wagtailadmin/generic/index_results.html +9 -35
  48. wagtail/admin/templates/wagtailadmin/generic/inspect.html +2 -21
  49. wagtail/admin/templates/wagtailadmin/generic/listing.html +11 -17
  50. wagtail/admin/templates/wagtailadmin/generic/listing_results.html +19 -1
  51. wagtail/admin/templates/wagtailadmin/home/account_summary.html +26 -0
  52. wagtail/admin/templates/wagtailadmin/home/locked_pages.html +28 -18
  53. wagtail/admin/templates/wagtailadmin/home/recent_edits.html +28 -17
  54. wagtail/admin/templates/wagtailadmin/home/site_summary_pages.html +2 -2
  55. wagtail/admin/templates/wagtailadmin/home/upgrade_notification.html +35 -13
  56. wagtail/admin/templates/wagtailadmin/home/user_objects_in_workflow_moderation.html +28 -18
  57. wagtail/admin/templates/wagtailadmin/home/workflow_objects_to_moderate.html +43 -32
  58. wagtail/admin/templates/wagtailadmin/home.html +22 -5
  59. wagtail/admin/templates/wagtailadmin/pages/_editor_js.html +0 -1
  60. wagtail/admin/templates/wagtailadmin/pages/action_menu/menu.html +1 -11
  61. wagtail/admin/templates/wagtailadmin/pages/action_menu/menu_item.html +1 -6
  62. wagtail/admin/templates/wagtailadmin/pages/action_menu/page_locked.html +1 -1
  63. wagtail/admin/templates/wagtailadmin/pages/action_menu/publish.html +1 -1
  64. wagtail/admin/templates/wagtailadmin/pages/action_menu/save_draft.html +1 -1
  65. wagtail/admin/templates/wagtailadmin/pages/bulk_actions/confirm_bulk_delete.html +12 -6
  66. wagtail/admin/templates/wagtailadmin/pages/bulk_actions/confirm_bulk_move.html +12 -7
  67. wagtail/admin/templates/wagtailadmin/pages/bulk_actions/confirm_bulk_publish.html +17 -11
  68. wagtail/admin/templates/wagtailadmin/pages/bulk_actions/confirm_bulk_unpublish.html +15 -9
  69. wagtail/admin/templates/wagtailadmin/pages/confirm_delete.html +9 -9
  70. wagtail/admin/templates/wagtailadmin/pages/confirm_move.html +2 -2
  71. wagtail/admin/templates/wagtailadmin/pages/confirm_unpublish.html +4 -4
  72. wagtail/admin/templates/wagtailadmin/pages/create.html +15 -34
  73. wagtail/admin/templates/wagtailadmin/pages/edit.html +15 -30
  74. wagtail/admin/templates/wagtailadmin/pages/explorable_index.html +6 -0
  75. wagtail/admin/templates/wagtailadmin/pages/explorable_index_results.html +60 -0
  76. wagtail/admin/templates/wagtailadmin/pages/index.html +1 -36
  77. wagtail/admin/templates/wagtailadmin/pages/index_results.html +2 -50
  78. wagtail/admin/templates/wagtailadmin/pages/listing/_locked_indicator.html +1 -1
  79. wagtail/admin/templates/wagtailadmin/pages/listing/_ordering_cell.html +1 -1
  80. wagtail/admin/templates/wagtailadmin/pages/listing/_page_header_buttons.html +1 -1
  81. wagtail/admin/templates/wagtailadmin/pages/listing/_page_title_column_header.html +3 -3
  82. wagtail/admin/templates/wagtailadmin/pages/listing/_pagination.html +1 -1
  83. wagtail/admin/templates/wagtailadmin/pages/listing.html +24 -0
  84. wagtail/admin/templates/wagtailadmin/pages/search.html +1 -20
  85. wagtail/admin/templates/wagtailadmin/pages/search_results.html +27 -25
  86. wagtail/admin/templates/wagtailadmin/permissions/includes/collection_member_permissions_formset.html +0 -1
  87. wagtail/admin/templates/wagtailadmin/reports/listing/_list_page_report.html +2 -2
  88. wagtail/admin/templates/wagtailadmin/reports/listing/_list_page_types_usage.html +6 -6
  89. wagtail/admin/templates/wagtailadmin/reports/workflow_tasks_results.html +1 -1
  90. wagtail/admin/templates/wagtailadmin/shared/action_menu/menu.html +14 -0
  91. wagtail/admin/templates/wagtailadmin/shared/action_menu/menu_item.html +6 -0
  92. wagtail/admin/templates/wagtailadmin/shared/avatar.html +13 -3
  93. wagtail/admin/templates/wagtailadmin/shared/header.html +0 -5
  94. wagtail/admin/templates/wagtailadmin/shared/headers/slim_header.html +1 -1
  95. wagtail/admin/templates/wagtailadmin/shared/page_status_tag_new.html +4 -1
  96. wagtail/admin/templates/wagtailadmin/shared/pagination_nav.html +1 -1
  97. wagtail/admin/templates/wagtailadmin/shared/side_panel_toggle.html +1 -1
  98. wagtail/admin/templates/wagtailadmin/shared/side_panels/includes/status/locale.html +1 -1
  99. wagtail/admin/templates/wagtailadmin/shared/side_panels/includes/status/usage.html +2 -2
  100. wagtail/admin/templates/wagtailadmin/shared/side_panels/preview.html +94 -52
  101. wagtail/admin/templates/wagtailadmin/{pages/_unsaved_changes_warning.html → shared/unsaved_changes_warning.html} +4 -4
  102. wagtail/admin/templates/wagtailadmin/shared/usage_summary.html +2 -2
  103. wagtail/admin/templates/wagtailadmin/shared/workflow_history/detail.html +1 -7
  104. wagtail/admin/templates/wagtailadmin/shared/workflow_history/listing.html +1 -0
  105. wagtail/admin/templates/wagtailadmin/shared/workflow_history/{list.html → listing_results.html} +33 -35
  106. wagtail/admin/templates/wagtailadmin/tables/references_cell.html +1 -1
  107. wagtail/admin/templates/wagtailadmin/workflows/create.html +11 -36
  108. wagtail/admin/templates/wagtailadmin/workflows/create_task.html +0 -38
  109. wagtail/admin/templates/wagtailadmin/workflows/edit.html +44 -74
  110. wagtail/admin/templates/wagtailadmin/workflows/edit_task.html +27 -66
  111. wagtail/admin/templates/wagtailadmin/workflows/includes/task_usage_cell.html +4 -2
  112. wagtail/admin/templates/wagtailadmin/workflows/includes/workflow_tasks_cell.html +4 -4
  113. wagtail/admin/templates/wagtailadmin/workflows/includes/workflow_used_by_cell.html +15 -11
  114. wagtail/admin/templates/wagtailadmin/workflows/task_chooser/includes/results.html +7 -5
  115. wagtail/admin/templatetags/wagtailadmin_tags.py +51 -22
  116. wagtail/admin/tests/pages/test_content_type_use_view.py +82 -2
  117. wagtail/admin/tests/pages/test_edit_page.py +70 -0
  118. wagtail/admin/tests/pages/test_explorer_view.py +65 -4
  119. wagtail/admin/tests/pages/test_page_search.py +8 -7
  120. wagtail/admin/tests/pages/test_page_usage.py +3 -1
  121. wagtail/admin/tests/pages/test_preview.py +208 -63
  122. wagtail/admin/tests/pages/test_reorder_page.py +91 -1
  123. wagtail/admin/tests/pages/test_view_draft.py +32 -1
  124. wagtail/admin/tests/pages/test_workflow_history.py +288 -7
  125. wagtail/admin/tests/test_account_management.py +23 -3
  126. wagtail/admin/tests/test_audit_log.py +24 -2
  127. wagtail/admin/tests/test_collections_views.py +17 -5
  128. wagtail/admin/tests/test_dashboard.py +1 -1
  129. wagtail/admin/tests/test_edit_handlers.py +3 -2
  130. wagtail/admin/tests/test_icon_sprite.py +4 -0
  131. wagtail/admin/tests/test_privacy.py +5 -19
  132. wagtail/admin/tests/test_reports_views.py +1 -1
  133. wagtail/admin/tests/test_site_summary.py +3 -3
  134. wagtail/admin/tests/test_templatetags.py +27 -3
  135. wagtail/admin/tests/test_upgrade_notification.py +71 -18
  136. wagtail/admin/tests/test_views.py +2 -2
  137. wagtail/admin/tests/test_views_generic.py +13 -0
  138. wagtail/admin/tests/test_widgets.py +3 -3
  139. wagtail/admin/tests/test_workflows.py +172 -27
  140. wagtail/admin/tests/tests.py +1 -1
  141. wagtail/admin/tests/viewsets/test_model_viewset.py +55 -3
  142. wagtail/admin/ui/side_panels.py +19 -0
  143. wagtail/admin/ui/sidebar.py +4 -3
  144. wagtail/admin/ui/tables/__init__.py +14 -1
  145. wagtail/admin/ui/tables/pages.py +6 -1
  146. wagtail/admin/urls/pages.py +10 -1
  147. wagtail/admin/urls/workflows.py +6 -1
  148. wagtail/admin/views/account.py +5 -1
  149. wagtail/admin/views/collections.py +0 -2
  150. wagtail/admin/views/generic/base.py +118 -1
  151. wagtail/admin/views/generic/history.py +158 -26
  152. wagtail/admin/views/generic/models.py +113 -99
  153. wagtail/admin/views/home.py +24 -9
  154. wagtail/admin/views/page_privacy.py +54 -30
  155. wagtail/admin/views/pages/history.py +11 -4
  156. wagtail/admin/views/pages/listing.py +76 -89
  157. wagtail/admin/views/pages/preview.py +1 -1
  158. wagtail/admin/views/pages/search.py +27 -71
  159. wagtail/admin/views/pages/usage.py +63 -24
  160. wagtail/admin/views/pages/utils.py +4 -3
  161. wagtail/admin/views/reports/base.py +0 -6
  162. wagtail/admin/views/workflows.py +67 -25
  163. wagtail/admin/viewsets/model.py +4 -3
  164. wagtail/admin/widgets/chooser.py +2 -1
  165. wagtail/api/v2/tests/test_pages.py +15 -2
  166. wagtail/blocks/field_block.py +15 -3
  167. wagtail/blocks/static_block.py +3 -0
  168. wagtail/contrib/forms/locale/cy/LC_MESSAGES/django.mo +0 -0
  169. wagtail/contrib/forms/locale/cy/LC_MESSAGES/django.po +29 -1
  170. wagtail/contrib/forms/locale/en/LC_MESSAGES/django.po +15 -11
  171. wagtail/contrib/forms/templates/wagtailforms/confirm_delete.html +1 -0
  172. wagtail/contrib/forms/templates/wagtailforms/index.html +1 -1
  173. wagtail/contrib/forms/templates/wagtailforms/index_results.html +1 -1
  174. wagtail/contrib/forms/templates/wagtailforms/list_submissions.html +2 -1
  175. wagtail/contrib/forms/templates/wagtailforms/panels/form_responses_panel.html +2 -2
  176. wagtail/contrib/forms/tests/test_views.py +234 -35
  177. wagtail/contrib/forms/utils.py +8 -14
  178. wagtail/contrib/forms/views.py +72 -27
  179. wagtail/contrib/frontend_cache/backends/azure.py +1 -1
  180. wagtail/contrib/frontend_cache/backends/cloudfront.py +2 -2
  181. wagtail/contrib/frontend_cache/backends/dummy.py +11 -0
  182. wagtail/contrib/frontend_cache/tests.py +31 -37
  183. wagtail/contrib/frontend_cache/utils.py +12 -5
  184. wagtail/contrib/redirects/locale/cy/LC_MESSAGES/django.mo +0 -0
  185. wagtail/contrib/redirects/locale/cy/LC_MESSAGES/django.po +16 -1
  186. wagtail/contrib/redirects/locale/en/LC_MESSAGES/django.po +20 -24
  187. wagtail/contrib/redirects/models.py +16 -1
  188. wagtail/contrib/redirects/signal_handlers.py +18 -3
  189. wagtail/contrib/redirects/templates/wagtailredirects/add.html +5 -16
  190. wagtail/contrib/redirects/templates/wagtailredirects/import_summary.html +1 -1
  191. wagtail/contrib/redirects/tests/test_redirects.py +49 -6
  192. wagtail/contrib/redirects/tests/test_signal_handlers.py +42 -1
  193. wagtail/contrib/redirects/views.py +27 -3
  194. wagtail/contrib/search_promotions/locale/cy/LC_MESSAGES/django.mo +0 -0
  195. wagtail/contrib/search_promotions/locale/cy/LC_MESSAGES/django.po +60 -1
  196. wagtail/contrib/search_promotions/locale/en/LC_MESSAGES/django.po +12 -18
  197. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/add.html +5 -8
  198. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/edit.html +15 -10
  199. wagtail/contrib/search_promotions/tests.py +13 -2
  200. wagtail/contrib/search_promotions/views.py +15 -3
  201. wagtail/contrib/settings/locale/cy/LC_MESSAGES/django.mo +0 -0
  202. wagtail/contrib/settings/locale/cy/LC_MESSAGES/django.po +6 -1
  203. wagtail/contrib/settings/locale/en/LC_MESSAGES/django.po +2 -10
  204. wagtail/contrib/settings/templates/wagtailsettings/edit.html +12 -45
  205. wagtail/contrib/simple_translation/locale/cy/LC_MESSAGES/django.mo +0 -0
  206. wagtail/contrib/simple_translation/locale/cy/LC_MESSAGES/django.po +13 -1
  207. wagtail/contrib/simple_translation/locale/dv/LC_MESSAGES/django.mo +0 -0
  208. wagtail/contrib/simple_translation/locale/dv/LC_MESSAGES/django.po +3 -0
  209. wagtail/contrib/simple_translation/locale/en/LC_MESSAGES/django.po +4 -4
  210. wagtail/contrib/simple_translation/locale/sl/LC_MESSAGES/django.mo +0 -0
  211. wagtail/contrib/simple_translation/locale/sl/LC_MESSAGES/django.po +5 -2
  212. wagtail/contrib/simple_translation/tests/test_views.py +51 -0
  213. wagtail/contrib/simple_translation/wagtail_hooks.py +16 -11
  214. wagtail/contrib/styleguide/locale/cy/LC_MESSAGES/django.mo +0 -0
  215. wagtail/contrib/styleguide/locale/cy/LC_MESSAGES/django.po +5 -1
  216. wagtail/contrib/styleguide/locale/en/LC_MESSAGES/django.po +1 -1
  217. wagtail/contrib/table_block/locale/cy/LC_MESSAGES/django.mo +0 -0
  218. wagtail/contrib/table_block/locale/cy/LC_MESSAGES/django.po +27 -1
  219. wagtail/contrib/table_block/locale/en/LC_MESSAGES/django.po +1 -1
  220. wagtail/contrib/typed_table_block/blocks.py +25 -0
  221. wagtail/contrib/typed_table_block/locale/cy/LC_MESSAGES/django.mo +0 -0
  222. wagtail/contrib/typed_table_block/locale/cy/LC_MESSAGES/django.po +12 -1
  223. wagtail/contrib/typed_table_block/locale/en/LC_MESSAGES/django.po +10 -10
  224. wagtail/contrib/typed_table_block/tests.py +24 -1
  225. wagtail/coreutils.py +5 -11
  226. wagtail/documents/admin_urls.py +2 -2
  227. wagtail/documents/locale/cy/LC_MESSAGES/django.mo +0 -0
  228. wagtail/documents/locale/cy/LC_MESSAGES/django.po +10 -0
  229. wagtail/documents/locale/en/LC_MESSAGES/django.po +61 -76
  230. wagtail/documents/migrations/0014_alter_document_file_size.py +18 -0
  231. wagtail/documents/models.py +1 -1
  232. wagtail/documents/rich_text/__init__.py +1 -3
  233. wagtail/documents/static/wagtaildocs/js/add-multiple.js +1 -1
  234. wagtail/documents/templates/wagtaildocs/bulk_actions/confirm_bulk_add_tags.html +5 -1
  235. wagtail/documents/templates/wagtaildocs/bulk_actions/confirm_bulk_add_to_collection.html +5 -1
  236. wagtail/documents/templates/wagtaildocs/bulk_actions/confirm_bulk_delete.html +11 -5
  237. wagtail/documents/templates/wagtaildocs/documents/add.html +13 -41
  238. wagtail/documents/templates/wagtaildocs/documents/edit.html +28 -56
  239. wagtail/documents/templates/wagtaildocs/documents/index.html +1 -4
  240. wagtail/documents/templates/wagtaildocs/homepage/site_summary_documents.html +2 -2
  241. wagtail/documents/templates/wagtaildocs/multiple/add.html +36 -41
  242. wagtail/documents/tests/test_admin_views.py +64 -6
  243. wagtail/documents/tests/test_site_summary.py +3 -3
  244. wagtail/documents/views/documents.py +103 -113
  245. wagtail/documents/views/multiple.py +19 -1
  246. wagtail/embeds/locale/en/LC_MESSAGES/django.po +1 -1
  247. wagtail/embeds/oembed_providers.py +9 -19
  248. wagtail/fields.py +43 -27
  249. wagtail/images/admin_urls.py +2 -2
  250. wagtail/images/blocks.py +230 -2
  251. wagtail/images/fields.py +17 -29
  252. wagtail/images/image_operations.py +1 -1
  253. wagtail/images/locale/cy/LC_MESSAGES/django.mo +0 -0
  254. wagtail/images/locale/cy/LC_MESSAGES/django.po +128 -1
  255. wagtail/images/locale/en/LC_MESSAGES/django.po +119 -129
  256. wagtail/images/migrations/0025_alter_image_file_alter_rendition_file.py +36 -43
  257. wagtail/images/migrations/0027_image_description.py +20 -0
  258. wagtail/images/models.py +120 -45
  259. wagtail/images/rich_text/__init__.py +1 -3
  260. wagtail/images/static/wagtailimages/js/add-multiple.js +1 -1
  261. wagtail/images/static/wagtailimages/js/image-block.js +1 -0
  262. wagtail/images/templates/wagtailimages/bulk_actions/confirm_bulk_add_tags.html +5 -1
  263. wagtail/images/templates/wagtailimages/bulk_actions/confirm_bulk_add_to_collection.html +5 -1
  264. wagtail/images/templates/wagtailimages/bulk_actions/confirm_bulk_delete.html +11 -5
  265. wagtail/images/templates/wagtailimages/chooser/results.html +2 -2
  266. wagtail/images/templates/wagtailimages/homepage/site_summary_images.html +2 -2
  267. wagtail/images/templates/wagtailimages/images/_file_field.html +2 -2
  268. wagtail/images/templates/wagtailimages/images/add.html +13 -31
  269. wagtail/images/templates/wagtailimages/images/edit.html +53 -82
  270. wagtail/images/templates/wagtailimages/images/index.html +1 -4
  271. wagtail/images/templates/wagtailimages/images/url_generator.html +1 -1
  272. wagtail/images/templates/wagtailimages/multiple/add.html +40 -47
  273. wagtail/images/templates/wagtailimages/widgets/image.html +5 -0
  274. wagtail/images/templates/wagtailimages/widgets/image_chooser.html +1 -1
  275. wagtail/images/tests/test_admin_views.py +70 -10
  276. wagtail/images/tests/test_blocks.py +367 -1
  277. wagtail/images/tests/test_image_operations.py +23 -0
  278. wagtail/images/tests/test_models.py +20 -0
  279. wagtail/images/tests/test_signal_handlers.py +99 -95
  280. wagtail/images/tests/test_site_summary.py +3 -3
  281. wagtail/images/tests/test_templatetags.py +11 -7
  282. wagtail/images/tests/tests.py +4 -0
  283. wagtail/images/views/images.py +103 -104
  284. wagtail/images/views/multiple.py +17 -1
  285. wagtail/locale/cy/LC_MESSAGES/django.mo +0 -0
  286. wagtail/locale/cy/LC_MESSAGES/django.po +3 -0
  287. wagtail/locale/en/LC_MESSAGES/django.po +137 -125
  288. wagtail/locale/sl/LC_MESSAGES/django.mo +0 -0
  289. wagtail/locale/sl/LC_MESSAGES/django.po +3 -0
  290. wagtail/locales/locale/en/LC_MESSAGES/django.po +8 -8
  291. wagtail/locales/views.py +4 -1
  292. wagtail/migrations/0089_log_entry_data_json_null_to_object.py +1 -7
  293. wagtail/models/__init__.py +122 -14
  294. wagtail/models/audit_log.py +1 -3
  295. wagtail/models/i18n.py +1 -2
  296. wagtail/project_template/Dockerfile +3 -3
  297. wagtail/project_template/requirements.txt +2 -2
  298. wagtail/query.py +17 -4
  299. wagtail/rich_text/__init__.py +2 -3
  300. wagtail/rich_text/pages.py +2 -4
  301. wagtail/rich_text/rewriters.py +2 -2
  302. wagtail/search/backends/database/mysql/query.py +3 -3
  303. wagtail/search/backends/database/sqlite/query.py +6 -6
  304. wagtail/search/locale/en/LC_MESSAGES/django.po +1 -1
  305. wagtail/sites/locale/en/LC_MESSAGES/django.po +6 -6
  306. wagtail/sites/views.py +0 -1
  307. wagtail/snippets/action_menu.py +14 -4
  308. wagtail/snippets/locale/cy/LC_MESSAGES/django.mo +0 -0
  309. wagtail/snippets/locale/cy/LC_MESSAGES/django.po +73 -1
  310. wagtail/snippets/locale/en/LC_MESSAGES/django.po +27 -33
  311. wagtail/snippets/static/wagtailsnippets/js/snippet-chooser-telepath.js +1 -1
  312. wagtail/snippets/static/wagtailsnippets/js/snippet-chooser.js +1 -1
  313. wagtail/snippets/templates/wagtailsnippets/bulk_actions/confirm_bulk_delete.html +5 -3
  314. wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/locked.html +1 -1
  315. wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/menu.html +1 -11
  316. wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/menu_item.html +1 -6
  317. wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/publish.html +1 -1
  318. wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/save.html +1 -1
  319. wagtail/snippets/templates/wagtailsnippets/snippets/create.html +1 -18
  320. wagtail/snippets/templates/wagtailsnippets/snippets/edit.html +1 -14
  321. wagtail/snippets/templates/wagtailsnippets/snippets/index.html +2 -5
  322. wagtail/snippets/tests/test_preview.py +193 -61
  323. wagtail/snippets/tests/test_snippets.py +247 -38
  324. wagtail/snippets/tests/test_usage.py +5 -0
  325. wagtail/snippets/tests/test_viewset.py +25 -9
  326. wagtail/snippets/tests/test_workflows.py +232 -19
  327. wagtail/snippets/views/snippets.py +1 -10
  328. wagtail/test/numberformat.py +104 -0
  329. wagtail/test/settings.py +10 -0
  330. wagtail/test/settings_ui.py +2 -0
  331. wagtail/test/testapp/migrations/0010_alter_customimage_file_and_more.py +71 -78
  332. wagtail/test/testapp/migrations/0040_nocreatablesubpagetypespage_nosubpagetypespage.py +54 -0
  333. wagtail/test/testapp/migrations/0041_alter_jsonstreammodel_options.py +17 -0
  334. wagtail/test/testapp/migrations/0042_alter_customdocument_file_size_and_more.py +28 -0
  335. wagtail/test/testapp/migrations/0043_customimage_description.py +41 -0
  336. wagtail/test/testapp/migrations/0044_custompreviewsizesmodel_custompreviewsizespage.py +52 -0
  337. wagtail/test/testapp/migrations/0045_alter_streampage_body.py +52 -0
  338. wagtail/test/testapp/models.py +62 -4
  339. wagtail/test/testapp/rich_text.py +2 -2
  340. wagtail/test/testapp/templates/tests/form_page_landing.html +2 -1
  341. wagtail/test/testapp/urls.py +5 -0
  342. wagtail/test/testapp/views.py +5 -0
  343. wagtail/test/utils/page_tests.py +5 -5
  344. wagtail/test/utils/template_tests.py +2 -2
  345. wagtail/tests/test_blocks.py +15 -0
  346. wagtail/tests/test_page_permissions.py +109 -0
  347. wagtail/tests/test_revision_model.py +27 -0
  348. wagtail/tests/test_signals.py +21 -2
  349. wagtail/tests/test_tests.py +30 -0
  350. wagtail/users/locale/cy/LC_MESSAGES/django.mo +0 -0
  351. wagtail/users/locale/cy/LC_MESSAGES/django.po +118 -1
  352. wagtail/users/locale/dv/LC_MESSAGES/django.mo +0 -0
  353. wagtail/users/locale/dv/LC_MESSAGES/django.po +3 -0
  354. wagtail/users/locale/en/LC_MESSAGES/django.po +89 -113
  355. wagtail/users/locale/sl/LC_MESSAGES/django.mo +0 -0
  356. wagtail/users/locale/sl/LC_MESSAGES/django.po +3 -0
  357. wagtail/users/migrations/0014_userprofile_contrast.py +23 -0
  358. wagtail/users/models.py +11 -0
  359. wagtail/users/templates/wagtailusers/bulk_actions/confirm_bulk_assign_role.html +5 -1
  360. wagtail/users/templates/wagtailusers/bulk_actions/confirm_bulk_delete.html +5 -1
  361. wagtail/users/templates/wagtailusers/bulk_actions/confirm_bulk_set_active_state.html +5 -1
  362. wagtail/users/templates/wagtailusers/groups/create.html +19 -17
  363. wagtail/users/templates/wagtailusers/groups/edit.html +2 -40
  364. wagtail/users/templates/wagtailusers/groups/includes/formatted_permissions.html +1 -62
  365. wagtail/users/templates/wagtailusers/groups/includes/page_permissions_formset.html +0 -1
  366. wagtail/users/templates/wagtailusers/users/create.html +46 -50
  367. wagtail/users/templates/wagtailusers/users/edit.html +45 -62
  368. wagtail/users/templates/wagtailusers/users/index.html +1 -4
  369. wagtail/users/templatetags/wagtailusers_tags.py +1 -5
  370. wagtail/users/tests/test_admin_views.py +85 -66
  371. wagtail/users/views/groups.py +4 -1
  372. wagtail/users/views/users.py +2 -0
  373. {wagtail-6.2.2.dist-info → wagtail-6.3rc2.dist-info}/METADATA +6 -6
  374. {wagtail-6.2.2.dist-info → wagtail-6.3rc2.dist-info}/RECORD +378 -367
  375. wagtail/admin/static/wagtailadmin/js/preview-panel.js +0 -2
  376. wagtail/admin/static/wagtailadmin/js/preview-panel.js.LICENSE.txt +0 -11
  377. wagtail/admin/templates/wagtailadmin/generic/history_results.html +0 -1
  378. wagtail/admin/templates/wagtailadmin/page_privacy/ancestor_privacy.html +0 -3
  379. wagtail/admin/templates/wagtailadmin/pages/usage_results.html +0 -6
  380. wagtail/admin/templates/wagtailadmin/shared/workflow_history/index.html +0 -17
  381. wagtail/admin/templates/wagtailadmin/shared/workflow_history/results.html +0 -17
  382. wagtail/admin/templates/wagtailadmin/workflows/usage.html +0 -44
  383. {wagtail-6.2.2.dist-info → wagtail-6.3rc2.dist-info}/LICENSE +0 -0
  384. {wagtail-6.2.2.dist-info → wagtail-6.3rc2.dist-info}/WHEEL +0 -0
  385. {wagtail-6.2.2.dist-info → wagtail-6.3rc2.dist-info}/entry_points.txt +0 -0
  386. {wagtail-6.2.2.dist-info → wagtail-6.3rc2.dist-info}/top_level.txt +0 -0
@@ -1,12 +1,20 @@
1
+ import datetime
2
+
3
+ from django.conf import settings
1
4
  from django.contrib.admin.utils import quote
2
5
  from django.contrib.auth.models import Permission
3
6
  from django.contrib.contenttypes.models import ContentType
4
7
  from django.test import TestCase, override_settings
5
8
  from django.urls import reverse
9
+ from django.utils import timezone
10
+ from django.utils.formats import localize
11
+ from freezegun import freeze_time
6
12
 
13
+ from wagtail.admin.utils import get_user_display_name
7
14
  from wagtail.models import Workflow, WorkflowContentType, WorkflowState
8
15
  from wagtail.test.testapp.models import FullFeaturedSnippet, ModeratedModel
9
16
  from wagtail.test.utils import WagtailTestUtils
17
+ from wagtail.test.utils.template_tests import AdminTemplateTestUtils
10
18
 
11
19
  # This module serves to gather snippets-equivalent of workflows-related tests
12
20
  # that are found throughout page-specific test modules, e.g. test_create_page.py,
@@ -153,18 +161,50 @@ class TestEditViewNotLockable(TestEditView):
153
161
  model = ModeratedModel
154
162
 
155
163
 
156
- class TestWorkflowHistory(BaseWorkflowsTestCase):
164
+ class TestWorkflowHistory(AdminTemplateTestUtils, BaseWorkflowsTestCase):
165
+ base_breadcrumb_items = AdminTemplateTestUtils.base_breadcrumb_items + [
166
+ {"label": "Snippets", "url": "/admin/snippets/"},
167
+ ]
168
+
157
169
  def setUp(self):
158
170
  super().setUp()
171
+ self.timestamps = [
172
+ datetime.datetime(2020, 1, 1, 10, 0, 0),
173
+ datetime.datetime(2020, 1, 1, 11, 0, 0),
174
+ datetime.datetime(2020, 1, 2, 12, 0, 0),
175
+ datetime.datetime(2020, 1, 3, 13, 0, 0),
176
+ datetime.datetime(2020, 1, 4, 14, 0, 0),
177
+ ]
178
+
179
+ if settings.USE_TZ:
180
+ self.timestamps[:] = [
181
+ timezone.make_aware(timestamp, timezone=datetime.timezone.utc)
182
+ for timestamp in self.timestamps
183
+ ]
184
+ self.localized_timestamps = [
185
+ localize(timezone.localtime(timestamp), "c")
186
+ for timestamp in self.timestamps
187
+ ]
188
+ else:
189
+ self.localized_timestamps = [
190
+ localize(timestamp, "c") for timestamp in self.timestamps
191
+ ]
192
+
193
+ self.moderator = self.create_superuser("moderator")
194
+ self.moderator_name = get_user_display_name(self.moderator)
195
+ self.user_name = get_user_display_name(self.user)
196
+
159
197
  self.object.text = "Edited!"
160
- self.object.save_revision()
161
- self.workflow_state = self.workflow.start(self.object, self.user)
198
+ with freeze_time(self.timestamps[0]):
199
+ self.object.save_revision()
200
+ with freeze_time(self.timestamps[1]):
201
+ self.workflow_state = self.workflow.start(self.object, self.user)
162
202
 
163
203
  def test_get_index(self):
164
204
  response = self.client.get(self.get_url("workflow_history"))
165
205
  self.assertEqual(response.status_code, 200)
166
206
  self.assertTemplateUsed(
167
- response, "wagtailadmin/shared/workflow_history/index.html"
207
+ response, "wagtailadmin/shared/workflow_history/listing.html"
168
208
  )
169
209
 
170
210
  self.assertContains(response, self.get_url("edit"))
@@ -196,12 +236,28 @@ class TestWorkflowHistory(BaseWorkflowsTestCase):
196
236
  self.assertRedirects(response, reverse("wagtailadmin_home"))
197
237
 
198
238
  def test_get_detail(self):
199
- response = self.client.get(
200
- self.get_url(
201
- "workflow_history_detail",
202
- (quote(self.object.pk), self.workflow_state.id),
203
- ),
239
+ task_state = self.workflow_state.current_task_state
240
+
241
+ with freeze_time(self.timestamps[2]):
242
+ task_state.task.on_action(
243
+ task_state, user=self.moderator, action_name="reject"
244
+ )
245
+ self.workflow_state.refresh_from_db()
246
+
247
+ with freeze_time(self.timestamps[3]):
248
+ self.object.save_revision(user=self.user)
249
+ self.workflow_state.resume(user=self.user)
250
+ self.workflow_state.refresh_from_db()
251
+
252
+ url = self.get_url(
253
+ "workflow_history_detail",
254
+ (quote(self.object.pk), self.workflow_state.id),
204
255
  )
256
+ self.client.get(url)
257
+
258
+ with self.assertNumQueries(18):
259
+ response = self.client.get(url)
260
+
205
261
  self.assertEqual(response.status_code, 200)
206
262
  self.assertTemplateUsed(
207
263
  response, "wagtailadmin/shared/workflow_history/detail.html"
@@ -212,8 +268,61 @@ class TestWorkflowHistory(BaseWorkflowsTestCase):
212
268
 
213
269
  self.assertContains(response, '<div class="w-tabs" data-tabs>')
214
270
  self.assertContains(response, '<div class="tab-content">')
215
- self.assertContains(response, "Tasks")
216
- self.assertContains(response, "Timeline")
271
+
272
+ soup = self.get_soup(response.content)
273
+ tasks = soup.select_one("#tab-tasks table")
274
+ self.assertIsNotNone(tasks)
275
+ cells = [
276
+ [td.get_text(separator=" ", strip=True) for td in tr.select("td")]
277
+ for tr in tasks.select("tr")
278
+ ]
279
+
280
+ self.assertEqual(
281
+ cells,
282
+ [
283
+ # This is divided into different columns per task, so it makes
284
+ # sense to start with the initial revision on the first cell and
285
+ # then it should be rendered in ascending order.
286
+ [
287
+ "Initial Revision",
288
+ f"Rejected by {self.moderator_name} at {self.localized_timestamps[2]}",
289
+ ],
290
+ [
291
+ f"Edited by {self.user_name} at {self.localized_timestamps[3]}",
292
+ "In progress",
293
+ ],
294
+ ],
295
+ )
296
+
297
+ timeline = soup.select_one("#tab-timeline table")
298
+ self.assertIsNotNone(timeline)
299
+ cells = [
300
+ [td.get_text(separator=" ", strip=True) for td in tr.select("td")]
301
+ for tr in timeline.select("tr")
302
+ ]
303
+ self.assertEqual(
304
+ cells,
305
+ [
306
+ # The items are merged into a single column as a timeline, so it
307
+ # should be rendered in reverse chronological order.
308
+ [
309
+ self.localized_timestamps[3],
310
+ "Edited",
311
+ ],
312
+ [
313
+ self.localized_timestamps[2],
314
+ f"Moderators approval Rejected by {self.moderator_name}",
315
+ ],
316
+ [
317
+ self.localized_timestamps[1],
318
+ "Workflow started",
319
+ ],
320
+ [
321
+ self.localized_timestamps[0],
322
+ "Edited",
323
+ ],
324
+ ],
325
+ )
217
326
 
218
327
  # Should show the currently in progress workflow with the latest revision
219
328
  self.assertContains(response, "Edited!")
@@ -221,14 +330,57 @@ class TestWorkflowHistory(BaseWorkflowsTestCase):
221
330
  self.assertContains(response, "In progress")
222
331
  self.assertContains(response, "test@email.com")
223
332
 
333
+ items = [
334
+ {
335
+ "url": self.get_url("list", args=()),
336
+ "label": "Full-featured snippets",
337
+ },
338
+ {
339
+ "url": self.get_url("edit"),
340
+ "label": str(self.object),
341
+ },
342
+ {
343
+ "url": self.get_url("workflow_history"),
344
+ "label": "Workflow history",
345
+ },
346
+ {
347
+ "url": "",
348
+ "label": "Workflow progress",
349
+ "sublabel": str(self.object),
350
+ },
351
+ ]
352
+ self.assertBreadcrumbsItemsRendered(items, response.content)
353
+
224
354
  def test_get_detail_completed(self):
225
- self.workflow_state.current_task_state.approve(user=None)
226
- response = self.client.get(
227
- self.get_url(
228
- "workflow_history_detail",
229
- (quote(self.object.pk), self.workflow_state.id),
230
- ),
355
+ task_state = self.workflow_state.current_task_state
356
+
357
+ with freeze_time(self.timestamps[2]):
358
+ task_state.task.on_action(
359
+ task_state, user=self.moderator, action_name="reject"
360
+ )
361
+ self.workflow_state.refresh_from_db()
362
+
363
+ with freeze_time(self.timestamps[3]):
364
+ self.object.save_revision(user=self.user)
365
+ self.workflow_state.resume(user=self.user)
366
+ self.workflow_state.refresh_from_db()
367
+
368
+ with freeze_time(self.timestamps[4]):
369
+ task_state = self.workflow_state.current_task_state
370
+ task_state.task.on_action(
371
+ task_state, user=self.moderator, action_name="approve"
372
+ )
373
+ self.workflow_state.refresh_from_db()
374
+
375
+ url = self.get_url(
376
+ "workflow_history_detail",
377
+ (quote(self.object.pk), self.workflow_state.id),
231
378
  )
379
+ self.client.get(url)
380
+
381
+ with self.assertNumQueries(19):
382
+ response = self.client.get(url)
383
+
232
384
  self.assertEqual(response.status_code, 200)
233
385
  self.assertTemplateUsed(
234
386
  response, "wagtailadmin/shared/workflow_history/detail.html"
@@ -239,8 +391,69 @@ class TestWorkflowHistory(BaseWorkflowsTestCase):
239
391
 
240
392
  self.assertContains(response, '<div class="w-tabs" data-tabs>')
241
393
  self.assertContains(response, '<div class="tab-content">')
242
- self.assertContains(response, "Tasks")
243
- self.assertContains(response, "Timeline")
394
+
395
+ soup = self.get_soup(response.content)
396
+ tasks = soup.select_one("#tab-tasks table")
397
+ self.assertIsNotNone(tasks)
398
+ cells = [
399
+ [td.get_text(separator=" ", strip=True) for td in tr.select("td")]
400
+ for tr in tasks.select("tr")
401
+ ]
402
+
403
+ self.assertEqual(
404
+ cells,
405
+ [
406
+ # This is divided into different columns per task, so it makes
407
+ # sense to start with the initial revision on the first cell and
408
+ # then it should be rendered in ascending order.
409
+ [
410
+ "Initial Revision",
411
+ f"Rejected by {self.moderator_name} at {self.localized_timestamps[2]}",
412
+ ],
413
+ [
414
+ f"Edited by {self.user_name} at {self.localized_timestamps[3]}",
415
+ f"Approved by {self.moderator_name} at {self.localized_timestamps[4]}",
416
+ ],
417
+ ],
418
+ )
419
+
420
+ timeline = soup.select_one("#tab-timeline table")
421
+ self.assertIsNotNone(timeline)
422
+ cells = [
423
+ [td.get_text(separator=" ", strip=True) for td in tr.select("td")]
424
+ for tr in timeline.select("tr")
425
+ ]
426
+ self.assertEqual(
427
+ cells,
428
+ [
429
+ # The items are merged into a single column as a timeline, so it
430
+ # should be rendered in reverse chronological order.
431
+ [
432
+ self.localized_timestamps[4],
433
+ "Workflow completed Approved",
434
+ ],
435
+ [
436
+ self.localized_timestamps[4],
437
+ f"Moderators approval Approved by {self.moderator_name}",
438
+ ],
439
+ [
440
+ self.localized_timestamps[3],
441
+ "Edited",
442
+ ],
443
+ [
444
+ self.localized_timestamps[2],
445
+ f"Moderators approval Rejected by {self.moderator_name}",
446
+ ],
447
+ [
448
+ self.localized_timestamps[1],
449
+ "Workflow started",
450
+ ],
451
+ [
452
+ self.localized_timestamps[0],
453
+ "Edited",
454
+ ],
455
+ ],
456
+ )
244
457
 
245
458
  # Should show the completed workflow with the latest revision
246
459
  self.assertContains(response, "Edited!")
@@ -77,7 +77,6 @@ class ModelIndexView(generic.BaseListingView):
77
77
  header_icon = "snippet"
78
78
  index_url_name = "wagtailsnippets:index"
79
79
  default_ordering = "name"
80
- _show_breadcrumbs = True
81
80
 
82
81
  def setup(self, request, *args, **kwargs):
83
82
  super().setup(request, *args, **kwargs)
@@ -100,9 +99,6 @@ class ModelIndexView(generic.BaseListingView):
100
99
  raise PermissionDenied
101
100
  return super().dispatch(request, *args, **kwargs)
102
101
 
103
- def get_breadcrumbs_items(self):
104
- return self.breadcrumbs_items + [{"url": "", "label": _("Snippets")}]
105
-
106
102
  def get_list_url(self, model):
107
103
  if model.snippet_viewset.permission_policy.user_has_any_permission(
108
104
  self.request.user,
@@ -765,11 +761,9 @@ class SnippetViewSet(ModelViewSet):
765
761
  "workflow_history/index",
766
762
  fallback=self.workflow_history_view_class.template_name,
767
763
  ),
768
- workflow_history_url_name=self.get_url_name("workflow_history"),
769
764
  workflow_history_detail_url_name=self.get_url_name(
770
765
  "workflow_history_detail"
771
766
  ),
772
- _show_breadcrumbs=False,
773
767
  )
774
768
 
775
769
  @property
@@ -780,10 +774,7 @@ class SnippetViewSet(ModelViewSet):
780
774
  "workflow_history/detail",
781
775
  fallback=self.workflow_history_detail_view_class.template_name,
782
776
  ),
783
- object_icon=self.icon,
784
- header_icon="list-ul",
785
777
  workflow_history_url_name=self.get_url_name("workflow_history"),
786
- _show_breadcrumbs=False,
787
778
  )
788
779
 
789
780
  @property
@@ -840,7 +831,7 @@ class SnippetViewSet(ModelViewSet):
840
831
 
841
832
  **Deprecated** - the preferred way to customise this is to define a ``menu_label`` property.
842
833
  """
843
- return self.model_opts.verbose_name_plural.title()
834
+ return capfirst(self.model_opts.verbose_name_plural)
844
835
 
845
836
  @cached_property
846
837
  def menu_name(self):
@@ -0,0 +1,104 @@
1
+ # Patch Django's number formatting functions during tests so that outputting a number onto a
2
+ # template without explicitly passing it through one of |intcomma, |localize, |unlocalize or
3
+ # |filesizeformat will raise an exception. This helps to catch bugs where
4
+ # USE_THOUSAND_SEPARATOR = True incorrectly reformats numbers that are not intended to be
5
+ # human-readable (such as image dimensions, or IDs within data attributes).
6
+
7
+ from decimal import Decimal
8
+
9
+ import django.contrib.humanize.templatetags.humanize
10
+ import django.template.defaultfilters
11
+ import django.templatetags.l10n
12
+ import django.utils.numberformat
13
+ from django.core.exceptions import ImproperlyConfigured
14
+ from django.utils import formats
15
+ from django.utils.html import avoid_wrapping
16
+ from django.utils.translation import gettext, ngettext
17
+
18
+ original_numberformat = django.utils.numberformat.format
19
+ original_intcomma = django.contrib.humanize.templatetags.humanize.intcomma
20
+
21
+
22
+ def patched_numberformat(*args, use_l10n=None, **kwargs):
23
+ if use_l10n is False or use_l10n == "explicit":
24
+ return original_numberformat(*args, use_l10n=use_l10n, **kwargs)
25
+
26
+ raise ImproperlyConfigured(
27
+ "A number was used directly on a template. "
28
+ "Numbers output on templates should be passed through one of |intcomma, |localize, "
29
+ "|unlocalize or |filesizeformat to avoid issues with USE_THOUSAND_SEPARATOR."
30
+ )
31
+
32
+
33
+ def patched_intcomma(value, use_l10n=True):
34
+ if use_l10n:
35
+ try:
36
+ if not isinstance(value, (float, Decimal)):
37
+ value = int(value)
38
+ except (TypeError, ValueError):
39
+ return original_intcomma(value, False)
40
+ else:
41
+ return formats.number_format(
42
+ value, use_l10n="explicit", force_grouping=True
43
+ )
44
+
45
+ return original_intcomma(value, use_l10n=use_l10n)
46
+
47
+
48
+ def patched_filesizeformat(bytes_):
49
+ """
50
+ Format the value like a 'human-readable' file size (i.e. 13 KB, 4.1 MB,
51
+ 102 bytes, etc.).
52
+ """
53
+ try:
54
+ bytes_ = int(bytes_)
55
+ except (TypeError, ValueError, UnicodeDecodeError):
56
+ value = ngettext("%(size)d byte", "%(size)d bytes", 0) % {"size": 0}
57
+ return avoid_wrapping(value)
58
+
59
+ def filesize_number_format(value):
60
+ return formats.number_format(round(value, 1), 1, use_l10n="explicit")
61
+
62
+ KB = 1 << 10
63
+ MB = 1 << 20
64
+ GB = 1 << 30
65
+ TB = 1 << 40
66
+ PB = 1 << 50
67
+
68
+ negative = bytes_ < 0
69
+ if negative:
70
+ bytes_ = -bytes_ # Allow formatting of negative numbers.
71
+
72
+ if bytes_ < KB:
73
+ value = ngettext("%(size)d byte", "%(size)d bytes", bytes_) % {"size": bytes_}
74
+ elif bytes_ < MB:
75
+ value = gettext("%s KB") % filesize_number_format(bytes_ / KB)
76
+ elif bytes_ < GB:
77
+ value = gettext("%s MB") % filesize_number_format(bytes_ / MB)
78
+ elif bytes_ < TB:
79
+ value = gettext("%s GB") % filesize_number_format(bytes_ / GB)
80
+ elif bytes_ < PB:
81
+ value = gettext("%s TB") % filesize_number_format(bytes_ / TB)
82
+ else:
83
+ value = gettext("%s PB") % filesize_number_format(bytes_ / PB)
84
+
85
+ if negative:
86
+ value = "-%s" % value
87
+ return avoid_wrapping(value)
88
+
89
+
90
+ def patched_localize(value):
91
+ return str(formats.localize(value, use_l10n="explicit"))
92
+
93
+
94
+ def patch_number_formats():
95
+ django.utils.numberformat.format = patched_numberformat
96
+ django.contrib.humanize.templatetags.humanize.intcomma = patched_intcomma
97
+ django.template.defaultfilters.filesizeformat = patched_filesizeformat
98
+ django.template.defaultfilters.register.filter(
99
+ "filesizeformat", patched_filesizeformat, is_safe=True
100
+ )
101
+ django.templatetags.l10n.localize = patched_localize
102
+ django.templatetags.l10n.register.filter(
103
+ "localize", patched_localize, is_safe=False
104
+ )
wagtail/test/settings.py CHANGED
@@ -3,6 +3,16 @@ import os
3
3
  from django.contrib.messages import constants as message_constants
4
4
  from django.utils.translation import gettext_lazy as _
5
5
 
6
+ from wagtail.test.numberformat import patch_number_formats
7
+
8
+ WAGTAIL_CHECK_TEMPLATE_NUMBER_FORMAT = (
9
+ os.environ.get("WAGTAIL_CHECK_TEMPLATE_NUMBER_FORMAT", "0") == "1"
10
+ )
11
+ if WAGTAIL_CHECK_TEMPLATE_NUMBER_FORMAT:
12
+ # Patch Django number formatting functions to raise exceptions if a number is output directly
13
+ # on a template (which is liable to cause bugs when USE_THOUSAND_SEPARATOR is in use).
14
+ patch_number_formats()
15
+
6
16
  DEBUG = os.environ.get("DJANGO_DEBUG", "false").lower() == "true"
7
17
  WAGTAIL_ROOT = os.path.dirname(os.path.dirname(__file__))
8
18
  WAGTAILADMIN_BASE_URL = "http://testserver"
@@ -25,3 +25,5 @@ PATTERN_LIBRARY = {
25
25
  "PATTERN_BASE_TEMPLATE_NAME": "",
26
26
  "BASE_TEMPLATE_NAMES": [],
27
27
  }
28
+
29
+ DEBUG = True
@@ -1,78 +1,71 @@
1
- # Generated by Django 4.0.7 on 2022-10-19 00:20
2
-
3
- from django import VERSION as DJANGO_VERSION
4
- from django.db import migrations
5
- import wagtail.images.models
6
-
7
-
8
- class Migration(migrations.Migration):
9
-
10
- dependencies = [
11
- ("tests", "0009_alter_eventpage_options"),
12
- ]
13
-
14
- rendition_file_options = {
15
- "height_field": "height",
16
- "upload_to": wagtail.images.models.get_rendition_upload_to,
17
- "width_field": "width",
18
- }
19
- # See https://code.djangoproject.com/ticket/34192 - prior to Django 4.2, a callable storage
20
- # argument that returns default_storage would be incorrectly omitted from the deconstructed
21
- # field. We need to match that behaviour and include/omit it accordingly to prevent
22
- # makemigrations from seeing a difference and generating a spurious migration in
23
- # wagtail.images.
24
- if DJANGO_VERSION >= (4, 2):
25
- rendition_file_options["storage"] = wagtail.images.models.get_rendition_storage
26
-
27
- operations = [
28
- migrations.AlterField(
29
- model_name="customimage",
30
- name="file",
31
- field=wagtail.images.models.WagtailImageField(
32
- height_field="height",
33
- upload_to=wagtail.images.models.get_upload_to,
34
- verbose_name="file",
35
- width_field="width",
36
- ),
37
- ),
38
- migrations.AlterField(
39
- model_name="customimagefilepath",
40
- name="file",
41
- field=wagtail.images.models.WagtailImageField(
42
- height_field="height",
43
- upload_to=wagtail.images.models.get_upload_to,
44
- verbose_name="file",
45
- width_field="width",
46
- ),
47
- ),
48
- migrations.AlterField(
49
- model_name="customimagewithauthor",
50
- name="file",
51
- field=wagtail.images.models.WagtailImageField(
52
- height_field="height",
53
- upload_to=wagtail.images.models.get_upload_to,
54
- verbose_name="file",
55
- width_field="width",
56
- ),
57
- ),
58
- migrations.AlterField(
59
- model_name="customrendition",
60
- name="file",
61
- field=wagtail.images.models.WagtailImageField(**rendition_file_options),
62
- ),
63
- migrations.AlterField(
64
- model_name="customrenditionwithauthor",
65
- name="file",
66
- field=wagtail.images.models.WagtailImageField(**rendition_file_options),
67
- ),
68
- migrations.AlterField(
69
- model_name="customrestaurantimage",
70
- name="file",
71
- field=wagtail.images.models.WagtailImageField(
72
- height_field="height",
73
- upload_to=wagtail.images.models.get_upload_to,
74
- verbose_name="file",
75
- width_field="width",
76
- ),
77
- ),
78
- ]
1
+ # Generated by Django 4.0.7 on 2022-10-19 00:20
2
+
3
+ from django.db import migrations
4
+ import wagtail.images.models
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ dependencies = [
10
+ ("tests", "0009_alter_eventpage_options"),
11
+ ]
12
+
13
+ rendition_file_options = {
14
+ "height_field": "height",
15
+ "upload_to": wagtail.images.models.get_rendition_upload_to,
16
+ "width_field": "width",
17
+ "storage": wagtail.images.models.get_rendition_storage,
18
+ }
19
+
20
+ operations = [
21
+ migrations.AlterField(
22
+ model_name="customimage",
23
+ name="file",
24
+ field=wagtail.images.models.WagtailImageField(
25
+ height_field="height",
26
+ upload_to=wagtail.images.models.get_upload_to,
27
+ verbose_name="file",
28
+ width_field="width",
29
+ ),
30
+ ),
31
+ migrations.AlterField(
32
+ model_name="customimagefilepath",
33
+ name="file",
34
+ field=wagtail.images.models.WagtailImageField(
35
+ height_field="height",
36
+ upload_to=wagtail.images.models.get_upload_to,
37
+ verbose_name="file",
38
+ width_field="width",
39
+ ),
40
+ ),
41
+ migrations.AlterField(
42
+ model_name="customimagewithauthor",
43
+ name="file",
44
+ field=wagtail.images.models.WagtailImageField(
45
+ height_field="height",
46
+ upload_to=wagtail.images.models.get_upload_to,
47
+ verbose_name="file",
48
+ width_field="width",
49
+ ),
50
+ ),
51
+ migrations.AlterField(
52
+ model_name="customrendition",
53
+ name="file",
54
+ field=wagtail.images.models.WagtailImageField(**rendition_file_options),
55
+ ),
56
+ migrations.AlterField(
57
+ model_name="customrenditionwithauthor",
58
+ name="file",
59
+ field=wagtail.images.models.WagtailImageField(**rendition_file_options),
60
+ ),
61
+ migrations.AlterField(
62
+ model_name="customrestaurantimage",
63
+ name="file",
64
+ field=wagtail.images.models.WagtailImageField(
65
+ height_field="height",
66
+ upload_to=wagtail.images.models.get_upload_to,
67
+ verbose_name="file",
68
+ width_field="width",
69
+ ),
70
+ ),
71
+ ]