wagtail 7.2.1__py3-none-any.whl → 7.3rc1__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 (312) hide show
  1. wagtail/__init__.py +1 -1
  2. wagtail/actions/copy_for_translation.py +4 -2
  3. wagtail/admin/action_menu.py +4 -1
  4. wagtail/admin/api/actions/convert_alias.py +2 -2
  5. wagtail/admin/api/actions/copy.py +2 -2
  6. wagtail/admin/api/actions/copy_for_translation.py +2 -2
  7. wagtail/admin/api/actions/create_alias.py +2 -2
  8. wagtail/admin/api/actions/delete.py +1 -1
  9. wagtail/admin/api/actions/move.py +1 -1
  10. wagtail/admin/api/actions/publish.py +2 -2
  11. wagtail/admin/api/actions/revert_to_page_revision.py +2 -2
  12. wagtail/admin/api/actions/unpublish.py +1 -1
  13. wagtail/admin/api/filters.py +2 -2
  14. wagtail/admin/compare.py +22 -0
  15. wagtail/admin/forms/account.py +52 -1
  16. wagtail/admin/forms/comments.py +53 -0
  17. wagtail/admin/forms/models.py +36 -0
  18. wagtail/admin/forms/pages.py +7 -0
  19. wagtail/admin/forms/workflows.py +5 -2
  20. wagtail/admin/icons.py +4 -3
  21. wagtail/admin/locale/ar/LC_MESSAGES/django.mo +0 -0
  22. wagtail/admin/locale/ar/LC_MESSAGES/django.po +35 -0
  23. wagtail/admin/locale/en/LC_MESSAGES/django.po +262 -234
  24. wagtail/admin/locale/en/LC_MESSAGES/djangojs.po +72 -43
  25. wagtail/admin/locale/it/LC_MESSAGES/django.mo +0 -0
  26. wagtail/admin/locale/it/LC_MESSAGES/django.po +566 -6
  27. wagtail/admin/locale/it/LC_MESSAGES/djangojs.mo +0 -0
  28. wagtail/admin/locale/it/LC_MESSAGES/djangojs.po +40 -2
  29. wagtail/admin/locale/nl/LC_MESSAGES/django.mo +0 -0
  30. wagtail/admin/locale/nl/LC_MESSAGES/django.po +2 -2
  31. wagtail/admin/locale/sv/LC_MESSAGES/django.mo +0 -0
  32. wagtail/admin/locale/sv/LC_MESSAGES/django.po +330 -15
  33. wagtail/admin/locale/sv/LC_MESSAGES/djangojs.mo +0 -0
  34. wagtail/admin/locale/sv/LC_MESSAGES/djangojs.po +3 -2
  35. wagtail/admin/panels/comment_panel.py +1 -51
  36. wagtail/admin/panels/title_field_panel.py +3 -1
  37. wagtail/admin/static/wagtailadmin/css/core.css +1 -1
  38. wagtail/admin/static/wagtailadmin/js/bulk-actions.js +1 -1
  39. wagtail/admin/static/wagtailadmin/js/comments.js +1 -1
  40. wagtail/admin/static/wagtailadmin/js/core.js +1 -1
  41. wagtail/admin/static/wagtailadmin/js/core.js.LICENSE.txt +1 -1
  42. wagtail/admin/static/wagtailadmin/js/draftail.js +1 -1
  43. wagtail/admin/static/wagtailadmin/js/privacy-switch.js +1 -1
  44. wagtail/admin/static/wagtailadmin/js/sidebar.js +1 -1
  45. wagtail/admin/static/wagtailadmin/js/telepath/blocks.js +1 -1
  46. wagtail/admin/static/wagtailadmin/js/userbar.js +1 -1
  47. wagtail/admin/static/wagtailadmin/js/userbar.js.LICENSE.txt +1 -1
  48. wagtail/admin/static/wagtailadmin/js/vendor.js +1 -1
  49. wagtail/admin/static/wagtailadmin/js/wagtailadmin.js +1 -1
  50. wagtail/admin/templates/wagtailadmin/base.html +1 -1
  51. wagtail/admin/templates/wagtailadmin/generic/edit_partials.html +100 -0
  52. wagtail/admin/templates/wagtailadmin/generic/form.html +26 -5
  53. wagtail/admin/templates/wagtailadmin/generic/includes/_loaded_revision_inputs.html +3 -0
  54. wagtail/admin/templates/wagtailadmin/generic/listing_results.html +1 -17
  55. wagtail/admin/templates/wagtailadmin/pages/create.html +14 -4
  56. wagtail/admin/templates/wagtailadmin/pages/edit.html +16 -3
  57. wagtail/admin/templates/wagtailadmin/pages/edit_partials.html +31 -0
  58. wagtail/admin/templates/wagtailadmin/pages/index_results.html +1 -9
  59. wagtail/admin/templates/wagtailadmin/shared/autosave/indicator.html +36 -0
  60. wagtail/admin/templates/wagtailadmin/shared/breadcrumbs.html +1 -1
  61. wagtail/admin/templates/wagtailadmin/shared/editing_sessions/list.html +2 -2
  62. wagtail/admin/templates/wagtailadmin/shared/editing_sessions/module.html +19 -3
  63. wagtail/admin/templates/wagtailadmin/shared/headers/_actions.html +5 -0
  64. wagtail/admin/templates/wagtailadmin/shared/headers/_history_icon_link.html +2 -2
  65. wagtail/admin/templates/wagtailadmin/shared/headers/slim_header.html +8 -9
  66. wagtail/admin/templates/wagtailadmin/shared/listing/filter_partials.html +19 -0
  67. wagtail/admin/templates/wagtailadmin/shared/side_panel_toggle.html +3 -3
  68. wagtail/admin/templates/wagtailadmin/shared/side_panels/includes/side_panel.html +3 -0
  69. wagtail/admin/templates/wagtailadmin/shared/side_panels/includes/status/privacy.html +18 -6
  70. wagtail/admin/templates/wagtailadmin/shared/side_panels/includes/status/usage.html +11 -4
  71. wagtail/admin/templates/wagtailadmin/shared/side_panels/includes/status/workflow.html +22 -1
  72. wagtail/admin/templates/wagtailadmin/shared/side_panels/preview.html +1 -0
  73. wagtail/admin/templates/wagtailadmin/shared/side_panels.html +1 -2
  74. wagtail/admin/templates/wagtailadmin/shared/unsaved_changes_warning.html +20 -20
  75. wagtail/admin/templates/wagtailadmin/userbar/base.html +2 -0
  76. wagtail/admin/templates/wagtailadmin/userbar/item_accessibility.html +1 -1
  77. wagtail/admin/templatetags/wagtailadmin_tags.py +6 -14
  78. wagtail/admin/tests/pages/test_create_page.py +298 -1
  79. wagtail/admin/tests/pages/test_custom_listing.py +48 -2
  80. wagtail/admin/tests/pages/test_edit_page.py +721 -7
  81. wagtail/admin/tests/pages/test_explorer_view.py +9 -5
  82. wagtail/admin/tests/pages/test_page_search.py +15 -0
  83. wagtail/admin/tests/pages/test_revisions.py +4 -0
  84. wagtail/admin/tests/test_account_management.py +88 -2
  85. wagtail/admin/tests/test_collections_views.py +15 -15
  86. wagtail/admin/tests/test_compare.py +34 -0
  87. wagtail/admin/tests/test_editing_sessions.py +230 -8
  88. wagtail/admin/tests/test_forms.py +192 -1
  89. wagtail/admin/tests/test_icon_sprite.py +22 -2
  90. wagtail/admin/tests/test_page_chooser.py +13 -13
  91. wagtail/admin/tests/test_reports_views.py +4 -1
  92. wagtail/admin/tests/test_userbar.py +69 -5
  93. wagtail/admin/tests/test_views_generic.py +5 -5
  94. wagtail/admin/tests/test_workflows.py +14 -12
  95. wagtail/admin/tests/viewsets/test_model_viewset.py +13 -0
  96. wagtail/admin/ui/autosave.py +5 -0
  97. wagtail/admin/ui/editing_sessions.py +3 -0
  98. wagtail/admin/ui/side_panels.py +19 -20
  99. wagtail/admin/userbar.py +48 -27
  100. wagtail/admin/views/bulk_action/dispatcher.py +2 -2
  101. wagtail/admin/views/chooser.py +6 -6
  102. wagtail/admin/views/editing_sessions.py +20 -7
  103. wagtail/admin/views/generic/__init__.py +1 -0
  104. wagtail/admin/views/generic/chooser.py +5 -5
  105. wagtail/admin/views/generic/mixins.py +143 -26
  106. wagtail/admin/views/generic/models.py +157 -27
  107. wagtail/admin/views/generic/ordering.py +1 -1
  108. wagtail/admin/views/generic/preview.py +4 -4
  109. wagtail/admin/views/home.py +3 -1
  110. wagtail/admin/views/pages/create.py +77 -29
  111. wagtail/admin/views/pages/edit.py +160 -34
  112. wagtail/admin/views/pages/preview.py +4 -4
  113. wagtail/admin/views/pages/revisions.py +3 -0
  114. wagtail/admin/views/pages/search.py +4 -4
  115. wagtail/admin/views/pages/usage.py +2 -2
  116. wagtail/admin/views/tags.py +2 -2
  117. wagtail/admin/views/workflows.py +73 -54
  118. wagtail/admin/viewsets/model.py +34 -8
  119. wagtail/admin/widgets/button.py +11 -4
  120. wagtail/admin/widgets/chooser.py +6 -4
  121. wagtail/admin/widgets/slug.py +1 -1
  122. wagtail/api/v2/filters.py +27 -21
  123. wagtail/api/v2/pagination.py +4 -4
  124. wagtail/api/v2/views.py +7 -7
  125. wagtail/blocks/list_block.py +0 -8
  126. wagtail/blocks/migrations/migrate_operation.py +8 -1
  127. wagtail/blocks/stream_block.py +2 -10
  128. wagtail/blocks/struct_block.py +192 -12
  129. wagtail/compat.py +2 -2
  130. wagtail/contrib/forms/locale/en/LC_MESSAGES/django.po +1 -1
  131. wagtail/contrib/forms/locale/it/LC_MESSAGES/django.mo +0 -0
  132. wagtail/contrib/forms/locale/it/LC_MESSAGES/django.po +40 -2
  133. wagtail/contrib/frontend_cache/backends/azure.py +6 -6
  134. wagtail/contrib/frontend_cache/backends/cloudfront.py +2 -2
  135. wagtail/contrib/frontend_cache/utils.py +1 -1
  136. wagtail/contrib/redirects/forms.py +1 -1
  137. wagtail/contrib/redirects/locale/en/LC_MESSAGES/django.po +14 -14
  138. wagtail/contrib/redirects/locale/it/LC_MESSAGES/django.mo +0 -0
  139. wagtail/contrib/redirects/locale/it/LC_MESSAGES/django.po +15 -2
  140. wagtail/contrib/redirects/locale/sv/LC_MESSAGES/django.mo +0 -0
  141. wagtail/contrib/redirects/locale/sv/LC_MESSAGES/django.po +16 -3
  142. wagtail/contrib/redirects/middleware.py +11 -7
  143. wagtail/contrib/redirects/models.py +17 -1
  144. wagtail/contrib/redirects/tests/test_import_admin_views.py +3 -3
  145. wagtail/contrib/redirects/tests/test_redirects.py +56 -8
  146. wagtail/contrib/search_promotions/locale/en/LC_MESSAGES/django.po +6 -6
  147. wagtail/contrib/search_promotions/locale/it/LC_MESSAGES/django.mo +0 -0
  148. wagtail/contrib/search_promotions/locale/it/LC_MESSAGES/django.po +43 -2
  149. wagtail/contrib/search_promotions/tests.py +1 -1
  150. wagtail/contrib/search_promotions/views/settings.py +24 -25
  151. wagtail/contrib/settings/jinja2tags.py +2 -2
  152. wagtail/contrib/settings/locale/en/LC_MESSAGES/django.po +2 -2
  153. wagtail/contrib/settings/locale/it/LC_MESSAGES/django.mo +0 -0
  154. wagtail/contrib/settings/locale/it/LC_MESSAGES/django.po +6 -2
  155. wagtail/contrib/settings/locale/sv/LC_MESSAGES/django.mo +0 -0
  156. wagtail/contrib/settings/locale/sv/LC_MESSAGES/django.po +3 -2
  157. wagtail/contrib/settings/tests/generic/test_admin.py +118 -2
  158. wagtail/contrib/settings/tests/site_specific/test_admin.py +78 -15
  159. wagtail/contrib/settings/tests/site_specific/test_model.py +2 -2
  160. wagtail/contrib/settings/views.py +7 -0
  161. wagtail/contrib/simple_translation/locale/en/LC_MESSAGES/django.po +1 -1
  162. wagtail/contrib/simple_translation/locale/it/LC_MESSAGES/django.mo +0 -0
  163. wagtail/contrib/simple_translation/locale/it/LC_MESSAGES/django.po +5 -2
  164. wagtail/contrib/styleguide/locale/en/LC_MESSAGES/django.po +7 -7
  165. wagtail/contrib/styleguide/tests.py +2 -0
  166. wagtail/contrib/styleguide/views.py +4 -5
  167. wagtail/contrib/table_block/locale/ar/LC_MESSAGES/django.mo +0 -0
  168. wagtail/contrib/table_block/locale/ar/LC_MESSAGES/django.po +5 -1
  169. wagtail/contrib/table_block/locale/en/LC_MESSAGES/django.po +1 -1
  170. wagtail/contrib/table_block/locale/it/LC_MESSAGES/django.mo +0 -0
  171. wagtail/contrib/table_block/locale/it/LC_MESSAGES/django.po +5 -2
  172. wagtail/contrib/typed_table_block/blocks.py +37 -0
  173. wagtail/contrib/typed_table_block/locale/en/LC_MESSAGES/django.po +10 -10
  174. wagtail/contrib/typed_table_block/locale/sv/LC_MESSAGES/django.mo +0 -0
  175. wagtail/contrib/typed_table_block/locale/sv/LC_MESSAGES/django.po +4 -3
  176. wagtail/contrib/typed_table_block/tests.py +108 -0
  177. wagtail/coreutils.py +4 -4
  178. wagtail/documents/__init__.py +4 -4
  179. wagtail/documents/locale/en/LC_MESSAGES/django.po +15 -15
  180. wagtail/documents/locale/it/LC_MESSAGES/django.mo +0 -0
  181. wagtail/documents/locale/it/LC_MESSAGES/django.po +32 -2
  182. wagtail/documents/locale/sv/LC_MESSAGES/django.mo +0 -0
  183. wagtail/documents/locale/sv/LC_MESSAGES/django.po +32 -4
  184. wagtail/documents/models.py +1 -1
  185. wagtail/documents/tests/test_admin_views.py +19 -4
  186. wagtail/documents/tests/test_search.py +0 -2
  187. wagtail/documents/tests/test_views.py +6 -4
  188. wagtail/documents/views/bulk_actions/add_tags.py +1 -1
  189. wagtail/embeds/finders/facebook.py +3 -3
  190. wagtail/embeds/finders/instagram.py +3 -3
  191. wagtail/embeds/finders/oembed.py +7 -2
  192. wagtail/embeds/locale/en/LC_MESSAGES/django.po +1 -1
  193. wagtail/embeds/oembed_providers.py +8 -0
  194. wagtail/embeds/tests/test_embeds.py +35 -0
  195. wagtail/images/__init__.py +4 -4
  196. wagtail/images/admin_urls.py +3 -3
  197. wagtail/images/blocks.py +1 -1
  198. wagtail/images/formats.py +2 -2
  199. wagtail/images/image_operations.py +2 -2
  200. wagtail/images/locale/en/LC_MESSAGES/django.po +44 -40
  201. wagtail/images/locale/it/LC_MESSAGES/django.mo +0 -0
  202. wagtail/images/locale/it/LC_MESSAGES/django.po +50 -4
  203. wagtail/images/locale/nl/LC_MESSAGES/django.mo +0 -0
  204. wagtail/images/locale/nl/LC_MESSAGES/django.po +3 -3
  205. wagtail/images/locale/sv/LC_MESSAGES/django.mo +0 -0
  206. wagtail/images/locale/sv/LC_MESSAGES/django.po +49 -6
  207. wagtail/images/models.py +11 -10
  208. wagtail/images/templates/wagtailimages/images/index_results.html +1 -1
  209. wagtail/images/templates/wagtailimages/images/url_generator.html +17 -38
  210. wagtail/images/templates/wagtailimages/images/url_generator_output.html +28 -0
  211. wagtail/images/templatetags/wagtailimages_tags.py +4 -4
  212. wagtail/images/tests/test_admin_views.py +432 -59
  213. wagtail/images/tests/test_image_operations.py +2 -2
  214. wagtail/images/tests/test_models.py +0 -2
  215. wagtail/images/views/bulk_actions/add_tags.py +1 -1
  216. wagtail/images/views/images.py +72 -39
  217. wagtail/locale/en/LC_MESSAGES/django.po +103 -105
  218. wagtail/locale/it/LC_MESSAGES/django.mo +0 -0
  219. wagtail/locale/it/LC_MESSAGES/django.po +105 -2
  220. wagtail/locale/sv/LC_MESSAGES/django.mo +0 -0
  221. wagtail/locale/sv/LC_MESSAGES/django.po +95 -12
  222. wagtail/locales/locale/en/LC_MESSAGES/django.po +1 -1
  223. wagtail/locales/locale/it/LC_MESSAGES/django.mo +0 -0
  224. wagtail/locales/locale/it/LC_MESSAGES/django.po +13 -2
  225. wagtail/locales/locale/sv/LC_MESSAGES/django.mo +0 -0
  226. wagtail/locales/locale/sv/LC_MESSAGES/django.po +4 -3
  227. wagtail/locales/tests.py +5 -5
  228. wagtail/models/i18n.py +4 -6
  229. wagtail/models/media.py +18 -0
  230. wagtail/models/pages.py +65 -11
  231. wagtail/models/reference_index.py +15 -0
  232. wagtail/models/revisions.py +40 -12
  233. wagtail/models/workflows.py +0 -3
  234. wagtail/permission_policies/base.py +2 -2
  235. wagtail/permission_policies/collections.py +2 -2
  236. wagtail/project_template/requirements.txt +2 -2
  237. wagtail/search/locale/en/LC_MESSAGES/django.po +1 -1
  238. wagtail/signal_handlers.py +1 -0
  239. wagtail/sites/locale/en/LC_MESSAGES/django.po +1 -1
  240. wagtail/sites/locale/sv/LC_MESSAGES/django.mo +0 -0
  241. wagtail/sites/locale/sv/LC_MESSAGES/django.po +3 -2
  242. wagtail/sites/tests.py +7 -7
  243. wagtail/snippets/action_menu.py +2 -1
  244. wagtail/snippets/locale/en/LC_MESSAGES/django.po +23 -13
  245. wagtail/snippets/locale/sv/LC_MESSAGES/django.mo +0 -0
  246. wagtail/snippets/locale/sv/LC_MESSAGES/django.po +12 -1
  247. wagtail/snippets/tests/test_chooser_block.py +197 -0
  248. wagtail/snippets/tests/test_chooser_panel.py +149 -0
  249. wagtail/snippets/tests/test_chooser_views.py +375 -0
  250. wagtail/snippets/tests/test_chooser_widget.py +22 -0
  251. wagtail/snippets/tests/test_compare_revisions_view.py +167 -0
  252. wagtail/snippets/tests/test_copy_view.py +38 -0
  253. wagtail/snippets/tests/test_create_view.py +1159 -0
  254. wagtail/snippets/tests/test_delete_view.py +225 -0
  255. wagtail/snippets/tests/test_edit_view.py +2882 -0
  256. wagtail/snippets/tests/test_history_view.py +182 -0
  257. wagtail/snippets/tests/test_index_view.py +105 -0
  258. wagtail/snippets/tests/test_list_view.py +786 -0
  259. wagtail/snippets/tests/test_locking.py +28 -0
  260. wagtail/snippets/tests/test_permissions.py +167 -0
  261. wagtail/snippets/tests/test_preview.py +3 -3
  262. wagtail/snippets/tests/test_revert_view.py +343 -0
  263. wagtail/snippets/tests/test_snippet_models.py +112 -0
  264. wagtail/snippets/tests/test_unpublish_view.py +228 -0
  265. wagtail/snippets/tests/test_unschedule_view.py +151 -0
  266. wagtail/snippets/tests/test_viewset.py +38 -5
  267. wagtail/snippets/views/snippets.py +78 -30
  268. wagtail/snippets/widgets.py +2 -2
  269. wagtail/templatetags/wagtailcore_tags.py +2 -2
  270. wagtail/test/dummy_external_storage.py +1 -1
  271. wagtail/test/testapp/fixtures/test.json +22 -0
  272. wagtail/test/testapp/fixtures/test_empty.json +2 -0
  273. wagtail/test/testapp/fixtures/test_explorable_pages.json +10 -0
  274. wagtail/test/testapp/fixtures/test_specific.json +9 -0
  275. wagtail/test/testapp/migrations/0059_nopromotepage.py +25 -0
  276. wagtail/test/testapp/models.py +7 -0
  277. wagtail/test/testapp/views.py +5 -0
  278. wagtail/test/utils/page_tests.py +7 -7
  279. wagtail/test/utils/wagtail_factories/builder.py +2 -2
  280. wagtail/tests/streamfield_migrations/test_migrations.py +35 -0
  281. wagtail/tests/test_blocks.py +321 -61
  282. wagtail/tests/test_collection_model.py +12 -0
  283. wagtail/tests/test_page_model.py +190 -1
  284. wagtail/tests/test_page_privacy.py +5 -0
  285. wagtail/tests/test_reference_index.py +42 -0
  286. wagtail/tests/test_revision_model.py +118 -1
  287. wagtail/tests/test_utils.py +2 -2
  288. wagtail/users/locale/en/LC_MESSAGES/django.po +14 -14
  289. wagtail/users/locale/id_ID/LC_MESSAGES/django.mo +0 -0
  290. wagtail/users/locale/id_ID/LC_MESSAGES/django.po +6 -2
  291. wagtail/users/locale/it/LC_MESSAGES/django.mo +0 -0
  292. wagtail/users/locale/it/LC_MESSAGES/django.po +14 -2
  293. wagtail/users/locale/sv/LC_MESSAGES/django.mo +0 -0
  294. wagtail/users/locale/sv/LC_MESSAGES/django.po +48 -17
  295. wagtail/users/tests/test_admin_views.py +39 -25
  296. wagtail/users/utils.py +4 -1
  297. wagtail/users/views/groups.py +19 -5
  298. wagtail/users/wagtail_hooks.py +1 -1
  299. wagtail/utils/loading.py +2 -2
  300. wagtail-7.3rc1.data/data/AGENTS.md +21 -0
  301. wagtail-7.3rc1.data/data/CHANGELOG.txt +4941 -0
  302. wagtail-7.3rc1.data/data/CODE_OF_CONDUCT.md +71 -0
  303. wagtail-7.3rc1.data/data/CONTRIBUTORS.md +999 -0
  304. wagtail-7.3rc1.data/data/SPONSORS.md +55 -0
  305. {wagtail-7.2.1.dist-info → wagtail-7.3rc1.dist-info}/METADATA +6 -6
  306. {wagtail-7.2.1.dist-info → wagtail-7.3rc1.dist-info}/RECORD +310 -280
  307. {wagtail-7.2.1.dist-info → wagtail-7.3rc1.dist-info}/WHEEL +1 -1
  308. wagtail/images/static/wagtailimages/js/image-url-generator.js +0 -1
  309. wagtail/snippets/tests/test_snippets.py +0 -6377
  310. {wagtail-7.2.1.dist-info → wagtail-7.3rc1.dist-info}/entry_points.txt +0 -0
  311. {wagtail-7.2.1.dist-info → wagtail-7.3rc1.dist-info}/licenses/LICENSE +0 -0
  312. {wagtail-7.2.1.dist-info → wagtail-7.3rc1.dist-info}/top_level.txt +0 -0
@@ -21,6 +21,7 @@ from willow.optimizers.base import OptimizerBase
21
21
  from willow.registry import registry
22
22
 
23
23
  from wagtail.admin.admin_url_finder import AdminURLFinder
24
+ from wagtail.admin.staticfiles import versioned_static
24
25
  from wagtail.admin.ui.tables import Table
25
26
  from wagtail.images import get_image_model
26
27
  from wagtail.images.utils import generate_signature
@@ -60,7 +61,7 @@ class TestImageIndexView(WagtailTestUtils, TestCase):
60
61
  file=get_test_image_file(size=(1, 1)),
61
62
  )
62
63
 
63
- def get(self, params={}):
64
+ def get(self, params=None):
64
65
  return self.client.get(reverse("wagtailimages:index"), params)
65
66
 
66
67
  def test_simple(self):
@@ -656,6 +657,20 @@ class TestImageIndexView(WagtailTestUtils, TestCase):
656
657
  [unused_image],
657
658
  )
658
659
 
660
+ def test_bulk_action_rendered(self):
661
+ response = self.get()
662
+ self.assertEqual(response.status_code, 200)
663
+ # Should render bulk actions markup
664
+ bulk_actions_js = versioned_static("wagtailadmin/js/bulk-actions.js")
665
+ soup = self.get_soup(response.content)
666
+ script = soup.select_one(f"script[src='{bulk_actions_js}']")
667
+ self.assertIsNotNone(script)
668
+ bulk_actions = soup.select("[data-bulk-action-button]")
669
+ self.assertTrue(bulk_actions)
670
+ # 'next' parameter is constructed client-side later based on filters state
671
+ for action in bulk_actions:
672
+ self.assertNotIn("next=", action["href"])
673
+
659
674
 
660
675
  class TestBulkActionsColumn(WagtailTestUtils, TestCase):
661
676
  def setUp(self):
@@ -710,7 +725,7 @@ class TestImageIndexViewSearch(WagtailTestUtils, TransactionTestCase):
710
725
  self.puppy_image.created_at = local_datetime(2022, 2, 2)
711
726
  self.puppy_image.save()
712
727
 
713
- def get(self, params={}):
728
+ def get(self, params=None):
714
729
  return self.client.get(reverse("wagtailimages:index"), params)
715
730
 
716
731
  def test_search(self):
@@ -876,7 +891,7 @@ class TestImageListingResultsView(WagtailTestUtils, TransactionTestCase):
876
891
  def setUp(self):
877
892
  self.login()
878
893
 
879
- def get(self, params={}):
894
+ def get(self, params=None):
880
895
  return self.client.get(reverse("wagtailimages:index_results"), params)
881
896
 
882
897
  def test_search(self):
@@ -898,10 +913,10 @@ class TestImageAddView(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
898
913
  def setUp(self):
899
914
  self.login()
900
915
 
901
- def get(self, params={}):
916
+ def get(self, params=None):
902
917
  return self.client.get(reverse("wagtailimages:add"), params)
903
918
 
904
- def post(self, post_data={}):
919
+ def post(self, post_data=None):
905
920
  return self.client.post(reverse("wagtailimages:add"), post_data)
906
921
 
907
922
  def test_get(self):
@@ -1280,10 +1295,10 @@ class TestImageAddViewWithLimitedCollectionPermissions(WagtailTestUtils, TestCas
1280
1295
 
1281
1296
  self.login(username="moriarty", password="password")
1282
1297
 
1283
- def get(self, params={}):
1298
+ def get(self, params=None):
1284
1299
  return self.client.get(reverse("wagtailimages:add"), params)
1285
1300
 
1286
- def post(self, post_data={}):
1301
+ def post(self, post_data=None):
1287
1302
  return self.client.post(reverse("wagtailimages:add"), post_data)
1288
1303
 
1289
1304
  def test_get(self):
@@ -1348,12 +1363,12 @@ class TestImageEditView(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
1348
1363
  def update_from_db(self):
1349
1364
  self.image = Image.objects.get(pk=self.image.pk)
1350
1365
 
1351
- def get(self, params={}):
1366
+ def get(self, params=None):
1352
1367
  return self.client.get(
1353
1368
  reverse("wagtailimages:edit", args=(self.image.id,)), params
1354
1369
  )
1355
1370
 
1356
- def post(self, post_data={}):
1371
+ def post(self, post_data=None):
1357
1372
  return self.client.post(
1358
1373
  reverse("wagtailimages:edit", args=(self.image.id,)), post_data
1359
1374
  )
@@ -1739,7 +1754,7 @@ class TestImageEditViewWithCustomImageModel(WagtailTestUtils, TestCase):
1739
1754
 
1740
1755
  self.storage = self.image.file.storage
1741
1756
 
1742
- def get(self, params={}):
1757
+ def get(self, params=None):
1743
1758
  return self.client.get(
1744
1759
  reverse("wagtailimages:edit", args=(self.image.id,)), params
1745
1760
  )
@@ -1768,10 +1783,10 @@ class TestImageDeleteView(WagtailTestUtils, TestCase):
1768
1783
 
1769
1784
  self.delete_url = reverse("wagtailimages:delete", args=(self.image.id,))
1770
1785
 
1771
- def get(self, params={}):
1786
+ def get(self, params=None):
1772
1787
  return self.client.get(self.delete_url, params)
1773
1788
 
1774
- def post(self, post_data={}, **kwargs):
1789
+ def post(self, post_data=None, **kwargs):
1775
1790
  return self.client.post(self.delete_url, post_data, **kwargs)
1776
1791
 
1777
1792
  def test_simple(self):
@@ -1987,7 +2002,7 @@ class TestImageChooserView(WagtailTestUtils, TestCase):
1987
2002
  def setUp(self):
1988
2003
  self.user = self.login()
1989
2004
 
1990
- def get(self, params={}):
2005
+ def get(self, params=None):
1991
2006
  return self.client.get(reverse("wagtailimages_chooser:choose"), params)
1992
2007
 
1993
2008
  def test_simple(self):
@@ -2288,7 +2303,7 @@ class TestImageChooserViewSearch(WagtailTestUtils, TransactionTestCase):
2288
2303
  def setUp(self):
2289
2304
  self.user = self.login()
2290
2305
 
2291
- def get(self, params={}):
2306
+ def get(self, params=None):
2292
2307
  return self.client.get(reverse("wagtailimages_chooser:choose"), params)
2293
2308
 
2294
2309
  def test_construct_queryset_hook_search(self):
@@ -2324,7 +2339,7 @@ class TestImageChooserChosenView(WagtailTestUtils, TestCase):
2324
2339
  description="Test description",
2325
2340
  )
2326
2341
 
2327
- def get(self, params={}):
2342
+ def get(self, params=None):
2328
2343
  return self.client.get(
2329
2344
  reverse("wagtailimages_chooser:chosen", args=(self.image.id,)), params
2330
2345
  )
@@ -2383,7 +2398,7 @@ class TestImageChooserChosenMultipleView(WagtailTestUtils, TestCase):
2383
2398
  description="Unchosen test description",
2384
2399
  )
2385
2400
 
2386
- def get(self, params={}):
2401
+ def get(self, params=None):
2387
2402
  return self.client.get(
2388
2403
  "%s?id=%d&id=%d"
2389
2404
  % (
@@ -2416,13 +2431,13 @@ class TestImageChooserSelectFormatView(WagtailTestUtils, TestCase):
2416
2431
  file=get_test_image_file(),
2417
2432
  )
2418
2433
 
2419
- def get(self, params={}):
2434
+ def get(self, params=None):
2420
2435
  return self.client.get(
2421
2436
  reverse("wagtailimages_chooser:select_format", args=(self.image.id,)),
2422
2437
  params,
2423
2438
  )
2424
2439
 
2425
- def post(self, post_data={}):
2440
+ def post(self, post_data=None):
2426
2441
  return self.client.post(
2427
2442
  reverse("wagtailimages_chooser:select_format", args=(self.image.id,)),
2428
2443
  post_data,
@@ -2505,7 +2520,7 @@ class TestImageChooserUploadView(WagtailTestUtils, TestCase):
2505
2520
  def setUp(self):
2506
2521
  self.login()
2507
2522
 
2508
- def get(self, params={}):
2523
+ def get(self, params=None):
2509
2524
  return self.client.get(reverse("wagtailimages_chooser:create"), params)
2510
2525
 
2511
2526
  def test_simple(self):
@@ -3943,8 +3958,46 @@ class TestURLGeneratorView(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
3943
3958
  # Check response
3944
3959
  self.assertEqual(response.status_code, 200)
3945
3960
  self.assertTemplateUsed(response, "wagtailimages/images/url_generator.html")
3961
+ self.assertTemplateUsed(
3962
+ response, "wagtailimages/images/url_generator_output.html"
3963
+ )
3946
3964
  self.assertTemplateUsed(response, "wagtailadmin/generic/base.html")
3947
3965
 
3966
+ # Check form defaults are based on image with correct defaults are provided to context
3967
+ self.assertEqual(response.context["form"].initial["width"], self.image.width)
3968
+ self.assertEqual(response.context["form"].initial["height"], self.image.height)
3969
+ self.assertEqual(response.context["form"].initial["filter_method"], "original")
3970
+ self.assertEqual(response.context["form"].initial["closeness"], "0")
3971
+
3972
+ # Check the attributes on the root form for swap usage
3973
+ soup = self.get_soup(response.content)
3974
+ form = soup.find("form", {"id": "image-url-generator-form"})
3975
+ self.assertIsNotNone(form)
3976
+ self.assertIn("w-swap", form["data-controller"])
3977
+ self.assertEqual(form["data-w-swap-loading-class"], "loading")
3978
+ self.assertEqual(
3979
+ form["data-w-swap-messages-value"],
3980
+ '{"400": "The filter options you have selected are not valid."}',
3981
+ )
3982
+ self.assertEqual(
3983
+ form["data-w-swap-src-value"],
3984
+ reverse("wagtailimages:url_generator_output", args=(self.image.id,)),
3985
+ )
3986
+ self.assertEqual(
3987
+ form["data-w-swap-target-value"], "output[form='image-url-generator-form']"
3988
+ )
3989
+
3990
+ # Check that the correct URLs are provided to context to show the result and preview on initial load
3991
+ self.assertTrue(
3992
+ response.context["preview_url"].endswith(
3993
+ f"/images/{self.image.id}/preview/original/"
3994
+ )
3995
+ )
3996
+ self.assertTrue(
3997
+ response.context["result_url"].endswith(f"/{self.image.id}/original/")
3998
+ )
3999
+
4000
+ # Check that the breadcrumbs are correct
3948
4001
  self.assertBreadcrumbsItemsRendered(
3949
4002
  [
3950
4003
  {"url": reverse("wagtailimages:index"), "label": "Images"},
@@ -3964,6 +4017,75 @@ class TestURLGeneratorView(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
3964
4017
  self.assertEqual(closeness.get("min"), "0")
3965
4018
  self.assertEqual(closeness.get("max"), "100")
3966
4019
 
4020
+ def test_get_with_search_params(self):
4021
+ """
4022
+ This tests that the view responds correctly with support for search params to override
4023
+ the form initial values & generated preview/result URLs when partial params are provided.
4024
+ """
4025
+ # Get
4026
+ response = self.client.get(
4027
+ reverse("wagtailimages:url_generator", args=(self.image.id,))
4028
+ + "?filter_method=max&closeness=5"
4029
+ )
4030
+
4031
+ # Check response
4032
+ self.assertEqual(response.status_code, 200)
4033
+
4034
+ # Check form defaults are based based on the search params & image sizes
4035
+ self.assertEqual(response.context["form"].initial["width"], self.image.width)
4036
+ self.assertEqual(response.context["form"].initial["height"], self.image.height)
4037
+ self.assertEqual(response.context["form"].initial["filter_method"], "max")
4038
+ self.assertEqual(response.context["form"].initial["closeness"], "5")
4039
+
4040
+ # Check that the correct URLs are provided to context to show the result based on the search params
4041
+ # -c5 should not be included as it's not part of that filter spec
4042
+ filter_spec = "max-640x480"
4043
+
4044
+ self.assertTrue(
4045
+ response.context["preview_url"].endswith(
4046
+ f"/images/{self.image.id}/preview/{filter_spec}/"
4047
+ ),
4048
+ f"`{response.context['preview_url']}` does not end with `/images/{self.image.id}/preview/{filter_spec}/`",
4049
+ )
4050
+ self.assertTrue(
4051
+ response.context["result_url"].endswith(f"/{self.image.id}/{filter_spec}/"),
4052
+ f"`{response.context['result_url']}` does not end with `/{self.image.id}/{filter_spec}/`",
4053
+ )
4054
+
4055
+ def test_get_with_all_search_params(self):
4056
+ """
4057
+ This tests that the view responds correctly with support for search params to override
4058
+ the form initial values & generated preview/result URLs.
4059
+ """
4060
+ # Get
4061
+ response = self.client.get(
4062
+ reverse("wagtailimages:url_generator", args=(self.image.id,))
4063
+ + "?filter_method=fill&width=75&height=50&closeness=5"
4064
+ )
4065
+
4066
+ # Check response
4067
+ self.assertEqual(response.status_code, 200)
4068
+
4069
+ # Check form defaults are based based on the search params
4070
+ self.assertEqual(response.context["form"].initial["width"], "75")
4071
+ self.assertEqual(response.context["form"].initial["height"], "50")
4072
+ self.assertEqual(response.context["form"].initial["filter_method"], "fill")
4073
+ self.assertEqual(response.context["form"].initial["closeness"], "5")
4074
+
4075
+ # Check that the correct URLs are provided to context to show the result based on the search params
4076
+ filter_spec = "fill-75x50-c5"
4077
+
4078
+ self.assertTrue(
4079
+ response.context["preview_url"].endswith(
4080
+ f"/images/{self.image.id}/preview/{filter_spec}/"
4081
+ ),
4082
+ f"`{response.context['preview_url']}` does not end with `/images/{self.image.id}/preview/{filter_spec}/`",
4083
+ )
4084
+ self.assertTrue(
4085
+ response.context["result_url"].endswith(f"/{self.image.id}/{filter_spec}/"),
4086
+ f"`{response.context['result_url']}` does not end with `/{self.image.id}/{filter_spec}/`",
4087
+ )
4088
+
3967
4089
  def test_get_bad_permissions(self):
3968
4090
  """
3969
4091
  This tests that the view returns a "permission denied" redirect if a user without correct
@@ -3986,8 +4108,33 @@ class TestURLGeneratorView(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
3986
4108
  # Check response
3987
4109
  self.assertRedirects(response, reverse("wagtailadmin_home"))
3988
4110
 
4111
+ def test_get_with_bad_search_params(self):
4112
+ """
4113
+ This tests how the view responds when the search params
4114
+ result in an invalid filter spec.
4115
+ """
4116
+ # Get
4117
+ response = self.client.get(
4118
+ reverse("wagtailimages:url_generator", args=(self.image.id,))
4119
+ + "?filter_method=bad&width=75&height=50&closeness=5"
4120
+ )
4121
+
4122
+ # Check response
4123
+ self.assertEqual(response.status_code, 200)
4124
+
4125
+ # Check message provided
4126
+ messages = [m.message for m in response.context["messages"]]
4127
+ self.assertEqual(len(messages), 1)
4128
+ self.assertIn(
4129
+ "The filter options you have selected are not valid.", messages[0]
4130
+ )
4131
+
4132
+
4133
+ class TestURLGeneratorViewOutput(WagtailTestUtils, TestCase):
4134
+ """
4135
+ Test the output partial HTML response for swapping into the image URL generator page.
4136
+ """
3989
4137
 
3990
- class TestGenerateURLView(WagtailTestUtils, TestCase):
3991
4138
  def setUp(self):
3992
4139
  # Create an image for running tests on
3993
4140
  self.image = Image.objects.create(
@@ -4004,17 +4151,27 @@ class TestGenerateURLView(WagtailTestUtils, TestCase):
4004
4151
  """
4005
4152
  # Get
4006
4153
  response = self.client.get(
4007
- reverse("wagtailimages:generate_url", args=(self.image.id, "fill-800x600"))
4154
+ reverse(
4155
+ "wagtailimages:url_generator_output",
4156
+ args=(self.image.id,),
4157
+ )
4158
+ + "?filter_method=fill&width=800&height=600"
4008
4159
  )
4009
4160
 
4010
4161
  # Check response
4011
4162
  self.assertEqual(response.status_code, 200)
4012
- self.assertEqual(response["Content-Type"], "application/json")
4013
4163
 
4014
- # Check JSON
4015
- content_json = json.loads(response.content.decode())
4164
+ # should only use the 'output' template
4165
+ self.assertTemplateNotUsed(response, "wagtailimages/images/url_generator.html")
4166
+ self.assertTemplateUsed(
4167
+ response, "wagtailimages/images/url_generator_output.html"
4168
+ )
4169
+ self.assertTemplateNotUsed(response, "wagtailadmin/generic/base.html")
4016
4170
 
4017
- self.assertEqual(set(content_json.keys()), {"url", "preview_url"})
4171
+ soup = self.get_soup(response.content)
4172
+
4173
+ result_url = soup.find("textarea", {"id": "result-url"}).get_text()
4174
+ preview_url = soup.find("img")["src"]
4018
4175
 
4019
4176
  expected_url = (
4020
4177
  "http://localhost/images/%(signature)s/%(image_id)d/fill-800x600/"
@@ -4026,12 +4183,12 @@ class TestGenerateURLView(WagtailTestUtils, TestCase):
4026
4183
  "image_id": self.image.id,
4027
4184
  }
4028
4185
  )
4029
- self.assertEqual(content_json["url"], expected_url)
4186
+ self.assertEqual(result_url, expected_url)
4030
4187
 
4031
4188
  expected_preview_url = reverse(
4032
4189
  "wagtailimages:preview", args=(self.image.id, "fill-800x600")
4033
4190
  )
4034
- self.assertEqual(content_json["preview_url"], expected_preview_url)
4191
+ self.assertEqual(preview_url, expected_preview_url)
4035
4192
 
4036
4193
  def test_get_bad_permissions(self):
4037
4194
  """
@@ -4048,21 +4205,18 @@ class TestGenerateURLView(WagtailTestUtils, TestCase):
4048
4205
 
4049
4206
  # Get
4050
4207
  response = self.client.get(
4051
- reverse("wagtailimages:generate_url", args=(self.image.id, "fill-800x600"))
4208
+ reverse(
4209
+ "wagtailimages:url_generator_output",
4210
+ args=(self.image.id,),
4211
+ )
4212
+ + "?filter_method=fill&width=800&height=600"
4052
4213
  )
4053
4214
 
4054
4215
  # Check response
4055
4216
  self.assertEqual(response.status_code, 403)
4056
- self.assertEqual(response["Content-Type"], "application/json")
4057
-
4058
- # Check JSON
4059
- self.assertJSONEqual(
4217
+ self.assertEqual(
4060
4218
  response.content.decode(),
4061
- json.dumps(
4062
- {
4063
- "error": "You do not have permission to generate a URL for this image.",
4064
- }
4065
- ),
4219
+ "You do not have permission to generate a URL for this image.",
4066
4220
  )
4067
4221
 
4068
4222
  def test_get_bad_image(self):
@@ -4072,23 +4226,14 @@ class TestGenerateURLView(WagtailTestUtils, TestCase):
4072
4226
  # Get
4073
4227
  response = self.client.get(
4074
4228
  reverse(
4075
- "wagtailimages:generate_url", args=(self.image.id + 1, "fill-800x600")
4229
+ "wagtailimages:url_generator_output",
4230
+ args=(self.image.id + 1,),
4076
4231
  )
4232
+ + "?filter_method=fill&width=800&height=600"
4077
4233
  )
4078
4234
 
4079
4235
  # Check response
4080
4236
  self.assertEqual(response.status_code, 404)
4081
- self.assertEqual(response["Content-Type"], "application/json")
4082
-
4083
- # Check JSON
4084
- self.assertJSONEqual(
4085
- response.content.decode(),
4086
- json.dumps(
4087
- {
4088
- "error": "Cannot find image.",
4089
- }
4090
- ),
4091
- )
4092
4237
 
4093
4238
  def test_get_bad_filter_spec(self):
4094
4239
  """
@@ -4097,23 +4242,251 @@ class TestGenerateURLView(WagtailTestUtils, TestCase):
4097
4242
  # Get
4098
4243
  response = self.client.get(
4099
4244
  reverse(
4100
- "wagtailimages:generate_url", args=(self.image.id, "bad-filter-spec")
4245
+ "wagtailimages:url_generator_output",
4246
+ args=(self.image.id,),
4101
4247
  )
4248
+ + "?filter_method=bad-filter-spec"
4102
4249
  )
4103
4250
 
4104
4251
  # Check response
4105
4252
  self.assertEqual(response.status_code, 400)
4106
- self.assertEqual(response["Content-Type"], "application/json")
4107
-
4108
- # Check JSON
4109
- self.assertJSONEqual(
4253
+ self.assertEqual(
4110
4254
  response.content.decode(),
4111
- json.dumps(
4112
- {
4113
- "error": "Invalid filter spec.",
4114
- }
4115
- ),
4255
+ "Invalid filter spec: `bad-filter-spec`. Unrecognised operation: bad.",
4256
+ )
4257
+
4258
+ def test_get_with_default_filter_spec(self):
4259
+ response = self.client.get(
4260
+ reverse("wagtailimages:url_generator_output", args=(self.image.id,))
4261
+ )
4262
+
4263
+ # check response and find key values
4264
+ self.assertEqual(response.status_code, 200)
4265
+ soup = self.get_soup(response.content)
4266
+
4267
+ # check the result URL from the textarea
4268
+ result_url = soup.find("textarea", {"id": "result-url"}).get_text()
4269
+ expected_url = (
4270
+ "http://localhost/images/%(signature)s/%(image_id)d/original/"
4271
+ % {
4272
+ "signature": urllib.parse.quote(
4273
+ generate_signature(self.image.id, "original"),
4274
+ safe=urlquote_safechars,
4275
+ ),
4276
+ "image_id": self.image.id,
4277
+ }
4278
+ )
4279
+ self.assertEqual(result_url, expected_url)
4280
+
4281
+ # check the preview URL from the image
4282
+ preview_url = soup.find("img")["src"]
4283
+ expected_preview_url = reverse(
4284
+ "wagtailimages:preview", args=(self.image.id, "original")
4285
+ )
4286
+ self.assertEqual(preview_url, expected_preview_url)
4287
+
4288
+ def test_get_with_width_filter_spec(self):
4289
+ response = self.client.get(
4290
+ reverse("wagtailimages:url_generator_output", args=(self.image.id,))
4291
+ + "?filter_method=width&width=800&height=300"
4292
+ # height should be ignored as it's not part of the width filter spec values
4293
+ )
4294
+
4295
+ # check response and find key values
4296
+ self.assertEqual(response.status_code, 200)
4297
+ soup = self.get_soup(response.content)
4298
+
4299
+ # check the result URL from the textarea
4300
+ result_url = soup.find("textarea", {"id": "result-url"}).get_text()
4301
+ expected_url = (
4302
+ "http://localhost/images/%(signature)s/%(image_id)d/width-800/"
4303
+ % {
4304
+ "signature": urllib.parse.quote(
4305
+ generate_signature(self.image.id, "width-800"),
4306
+ safe=urlquote_safechars,
4307
+ ),
4308
+ "image_id": self.image.id,
4309
+ }
4310
+ )
4311
+ self.assertEqual(result_url, expected_url)
4312
+
4313
+ # check the preview URL from the image
4314
+ preview_url = soup.find("img")["src"]
4315
+ expected_preview_url = reverse(
4316
+ "wagtailimages:preview", args=(self.image.id, "width-800")
4317
+ )
4318
+ self.assertEqual(preview_url, expected_preview_url)
4319
+
4320
+ def test_get_with_height_filter_spec(self):
4321
+ response = self.client.get(
4322
+ reverse("wagtailimages:url_generator_output", args=(self.image.id,))
4323
+ + "?filter_method=height&width=800&height=320&closeness=20"
4324
+ # width & closeness should be ignored as it's not part of the height filter spec values
4325
+ )
4326
+
4327
+ # check response and find key values
4328
+ self.assertEqual(response.status_code, 200)
4329
+ soup = self.get_soup(response.content)
4330
+
4331
+ # check the result URL from the textarea
4332
+ result_url = soup.find("textarea", {"id": "result-url"}).get_text()
4333
+ expected_url = (
4334
+ "http://localhost/images/%(signature)s/%(image_id)d/height-320/"
4335
+ % {
4336
+ "signature": urllib.parse.quote(
4337
+ generate_signature(self.image.id, "height-320"),
4338
+ safe=urlquote_safechars,
4339
+ ),
4340
+ "image_id": self.image.id,
4341
+ }
4342
+ )
4343
+ self.assertEqual(result_url, expected_url)
4344
+
4345
+ # check the preview URL from the image
4346
+ preview_url = soup.find("img")["src"]
4347
+ expected_preview_url = reverse(
4348
+ "wagtailimages:preview", args=(self.image.id, "height-320")
4349
+ )
4350
+ self.assertEqual(preview_url, expected_preview_url)
4351
+
4352
+ def test_get_with_fill_with_defaults_filter_spec(self):
4353
+ """
4354
+ When only the `fill` filter spec is provided on its own, it should
4355
+ resolve default width & height values from the image size.
4356
+ """
4357
+
4358
+ response = self.client.get(
4359
+ reverse("wagtailimages:url_generator_output", args=(self.image.id,))
4360
+ + "?filter_method=fill"
4361
+ )
4362
+
4363
+ # check response and find key values
4364
+ self.assertEqual(response.status_code, 200)
4365
+ soup = self.get_soup(response.content)
4366
+
4367
+ # check the result URL from the textarea
4368
+ result_url = soup.find("textarea", {"id": "result-url"}).get_text()
4369
+ expected_url = (
4370
+ "http://localhost/images/%(signature)s/%(image_id)d/fill-640x480/"
4371
+ % {
4372
+ "signature": urllib.parse.quote(
4373
+ generate_signature(self.image.id, "fill-640x480"),
4374
+ safe=urlquote_safechars,
4375
+ ),
4376
+ "image_id": self.image.id,
4377
+ }
4378
+ )
4379
+ self.assertEqual(result_url, expected_url)
4380
+
4381
+ # check the preview URL from the image
4382
+ preview_url = soup.find("img")["src"]
4383
+ expected_preview_url = reverse(
4384
+ "wagtailimages:preview", args=(self.image.id, "fill-640x480")
4385
+ )
4386
+ self.assertEqual(preview_url, expected_preview_url)
4387
+
4388
+ def test_get_with_min_with_defaults_filter_spec(self):
4389
+ """
4390
+ When only the `min` filter spec is provided on its own, it should
4391
+ resolve default width & height values from the image size.
4392
+ """
4393
+
4394
+ response = self.client.get(
4395
+ reverse("wagtailimages:url_generator_output", args=(self.image.id,))
4396
+ + "?filter_method=min"
4397
+ )
4398
+
4399
+ # check response and find key values
4400
+ self.assertEqual(response.status_code, 200)
4401
+ soup = self.get_soup(response.content)
4402
+
4403
+ # check the result URL from the textarea
4404
+ result_url = soup.find("textarea", {"id": "result-url"}).get_text()
4405
+ expected_url = (
4406
+ "http://localhost/images/%(signature)s/%(image_id)d/min-640x480/"
4407
+ % {
4408
+ "signature": urllib.parse.quote(
4409
+ generate_signature(self.image.id, "min-640x480"),
4410
+ safe=urlquote_safechars,
4411
+ ),
4412
+ "image_id": self.image.id,
4413
+ }
4414
+ )
4415
+ self.assertEqual(result_url, expected_url)
4416
+
4417
+ # check the preview URL from the image
4418
+ preview_url = soup.find("img")["src"]
4419
+ expected_preview_url = reverse(
4420
+ "wagtailimages:preview", args=(self.image.id, "min-640x480")
4421
+ )
4422
+ self.assertEqual(preview_url, expected_preview_url)
4423
+
4424
+ def test_get_with_max_with_defaults_filter_spec(self):
4425
+ """
4426
+ When only the `max` filter spec is provided on its own, it should
4427
+ resolve default width & height values from the image size.
4428
+ """
4429
+
4430
+ response = self.client.get(
4431
+ reverse("wagtailimages:url_generator_output", args=(self.image.id,))
4432
+ + "?filter_method=max"
4433
+ )
4434
+
4435
+ # check response and find key values
4436
+ self.assertEqual(response.status_code, 200)
4437
+ soup = self.get_soup(response.content)
4438
+
4439
+ # check the result URL from the textarea
4440
+ result_url = soup.find("textarea", {"id": "result-url"}).get_text()
4441
+ expected_url = (
4442
+ "http://localhost/images/%(signature)s/%(image_id)d/max-640x480/"
4443
+ % {
4444
+ "signature": urllib.parse.quote(
4445
+ generate_signature(self.image.id, "max-640x480"),
4446
+ safe=urlquote_safechars,
4447
+ ),
4448
+ "image_id": self.image.id,
4449
+ }
4450
+ )
4451
+ self.assertEqual(result_url, expected_url)
4452
+
4453
+ # check the preview URL from the image
4454
+ preview_url = soup.find("img")["src"]
4455
+ expected_preview_url = reverse(
4456
+ "wagtailimages:preview", args=(self.image.id, "max-640x480")
4457
+ )
4458
+ self.assertEqual(preview_url, expected_preview_url)
4459
+
4460
+ def test_get_with_fill_with_all_values_filter_spec(self):
4461
+ response = self.client.get(
4462
+ reverse("wagtailimages:url_generator_output", args=(self.image.id,))
4463
+ + "?filter_method=fill&width=320&height=120&closeness=20"
4464
+ )
4465
+
4466
+ # check response and find key values
4467
+ self.assertEqual(response.status_code, 200)
4468
+ soup = self.get_soup(response.content)
4469
+
4470
+ # check the result URL from the textarea
4471
+ result_url = soup.find("textarea", {"id": "result-url"}).get_text()
4472
+ expected_url = (
4473
+ "http://localhost/images/%(signature)s/%(image_id)d/fill-320x120-c20/"
4474
+ % {
4475
+ "signature": urllib.parse.quote(
4476
+ generate_signature(self.image.id, "fill-320x120-c20"),
4477
+ safe=urlquote_safechars,
4478
+ ),
4479
+ "image_id": self.image.id,
4480
+ }
4481
+ )
4482
+ self.assertEqual(result_url, expected_url)
4483
+
4484
+ # check the preview URL from the image
4485
+ preview_url = soup.find("img")["src"]
4486
+ expected_preview_url = reverse(
4487
+ "wagtailimages:preview", args=(self.image.id, "fill-320x120-c20")
4116
4488
  )
4489
+ self.assertEqual(preview_url, expected_preview_url)
4117
4490
 
4118
4491
 
4119
4492
  class TestPreviewView(WagtailTestUtils, TestCase):