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
@@ -7,7 +7,7 @@
7
7
  # Giacomo Ghizzani <giacomo.ghz@gmail.com>, 2015,2017
8
8
  # giammi <gian-maria.daffre@giammi.org>, 2018
9
9
  # giammi <gian-maria.daffre@giammi.org>, 2018
10
- # Marco Badan <marco.badan@gmail.com>, 2021-2022,2024
10
+ # Marco Badan <marco.badan@gmail.com>, 2021-2022,2024,2026
11
11
  # Sandro Badalamenti <sandro@mailinator.com>, 2019
12
12
  msgid ""
13
13
  msgstr ""
@@ -15,7 +15,7 @@ msgstr ""
15
15
  "Report-Msgid-Bugs-To: \n"
16
16
  "POT-Creation-Date: 2025-10-23 16:45+0100\n"
17
17
  "PO-Revision-Date: 2015-08-26 14:04+0000\n"
18
- "Last-Translator: Marco Badan <marco.badan@gmail.com>, 2021-2022,2024\n"
18
+ "Last-Translator: Marco Badan <marco.badan@gmail.com>, 2021-2022,2024,2026\n"
19
19
  "Language-Team: Italian (http://app.transifex.com/torchbox/wagtail/language/"
20
20
  "it/)\n"
21
21
  "MIME-Version: 1.0\n"
@@ -39,6 +39,11 @@ msgstr ""
39
39
  "corrispondenza esatta per visualizzare i risultati in evidenza, i caratteri "
40
40
  "wildcard NON sono consentiti."
41
41
 
42
+ msgid "You must enter an external link text if you enter an external link URL."
43
+ msgstr ""
44
+ "Devi inserire il testo del collegamento se inserisci l'URL di un "
45
+ "collegamento esterno."
46
+
42
47
  msgid "You must recommend a page OR an external link."
43
48
  msgstr "Devi consigliare una pagina O un collegamento esterno."
44
49
 
@@ -54,15 +59,36 @@ msgstr "Query giornaliere"
54
59
  msgid "page"
55
60
  msgstr "pagina"
56
61
 
62
+ msgid "Choose an internal page for this promotion"
63
+ msgstr "Scegli una pagina interna per questa promozione"
64
+
57
65
  msgid "External link URL"
58
66
  msgstr "Collegamento esterno"
59
67
 
68
+ msgid "Alternatively, use an external link for this promotion"
69
+ msgstr "In alternativa, usa un collegamento esterno per questa promozione"
70
+
60
71
  msgid "description"
61
72
  msgstr "descrizione"
62
73
 
74
+ msgid "Applies to internal page or external link"
75
+ msgstr "Si applica a pagina interna o collegamento esterno"
76
+
63
77
  msgid "search promotion"
64
78
  msgstr "ricerca in evidenza"
65
79
 
80
+ msgid ""
81
+ "<p>Promoted search results are a means of recommending specific pages or "
82
+ "external links that might not organically come high up in search results. "
83
+ "E.g recommending your primary donation page to a user searching with the "
84
+ "less common term \"<em>giving</em>\".</p>"
85
+ msgstr ""
86
+ "<p>I risultati di ricerca promossi sono un mezzo per raccomandare pagine "
87
+ "specifiche o collegamenti esterni che potrebbero non apparire in alto nei "
88
+ "risultati organici. Es. raccomandare la tua pagina principale delle "
89
+ "donazioni a un utente che cerca con il termine meno comune \"<em>elargire</"
90
+ "em>\".</p>"
91
+
66
92
  msgid ""
67
93
  "<p>The \"Search term(s)/phrase\" field below must contain the full and exact "
68
94
  "search for which you wish to provide recommended results, <em>including</em> "
@@ -120,6 +146,9 @@ msgstr ""
120
146
  "Non è stato creato nessun risultato in evidenza. Perché non ne <a "
121
147
  "href=\"%(wagtailsearchpromotions_add_url)s\">aggiungi uno</a>?"
122
148
 
149
+ msgid "No promoted results have been created."
150
+ msgstr "Non sono stati creati risultati promossi."
151
+
123
152
  msgid "Popular search terms"
124
153
  msgstr "Termini di ricerca popolari"
125
154
 
@@ -129,6 +158,9 @@ msgstr "Cerca"
129
158
  msgid "Terms"
130
159
  msgstr "Termini"
131
160
 
161
+ msgid "Views"
162
+ msgstr "Visualizzazioni"
163
+
132
164
  msgid "No results found"
133
165
  msgstr "Nessun risultato"
134
166
 
@@ -144,6 +176,9 @@ msgstr "Nessuno"
144
176
  msgid "Date"
145
177
  msgstr "Data"
146
178
 
179
+ msgid "Search terms"
180
+ msgstr "Termini di ricerca"
181
+
147
182
  msgid "Search term(s)"
148
183
  msgstr "Termine(i) di ricerca"
149
184
 
@@ -160,9 +195,15 @@ msgstr "Risultati di ricerca in evidenza"
160
195
  msgid "Editor's picks for '%(query)s' created."
161
196
  msgstr "Scelta dalla redazione per '%(query)s' creata."
162
197
 
198
+ msgid "Recommendations have not been created due to errors."
199
+ msgstr "Le raccomandazioni non sono state create a causa di errori."
200
+
163
201
  #, python-format
164
202
  msgid "Editor's picks for '%(query)s' updated."
165
203
  msgstr "Scelta dalla redazione per '%(query)s' aggiornata."
166
204
 
205
+ msgid "Recommendations have not been saved due to errors."
206
+ msgstr "Le raccomandazioni non sono state salvate a causa di errori."
207
+
167
208
  msgid "Editor's picks deleted."
168
209
  msgstr "Scelte dalla redazione eliminate."
@@ -1501,7 +1501,7 @@ class TestQueryChooserView(WagtailTestUtils, TestCase):
1501
1501
  def setUp(self):
1502
1502
  self.login()
1503
1503
 
1504
- def get(self, params={}):
1504
+ def get(self, params=None):
1505
1505
  return self.client.get("/admin/searchpicks/queries/chooser/", params)
1506
1506
 
1507
1507
  def test_simple(self):
@@ -96,12 +96,6 @@ class SearchPromotionCreateEditMixin:
96
96
  def get_success_message(self, instance=None):
97
97
  return self.success_message % {"query": instance}
98
98
 
99
- def get_error_message(self):
100
- if formset_errors := self.searchpicks_formset.non_form_errors():
101
- # formset level error (e.g. no forms submitted)
102
- return " ".join(error for error in formset_errors)
103
- return super().get_error_message()
104
-
105
99
  def get_breadcrumbs_items(self):
106
100
  breadcrumbs = super().get_breadcrumbs_items()
107
101
  breadcrumbs[-2]["label"] = IndexView.page_title
@@ -113,10 +107,23 @@ class SearchPromotionCreateEditMixin:
113
107
  context["media"] += self.searchpicks_formset.media
114
108
  return context
115
109
 
110
+ def is_valid(self, form):
111
+ if not super().is_valid(form):
112
+ return False
113
+
114
+ self.new_query = Query.get(form.cleaned_data["query_string"])
115
+ if not self.object:
116
+ self.object = self.new_query
117
+
118
+ result = self.searchpicks_formset.is_valid()
119
+ if not result:
120
+ formset_errors = self.searchpicks_formset.non_form_errors()
121
+ self.produced_error_message = " ".join(error for error in formset_errors)
122
+
123
+ return result
124
+
116
125
  def save_searchpicks(self, query, new_query):
117
126
  searchpicks_formset = self.searchpicks_formset
118
- if not searchpicks_formset.is_valid():
119
- return False
120
127
 
121
128
  # Set sort_order
122
129
  for i, form in enumerate(searchpicks_formset.ordered_forms):
@@ -152,8 +159,6 @@ class SearchPromotionCreateEditMixin:
152
159
  if changed_fields:
153
160
  log(search_pick, "wagtail.edit")
154
161
 
155
- return True
156
-
157
162
  @cached_property
158
163
  def searchpicks_formset(self):
159
164
  if self.request.method == "POST":
@@ -164,19 +169,13 @@ class SearchPromotionCreateEditMixin:
164
169
 
165
170
  def form_valid(self, form):
166
171
  self.form = form
167
- new_query = Query.get(form.cleaned_data["query_string"])
168
- if not self.object:
169
- self.object = new_query
170
-
171
- if self.save_searchpicks(self.object, new_query):
172
- messages.success(
173
- self.request,
174
- self.get_success_message(self.object),
175
- buttons=self.get_success_buttons(),
176
- )
177
- return redirect(self.index_url_name)
178
-
179
- return super().form_invalid(form)
172
+ self.save_searchpicks(self.object, self.new_query)
173
+ messages.success(
174
+ self.request,
175
+ self.get_success_message(self.object),
176
+ buttons=self.get_success_buttons(),
177
+ )
178
+ return redirect(self.index_url_name)
180
179
 
181
180
 
182
181
  class CreateView(SearchPromotionCreateEditMixin, generic.CreateView):
@@ -232,8 +231,8 @@ def chooser(request, get_results=False):
232
231
  paginator = Paginator(queries, per_page=10)
233
232
  try:
234
233
  queries = paginator.page(request.GET.get("p", 1))
235
- except InvalidPage:
236
- raise Http404
234
+ except InvalidPage as e:
235
+ raise Http404 from e
237
236
 
238
237
  # Render
239
238
  if get_results:
@@ -39,8 +39,8 @@ class Setting(dict):
39
39
  """
40
40
  try:
41
41
  app_label, model_name = key.split(".", 1)
42
- except ValueError:
43
- raise KeyError(f"Invalid model name: `{key}`")
42
+ except ValueError as e:
43
+ raise KeyError(f"Invalid model name: `{key}`") from e
44
44
 
45
45
  Model = registry.get_by_natural_key(app_label, model_name)
46
46
  if Model is None:
@@ -8,7 +8,7 @@ msgid ""
8
8
  msgstr ""
9
9
  "Project-Id-Version: PACKAGE VERSION\n"
10
10
  "Report-Msgid-Bugs-To: \n"
11
- "POT-Creation-Date: 2025-10-23 16:45+0100\n"
11
+ "POT-Creation-Date: 2026-01-21 18:00+0000\n"
12
12
  "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13
13
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
14
  "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -53,7 +53,7 @@ msgstr ""
53
53
  msgid "The setting could not be saved due to errors."
54
54
  msgstr ""
55
55
 
56
- #: views.py:175
56
+ #: views.py:182
57
57
  #, python-format
58
58
  msgid "%(setting_type)s updated."
59
59
  msgstr ""
@@ -10,7 +10,7 @@
10
10
  # Giacomo Ghizzani <giacomo.ghz@gmail.com>, 2016
11
11
  # giammi <gian-maria.daffre@giammi.org>, 2018
12
12
  # giammi <gian-maria.daffre@giammi.org>, 2018
13
- # Marco Badan <marco.badan@gmail.com>, 2022
13
+ # Marco Badan <marco.badan@gmail.com>, 2022,2026
14
14
  # Marco Lerco <marcolerco@gmail.com>, 2021
15
15
  # Stefano Marchetto <airbatum@gmail.com>, 2020
16
16
  msgid ""
@@ -19,7 +19,7 @@ msgstr ""
19
19
  "Report-Msgid-Bugs-To: \n"
20
20
  "POT-Creation-Date: 2025-10-23 16:45+0100\n"
21
21
  "PO-Revision-Date: 2016-03-01 19:20+0000\n"
22
- "Last-Translator: Stefano Marchetto <airbatum@gmail.com>, 2020\n"
22
+ "Last-Translator: Marco Badan <marco.badan@gmail.com>, 2022,2026\n"
23
23
  "Language-Team: Italian (http://app.transifex.com/torchbox/wagtail/language/"
24
24
  "it/)\n"
25
25
  "MIME-Version: 1.0\n"
@@ -35,6 +35,10 @@ msgstr "default"
35
35
  msgid "Sites"
36
36
  msgstr "Siti"
37
37
 
38
+ #, python-format
39
+ msgid "%(model)s permissions"
40
+ msgstr "%(model)s permessi"
41
+
38
42
  #, python-format
39
43
  msgid "%(site_setting)s for %(site)s"
40
44
  msgstr "%(site_setting)s per %(site)s"
@@ -5,6 +5,7 @@
5
5
  # Translators:
6
6
  # Andreas Bergström <andreas.bergstrom@gmail.com>, 2018
7
7
  # André Karlsson <andre@sess.se>, 2017
8
+ # Jonathan Lindén, 2025
8
9
  # Martin Sandström <martin@marteinn.se>, 2020
9
10
  # Philip Andersen <renegadevi@codeofmagi.net>, 2018-2019,2022
10
11
  # Thomas Kunambi <kunambi@gmail.com>, 2016,2022
@@ -14,7 +15,7 @@ msgstr ""
14
15
  "Report-Msgid-Bugs-To: \n"
15
16
  "POT-Creation-Date: 2025-10-23 16:45+0100\n"
16
17
  "PO-Revision-Date: 2016-03-01 19:20+0000\n"
17
- "Last-Translator: Thomas Kunambi <kunambi@gmail.com>, 2016,2022\n"
18
+ "Last-Translator: Jonathan Lindén, 2025\n"
18
19
  "Language-Team: Swedish (http://app.transifex.com/torchbox/wagtail/language/"
19
20
  "sv/)\n"
20
21
  "MIME-Version: 1.0\n"
@@ -45,7 +46,7 @@ msgstr ""
45
46
  "definierad webbplats."
46
47
 
47
48
  msgid "The setting could not be saved due to errors."
48
- msgstr "Inställningen kunde inte sparas ett fel uppstod."
49
+ msgstr "Inställningen kunde inte sparas grund av fel."
49
50
 
50
51
  #, python-format
51
52
  msgid "%(setting_type)s updated."
@@ -1,4 +1,5 @@
1
1
  from django.contrib.auth.models import Group, Permission
2
+ from django.http import HttpRequest, HttpResponse
2
3
  from django.test import TestCase
3
4
  from django.urls import reverse
4
5
  from django.utils.text import capfirst
@@ -60,11 +61,11 @@ class TestGenericSettingMenu(WagtailTestUtils, TestCase):
60
61
 
61
62
 
62
63
  class BaseTestGenericSettingView(WagtailTestUtils, TestCase):
63
- def get(self, params={}, setting=TestGenericSetting):
64
+ def get(self, params=None, setting=TestGenericSetting):
64
65
  url = self.edit_url(setting=setting)
65
66
  return self.client.get(url, params)
66
67
 
67
- def post(self, post_data={}, setting=TestGenericSetting):
68
+ def post(self, post_data=None, setting=TestGenericSetting):
68
69
  url = self.edit_url(setting=setting)
69
70
  return self.client.post(url, post_data)
70
71
 
@@ -211,6 +212,64 @@ class TestGenericSettingCreateView(BaseTestGenericSettingView):
211
212
  self.assertEqual(settings.title, "test")
212
213
  self.assertEqual(settings.sensitive_email, "test@example.com")
213
214
 
215
+ def test_before_edit_setting_hook_get(self):
216
+ def hook_func(request, instance):
217
+ self.assertIsInstance(request, HttpRequest)
218
+ self.assertEqual(instance.title, "")
219
+ self.assertEqual(instance.email, "")
220
+ return HttpResponse("Overridden!")
221
+
222
+ with self.register_hook("before_edit_setting", hook_func):
223
+ response = self.get()
224
+
225
+ self.assertEqual(response.status_code, 200)
226
+ self.assertEqual(response.content, b"Overridden!")
227
+
228
+ def test_before_edit_setting_hook_post(self):
229
+ def hook_func(request, instance):
230
+ self.assertIsInstance(request, HttpRequest)
231
+ self.assertEqual(instance.title, "")
232
+ self.assertEqual(instance.email, "")
233
+ return HttpResponse("Overridden!")
234
+
235
+ with self.register_hook("before_edit_setting", hook_func):
236
+ response = self.post(
237
+ post_data={
238
+ "title": "Setting title",
239
+ "email": "email@example.com",
240
+ }
241
+ )
242
+
243
+ self.assertEqual(response.status_code, 200)
244
+ self.assertEqual(response.content, b"Overridden!")
245
+
246
+ # Request intercepted before advert was updated
247
+ self.assertEqual(TestGenericSetting.load().title, "")
248
+ self.assertEqual(TestGenericSetting.load().email, "")
249
+
250
+ def test_after_edit_setting_hook(self):
251
+ def hook_func(request, instance):
252
+ self.assertIsInstance(request, HttpRequest)
253
+ self.assertIsNotNone(instance.pk)
254
+ self.assertEqual(instance.title, "Setting title")
255
+ self.assertEqual(instance.email, "email@example.com")
256
+ return HttpResponse("Overridden!")
257
+
258
+ with self.register_hook("after_edit_setting", hook_func):
259
+ response = self.post(
260
+ post_data={
261
+ "title": "Setting title",
262
+ "email": "email@example.com",
263
+ }
264
+ )
265
+
266
+ self.assertEqual(response.status_code, 200)
267
+ self.assertEqual(response.content, b"Overridden!")
268
+
269
+ # Request intercepted after advert was updated
270
+ self.assertEqual(TestGenericSetting.load().title, "Setting title")
271
+ self.assertEqual(TestGenericSetting.load().email, "email@example.com")
272
+
214
273
 
215
274
  class TestGenericSettingEditView(BaseTestGenericSettingView):
216
275
  def setUp(self):
@@ -374,6 +433,63 @@ class TestGenericSettingEditView(BaseTestGenericSettingView):
374
433
  self.assertEqual(test_setting.sensitive_email, "test@example.com")
375
434
  self.assertEqual(test_setting.title, "Old title")
376
435
 
436
+ def test_before_edit_setting_hook_get(self):
437
+ def hook_func(request, instance):
438
+ self.assertIsInstance(request, HttpRequest)
439
+ self.assertEqual(instance.title, "Setting title")
440
+ self.assertEqual(instance.email, "")
441
+ return HttpResponse("Overridden!")
442
+
443
+ with self.register_hook("before_edit_setting", hook_func):
444
+ response = self.get()
445
+
446
+ self.assertEqual(response.status_code, 200)
447
+ self.assertEqual(response.content, b"Overridden!")
448
+
449
+ def test_before_edit_setting_hook_post(self):
450
+ def hook_func(request, instance):
451
+ self.assertIsInstance(request, HttpRequest)
452
+ self.assertEqual(instance.title, "Setting title")
453
+ self.assertEqual(instance.email, "")
454
+ return HttpResponse("Overridden!")
455
+
456
+ with self.register_hook("before_edit_setting", hook_func):
457
+ response = self.post(
458
+ post_data={
459
+ "title": "Edited setting title",
460
+ "email": "different.email@example.com",
461
+ }
462
+ )
463
+
464
+ self.assertEqual(response.status_code, 200)
465
+ self.assertEqual(response.content, b"Overridden!")
466
+
467
+ # Request intercepted before advert was updated
468
+ self.assertEqual(TestGenericSetting.load().title, "Setting title")
469
+ self.assertEqual(TestGenericSetting.load().email, "")
470
+
471
+ def test_after_edit_setting_hook(self):
472
+ def hook_func(request, instance):
473
+ self.assertIsInstance(request, HttpRequest)
474
+ self.assertEqual(instance.title, "Edited setting title")
475
+ self.assertEqual(instance.email, "different.email@example.com")
476
+ return HttpResponse("Overridden!")
477
+
478
+ with self.register_hook("after_edit_setting", hook_func):
479
+ response = self.post(
480
+ post_data={
481
+ "title": "Edited setting title",
482
+ "email": "different.email@example.com",
483
+ }
484
+ )
485
+
486
+ self.assertEqual(response.status_code, 200)
487
+ self.assertEqual(response.content, b"Overridden!")
488
+
489
+ # Request intercepted after advert was updated
490
+ self.assertEqual(TestGenericSetting.load().title, "Edited setting title")
491
+ self.assertEqual(TestGenericSetting.load().email, "different.email@example.com")
492
+
377
493
 
378
494
  class TestAdminPermission(WagtailTestUtils, TestCase):
379
495
  def test_registered_permission(self):
@@ -1,4 +1,5 @@
1
1
  from django.contrib.auth.models import Group, Permission
2
+ from django.http import HttpRequest, HttpResponse
2
3
  from django.test import TestCase, override_settings
3
4
  from django.urls import reverse
4
5
 
@@ -20,6 +21,11 @@ from wagtail.test.utils import WagtailTestUtils
20
21
 
21
22
 
22
23
  class SiteSettingTestMixin:
24
+ @classmethod
25
+ def setUpTestData(cls):
26
+ super().setUpTestData()
27
+ cls.default_site = Site.objects.get(is_default_site=True)
28
+
23
29
  def login_only_admin(self):
24
30
  """Log in with a user that only has permission to access the admin"""
25
31
  user = self.create_user(username="test", password="password")
@@ -39,7 +45,7 @@ class SiteSettingTestMixin:
39
45
  site_owners = Group.objects.create(name="Site Owners")
40
46
  GroupSitePermission.objects.create(
41
47
  group=site_owners,
42
- site=Site.objects.get(is_default_site=True),
48
+ site=self.default_site,
43
49
  permission=Permission.objects.get_by_natural_key(
44
50
  app_label="tests",
45
51
  model="testsitesetting",
@@ -89,11 +95,11 @@ class TestSiteSettingMenu(SiteSettingTestMixin, WagtailTestUtils, TestCase):
89
95
 
90
96
 
91
97
  class BaseTestSiteSettingView(WagtailTestUtils, TestCase):
92
- def get(self, site_pk=1, params={}, setting=TestSiteSetting):
98
+ def get(self, site_pk=1, params=None, setting=TestSiteSetting):
93
99
  url = self.edit_url(setting=setting, site_pk=site_pk)
94
100
  return self.client.get(url, params)
95
101
 
96
- def post(self, site_pk=1, post_data={}, setting=TestSiteSetting):
102
+ def post(self, site_pk=1, post_data=None, setting=TestSiteSetting):
97
103
  url = self.edit_url(setting=setting, site_pk=site_pk)
98
104
  return self.client.post(url, post_data)
99
105
 
@@ -166,13 +172,14 @@ class TestSiteSettingCreateView(SiteSettingTestMixin, BaseTestSiteSettingView):
166
172
  )
167
173
  self.assertEqual(response.status_code, 302)
168
174
 
169
- default_site = Site.objects.get(is_default_site=True)
170
- setting = TestSiteSetting.objects.get(site=default_site)
175
+ setting = TestSiteSetting.objects.get(site=self.default_site)
171
176
  self.assertEqual(setting.title, "Edited site title")
172
177
  self.assertEqual(setting.email, "test@example.com")
173
178
 
174
179
  url_finder = AdminURLFinder(self.user)
175
- expected_url = "/admin/settings/tests/testsitesetting/%d/" % default_site.pk
180
+ expected_url = (
181
+ "/admin/settings/tests/testsitesetting/%d/" % self.default_site.pk
182
+ )
176
183
  self.assertEqual(url_finder.get_edit_url(setting), expected_url)
177
184
 
178
185
  def test_edit_without_permission(self):
@@ -192,8 +199,7 @@ class TestSiteSettingCreateView(SiteSettingTestMixin, BaseTestSiteSettingView):
192
199
  post_data={"title": "Edited site title", "email": "test@example.com"}
193
200
  )
194
201
  self.assertEqual(response.status_code, 302)
195
- default_site = Site.objects.get(is_default_site=True)
196
- setting = TestSiteSetting.objects.get(site=default_site)
202
+ setting = TestSiteSetting.objects.get(site=self.default_site)
197
203
  self.assertEqual(setting.title, "Edited site title")
198
204
  self.assertEqual(setting.email, "test@example.com")
199
205
 
@@ -317,11 +323,71 @@ class TestSiteSettingCreateView(SiteSettingTestMixin, BaseTestSiteSettingView):
317
323
  self.assertEqual(settings.title, "test")
318
324
  self.assertEqual(settings.sensitive_email, "test@example.com")
319
325
 
326
+ def test_before_edit_setting_hook_get(self):
327
+ def hook_func(request, instance):
328
+ self.assertIsInstance(request, HttpRequest)
329
+ self.assertEqual(instance.title, "")
330
+ self.assertEqual(instance.email, "")
331
+ return HttpResponse("Overridden!")
332
+
333
+ with self.register_hook("before_edit_setting", hook_func):
334
+ response = self.get()
335
+
336
+ self.assertEqual(response.status_code, 200)
337
+ self.assertEqual(response.content, b"Overridden!")
338
+
339
+ def test_before_edit_setting_hook_post(self):
340
+ def hook_func(request, instance):
341
+ self.assertIsInstance(request, HttpRequest)
342
+ self.assertEqual(instance.title, "")
343
+ self.assertEqual(instance.email, "")
344
+ return HttpResponse("Overridden!")
345
+
346
+ with self.register_hook("before_edit_setting", hook_func):
347
+ response = self.post(
348
+ post_data={
349
+ "title": "Setting title",
350
+ "email": "email@example.com",
351
+ }
352
+ )
353
+
354
+ self.assertEqual(response.status_code, 200)
355
+ self.assertEqual(response.content, b"Overridden!")
356
+
357
+ # Request intercepted before advert was updated
358
+ self.assertEqual(TestSiteSetting.for_site(self.default_site).title, "")
359
+ self.assertEqual(TestSiteSetting.for_site(self.default_site).email, "")
360
+
361
+ def test_after_edit_setting_hook(self):
362
+ def hook_func(request, instance):
363
+ self.assertIsInstance(request, HttpRequest)
364
+ self.assertIsNotNone(instance.pk)
365
+ self.assertEqual(instance.title, "Setting title")
366
+ self.assertEqual(instance.email, "email@example.com")
367
+ return HttpResponse("Overridden!")
368
+
369
+ with self.register_hook("after_edit_setting", hook_func):
370
+ response = self.post(
371
+ post_data={
372
+ "title": "Setting title",
373
+ "email": "email@example.com",
374
+ }
375
+ )
376
+
377
+ self.assertEqual(response.status_code, 200)
378
+ self.assertEqual(response.content, b"Overridden!")
379
+
380
+ # Request intercepted after advert was updated
381
+ self.assertEqual(
382
+ TestSiteSetting.for_site(self.default_site).title, "Setting title"
383
+ )
384
+ self.assertEqual(
385
+ TestSiteSetting.for_site(self.default_site).email, "email@example.com"
386
+ )
387
+
320
388
 
321
389
  class TestSiteSettingEditView(SiteSettingTestMixin, BaseTestSiteSettingView):
322
390
  def setUp(self):
323
- self.default_site = Site.objects.get(is_default_site=True)
324
-
325
391
  self.test_setting = TestSiteSetting()
326
392
  self.test_setting.title = "Site title"
327
393
  self.test_setting.email = "initial@example.com"
@@ -400,8 +466,7 @@ class TestSiteSettingEditView(SiteSettingTestMixin, BaseTestSiteSettingView):
400
466
  )
401
467
  self.assertEqual(response.status_code, 302)
402
468
 
403
- default_site = Site.objects.get(is_default_site=True)
404
- setting = TestSiteSetting.objects.get(site=default_site)
469
+ setting = TestSiteSetting.objects.get(site=self.default_site)
405
470
  self.assertEqual(setting.title, "Edited site title")
406
471
  self.assertEqual(setting.email, "test@example.com")
407
472
 
@@ -447,11 +512,10 @@ class TestSiteSettingEditView(SiteSettingTestMixin, BaseTestSiteSettingView):
447
512
 
448
513
  def test_get_redirect_to_relevant_instance(self):
449
514
  url = reverse("wagtailsettings:edit", args=("tests", "testsitesetting"))
450
- default_site = Site.objects.get(is_default_site=True)
451
515
 
452
516
  response = self.client.get(url)
453
517
  self.assertRedirects(
454
- response, status_code=302, expected_url=f"{url}{default_site.pk}/"
518
+ response, status_code=302, expected_url=f"{url}{self.default_site.pk}/"
455
519
  )
456
520
 
457
521
  def test_get_redirect_to_relevant_instance_invalid(self):
@@ -605,7 +669,6 @@ class TestSiteSettingEditView(SiteSettingTestMixin, BaseTestSiteSettingView):
605
669
  )
606
670
  class TestMultiSite(SiteSettingTestMixin, BaseTestSiteSettingView):
607
671
  def setUp(self):
608
- self.default_site = Site.objects.get(is_default_site=True)
609
672
  self.other_site = Site.objects.create(
610
673
  hostname="example.com", root_page=Page.objects.get(pk=2)
611
674
  )
@@ -83,7 +83,7 @@ class SettingModelTestCase(SiteSettingsTestMixin, TestCase):
83
83
  except Exception as e: # noqa: BLE001
84
84
  raise AssertionError(
85
85
  f"An error occurred when attempting to pickle {obj!r}: {e}"
86
- )
86
+ ) from e
87
87
 
88
88
  # Now unpickle the pickled ImportantPages
89
89
  try:
@@ -91,7 +91,7 @@ class SettingModelTestCase(SiteSettingsTestMixin, TestCase):
91
91
  except Exception as e: # noqa: BLE001
92
92
  raise AssertionError(
93
93
  f"An error occurred when attempting to unpickle {obj!r}: {e}"
94
- )
94
+ ) from e
95
95
 
96
96
  # Using 'page_url' should create a new InvokeViaAttributeShortcut
97
97
  # instance, which should give the same result as the original
@@ -112,6 +112,13 @@ class EditView(generic.EditView):
112
112
  self.permission_policy = self.model.get_permission_policy()
113
113
  self.pk = kwargs.get(self.pk_url_kwarg)
114
114
  super().setup(request, app_name, model_name, *args, **kwargs)
115
+ self.object = self.get_object()
116
+
117
+ def run_before_hook(self):
118
+ return self.run_hook("before_edit_setting", self.request, self.object)
119
+
120
+ def run_after_hook(self):
121
+ return self.run_hook("after_edit_setting", self.request, self.object)
115
122
 
116
123
  def get_header_icon(self):
117
124
  return registry._model_icons.get(self.model)
@@ -8,7 +8,7 @@ msgid ""
8
8
  msgstr ""
9
9
  "Project-Id-Version: PACKAGE VERSION\n"
10
10
  "Report-Msgid-Bugs-To: \n"
11
- "POT-Creation-Date: 2025-10-23 16:45+0100\n"
11
+ "POT-Creation-Date: 2026-01-21 18:00+0000\n"
12
12
  "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13
13
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
14
  "Language-Team: LANGUAGE <LL@li.org>\n"