wagtail 6.0.1__py3-none-any.whl → 6.1rc1__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 (512) hide show
  1. wagtail/__init__.py +1 -1
  2. wagtail/admin/checks.py +51 -0
  3. wagtail/admin/compare.py +1 -1
  4. wagtail/admin/filters.py +70 -1
  5. wagtail/admin/forms/account.py +1 -1
  6. wagtail/admin/forms/collections.py +15 -0
  7. wagtail/admin/forms/pages.py +49 -0
  8. wagtail/admin/locale/ca/LC_MESSAGES/django.mo +0 -0
  9. wagtail/admin/locale/ca/LC_MESSAGES/django.po +122 -0
  10. wagtail/admin/locale/de/LC_MESSAGES/django.mo +0 -0
  11. wagtail/admin/locale/de/LC_MESSAGES/django.po +5 -5
  12. wagtail/admin/locale/en/LC_MESSAGES/django.po +474 -385
  13. wagtail/admin/locale/en/LC_MESSAGES/djangojs.po +3 -3
  14. wagtail/admin/locale/es/LC_MESSAGES/django.mo +0 -0
  15. wagtail/admin/locale/es/LC_MESSAGES/django.po +6 -6
  16. wagtail/admin/locale/fr/LC_MESSAGES/django.mo +0 -0
  17. wagtail/admin/locale/fr/LC_MESSAGES/django.po +70 -3
  18. wagtail/admin/locale/he_IL/LC_MESSAGES/django.mo +0 -0
  19. wagtail/admin/locale/he_IL/LC_MESSAGES/django.po +2 -6
  20. wagtail/admin/locale/he_IL/LC_MESSAGES/djangojs.mo +0 -0
  21. wagtail/admin/locale/he_IL/LC_MESSAGES/djangojs.po +2 -2
  22. wagtail/admin/locale/hr_HR/LC_MESSAGES/django.mo +0 -0
  23. wagtail/admin/locale/hr_HR/LC_MESSAGES/django.po +4 -0
  24. wagtail/admin/locale/hu/LC_MESSAGES/django.mo +0 -0
  25. wagtail/admin/locale/hu/LC_MESSAGES/django.po +142 -2
  26. wagtail/admin/locale/it/LC_MESSAGES/django.mo +0 -0
  27. wagtail/admin/locale/it/LC_MESSAGES/django.po +80 -8
  28. wagtail/admin/locale/it/LC_MESSAGES/djangojs.mo +0 -0
  29. wagtail/admin/locale/it/LC_MESSAGES/djangojs.po +14 -2
  30. wagtail/admin/locale/lv/LC_MESSAGES/django.mo +0 -0
  31. wagtail/admin/locale/lv/LC_MESSAGES/django.po +154 -1
  32. wagtail/admin/locale/pt_PT/LC_MESSAGES/django.mo +0 -0
  33. wagtail/admin/locale/pt_PT/LC_MESSAGES/django.po +73 -2
  34. wagtail/admin/locale/ro/LC_MESSAGES/django.mo +0 -0
  35. wagtail/admin/locale/ro/LC_MESSAGES/django.po +3 -3
  36. wagtail/admin/locale/sl/LC_MESSAGES/django.mo +0 -0
  37. wagtail/admin/locale/sl/LC_MESSAGES/django.po +145 -2
  38. wagtail/admin/locale/sv/LC_MESSAGES/django.mo +0 -0
  39. wagtail/admin/locale/sv/LC_MESSAGES/django.po +77 -3
  40. wagtail/admin/locale/zh_Hant/LC_MESSAGES/django.mo +0 -0
  41. wagtail/admin/locale/zh_Hant/LC_MESSAGES/django.po +17 -1
  42. wagtail/admin/panels/comment_panel.py +1 -1
  43. wagtail/admin/panels/field_panel.py +1 -1
  44. wagtail/admin/rich_text/converters/editor_html.py +3 -1
  45. wagtail/admin/rich_text/editors/draftail/__init__.py +28 -2
  46. wagtail/admin/static/wagtailadmin/css/core.css +1 -1
  47. wagtail/admin/static/wagtailadmin/css/panels/draftail.css +1 -1
  48. wagtail/admin/static/wagtailadmin/images/favicon.ico +0 -0
  49. wagtail/admin/static/wagtailadmin/js/bulk-actions.js +1 -1
  50. wagtail/admin/static/wagtailadmin/js/chooser-modal.js +1 -1
  51. wagtail/admin/static/wagtailadmin/js/chooser-widget-telepath.js +1 -1
  52. wagtail/admin/static/wagtailadmin/js/chooser-widget.js +1 -1
  53. wagtail/admin/static/wagtailadmin/js/comments.js +1 -1
  54. wagtail/admin/static/wagtailadmin/js/core.js +1 -1
  55. wagtail/admin/static/wagtailadmin/js/core.js.LICENSE.txt +1 -1
  56. wagtail/admin/static/wagtailadmin/js/date-time-chooser.js +1 -1
  57. wagtail/admin/static/wagtailadmin/js/draftail.js +1 -1
  58. wagtail/admin/static/wagtailadmin/js/expanding-formset.js +1 -1
  59. wagtail/admin/static/wagtailadmin/js/filtered-select.js +1 -1
  60. wagtail/admin/static/wagtailadmin/js/modal-workflow.js +1 -1
  61. wagtail/admin/static/wagtailadmin/js/page-chooser-modal.js +1 -1
  62. wagtail/admin/static/wagtailadmin/js/page-chooser-telepath.js +1 -1
  63. wagtail/admin/static/wagtailadmin/js/page-chooser.js +1 -1
  64. wagtail/admin/static/wagtailadmin/js/preview-panel.js +1 -1
  65. wagtail/admin/static/wagtailadmin/js/privacy-switch.js +1 -1
  66. wagtail/admin/static/wagtailadmin/js/sidebar.js +1 -1
  67. wagtail/admin/static/wagtailadmin/js/task-chooser-modal.js +1 -1
  68. wagtail/admin/static/wagtailadmin/js/task-chooser.js +1 -1
  69. wagtail/admin/static/wagtailadmin/js/telepath/blocks.js +1 -1
  70. wagtail/admin/static/wagtailadmin/js/telepath/telepath.js +1 -1
  71. wagtail/admin/static/wagtailadmin/js/telepath/widgets.js +1 -1
  72. wagtail/admin/static/wagtailadmin/js/userbar.js +1 -1
  73. wagtail/admin/static/wagtailadmin/js/vendor.js +1 -1
  74. wagtail/admin/static/wagtailadmin/js/vendor.js.LICENSE.txt +4 -4
  75. wagtail/admin/static/wagtailadmin/js/wagtailadmin.js +1 -1
  76. wagtail/admin/static/wagtailadmin/js/workflow-action.js +1 -1
  77. wagtail/admin/staticfiles.py +1 -0
  78. wagtail/admin/templates/wagtailadmin/admin_base.html +1 -0
  79. wagtail/admin/templates/wagtailadmin/base.html +1 -0
  80. wagtail/admin/templates/wagtailadmin/collection_privacy/set_privacy.html +3 -1
  81. wagtail/admin/templates/wagtailadmin/collections/edit.html +0 -1
  82. wagtail/admin/templates/wagtailadmin/collections/index_results.html +10 -0
  83. wagtail/admin/templates/wagtailadmin/generic/base.html +1 -9
  84. wagtail/admin/templates/wagtailadmin/generic/form.html +4 -2
  85. wagtail/admin/templates/wagtailadmin/generic/history/action_cell.html +27 -0
  86. wagtail/admin/templates/wagtailadmin/generic/index_results.html +8 -0
  87. wagtail/admin/templates/wagtailadmin/home/workflow_objects_to_moderate.html +3 -4
  88. wagtail/admin/templates/wagtailadmin/icons/keyboard.svg +1 -0
  89. wagtail/admin/templates/wagtailadmin/page_privacy/set_privacy.html +3 -1
  90. wagtail/admin/templates/wagtailadmin/pages/_editor_js.html +0 -15
  91. wagtail/admin/templates/wagtailadmin/pages/action_menu/save_draft.html +3 -1
  92. wagtail/admin/templates/wagtailadmin/pages/choose_parent.html +17 -0
  93. wagtail/admin/templates/wagtailadmin/pages/explorable_index.html +8 -0
  94. wagtail/admin/templates/wagtailadmin/pages/history.html +1 -61
  95. wagtail/admin/templates/wagtailadmin/pages/index.html +1 -5
  96. wagtail/admin/templates/wagtailadmin/pages/listing/_locked_indicator.html +2 -2
  97. wagtail/admin/templates/wagtailadmin/pages/listing/_page_title_column_header.html +25 -27
  98. wagtail/admin/templates/wagtailadmin/pages/page_listing_header.html +2 -1
  99. wagtail/admin/templates/wagtailadmin/panels/multi_field_panel_child.html +1 -1
  100. wagtail/admin/templates/wagtailadmin/panels/publishing/schedule_publishing_panel.html +3 -1
  101. wagtail/admin/templates/wagtailadmin/panels/tabbed_interface.html +1 -1
  102. wagtail/admin/templates/wagtailadmin/shared/active_filters.html +2 -1
  103. wagtail/admin/templates/wagtailadmin/shared/breadcrumbs.html +8 -0
  104. wagtail/admin/templates/wagtailadmin/shared/forms/single_checkbox.html +1 -1
  105. wagtail/admin/templates/wagtailadmin/shared/headers/page_edit_header.html +1 -1
  106. wagtail/admin/templates/wagtailadmin/shared/headers/slim_header.html +21 -9
  107. wagtail/admin/templates/wagtailadmin/shared/human_readable_date.html +1 -1
  108. wagtail/admin/templates/wagtailadmin/shared/keyboard_shortcuts_dialog.html +29 -0
  109. wagtail/admin/templates/wagtailadmin/shared/side_panel_toggle.html +2 -1
  110. wagtail/admin/templates/wagtailadmin/skeleton.html +2 -1
  111. wagtail/admin/templates/wagtailadmin/tables/related_objects_cell.html +9 -0
  112. wagtail/admin/templates/wagtailadmin/tables/title_cell.html +9 -7
  113. wagtail/admin/templates/wagtailadmin/widgets/draftail_rich_text_area.html +1 -1
  114. wagtail/admin/templates/wagtailadmin/workflows/create.html +6 -23
  115. wagtail/admin/templates/wagtailadmin/workflows/create_task.html +6 -15
  116. wagtail/admin/templates/wagtailadmin/workflows/edit.html +6 -23
  117. wagtail/admin/templates/wagtailadmin/workflows/edit_task.html +6 -13
  118. wagtail/admin/templates/wagtailadmin/workflows/includes/task_usage_cell.html +4 -4
  119. wagtail/admin/templates/wagtailadmin/workflows/includes/workflow_tasks_cell.html +18 -0
  120. wagtail/admin/templates/wagtailadmin/workflows/includes/workflow_title_cell.html +7 -0
  121. wagtail/admin/templates/wagtailadmin/workflows/includes/workflow_used_by_cell.html +25 -0
  122. wagtail/admin/templates/wagtailadmin/workflows/index.html +0 -99
  123. wagtail/admin/templates/wagtailadmin/workflows/index_results.html +10 -0
  124. wagtail/admin/templates/wagtailadmin/workflows/task_index.html +0 -30
  125. wagtail/admin/templates/wagtailadmin/workflows/task_index_results.html +10 -0
  126. wagtail/admin/templates/wagtailadmin/workflows/usage.html +1 -1
  127. wagtail/admin/templatetags/wagtailadmin_tags.py +116 -39
  128. wagtail/admin/tests/api/test_pages.py +26 -10
  129. wagtail/admin/tests/pages/test_create_page.py +10 -4
  130. wagtail/admin/tests/pages/test_custom_listing.py +37 -0
  131. wagtail/admin/tests/pages/test_edit_page.py +6 -6
  132. wagtail/admin/tests/pages/test_explorer_view.py +19 -18
  133. wagtail/admin/tests/pages/test_move_page.py +1 -1
  134. wagtail/admin/tests/pages/test_page_usage.py +50 -2
  135. wagtail/admin/tests/pages/test_parent_page_chooser_view.py +119 -0
  136. wagtail/admin/tests/pages/test_preview.py +18 -4
  137. wagtail/admin/tests/test_account_management.py +20 -1
  138. wagtail/admin/tests/test_audit_log.py +172 -5
  139. wagtail/admin/tests/test_checks.py +92 -0
  140. wagtail/admin/tests/test_collections_views.py +19 -5
  141. wagtail/admin/tests/test_compare.py +6 -6
  142. wagtail/admin/tests/test_dashboard.py +404 -0
  143. wagtail/admin/tests/test_dbwhitelister.py +4 -5
  144. wagtail/admin/tests/test_edit_handlers.py +2 -2
  145. wagtail/admin/tests/test_keyboard_shortcuts.py +84 -0
  146. wagtail/admin/tests/test_page_chooser.py +31 -18
  147. wagtail/admin/tests/test_privacy.py +36 -2
  148. wagtail/admin/tests/test_rich_text.py +168 -23
  149. wagtail/admin/tests/test_templatetags.py +411 -43
  150. wagtail/admin/tests/test_views.py +4 -2
  151. wagtail/admin/tests/test_workflows.py +531 -9
  152. wagtail/admin/tests/tests.py +3 -1
  153. wagtail/admin/tests/ui/test_tables.py +48 -1
  154. wagtail/admin/tests/viewsets/test_model_viewset.py +130 -23
  155. wagtail/admin/ui/side_panels.py +3 -1
  156. wagtail/admin/ui/tables/__init__.py +13 -1
  157. wagtail/admin/ui/tables/pages.py +17 -6
  158. wagtail/admin/urls/__init__.py +8 -3
  159. wagtail/admin/urls/pages.py +5 -0
  160. wagtail/admin/urls/workflows.py +10 -0
  161. wagtail/admin/views/chooser.py +20 -24
  162. wagtail/admin/views/collections.py +17 -1
  163. wagtail/admin/views/generic/base.py +34 -4
  164. wagtail/admin/views/generic/history.py +220 -51
  165. wagtail/admin/views/generic/mixins.py +7 -4
  166. wagtail/admin/views/generic/models.py +54 -47
  167. wagtail/admin/views/generic/multiple_upload.py +17 -8
  168. wagtail/admin/views/generic/usage.py +17 -11
  169. wagtail/admin/views/home.py +15 -12
  170. wagtail/admin/views/mixins.py +30 -0
  171. wagtail/admin/views/pages/choose_parent.py +73 -0
  172. wagtail/admin/views/pages/history.py +54 -66
  173. wagtail/admin/views/pages/listing.py +187 -106
  174. wagtail/admin/views/pages/usage.py +6 -1
  175. wagtail/admin/views/pages/utils.py +70 -1
  176. wagtail/admin/views/workflows.py +150 -21
  177. wagtail/admin/viewsets/model.py +2 -2
  178. wagtail/admin/viewsets/pages.py +77 -0
  179. wagtail/admin/wagtail_hooks.py +40 -2
  180. wagtail/admin/widgets/button.py +10 -10
  181. wagtail/api/v2/filters.py +1 -1
  182. wagtail/api/v2/tests/test_pages.py +1 -1
  183. wagtail/blocks/base.py +18 -9
  184. wagtail/blocks/field_block.py +9 -7
  185. wagtail/blocks/list_block.py +16 -6
  186. wagtail/blocks/static_block.py +3 -0
  187. wagtail/blocks/stream_block.py +58 -23
  188. wagtail/blocks/struct_block.py +15 -9
  189. wagtail/contrib/forms/locale/en/LC_MESSAGES/django.po +39 -47
  190. wagtail/contrib/forms/locale/he_IL/LC_MESSAGES/django.mo +0 -0
  191. wagtail/contrib/forms/locale/he_IL/LC_MESSAGES/django.po +2 -2
  192. wagtail/contrib/forms/models.py +5 -5
  193. wagtail/contrib/forms/templates/wagtailforms/list_submissions.html +44 -33
  194. wagtail/contrib/forms/templates/wagtailforms/submissions_index.html +2 -63
  195. wagtail/contrib/forms/tests/test_models.py +26 -0
  196. wagtail/contrib/forms/urls.py +6 -0
  197. wagtail/contrib/forms/views.py +52 -49
  198. wagtail/contrib/redirects/locale/ca/LC_MESSAGES/django.mo +0 -0
  199. wagtail/contrib/redirects/locale/ca/LC_MESSAGES/django.po +3 -3
  200. wagtail/contrib/redirects/locale/en/LC_MESSAGES/django.po +34 -42
  201. wagtail/contrib/redirects/locale/fr/LC_MESSAGES/django.po +2 -2
  202. wagtail/contrib/redirects/locale/he_IL/LC_MESSAGES/django.mo +0 -0
  203. wagtail/contrib/redirects/locale/he_IL/LC_MESSAGES/django.po +2 -2
  204. wagtail/contrib/redirects/signal_handlers.py +1 -1
  205. wagtail/contrib/redirects/templates/wagtailredirects/index.html +1 -36
  206. wagtail/contrib/redirects/templates/wagtailredirects/index_results.html +18 -0
  207. wagtail/contrib/redirects/templates/wagtailredirects/redirect_target_cell.html +8 -0
  208. wagtail/contrib/redirects/tests/test_import_command.py +1 -1
  209. wagtail/contrib/redirects/tests/test_redirects.py +79 -8
  210. wagtail/contrib/redirects/urls.py +2 -1
  211. wagtail/contrib/redirects/views.py +85 -55
  212. wagtail/contrib/search_promotions/admin_urls.py +2 -1
  213. wagtail/contrib/search_promotions/locale/en/LC_MESSAGES/django.po +41 -64
  214. wagtail/contrib/search_promotions/locale/fr/LC_MESSAGES/django.po +2 -2
  215. wagtail/contrib/search_promotions/locale/he_IL/LC_MESSAGES/django.mo +0 -0
  216. wagtail/contrib/search_promotions/locale/he_IL/LC_MESSAGES/django.po +2 -2
  217. wagtail/contrib/search_promotions/locale/hr_HR/LC_MESSAGES/django.mo +0 -0
  218. wagtail/contrib/search_promotions/locale/hr_HR/LC_MESSAGES/django.po +41 -2
  219. wagtail/contrib/search_promotions/locale/it/LC_MESSAGES/django.mo +0 -0
  220. wagtail/contrib/search_promotions/locale/it/LC_MESSAGES/django.po +9 -3
  221. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/index.html +1 -16
  222. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/index_results.html +11 -0
  223. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/list.html +0 -51
  224. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/results.html +3 -16
  225. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/search_promotion_column.html +15 -0
  226. wagtail/contrib/search_promotions/tests.py +122 -9
  227. wagtail/contrib/search_promotions/views.py +66 -65
  228. wagtail/contrib/settings/locale/en/LC_MESSAGES/django.po +3 -3
  229. wagtail/contrib/settings/locale/he_IL/LC_MESSAGES/django.mo +0 -0
  230. wagtail/contrib/settings/locale/he_IL/LC_MESSAGES/django.po +2 -2
  231. wagtail/contrib/settings/locale/tr/LC_MESSAGES/django.mo +0 -0
  232. wagtail/contrib/settings/locale/tr/LC_MESSAGES/django.po +6 -2
  233. wagtail/contrib/settings/registry.py +10 -5
  234. wagtail/contrib/settings/tests/generic/test_admin.py +9 -0
  235. wagtail/contrib/settings/tests/site_specific/test_admin.py +10 -1
  236. wagtail/contrib/settings/tests/site_specific/test_model.py +3 -3
  237. wagtail/contrib/settings/tests/site_specific/test_templates.py +1 -1
  238. wagtail/contrib/settings/views.py +3 -1
  239. wagtail/contrib/simple_translation/locale/en/LC_MESSAGES/django.po +1 -1
  240. wagtail/contrib/simple_translation/tests/test_wagtail_hooks.py +2 -2
  241. wagtail/contrib/styleguide/locale/en/LC_MESSAGES/django.po +7 -7
  242. wagtail/contrib/styleguide/locale/he_IL/LC_MESSAGES/django.mo +0 -0
  243. wagtail/contrib/styleguide/locale/he_IL/LC_MESSAGES/django.po +2 -2
  244. wagtail/contrib/table_block/blocks.py +2 -2
  245. wagtail/contrib/table_block/locale/ca/LC_MESSAGES/django.mo +0 -0
  246. wagtail/contrib/table_block/locale/ca/LC_MESSAGES/django.po +27 -2
  247. wagtail/contrib/table_block/locale/en/LC_MESSAGES/django.po +1 -1
  248. wagtail/contrib/table_block/locale/hu/LC_MESSAGES/django.mo +0 -0
  249. wagtail/contrib/table_block/locale/hu/LC_MESSAGES/django.po +27 -2
  250. wagtail/contrib/table_block/locale/it/LC_MESSAGES/django.mo +0 -0
  251. wagtail/contrib/table_block/locale/it/LC_MESSAGES/django.po +27 -2
  252. wagtail/contrib/table_block/static/table_block/js/table.js +1 -1
  253. wagtail/contrib/table_block/tests.py +6 -0
  254. wagtail/contrib/typed_table_block/locale/ca/LC_MESSAGES/django.mo +0 -0
  255. wagtail/contrib/typed_table_block/locale/ca/LC_MESSAGES/django.po +12 -2
  256. wagtail/contrib/typed_table_block/locale/en/LC_MESSAGES/django.po +1 -1
  257. wagtail/contrib/typed_table_block/locale/hu/LC_MESSAGES/django.mo +0 -0
  258. wagtail/contrib/typed_table_block/locale/hu/LC_MESSAGES/django.po +12 -2
  259. wagtail/contrib/typed_table_block/locale/it/LC_MESSAGES/django.mo +0 -0
  260. wagtail/contrib/typed_table_block/locale/it/LC_MESSAGES/django.po +12 -2
  261. wagtail/contrib/typed_table_block/static/typed_table_block/js/typed_table_block.js +1 -1
  262. wagtail/coreutils.py +3 -2
  263. wagtail/documents/admin_urls.py +2 -2
  264. wagtail/documents/locale/en/LC_MESSAGES/django.po +22 -22
  265. wagtail/documents/locale/fr/LC_MESSAGES/django.po +2 -2
  266. wagtail/documents/locale/he_IL/LC_MESSAGES/django.mo +0 -0
  267. wagtail/documents/locale/he_IL/LC_MESSAGES/django.po +2 -2
  268. wagtail/documents/locale/hr_HR/LC_MESSAGES/django.mo +0 -0
  269. wagtail/documents/locale/hr_HR/LC_MESSAGES/django.po +19 -2
  270. wagtail/documents/locale/hu/LC_MESSAGES/django.mo +0 -0
  271. wagtail/documents/locale/hu/LC_MESSAGES/django.po +16 -2
  272. wagtail/documents/locale/it/LC_MESSAGES/django.mo +0 -0
  273. wagtail/documents/locale/it/LC_MESSAGES/django.po +19 -2
  274. wagtail/documents/migrations/0013_delete_uploadeddocument.py +16 -0
  275. wagtail/documents/models.py +1 -20
  276. wagtail/documents/rich_text/__init__.py +11 -7
  277. wagtail/documents/static/wagtaildocs/js/document-chooser-modal.js +1 -1
  278. wagtail/documents/static/wagtaildocs/js/document-chooser-telepath.js +1 -1
  279. wagtail/documents/static/wagtaildocs/js/document-chooser.js +1 -1
  280. wagtail/documents/templates/wagtaildocs/documents/index.html +0 -16
  281. wagtail/documents/tests/test_admin_views.py +155 -23
  282. wagtail/documents/tests/test_collection_privacy.py +55 -1
  283. wagtail/documents/tests/test_rich_text.py +14 -0
  284. wagtail/documents/views/documents.py +25 -22
  285. wagtail/documents/views/multiple.py +6 -7
  286. wagtail/documents/views/serve.py +16 -1
  287. wagtail/documents/wagtail_hooks.py +20 -15
  288. wagtail/embeds/blocks.py +5 -0
  289. wagtail/embeds/locale/en/LC_MESSAGES/django.po +2 -2
  290. wagtail/embeds/locale/fr/LC_MESSAGES/django.po +2 -2
  291. wagtail/embeds/locale/he_IL/LC_MESSAGES/django.mo +0 -0
  292. wagtail/embeds/locale/he_IL/LC_MESSAGES/django.po +2 -2
  293. wagtail/embeds/rich_text/__init__.py +1 -1
  294. wagtail/embeds/tests/test_rich_text.py +14 -0
  295. wagtail/embeds/wagtail_hooks.py +4 -14
  296. wagtail/fields.py +3 -48
  297. wagtail/images/admin_urls.py +2 -2
  298. wagtail/images/check_files/wagtail.jpg +0 -0
  299. wagtail/images/check_files/wagtail.png +0 -0
  300. wagtail/images/fields.py +2 -0
  301. wagtail/images/image_operations.py +1 -1
  302. wagtail/images/locale/ca/LC_MESSAGES/django.mo +0 -0
  303. wagtail/images/locale/ca/LC_MESSAGES/django.po +12 -0
  304. wagtail/images/locale/en/LC_MESSAGES/django.po +33 -45
  305. wagtail/images/locale/fr/LC_MESSAGES/django.po +2 -2
  306. wagtail/images/locale/he_IL/LC_MESSAGES/django.mo +0 -0
  307. wagtail/images/locale/he_IL/LC_MESSAGES/django.po +2 -2
  308. wagtail/images/locale/hu/LC_MESSAGES/django.mo +0 -0
  309. wagtail/images/locale/hu/LC_MESSAGES/django.po +28 -2
  310. wagtail/images/locale/it/LC_MESSAGES/django.mo +0 -0
  311. wagtail/images/locale/it/LC_MESSAGES/django.po +14 -2
  312. wagtail/images/locale/pt_PT/LC_MESSAGES/django.mo +0 -0
  313. wagtail/images/locale/pt_PT/LC_MESSAGES/django.po +4 -0
  314. wagtail/images/migrations/0026_delete_uploadedimage.py +16 -0
  315. wagtail/images/models.py +49 -43
  316. wagtail/images/rich_text/__init__.py +18 -8
  317. wagtail/images/static/wagtailimages/js/image-chooser-modal.js +1 -1
  318. wagtail/images/static/wagtailimages/js/image-chooser-telepath.js +1 -1
  319. wagtail/images/static/wagtailimages/js/image-chooser.js +1 -1
  320. wagtail/images/templates/wagtailimages/images/image_listing_header.html +6 -0
  321. wagtail/images/templates/wagtailimages/images/index.html +11 -51
  322. wagtail/images/tests/test_admin_views.py +119 -62
  323. wagtail/images/tests/test_image_operations.py +10 -0
  324. wagtail/images/tests/test_models.py +35 -33
  325. wagtail/images/tests/test_rich_text.py +14 -0
  326. wagtail/images/tests/utils.py +1 -1
  327. wagtail/images/views/images.py +35 -64
  328. wagtail/images/views/multiple.py +6 -7
  329. wagtail/images/wagtail_hooks.py +4 -14
  330. wagtail/locale/en/LC_MESSAGES/django.po +150 -136
  331. wagtail/locale/es/LC_MESSAGES/django.mo +0 -0
  332. wagtail/locale/es/LC_MESSAGES/django.po +3 -2
  333. wagtail/locale/fr/LC_MESSAGES/django.po +2 -2
  334. wagtail/locale/he_IL/LC_MESSAGES/django.mo +0 -0
  335. wagtail/locale/he_IL/LC_MESSAGES/django.po +2 -2
  336. wagtail/locale/it/LC_MESSAGES/django.mo +0 -0
  337. wagtail/locale/it/LC_MESSAGES/django.po +5 -5
  338. wagtail/locale/sl/LC_MESSAGES/django.mo +0 -0
  339. wagtail/locale/sl/LC_MESSAGES/django.po +27 -2
  340. wagtail/locales/locale/ar/LC_MESSAGES/django.po +1 -1
  341. wagtail/locales/locale/be/LC_MESSAGES/django.po +1 -1
  342. wagtail/locales/locale/bg/LC_MESSAGES/django.po +1 -1
  343. wagtail/locales/locale/ca/LC_MESSAGES/django.po +1 -1
  344. wagtail/locales/locale/cs/LC_MESSAGES/django.po +1 -1
  345. wagtail/locales/locale/cy/LC_MESSAGES/django.po +1 -1
  346. wagtail/locales/locale/da/LC_MESSAGES/django.po +1 -1
  347. wagtail/locales/locale/de/LC_MESSAGES/django.po +1 -1
  348. wagtail/locales/locale/el/LC_MESSAGES/django.po +1 -1
  349. wagtail/locales/locale/en/LC_MESSAGES/django.po +1 -1
  350. wagtail/locales/locale/es/LC_MESSAGES/django.po +1 -1
  351. wagtail/locales/locale/et/LC_MESSAGES/django.po +2 -2
  352. wagtail/locales/locale/fa/LC_MESSAGES/django.po +1 -1
  353. wagtail/locales/locale/fi/LC_MESSAGES/django.po +1 -1
  354. wagtail/locales/locale/fr/LC_MESSAGES/django.po +1 -1
  355. wagtail/locales/locale/gl/LC_MESSAGES/django.po +1 -1
  356. wagtail/locales/locale/he_IL/LC_MESSAGES/django.mo +0 -0
  357. wagtail/locales/locale/he_IL/LC_MESSAGES/django.po +3 -3
  358. wagtail/locales/locale/hr_HR/LC_MESSAGES/django.po +1 -1
  359. wagtail/locales/locale/hu/LC_MESSAGES/django.po +1 -1
  360. wagtail/locales/locale/id_ID/LC_MESSAGES/django.po +1 -1
  361. wagtail/locales/locale/is_IS/LC_MESSAGES/django.po +1 -1
  362. wagtail/locales/locale/it/LC_MESSAGES/django.po +1 -1
  363. wagtail/locales/locale/ja/LC_MESSAGES/django.po +1 -1
  364. wagtail/locales/locale/ko/LC_MESSAGES/django.po +1 -1
  365. wagtail/locales/locale/lt/LC_MESSAGES/django.po +1 -1
  366. wagtail/locales/locale/lv/LC_MESSAGES/django.po +1 -1
  367. wagtail/locales/locale/mi/LC_MESSAGES/django.po +1 -1
  368. wagtail/locales/locale/mn/LC_MESSAGES/django.po +1 -1
  369. wagtail/locales/locale/my/LC_MESSAGES/django.po +1 -1
  370. wagtail/locales/locale/nb/LC_MESSAGES/django.po +1 -1
  371. wagtail/locales/locale/nl/LC_MESSAGES/django.po +1 -1
  372. wagtail/locales/locale/pl/LC_MESSAGES/django.po +1 -1
  373. wagtail/locales/locale/pt_BR/LC_MESSAGES/django.po +1 -1
  374. wagtail/locales/locale/pt_PT/LC_MESSAGES/django.po +1 -1
  375. wagtail/locales/locale/ro/LC_MESSAGES/django.po +1 -1
  376. wagtail/locales/locale/ru/LC_MESSAGES/django.po +1 -1
  377. wagtail/locales/locale/sk_SK/LC_MESSAGES/django.po +1 -1
  378. wagtail/locales/locale/sl/LC_MESSAGES/django.po +1 -1
  379. wagtail/locales/locale/sv/LC_MESSAGES/django.po +1 -1
  380. wagtail/locales/locale/tet/LC_MESSAGES/django.po +1 -1
  381. wagtail/locales/locale/th/LC_MESSAGES/django.po +1 -1
  382. wagtail/locales/locale/tr/LC_MESSAGES/django.po +1 -1
  383. wagtail/locales/locale/tr_TR/LC_MESSAGES/django.po +1 -1
  384. wagtail/locales/locale/uk/LC_MESSAGES/django.po +1 -1
  385. wagtail/locales/locale/vi/LC_MESSAGES/django.po +1 -1
  386. wagtail/locales/locale/zh/LC_MESSAGES/django.po +1 -1
  387. wagtail/locales/locale/zh_Hans/LC_MESSAGES/django.po +1 -1
  388. wagtail/locales/locale/zh_Hant/LC_MESSAGES/django.po +1 -1
  389. wagtail/locales/tests.py +18 -3
  390. wagtail/locales/views.py +0 -1
  391. wagtail/management/commands/rebuild_references_index.py +3 -1
  392. wagtail/migrations/0092_alter_collectionviewrestriction_password_and_more.py +33 -0
  393. wagtail/migrations/0093_uploadedfile.py +53 -0
  394. wagtail/models/__init__.py +147 -32
  395. wagtail/models/i18n.py +1 -1
  396. wagtail/models/{collections.py → media.py} +33 -2
  397. wagtail/models/reference_index.py +1 -1
  398. wagtail/models/view_restrictions.py +10 -3
  399. wagtail/project_template/project_name/settings/base.py +6 -0
  400. wagtail/project_template/requirements.txt +1 -1
  401. wagtail/rich_text/__init__.py +25 -8
  402. wagtail/rich_text/pages.py +19 -8
  403. wagtail/rich_text/rewriters.py +140 -68
  404. wagtail/search/backends/database/mysql/mysql.py +3 -3
  405. wagtail/search/backends/database/postgres/postgres.py +3 -3
  406. wagtail/search/backends/database/sqlite/sqlite.py +2 -2
  407. wagtail/search/backends/elasticsearch7.py +4 -0
  408. wagtail/search/locale/en/LC_MESSAGES/django.po +3 -3
  409. wagtail/search/tests/test_postgres_backend.py +50 -0
  410. wagtail/sites/locale/en/LC_MESSAGES/django.po +8 -8
  411. wagtail/sites/locale/he_IL/LC_MESSAGES/django.mo +0 -0
  412. wagtail/sites/locale/he_IL/LC_MESSAGES/django.po +2 -2
  413. wagtail/sites/locale/ro/LC_MESSAGES/django.mo +0 -0
  414. wagtail/sites/locale/ro/LC_MESSAGES/django.po +3 -2
  415. wagtail/sites/tests.py +35 -9
  416. wagtail/sites/views.py +3 -1
  417. wagtail/snippets/locale/de/LC_MESSAGES/django.mo +0 -0
  418. wagtail/snippets/locale/de/LC_MESSAGES/django.po +7 -8
  419. wagtail/snippets/locale/en/LC_MESSAGES/django.po +16 -56
  420. wagtail/snippets/locale/fr/LC_MESSAGES/django.po +2 -2
  421. wagtail/snippets/locale/he_IL/LC_MESSAGES/django.mo +0 -0
  422. wagtail/snippets/locale/he_IL/LC_MESSAGES/django.po +2 -2
  423. wagtail/snippets/locale/hr_HR/LC_MESSAGES/django.mo +0 -0
  424. wagtail/snippets/locale/hr_HR/LC_MESSAGES/django.po +6 -2
  425. wagtail/snippets/locale/lv/LC_MESSAGES/django.mo +0 -0
  426. wagtail/snippets/locale/lv/LC_MESSAGES/django.po +12 -0
  427. wagtail/snippets/locale/zh_Hant/LC_MESSAGES/django.mo +0 -0
  428. wagtail/snippets/locale/zh_Hant/LC_MESSAGES/django.po +4 -0
  429. wagtail/snippets/static/wagtailsnippets/js/snippet-chooser-telepath.js +1 -1
  430. wagtail/snippets/static/wagtailsnippets/js/snippet-chooser.js +1 -1
  431. wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/publish.html +3 -1
  432. wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/save.html +3 -1
  433. wagtail/snippets/templates/wagtailsnippets/snippets/create.html +2 -3
  434. wagtail/snippets/templates/wagtailsnippets/snippets/edit.html +2 -3
  435. wagtail/snippets/tests/test_preview.py +13 -2
  436. wagtail/snippets/tests/test_snippets.py +41 -16
  437. wagtail/snippets/tests/test_viewset.py +95 -18
  438. wagtail/snippets/tests/test_workflows.py +12 -0
  439. wagtail/snippets/views/snippets.py +1 -40
  440. wagtail/templatetags/wagtailcore_tags.py +1 -1
  441. wagtail/test/demosite/models.py +1 -1
  442. wagtail/test/middleware.py +14 -1
  443. wagtail/test/testapp/fixtures/test.json +20 -0
  444. wagtail/test/testapp/migrations/0001_squashed_0073_revisablechildmodel_secret_text.py +8 -8
  445. wagtail/test/testapp/migrations/0023_snippetchoosermodel_full_featured.py +1 -0
  446. wagtail/test/testapp/migrations/0034_custompermissionmodel.py +44 -0
  447. wagtail/test/testapp/migrations/0035_modelwithcustommanager.py +30 -0
  448. wagtail/test/testapp/migrations/0036_complexdefaultstreampage.py +28 -0
  449. wagtail/test/testapp/models.py +79 -2
  450. wagtail/test/testapp/templates/tests/custom_docs_password_required.html +10 -0
  451. wagtail/test/testapp/templates/tests/custom_page_password_required.html +10 -0
  452. wagtail/test/testapp/views.py +24 -2
  453. wagtail/test/testapp/wagtail_hooks.py +19 -0
  454. wagtail/test/utils/wagtail_tests.py +2 -2
  455. wagtail/tests/test_blocks.py +262 -1
  456. wagtail/tests/test_migrations.py +1 -1
  457. wagtail/tests/test_page_model.py +77 -0
  458. wagtail/tests/test_page_privacy.py +18 -1
  459. wagtail/tests/test_rich_text.py +95 -5
  460. wagtail/tests/test_streamfield.py +43 -0
  461. wagtail/tests/test_utils.py +8 -2
  462. wagtail/tests/test_views.py +52 -1
  463. wagtail/tests/test_whitelist.py +7 -7
  464. wagtail/users/forms.py +3 -1
  465. wagtail/users/locale/en/LC_MESSAGES/django.po +124 -96
  466. wagtail/users/locale/fr/LC_MESSAGES/django.po +2 -2
  467. wagtail/users/locale/he_IL/LC_MESSAGES/django.mo +0 -0
  468. wagtail/users/locale/he_IL/LC_MESSAGES/django.po +2 -2
  469. wagtail/users/locale/hr_HR/LC_MESSAGES/django.mo +0 -0
  470. wagtail/users/locale/hr_HR/LC_MESSAGES/django.po +13 -2
  471. wagtail/users/migrations/0013_userprofile_density.py +23 -0
  472. wagtail/users/models.py +14 -3
  473. wagtail/users/templates/wagtailusers/groups/create.html +1 -7
  474. wagtail/users/templates/wagtailusers/groups/edit.html +1 -13
  475. wagtail/users/templates/wagtailusers/groups/includes/formatted_permissions.html +46 -2
  476. wagtail/users/templates/wagtailusers/groups/includes/group_form_js.html +0 -3
  477. wagtail/users/templates/wagtailusers/users/create.html +1 -14
  478. wagtail/users/templates/wagtailusers/users/edit.html +1 -14
  479. wagtail/users/templates/wagtailusers/users/index.html +2 -5
  480. wagtail/users/templates/wagtailusers/users/index_results.html +3 -13
  481. wagtail/users/templates/wagtailusers/users/user_cell.html +9 -0
  482. wagtail/users/templatetags/wagtailusers_tags.py +107 -20
  483. wagtail/users/tests/test_admin_views.py +669 -90
  484. wagtail/users/views/groups.py +58 -61
  485. wagtail/users/views/users.py +211 -92
  486. wagtail/users/wagtail_hooks.py +6 -38
  487. wagtail/users/widgets.py +3 -5
  488. wagtail/utils/text.py +1 -1
  489. wagtail/views.py +5 -9
  490. wagtail/whitelist.py +1 -1
  491. {wagtail-6.0.1.dist-info → wagtail-6.1rc1.dist-info}/METADATA +5 -6
  492. {wagtail-6.0.1.dist-info → wagtail-6.1rc1.dist-info}/RECORD +496 -477
  493. wagtail/admin/static/wagtailadmin/js/page-editor.js +0 -1
  494. wagtail/admin/static/wagtailadmin/js/vendor/mousetrap.min.js +0 -1
  495. wagtail/admin/static/wagtailadmin/js/vendor/urlify.js +0 -1
  496. wagtail/admin/static/wagtailadmin/js/vendor/xregexp.min.js +0 -1
  497. wagtail/admin/templates/wagtailadmin/collections/index.html +0 -34
  498. wagtail/admin/templates/wagtailadmin/pages/revisions/_actions.html +0 -22
  499. wagtail/admin/templates/wagtailadmin/shared/page_breadcrumbs.html +0 -55
  500. wagtail/admin/tests/pages/test_dashboard.py +0 -172
  501. wagtail/contrib/redirects/templates/wagtailredirects/results.html +0 -23
  502. wagtail/documents/templates/wagtaildocs/documents/list.html +0 -2
  503. wagtail/search/tests/test_postgres_stemming.py +0 -40
  504. wagtail/sites/templates/wagtailsites/create.html +0 -7
  505. wagtail/sites/templates/wagtailsites/edit.html +0 -7
  506. wagtail/snippets/templates/wagtailsnippets/snippets/revisions/_actions.html +0 -36
  507. wagtail/users/templates/wagtailusers/users/list.html +0 -62
  508. wagtail/users/urls/users.py +0 -12
  509. {wagtail-6.0.1.dist-info → wagtail-6.1rc1.dist-info}/LICENSE +0 -0
  510. {wagtail-6.0.1.dist-info → wagtail-6.1rc1.dist-info}/WHEEL +0 -0
  511. {wagtail-6.0.1.dist-info → wagtail-6.1rc1.dist-info}/entry_points.txt +0 -0
  512. {wagtail-6.0.1.dist-info → wagtail-6.1rc1.dist-info}/top_level.txt +0 -0
@@ -9,57 +9,17 @@
9
9
  <script defer src="{% versioned_static 'wagtailadmin/js/bulk-actions.js' %}"></script>
10
10
  {% endblock %}
11
11
 
12
- {% block listing %}
13
- <div>
14
- <form class="image-search nice-padding" action="{{ index_url }}" method="GET" novalidate>
15
- {% if current_tag %}
16
- <input type="hidden" name="tag" value="{{ current_tag }}" />
17
- {% endif %}
18
-
19
- {% field_row max_content=True %}
20
- {% if collections %}
21
- {% include "wagtailadmin/shared/collection_chooser.html" %}
22
- {% endif %}
23
-
24
- {% trans "Sort by" as sort_by %}
25
- {% rawformattedfield label_text=sort_by id_for_label="order_images_by" %}
26
- <select id="order_images_by" name="ordering" data-controller="w-submit" data-action="change->w-submit#submit">
27
- {% for ordering, ordering_text in ORDERING_OPTIONS.items %}
28
- <option value="{{ ordering }}" {% if current_ordering == ordering %}selected="selected"{% endif %}>{{ ordering_text }}</option>
29
- {% endfor %}
30
- </select>
31
- {% endrawformattedfield %}
32
-
33
- {% trans "Entries per page" as entries_per_page_label %}
34
- {% rawformattedfield label_text=entries_per_page_label id_for_label="entries_per_page_label" %}
35
- <select id="entries_per_page" name="entries_per_page" data-controller="w-submit" data-action="change->w-submit#submit">
36
- {% for value in ENTRIES_PER_PAGE_CHOICES %}
37
- <option value="{{ value }}" {% if entries_per_page == value %}selected="selected"{% endif %}>{{ value }}</option>
38
- {% endfor %}
39
- </select>
40
- {% endrawformattedfield %}
41
- {% endfield_row %}
42
-
43
- {% if popular_tags %}
44
- <fieldset class="tagfilter">
45
- <legend>{% trans 'Popular Tags:' %}</legend>
46
- {% for tag in popular_tags %}
47
- {% if tag.name != current_tag %}
48
- <a class="button button-small button-secondary bicolor button--icon" href="{{ index_url }}{% querystring tag=tag.name %}">{% icon name="tag" wrapped=1 %}{{ tag.name }}</a>
49
- {% else %}
50
- <a class="button button-small bicolor button--icon" href="{{ index_url }}{% querystring tag=tag.name %}">{% icon name="tag" wrapped=1 %}{{ tag.name }}</a>
51
- {% endif %}
52
- {% endfor %}
53
- {% if current_tag %}
54
- <a class="button button-small bicolor button-secondary button--icon" href="{{ index_url }}{% querystring tag='' %}">{% icon name="cross" wrapped=1 %}{% trans 'Clear' %}</a>
55
- {% endif %}
56
- </fieldset>
57
- {% endif %}
58
- </form>
59
- <div id="listing-results">
60
- {% include "wagtailimages/images/index_results.html" %}
61
- </div>
62
- </div>
12
+ {% block slim_header %}
13
+ {% fragment as extra_form_fields %}
14
+ {% rawformattedfield label_text=_("Sort by") id_for_label="order_images_by" sr_only_label=True %}
15
+ <select id="order_images_by" name="ordering">
16
+ {% for ordering, ordering_text in ORDERING_OPTIONS.items %}
17
+ <option value="{{ ordering }}" {% if current_ordering == ordering %}selected="selected"{% endif %}>{{ ordering_text }}</option>
18
+ {% endfor %}
19
+ </select>
20
+ {% endrawformattedfield %}
21
+ {% endfragment %}
22
+ {% include "wagtailimages/images/image_listing_header.html" with breadcrumbs_items=breadcrumbs_items side_panels=side_panels history_url=history_url title=header_title search_url=index_results_url search_form=search_form filters=filters buttons=header_buttons icon_name=header_icon extra_form_fields=extra_form_fields only %}
63
23
  {% endblock %}
64
24
 
65
25
  {% block bulk_actions %}
@@ -4,6 +4,7 @@ import urllib
4
4
 
5
5
  from django.conf import settings
6
6
  from django.contrib.auth.models import Group, Permission
7
+ from django.contrib.contenttypes.models import ContentType
7
8
  from django.core.files.uploadedfile import SimpleUploadedFile, TemporaryUploadedFile
8
9
  from django.template.defaultfilters import filesizeformat
9
10
  from django.template.loader import render_to_string
@@ -16,12 +17,12 @@ from django.utils.safestring import mark_safe
16
17
 
17
18
  from wagtail.admin.admin_url_finder import AdminURLFinder
18
19
  from wagtail.images import get_image_model
19
- from wagtail.images.models import UploadedImage
20
20
  from wagtail.images.utils import generate_signature
21
21
  from wagtail.models import (
22
22
  Collection,
23
23
  GroupCollectionPermission,
24
24
  Page,
25
+ UploadedFile,
25
26
  get_root_collection_id,
26
27
  )
27
28
  from wagtail.test.testapp.models import (
@@ -31,6 +32,7 @@ from wagtail.test.testapp.models import (
31
32
  VariousOnDeleteModel,
32
33
  )
33
34
  from wagtail.test.utils import WagtailTestUtils
35
+ from wagtail.test.utils.timestamps import local_datetime
34
36
 
35
37
  from .utils import Image, get_test_image_file, get_test_image_file_svg
36
38
 
@@ -44,12 +46,10 @@ class TestImageIndexView(WagtailTestUtils, TestCase):
44
46
  self.kitten_image = Image.objects.create(
45
47
  title="a cute kitten",
46
48
  file=get_test_image_file(size=(1, 1)),
47
- created_at=datetime.datetime(2020, 1, 1),
48
49
  )
49
50
  self.puppy_image = Image.objects.create(
50
51
  title="a cute puppy",
51
52
  file=get_test_image_file(size=(1, 1)),
52
- created_at=datetime.datetime(2022, 2, 2),
53
53
  )
54
54
 
55
55
  def get(self, params={}):
@@ -85,12 +85,6 @@ class TestImageIndexView(WagtailTestUtils, TestCase):
85
85
  response = self.get({"p": 9999})
86
86
  self.assertEqual(response.status_code, 404)
87
87
 
88
- def test_per_page(self):
89
- response = self.get({"entries_per_page": 60})
90
- self.assertContains(
91
- response, '<option value="60" selected="selected">60</option>', html=True
92
- )
93
-
94
88
  def test_pagination_preserves_other_params(self):
95
89
  root_collection = Collection.get_first_root_node()
96
90
  evil_plans_collection = root_collection.add_child(name="Evil plans")
@@ -151,41 +145,40 @@ class TestImageIndexView(WagtailTestUtils, TestCase):
151
145
  self.assertEqual(context["page_obj"].object_list[0], self.puppy_image)
152
146
  self.assertEqual(context["page_obj"].object_list[1], self.kitten_image)
153
147
 
148
+ @override_settings(WAGTAILIMAGES_INDEX_PAGE_SIZE=15)
154
149
  def test_default_entries_per_page(self):
155
- for i in range(1, 33):
156
- self.image = Image.objects.create(
150
+ images = [
151
+ Image(
157
152
  title="Test image %i" % i,
158
153
  file=get_test_image_file(size=(1, 1)),
159
154
  )
155
+ for i in range(1, 33)
156
+ ]
157
+ Image.objects.bulk_create(images)
160
158
 
161
159
  response = self.get()
162
160
  self.assertEqual(response.status_code, 200)
163
161
 
164
162
  object_list = response.context["page_obj"].object_list
165
- # The default number of images shown is 30
166
- self.assertEqual(len(object_list), 30)
167
-
168
- response = self.get({"entries_per_page": 10})
169
- self.assertEqual(response.status_code, 200)
170
-
171
- object_list = response.context["page_obj"].object_list
172
- self.assertEqual(len(object_list), 10)
163
+ # The number of images shown is 15
164
+ self.assertEqual(len(object_list), 15)
173
165
 
174
166
  def test_default_entries_per_page_uses_default(self):
175
- for i in range(1, 33):
176
- self.image = Image.objects.create(
167
+ images = [
168
+ Image(
177
169
  title="Test image %i" % i,
178
170
  file=get_test_image_file(size=(1, 1)),
179
171
  )
172
+ for i in range(1, 33)
173
+ ]
174
+ Image.objects.bulk_create(images)
180
175
 
181
176
  default_num_entries_per_page = 30
182
- invalid_num_entries_values = [66, "a"]
183
- for value in invalid_num_entries_values:
184
- response = self.get({"entries_per_page": value})
185
- self.assertEqual(response.status_code, 200)
177
+ response = self.get()
178
+ self.assertEqual(response.status_code, 200)
186
179
 
187
- object_list = response.context["page_obj"].object_list
188
- self.assertEqual(len(object_list), default_num_entries_per_page)
180
+ object_list = response.context["page_obj"].object_list
181
+ self.assertEqual(len(object_list), default_num_entries_per_page)
189
182
 
190
183
  def test_collection_order(self):
191
184
  root_collection = Collection.get_first_root_node()
@@ -193,8 +186,16 @@ class TestImageIndexView(WagtailTestUtils, TestCase):
193
186
  root_collection.add_child(name="Good plans")
194
187
 
195
188
  response = self.get()
189
+ soup = self.get_soup(response.content)
190
+ collection_options = soup.select(
191
+ 'select[name="collection_id"] option[value]:not(option[value=""])'
192
+ )
193
+
196
194
  self.assertEqual(
197
- [collection.name for collection in response.context["collections"]],
195
+ [
196
+ collection.get_text(strip=True).lstrip("↳ ")
197
+ for collection in collection_options
198
+ ],
198
199
  ["Root", "Evil plans", "Good plans"],
199
200
  )
200
201
 
@@ -234,13 +235,14 @@ class TestImageIndexView(WagtailTestUtils, TestCase):
234
235
  response = self.get()
235
236
  self.assertEqual(response.status_code, 200)
236
237
 
237
- current_tag = response.context["current_tag"]
238
- self.assertIsNone(current_tag)
238
+ soup = self.get_soup(response.content)
239
+ current_tags = soup.select("input[name=tag][checked]")
240
+ self.assertFalse(current_tags)
239
241
 
240
- tags = response.context["popular_tags"]
241
- self.assertTrue(
242
- [tag.name for tag in tags] == ["one", "two"]
243
- or [tag.name for tag in tags] == ["two", "one"]
242
+ tags = soup.select("#id_tag label")
243
+ self.assertCountEqual(
244
+ [tags.get_text(strip=True) for tags in tags],
245
+ ["one", "two"],
244
246
  )
245
247
 
246
248
  def test_tag_filtering(self):
@@ -261,10 +263,16 @@ class TestImageIndexView(WagtailTestUtils, TestCase):
261
263
  )
262
264
  image_two_tags.tags.add("one", "two")
263
265
 
266
+ image_unrelated_tag = Image.objects.create(
267
+ title="Test image with a different tag",
268
+ file=get_test_image_file(),
269
+ )
270
+ image_unrelated_tag.tags.add("unrelated")
271
+
264
272
  # no filtering
265
273
  response = self.get()
266
- # three images created above plus the two untagged ones created in setUp()
267
- self.assertEqual(response.context["page_obj"].paginator.count, 5)
274
+ # four images created above plus the two untagged ones created in setUp()
275
+ self.assertEqual(response.context["page_obj"].paginator.count, 6)
268
276
 
269
277
  # filter all images with tag 'one'
270
278
  response = self.get({"tag": "one"})
@@ -274,6 +282,30 @@ class TestImageIndexView(WagtailTestUtils, TestCase):
274
282
  response = self.get({"tag": "two"})
275
283
  self.assertEqual(response.context["page_obj"].paginator.count, 1)
276
284
 
285
+ # filter all images with tag 'one' or 'unrelated'
286
+ response = self.get({"tag": ["one", "unrelated"]})
287
+ self.assertEqual(response.context["page_obj"].paginator.count, 3)
288
+
289
+ soup = self.get_soup(response.content)
290
+
291
+ # Should check the 'one' and 'unrelated' tags checkboxes
292
+ tags = soup.select("#id_tag label")
293
+ self.assertCountEqual(
294
+ [
295
+ tag.get_text(strip=True)
296
+ for tag in tags
297
+ if tag.select_one("input[checked]") is not None
298
+ ],
299
+ ["one", "unrelated"],
300
+ )
301
+
302
+ # Should render the active filter pills separately for each tag
303
+ active_filters = soup.select('[data-w-active-filter-id="id_tag"]')
304
+ self.assertCountEqual(
305
+ [filter.get_text(separator=" ", strip=True) for filter in active_filters],
306
+ ["Tag: one", "Tag: unrelated"],
307
+ )
308
+
277
309
  def test_tag_filtering_preserves_other_params(self):
278
310
  for i in range(1, 130):
279
311
  image = Image.objects.create(
@@ -301,7 +333,7 @@ class TestImageIndexView(WagtailTestUtils, TestCase):
301
333
  def test_search_form_rendered(self):
302
334
  response = self.get()
303
335
  html = response.content.decode()
304
- search_url = reverse("wagtailimages:index")
336
+ search_url = reverse("wagtailimages:index_results")
305
337
 
306
338
  # Search form in the header should be rendered.
307
339
  self.assertTagInHTML(
@@ -348,13 +380,17 @@ class TestImageIndexViewSearch(WagtailTestUtils, TransactionTestCase):
348
380
  self.kitten_image = Image.objects.create(
349
381
  title="a cute kitten",
350
382
  file=get_test_image_file(size=(1, 1)),
351
- created_at=datetime.datetime(2020, 1, 1),
352
383
  )
353
384
  self.puppy_image = Image.objects.create(
354
385
  title="a cute puppy",
355
386
  file=get_test_image_file(size=(1, 1)),
356
- created_at=datetime.datetime(2022, 2, 2),
357
387
  )
388
+ # The created_at field uses auto_now_add, so changing it needs to be
389
+ # done after the image is created.
390
+ self.kitten_image.created_at = local_datetime(2020, 1, 1)
391
+ self.kitten_image.save()
392
+ self.puppy_image.created_at = local_datetime(2022, 2, 2)
393
+ self.puppy_image.save()
358
394
 
359
395
  def get(self, params={}):
360
396
  return self.client.get(reverse("wagtailimages:index"), params)
@@ -405,9 +441,29 @@ class TestImageIndexViewSearch(WagtailTestUtils, TransactionTestCase):
405
441
  url = reverse("wagtailimages:add_multiple")
406
442
  self.assertContains(
407
443
  response,
408
- f'<a href="{url}?q=Baker&amp;collection_id={child_collection[0].pk}"',
444
+ f'<a href="{url}?collection_id={child_collection[0].pk}"',
409
445
  )
410
446
 
447
+ def test_search_and_order_by_created_at(self):
448
+ old_image = Image.objects.create(
449
+ title="decades old cute tortoise",
450
+ file=get_test_image_file(size=(1, 1)),
451
+ )
452
+ old_image.created_at = local_datetime(2000, 1, 1)
453
+ old_image.save()
454
+ response = self.get({"q": "cute", "ordering": "created_at"})
455
+ self.assertEqual(response.status_code, 200)
456
+ self.assertEqual(response.context["query_string"], "cute")
457
+ self.assertEqual(
458
+ list(response.context["page_obj"].object_list),
459
+ [old_image, self.kitten_image, self.puppy_image],
460
+ )
461
+ soup = self.get_soup(response.content)
462
+ option = soup.select_one('select[name="ordering"] option[selected]')
463
+ self.assertIsNotNone(option)
464
+ self.assertEqual(option["value"], "created_at")
465
+ self.assertEqual(option.get_text(strip=True), "Oldest")
466
+
411
467
  def test_tag_filtering_with_search_term(self):
412
468
  Image.objects.create(
413
469
  title="Test image with no tags",
@@ -426,10 +482,10 @@ class TestImageIndexViewSearch(WagtailTestUtils, TransactionTestCase):
426
482
  )
427
483
  image_two_tags.tags.add("one", "two")
428
484
 
429
- # The tag gets ignored, if a valid search term is present, so this will find all
430
- # images, as all of them contain "test" in their titles.
485
+ # The tag shouldn't be ignored, so the result should be the images
486
+ # that have the "one" tag and "test" in the title.
431
487
  response = self.get({"tag": "one", "q": "test"})
432
- self.assertEqual(response.context["page_obj"].paginator.count, 3)
488
+ self.assertEqual(response.context["page_obj"].paginator.count, 2)
433
489
 
434
490
 
435
491
  class TestImageListingResultsView(WagtailTestUtils, TransactionTestCase):
@@ -2886,7 +2942,7 @@ class TestMultipleImageUploaderWithCustomImageModel(WagtailTestUtils, TestCase):
2886
2942
 
2887
2943
  def test_unique_together_validation_error(self):
2888
2944
  """
2889
- If unique_together validation fails, create an UploadedImage and return a form so the
2945
+ If unique_together validation fails, create an UploadedFile and return a form so the
2890
2946
  user can fix it
2891
2947
  """
2892
2948
  root_collection = Collection.get_first_root_node()
@@ -2895,7 +2951,7 @@ class TestMultipleImageUploaderWithCustomImageModel(WagtailTestUtils, TestCase):
2895
2951
  self.image.save()
2896
2952
 
2897
2953
  image_count_before = CustomImage.objects.count()
2898
- uploaded_image_count_before = UploadedImage.objects.count()
2954
+ uploaded_image_count_before = UploadedFile.objects.count()
2899
2955
 
2900
2956
  response = self.client.post(
2901
2957
  reverse("wagtailimages:add_multiple"),
@@ -2908,9 +2964,9 @@ class TestMultipleImageUploaderWithCustomImageModel(WagtailTestUtils, TestCase):
2908
2964
  )
2909
2965
 
2910
2966
  image_count_after = CustomImage.objects.count()
2911
- uploaded_image_count_after = UploadedImage.objects.count()
2967
+ uploaded_image_count_after = UploadedFile.objects.count()
2912
2968
 
2913
- # an UploadedImage should have been created now, but not a CustomImage
2969
+ # an UploadedFile should have been created now, but not a CustomImage
2914
2970
  self.assertEqual(image_count_after, image_count_before)
2915
2971
  self.assertEqual(uploaded_image_count_after, uploaded_image_count_before + 1)
2916
2972
 
@@ -3034,8 +3090,9 @@ class TestMultipleImageUploaderWithCustomRequiredFields(WagtailTestUtils, TestCa
3034
3090
  def setUp(self):
3035
3091
  self.user = self.login()
3036
3092
 
3037
- # Create an UploadedImage for running tests on
3038
- self.uploaded_image = UploadedImage.objects.create(
3093
+ # Create an UploadedFile for running tests on
3094
+ self.uploaded_image = UploadedFile.objects.create(
3095
+ for_content_type=ContentType.objects.get_for_model(get_image_model()),
3039
3096
  file=get_test_image_file(),
3040
3097
  uploaded_by_user=self.user,
3041
3098
  )
@@ -3053,11 +3110,11 @@ class TestMultipleImageUploaderWithCustomRequiredFields(WagtailTestUtils, TestCa
3053
3110
 
3054
3111
  def test_add_post(self):
3055
3112
  """
3056
- A POST request to the add view should create an UploadedImage rather than an image,
3113
+ A POST request to the add view should create an UploadedFile rather than an image,
3057
3114
  as we do not have enough data to pass CustomImageWithAuthor's validation yet
3058
3115
  """
3059
3116
  image_count_before = CustomImageWithAuthor.objects.count()
3060
- uploaded_image_count_before = UploadedImage.objects.count()
3117
+ uploaded_image_count_before = UploadedFile.objects.count()
3061
3118
 
3062
3119
  response = self.client.post(
3063
3120
  reverse("wagtailimages:add_multiple"),
@@ -3069,9 +3126,9 @@ class TestMultipleImageUploaderWithCustomRequiredFields(WagtailTestUtils, TestCa
3069
3126
  )
3070
3127
 
3071
3128
  image_count_after = CustomImageWithAuthor.objects.count()
3072
- uploaded_image_count_after = UploadedImage.objects.count()
3129
+ uploaded_image_count_after = UploadedFile.objects.count()
3073
3130
 
3074
- # an UploadedImage should have been created now, but not a CustomImageWithAuthor
3131
+ # an UploadedFile should have been created now, but not a CustomImageWithAuthor
3075
3132
  self.assertEqual(image_count_after, image_count_before)
3076
3133
  self.assertEqual(uploaded_image_count_after, uploaded_image_count_before + 1)
3077
3134
 
@@ -3137,10 +3194,10 @@ class TestMultipleImageUploaderWithCustomRequiredFields(WagtailTestUtils, TestCa
3137
3194
  def test_create_from_upload_invalid_post(self):
3138
3195
  """
3139
3196
  Posting an invalid form to the create_from_uploaded_image view throws a validation error and leaves the
3140
- UploadedImage intact
3197
+ UploadedFile intact
3141
3198
  """
3142
3199
  image_count_before = CustomImageWithAuthor.objects.count()
3143
- uploaded_image_count_before = UploadedImage.objects.count()
3200
+ uploaded_image_count_before = UploadedFile.objects.count()
3144
3201
 
3145
3202
  # Send request
3146
3203
  response = self.client.post(
@@ -3156,9 +3213,9 @@ class TestMultipleImageUploaderWithCustomRequiredFields(WagtailTestUtils, TestCa
3156
3213
  )
3157
3214
 
3158
3215
  image_count_after = CustomImageWithAuthor.objects.count()
3159
- uploaded_image_count_after = UploadedImage.objects.count()
3216
+ uploaded_image_count_after = UploadedFile.objects.count()
3160
3217
 
3161
- # no changes to image / UploadedImage count
3218
+ # no changes to image / UploadedFile count
3162
3219
  self.assertEqual(image_count_after, image_count_before)
3163
3220
  self.assertEqual(uploaded_image_count_after, uploaded_image_count_before)
3164
3221
 
@@ -3194,7 +3251,7 @@ class TestMultipleImageUploaderWithCustomRequiredFields(WagtailTestUtils, TestCa
3194
3251
  Posting a valid form to the create_from_uploaded_image view will create the image
3195
3252
  """
3196
3253
  image_count_before = CustomImageWithAuthor.objects.count()
3197
- uploaded_image_count_before = UploadedImage.objects.count()
3254
+ uploaded_image_count_before = UploadedFile.objects.count()
3198
3255
 
3199
3256
  # Send request
3200
3257
  response = self.client.post(
@@ -3212,7 +3269,7 @@ class TestMultipleImageUploaderWithCustomRequiredFields(WagtailTestUtils, TestCa
3212
3269
  )
3213
3270
 
3214
3271
  image_count_after = CustomImageWithAuthor.objects.count()
3215
- uploaded_image_count_after = UploadedImage.objects.count()
3272
+ uploaded_image_count_after = UploadedFile.objects.count()
3216
3273
 
3217
3274
  # Check response
3218
3275
  self.assertEqual(response.status_code, 200)
@@ -3223,7 +3280,7 @@ class TestMultipleImageUploaderWithCustomRequiredFields(WagtailTestUtils, TestCa
3223
3280
  self.assertIn("image_id", response_json)
3224
3281
  self.assertTrue(response_json["success"])
3225
3282
 
3226
- # Image should have been created, UploadedImage deleted
3283
+ # Image should have been created, UploadedFile deleted
3227
3284
  self.assertEqual(image_count_after, image_count_before + 1)
3228
3285
  self.assertEqual(uploaded_image_count_after, uploaded_image_count_before - 1)
3229
3286
 
@@ -3239,7 +3296,7 @@ class TestMultipleImageUploaderWithCustomRequiredFields(WagtailTestUtils, TestCa
3239
3296
 
3240
3297
  def test_delete_uploaded_image(self):
3241
3298
  """
3242
- This tests that a POST request to the delete view deletes the UploadedImage
3299
+ This tests that a POST request to the delete view deletes the UploadedFile
3243
3300
  """
3244
3301
  # Send request
3245
3302
  response = self.client.post(
@@ -3254,7 +3311,7 @@ class TestMultipleImageUploaderWithCustomRequiredFields(WagtailTestUtils, TestCa
3254
3311
 
3255
3312
  # Make sure the image is deleted
3256
3313
  self.assertFalse(
3257
- UploadedImage.objects.filter(id=self.uploaded_image.id).exists()
3314
+ UploadedFile.objects.filter(id=self.uploaded_image.id).exists()
3258
3315
  )
3259
3316
 
3260
3317
  # Check JSON
@@ -683,6 +683,16 @@ class TestFormatFilter(TestCase):
683
683
 
684
684
  self.assertEqual(out.format_name, "webp")
685
685
 
686
+ def test_ico(self):
687
+ fil = Filter(spec="width-400|format-ico")
688
+ image = Image.objects.create(
689
+ title="Test image",
690
+ file=get_test_image_file(),
691
+ )
692
+ out = fil.run(image, BytesIO())
693
+
694
+ self.assertEqual(out.format_name, "ico")
695
+
686
696
  def test_webp_lossless(self):
687
697
  fil = Filter(spec="width-400|format-webp-lossless")
688
698
  image = Image.objects.create(
@@ -4,7 +4,7 @@ from django.conf import settings
4
4
  from django.contrib.auth.models import Group, Permission
5
5
  from django.core.cache import caches
6
6
  from django.core.files import File
7
- from django.core.files.storage import DefaultStorage, Storage
7
+ from django.core.files.storage import Storage, default_storage, storages
8
8
  from django.core.files.uploadedfile import SimpleUploadedFile
9
9
  from django.db.models import Prefetch
10
10
  from django.db.utils import IntegrityError
@@ -38,8 +38,7 @@ from .utils import (
38
38
 
39
39
 
40
40
  class CustomStorage(Storage):
41
- def __init__(self):
42
- super().__init__()
41
+ pass
43
42
 
44
43
 
45
44
  class TestImage(TestCase):
@@ -668,7 +667,7 @@ class TestRenditions(TestCase):
668
667
  self._test_get_renditions_performance(1)
669
668
 
670
669
  # ATTEMPT 3
671
- # If the existing renditions are prefetched, no futher queries should
670
+ # If the existing renditions are prefetched, no further queries should
672
671
  # be needed, whether that's with prefetch_related("renditions") or
673
672
  # prefetch_renditions()
674
673
  self._test_get_renditions_performance(0, prefetch_all=True)
@@ -856,39 +855,42 @@ class TestRenditions(TestCase):
856
855
  rendition.background_position_style, "background-position: 50% 50%;"
857
856
  )
858
857
 
859
- def test_custom_rendition_backend_setting(self):
860
- """
861
- Test the usage of WAGTAILIMAGES_RENDITION_STORAGE setting.
862
- """
863
- # when setting is not set, instance.get_storage() returns DefaultStorage
864
- from django.conf import settings
865
-
866
- bkp = settings
867
-
858
+ @override_settings()
859
+ def test_rendition_storage_setting_absent(self):
860
+ del settings.WAGTAILIMAGES_RENDITION_STORAGE
868
861
  self.assertFalse(hasattr(settings, "WAGTAILIMAGES_RENDITION_STORAGE"))
869
- rendition1 = self.image.get_rendition("min-120x120")
870
- self.assertIsInstance(rendition1.image.file.storage, DefaultStorage)
871
-
872
- # when setting is set to a path
873
- setattr(
874
- settings,
875
- "WAGTAILIMAGES_RENDITION_STORAGE",
876
- "wagtail.images.tests.test_models.CustomStorage",
877
- )
878
- backend = get_rendition_storage()
879
- self.assertIsInstance(backend, CustomStorage)
862
+ self.assertEqual(get_rendition_storage(), default_storage)
880
863
 
881
- # when setting is set directly, get_rendition_storage() returns the custom storage backend
882
- class CustomStorage2(Storage):
883
- def __init__(self):
884
- super().__init__()
864
+ @override_settings(
865
+ WAGTAILIMAGES_RENDITION_STORAGE="wagtail.images.tests.test_models.CustomStorage"
866
+ )
867
+ def test_rendition_storage_setting_given_dotted_path(self):
868
+ self.assertIsInstance(get_rendition_storage(), CustomStorage)
885
869
 
886
- setattr(settings, "WAGTAILIMAGES_RENDITION_STORAGE", CustomStorage2())
887
- backend = get_rendition_storage()
888
- self.assertIsInstance(backend, CustomStorage2)
870
+ @override_settings(WAGTAILIMAGES_RENDITION_STORAGE=CustomStorage())
871
+ def test_rendition_storage_setting_given_storage_instance(self):
872
+ self.assertEqual(
873
+ get_rendition_storage(), settings.WAGTAILIMAGES_RENDITION_STORAGE
874
+ )
889
875
 
890
- # clean up
891
- settings = bkp
876
+ @override_settings(
877
+ STORAGES={
878
+ "default": {
879
+ "BACKEND": "django.core.files.storage.FileSystemStorage",
880
+ },
881
+ "staticfiles": {
882
+ "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage",
883
+ },
884
+ "custom_storage": {
885
+ "BACKEND": "wagtail.images.tests.test_models.CustomStorage",
886
+ },
887
+ },
888
+ WAGTAILIMAGES_RENDITION_STORAGE="custom_storage",
889
+ )
890
+ def test_rendition_storage_setting_given_storage_alias(self):
891
+ self.assertEqual(
892
+ get_rendition_storage(), storages[settings.WAGTAILIMAGES_RENDITION_STORAGE]
893
+ )
892
894
 
893
895
 
894
896
  @override_settings(
@@ -1,10 +1,12 @@
1
1
  from django.test import TestCase
2
+ from django.urls import reverse_lazy
2
3
 
3
4
  from wagtail.fields import RichTextField
4
5
  from wagtail.images.rich_text import ImageEmbedHandler as FrontendImageEmbedHandler
5
6
  from wagtail.images.rich_text.editor_html import (
6
7
  ImageEmbedHandler as EditorHtmlImageEmbedHandler,
7
8
  )
9
+ from wagtail.rich_text.feature_registry import FeatureRegistry
8
10
  from wagtail.test.utils import WagtailTestUtils
9
11
 
10
12
  from .utils import Image, get_test_image_file
@@ -140,3 +142,15 @@ class TestExtractReferencesWithImage(WagtailTestUtils, TestCase):
140
142
  ),
141
143
  [(Image, "52", "", "")],
142
144
  )
145
+
146
+
147
+ class TestEntityFeatureChooserUrls(TestCase):
148
+ def test_chooser_urls_exist(self):
149
+ features = FeatureRegistry()
150
+ image = features.get_editor_plugin("draftail", "image")
151
+
152
+ self.assertIsNotNone(image.data.get("chooserUrls"))
153
+ self.assertEqual(
154
+ image.data["chooserUrls"]["imageChooser"],
155
+ reverse_lazy("wagtailimages_chooser:choose"),
156
+ )
@@ -73,7 +73,7 @@ def get_test_image_file_svg(
73
73
 
74
74
 
75
75
  def get_test_bad_image():
76
- # Create an image with a missing file, by deserializing fom a python object
76
+ # Create an image with a missing file, by deserializing from a python object
77
77
  # (which bypasses FileField's attempt to read the file)
78
78
  return list(
79
79
  serializers.deserialize(