wagtail 6.1.3__py3-none-any.whl → 6.2rc1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (257) hide show
  1. wagtail/__init__.py +1 -1
  2. wagtail/actions/copy_for_translation.py +15 -1
  3. wagtail/admin/checks.py +20 -30
  4. wagtail/admin/forms/pages.py +10 -0
  5. wagtail/admin/icons.py +43 -0
  6. wagtail/admin/locale/en/LC_MESSAGES/django.po +405 -295
  7. wagtail/admin/locale/en/LC_MESSAGES/djangojs.po +21 -3
  8. wagtail/admin/locale/sl/LC_MESSAGES/django.mo +0 -0
  9. wagtail/admin/locale/sl/LC_MESSAGES/django.po +30 -0
  10. wagtail/admin/menu.py +2 -2
  11. wagtail/admin/migrations/0004_editingsession.py +57 -0
  12. wagtail/admin/migrations/0005_editingsession_is_editing.py +18 -0
  13. wagtail/admin/models.py +36 -3
  14. wagtail/admin/rich_text/editors/draftail/__init__.py +2 -20
  15. wagtail/admin/static/wagtailadmin/css/core.css +1 -1
  16. wagtail/admin/static/wagtailadmin/js/bulk-actions.js +1 -1
  17. wagtail/admin/static/wagtailadmin/js/chooser-modal.js +1 -1
  18. wagtail/admin/static/wagtailadmin/js/chooser-widget-telepath.js +1 -1
  19. wagtail/admin/static/wagtailadmin/js/chooser-widget.js +1 -1
  20. wagtail/admin/static/wagtailadmin/js/comments.js +1 -1
  21. wagtail/admin/static/wagtailadmin/js/core.js +1 -1
  22. wagtail/admin/static/wagtailadmin/js/date-time-chooser.js +1 -1
  23. wagtail/admin/static/wagtailadmin/js/draftail.js +1 -1
  24. wagtail/admin/static/wagtailadmin/js/expanding-formset.js +1 -1
  25. wagtail/admin/static/wagtailadmin/js/filtered-select.js +1 -1
  26. wagtail/admin/static/wagtailadmin/js/modal-workflow.js +1 -1
  27. wagtail/admin/static/wagtailadmin/js/page-chooser-modal.js +1 -1
  28. wagtail/admin/static/wagtailadmin/js/page-chooser-telepath.js +1 -1
  29. wagtail/admin/static/wagtailadmin/js/page-chooser.js +1 -1
  30. wagtail/admin/static/wagtailadmin/js/preview-panel.js +2 -1
  31. wagtail/admin/static/wagtailadmin/js/preview-panel.js.LICENSE.txt +11 -0
  32. wagtail/admin/static/wagtailadmin/js/privacy-switch.js +1 -1
  33. wagtail/admin/static/wagtailadmin/js/sidebar.js +1 -1
  34. wagtail/admin/static/wagtailadmin/js/task-chooser-modal.js +1 -1
  35. wagtail/admin/static/wagtailadmin/js/task-chooser.js +1 -1
  36. wagtail/admin/static/wagtailadmin/js/telepath/blocks.js +1 -1
  37. wagtail/admin/static/wagtailadmin/js/telepath/widgets.js +1 -1
  38. wagtail/admin/static/wagtailadmin/js/userbar.js +2 -1
  39. wagtail/admin/static/wagtailadmin/js/userbar.js.LICENSE.txt +11 -0
  40. wagtail/admin/static/wagtailadmin/js/vendor.js +1 -1
  41. wagtail/admin/static/wagtailadmin/js/vendor.js.LICENSE.txt +0 -12
  42. wagtail/admin/static/wagtailadmin/js/wagtailadmin.js +1 -1
  43. wagtail/admin/static/wagtailadmin/js/workflow-action.js +1 -1
  44. wagtail/admin/templates/wagtailadmin/collection_privacy/ancestor_privacy.html +2 -6
  45. wagtail/admin/templates/wagtailadmin/generic/index_results.html +1 -17
  46. wagtail/admin/templates/wagtailadmin/generic/listing_results.html +20 -1
  47. wagtail/admin/templates/wagtailadmin/home/workflow_objects_to_moderate.html +2 -11
  48. wagtail/admin/templates/wagtailadmin/page_privacy/ancestor_privacy.html +2 -6
  49. wagtail/admin/templates/wagtailadmin/page_privacy/no_privacy.html +2 -0
  50. wagtail/admin/templates/wagtailadmin/pages/_editor_js.html +0 -1
  51. wagtail/admin/templates/wagtailadmin/pages/action_menu/menu.html +1 -1
  52. wagtail/admin/templates/wagtailadmin/reports/aging_pages_results.html +54 -0
  53. wagtail/admin/templates/wagtailadmin/reports/base_page_report.html +1 -17
  54. wagtail/admin/templates/wagtailadmin/reports/base_page_report_results.html +10 -0
  55. wagtail/admin/templates/wagtailadmin/reports/base_report.html +1 -40
  56. wagtail/admin/templates/wagtailadmin/reports/base_report_results.html +1 -0
  57. wagtail/admin/templates/wagtailadmin/reports/listing/_list_page_report.html +21 -27
  58. wagtail/admin/templates/wagtailadmin/reports/listing/_list_page_types_usage.html +48 -54
  59. wagtail/admin/templates/wagtailadmin/reports/{locked_pages.html → locked_pages_results.html} +3 -3
  60. wagtail/admin/templates/wagtailadmin/reports/page_types_usage_results.html +10 -0
  61. wagtail/admin/templates/wagtailadmin/reports/site_history_results.html +53 -0
  62. wagtail/admin/templates/wagtailadmin/reports/workflow_results.html +74 -0
  63. wagtail/admin/templates/wagtailadmin/reports/workflow_tasks_results.html +56 -0
  64. wagtail/admin/templates/wagtailadmin/shared/_workflow_init.html +8 -44
  65. wagtail/admin/templates/wagtailadmin/shared/avatar.html +11 -1
  66. wagtail/admin/templates/wagtailadmin/shared/dialog/dialog.html +5 -4
  67. wagtail/admin/templates/wagtailadmin/shared/dropdown/dropdown_button.html +2 -1
  68. wagtail/admin/templates/wagtailadmin/shared/editing_sessions/list.html +132 -0
  69. wagtail/admin/templates/wagtailadmin/shared/editing_sessions/module.html +44 -0
  70. wagtail/admin/templates/wagtailadmin/shared/headers/slim_header.html +7 -1
  71. wagtail/admin/templates/wagtailadmin/shared/page_status_tag_new.html +1 -1
  72. wagtail/admin/templates/wagtailadmin/shared/side_panels/checks.html +32 -16
  73. wagtail/admin/templates/wagtailadmin/skeleton.html +1 -1
  74. wagtail/admin/templates/wagtailadmin/userbar/item_accessibility.html +9 -11
  75. wagtail/admin/templatetags/wagtailadmin_tags.py +13 -2
  76. wagtail/admin/tests/formats/en/__init__.py +0 -0
  77. wagtail/admin/tests/formats/en/formats.py +1 -0
  78. wagtail/admin/tests/pages/test_create_page.py +47 -0
  79. wagtail/admin/tests/pages/test_edit_page.py +10 -8
  80. wagtail/admin/tests/pages/test_parent_page_chooser_view.py +45 -1
  81. wagtail/admin/tests/test_checks.py +53 -3
  82. wagtail/admin/tests/test_collections_views.py +62 -1
  83. wagtail/admin/tests/test_edit_handlers.py +37 -0
  84. wagtail/admin/tests/test_editing_sessions.py +1336 -0
  85. wagtail/admin/tests/test_icon_sprite.py +12 -21
  86. wagtail/admin/tests/test_page_chooser.py +309 -7
  87. wagtail/admin/tests/test_privacy.py +82 -0
  88. wagtail/admin/tests/test_reports_views.py +464 -70
  89. wagtail/admin/tests/test_userbar.py +93 -6
  90. wagtail/admin/tests/test_workflows.py +223 -33
  91. wagtail/admin/tests/viewsets/test_model_viewset.py +151 -2
  92. wagtail/admin/ui/editing_sessions.py +57 -0
  93. wagtail/admin/urls/__init__.py +9 -15
  94. wagtail/admin/urls/editing_sessions.py +17 -0
  95. wagtail/admin/urls/reports.py +33 -1
  96. wagtail/admin/userbar.py +77 -20
  97. wagtail/admin/views/chooser.py +49 -22
  98. wagtail/admin/views/collections.py +0 -11
  99. wagtail/admin/views/editing_sessions.py +193 -0
  100. wagtail/admin/views/generic/__init__.py +1 -0
  101. wagtail/admin/views/generic/history.py +9 -3
  102. wagtail/admin/views/generic/mixins.py +44 -3
  103. wagtail/admin/views/generic/models.py +46 -72
  104. wagtail/admin/views/generic/permissions.py +20 -10
  105. wagtail/admin/views/home.py +2 -31
  106. wagtail/admin/views/page_privacy.py +20 -5
  107. wagtail/admin/views/pages/choose_parent.py +62 -0
  108. wagtail/admin/views/pages/edit.py +28 -0
  109. wagtail/admin/views/reports/aging_pages.py +6 -10
  110. wagtail/admin/views/reports/audit_logging.py +13 -42
  111. wagtail/admin/views/reports/base.py +31 -4
  112. wagtail/admin/views/reports/locked_pages.py +5 -8
  113. wagtail/admin/views/reports/page_types_usage.py +6 -10
  114. wagtail/admin/views/reports/workflows.py +36 -12
  115. wagtail/admin/viewsets/base.py +8 -3
  116. wagtail/admin/viewsets/chooser.py +1 -1
  117. wagtail/admin/viewsets/model.py +26 -1
  118. wagtail/admin/wagtail_hooks.py +2 -1
  119. wagtail/api/v2/filters.py +6 -0
  120. wagtail/api/v2/tests/test_documents.py +1 -1
  121. wagtail/api/v2/tests/test_images.py +1 -1
  122. wagtail/api/v2/tests/test_pages.py +11 -1
  123. wagtail/api/v2/utils.py +2 -2
  124. wagtail/blocks/base.py +35 -12
  125. wagtail/blocks/definition_lookup.py +85 -0
  126. wagtail/blocks/list_block.py +12 -0
  127. wagtail/blocks/migrations/migrate_operation.py +2 -0
  128. wagtail/blocks/stream_block.py +19 -0
  129. wagtail/blocks/struct_block.py +19 -0
  130. wagtail/contrib/forms/locale/en/LC_MESSAGES/django.po +1 -1
  131. wagtail/contrib/frontend_cache/backends/__init__.py +5 -0
  132. wagtail/contrib/frontend_cache/backends/azure.py +179 -0
  133. wagtail/contrib/frontend_cache/backends/base.py +28 -0
  134. wagtail/contrib/frontend_cache/backends/cloudflare.py +114 -0
  135. wagtail/contrib/frontend_cache/backends/cloudfront.py +99 -0
  136. wagtail/contrib/frontend_cache/backends/http.py +64 -0
  137. wagtail/contrib/frontend_cache/tests.py +59 -17
  138. wagtail/contrib/frontend_cache/utils.py +26 -8
  139. wagtail/contrib/redirects/filters.py +15 -1
  140. wagtail/contrib/redirects/locale/en/LC_MESSAGES/django.po +37 -72
  141. wagtail/contrib/redirects/models.py +6 -5
  142. wagtail/contrib/redirects/templates/wagtailredirects/edit.html +1 -38
  143. wagtail/contrib/redirects/tests/test_redirects.py +141 -1
  144. wagtail/contrib/redirects/urls.py +1 -2
  145. wagtail/contrib/redirects/views.py +39 -80
  146. wagtail/contrib/routable_page/models.py +6 -4
  147. wagtail/contrib/routable_page/tests.py +11 -0
  148. wagtail/contrib/search_promotions/locale/en/LC_MESSAGES/django.po +1 -1
  149. wagtail/contrib/settings/locale/en/LC_MESSAGES/django.po +4 -4
  150. wagtail/contrib/simple_translation/locale/en/LC_MESSAGES/django.po +5 -1
  151. wagtail/contrib/simple_translation/models.py +2 -1
  152. wagtail/contrib/styleguide/locale/en/LC_MESSAGES/django.po +7 -7
  153. wagtail/contrib/table_block/locale/en/LC_MESSAGES/django.po +1 -1
  154. wagtail/contrib/table_block/static/table_block/js/table.js +1 -1
  155. wagtail/contrib/typed_table_block/blocks.py +19 -0
  156. wagtail/contrib/typed_table_block/locale/en/LC_MESSAGES/django.po +10 -10
  157. wagtail/contrib/typed_table_block/static/typed_table_block/js/typed_table_block.js +1 -1
  158. wagtail/contrib/typed_table_block/tests.py +38 -0
  159. wagtail/coreutils.py +1 -1
  160. wagtail/documents/__init__.py +1 -1
  161. wagtail/documents/locale/en/LC_MESSAGES/django.po +8 -8
  162. wagtail/documents/locale/sl/LC_MESSAGES/django.mo +0 -0
  163. wagtail/documents/locale/sl/LC_MESSAGES/django.po +20 -0
  164. wagtail/documents/models.py +5 -1
  165. wagtail/documents/static/wagtaildocs/js/document-chooser-modal.js +1 -1
  166. wagtail/documents/static/wagtaildocs/js/document-chooser-telepath.js +1 -1
  167. wagtail/documents/static/wagtaildocs/js/document-chooser.js +1 -1
  168. wagtail/documents/tests/test_models.py +5 -1
  169. wagtail/embeds/apps.py +2 -0
  170. wagtail/embeds/embeds.py +12 -14
  171. wagtail/embeds/finders/__init__.py +2 -0
  172. wagtail/embeds/finders/facebook.py +17 -33
  173. wagtail/embeds/finders/instagram.py +19 -16
  174. wagtail/embeds/locale/en/LC_MESSAGES/django.po +1 -1
  175. wagtail/embeds/signal_handlers.py +13 -0
  176. wagtail/embeds/tests/test_embeds.py +7 -7
  177. wagtail/fields.py +58 -14
  178. wagtail/images/__init__.py +1 -1
  179. wagtail/images/locale/en/LC_MESSAGES/django.po +34 -34
  180. wagtail/images/locale/sl/LC_MESSAGES/django.mo +0 -0
  181. wagtail/images/locale/sl/LC_MESSAGES/django.po +20 -0
  182. wagtail/images/models.py +2 -0
  183. wagtail/images/static/wagtailimages/js/image-chooser-modal.js +1 -1
  184. wagtail/images/static/wagtailimages/js/image-chooser-telepath.js +1 -1
  185. wagtail/images/static/wagtailimages/js/image-chooser.js +1 -1
  186. wagtail/images/templates/wagtailimages/images/edit.html +4 -4
  187. wagtail/images/tests/test_admin_views.py +26 -2
  188. wagtail/images/views/chooser.py +6 -1
  189. wagtail/locale/en/LC_MESSAGES/django.po +84 -80
  190. wagtail/locales/locale/en/LC_MESSAGES/django.po +2 -2
  191. wagtail/locales/tests.py +16 -0
  192. wagtail/locales/wagtail_hooks.py +0 -9
  193. wagtail/migrations/0094_alter_page_locale.py +19 -0
  194. wagtail/models/__init__.py +11 -5
  195. wagtail/models/i18n.py +6 -1
  196. wagtail/project_template/requirements.txt +1 -1
  197. wagtail/search/locale/en/LC_MESSAGES/django.po +1 -1
  198. wagtail/signals.py +4 -0
  199. wagtail/sites/locale/en/LC_MESSAGES/django.po +2 -2
  200. wagtail/sites/tests.py +15 -0
  201. wagtail/sites/wagtail_hooks.py +0 -9
  202. wagtail/snippets/locale/en/LC_MESSAGES/django.po +9 -9
  203. wagtail/snippets/permissions.py +5 -3
  204. wagtail/snippets/static/wagtailsnippets/js/snippet-chooser-telepath.js +1 -1
  205. wagtail/snippets/static/wagtailsnippets/js/snippet-chooser.js +1 -1
  206. wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/menu.html +1 -1
  207. wagtail/snippets/tests/test_snippets.py +78 -12
  208. wagtail/snippets/tests/test_viewset.py +22 -0
  209. wagtail/snippets/views/snippets.py +19 -14
  210. wagtail/snippets/wagtail_hooks.py +2 -10
  211. wagtail/templatetags/wagtailcore_tags.py +3 -0
  212. wagtail/test/dummy_external_storage.py +1 -1
  213. wagtail/test/i18n/migrations/0003_alter_clusterabletestmodel_locale_and_more.py +40 -0
  214. wagtail/test/routablepage/models.py +4 -0
  215. wagtail/test/snippets/migrations/0012_alter_translatablesnippet_locale.py +20 -0
  216. wagtail/test/testapp/migrations/0038_sociallink.py +52 -0
  217. wagtail/test/testapp/migrations/0039_alter_eventcategory_locale_and_more.py +45 -0
  218. wagtail/test/testapp/models.py +24 -0
  219. wagtail/test/testapp/views.py +1 -0
  220. wagtail/test/testapp/wagtail_hooks.py +9 -0
  221. wagtail/test/urls_multilang.py +6 -1
  222. wagtail/test/urls_multilang_non_root.py +11 -0
  223. wagtail/tests/streamfield_migrations/test_migrations.py +53 -12
  224. wagtail/tests/test_audit_log.py +72 -2
  225. wagtail/tests/test_blocks.py +103 -0
  226. wagtail/tests/test_signals.py +49 -2
  227. wagtail/tests/test_streamfield.py +153 -0
  228. wagtail/tests/test_utils.py +14 -0
  229. wagtail/tests/tests.py +5 -0
  230. wagtail/users/apps.py +1 -0
  231. wagtail/users/forms.py +7 -0
  232. wagtail/users/locale/en/LC_MESSAGES/django.po +55 -50
  233. wagtail/users/models.py +1 -0
  234. wagtail/users/templates/wagtailusers/groups/includes/formatted_permissions.html +3 -2
  235. wagtail/users/templatetags/wagtailusers_tags.py +9 -0
  236. wagtail/users/tests/__init__.py +7 -1
  237. wagtail/users/tests/test_admin_views.py +117 -32
  238. wagtail/users/views/groups.py +4 -0
  239. wagtail/users/views/users.py +58 -14
  240. wagtail/users/wagtail_hooks.py +7 -123
  241. wagtail/utils/utils.py +1 -0
  242. wagtail/utils/version.py +5 -2
  243. {wagtail-6.1.3.dist-info → wagtail-6.2rc1.dist-info}/METADATA +3 -3
  244. {wagtail-6.1.3.dist-info → wagtail-6.2rc1.dist-info}/RECORD +248 -222
  245. wagtail/admin/templates/wagtailadmin/reports/aging_pages.html +0 -58
  246. wagtail/admin/templates/wagtailadmin/reports/page_types_usage.html +0 -18
  247. wagtail/admin/templates/wagtailadmin/reports/site_history.html +0 -57
  248. wagtail/admin/templates/wagtailadmin/reports/workflow.html +0 -81
  249. wagtail/admin/templates/wagtailadmin/reports/workflow_tasks.html +0 -63
  250. wagtail/contrib/frontend_cache/backends.py +0 -400
  251. wagtail/contrib/redirects/templates/wagtailredirects/list.html +0 -43
  252. wagtail/contrib/redirects/templates/wagtailredirects/reports/redirects_report.html +0 -14
  253. wagtail/contrib/redirects/tests/test_reports_view.py +0 -82
  254. {wagtail-6.1.3.dist-info → wagtail-6.2rc1.dist-info}/LICENSE +0 -0
  255. {wagtail-6.1.3.dist-info → wagtail-6.2rc1.dist-info}/WHEEL +0 -0
  256. {wagtail-6.1.3.dist-info → wagtail-6.2rc1.dist-info}/entry_points.txt +0 -0
  257. {wagtail-6.1.3.dist-info → wagtail-6.2rc1.dist-info}/top_level.txt +0 -0
@@ -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: 2024-04-18 17:28+0100\n"
11
+ "POT-Creation-Date: 2024-07-19 16:26+0100\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"
@@ -22,20 +22,19 @@ msgstr ""
22
22
  msgid "Wagtail redirects"
23
23
  msgstr ""
24
24
 
25
- #: filters.py:12 templates/wagtailredirects/list.html:20 views.py:102
26
- #: views.py:466
25
+ #: filters.py:26 views.py:102 views.py:119
27
26
  msgid "Type"
28
27
  msgstr ""
29
28
 
30
- #: filters.py:15
29
+ #: filters.py:29
31
30
  msgid "Permanent"
32
31
  msgstr ""
33
32
 
34
- #: filters.py:16
33
+ #: filters.py:30
35
34
  msgid "Temporary"
36
35
  msgstr ""
37
36
 
38
- #: filters.py:18
37
+ #: filters.py:32
39
38
  msgid "All"
40
39
  msgstr ""
41
40
 
@@ -68,59 +67,59 @@ msgstr ""
68
67
  msgid "To field"
69
68
  msgstr ""
70
69
 
71
- #: models.py:12
70
+ #: models.py:13
72
71
  msgid "redirect from"
73
72
  msgstr ""
74
73
 
75
- #: models.py:16
74
+ #: models.py:17
76
75
  msgid "site"
77
76
  msgstr ""
78
77
 
79
- #: models.py:24 models.py:84
78
+ #: models.py:25 models.py:85
80
79
  msgid "permanent"
81
80
  msgstr ""
82
81
 
83
- #: models.py:27
82
+ #: models.py:28
84
83
  msgid ""
85
84
  "Recommended. Permanent redirects ensure search engines forget the old page "
86
85
  "(the 'Redirect from') and index the new page instead."
87
86
  msgstr ""
88
87
 
89
- #: models.py:33
88
+ #: models.py:34
90
89
  msgid "redirect to a page"
91
90
  msgstr ""
92
91
 
93
- #: models.py:39
92
+ #: models.py:40
94
93
  msgid "target page route"
95
94
  msgstr ""
96
95
 
97
- #: models.py:41
96
+ #: models.py:42
98
97
  msgid ""
99
98
  "Optionally specify a route on the target page to redirect to. Leave blank to "
100
99
  "redirect to the default page route."
101
100
  msgstr ""
102
101
 
103
- #: models.py:48
102
+ #: models.py:49
104
103
  msgid "redirect to any URL"
105
104
  msgstr ""
106
105
 
107
- #: models.py:51
106
+ #: models.py:52
108
107
  msgid "automatically created"
109
108
  msgstr ""
110
109
 
111
- #: models.py:56
110
+ #: models.py:57
112
111
  msgid "created at"
113
112
  msgstr ""
114
113
 
115
- #: models.py:86
114
+ #: models.py:87
116
115
  msgid "temporary"
117
116
  msgstr ""
118
117
 
119
- #: models.py:203
118
+ #: models.py:204
120
119
  msgid "redirect"
121
120
  msgstr ""
122
121
 
123
- #: models.py:204
122
+ #: models.py:205
124
123
  msgid "redirects"
125
124
  msgstr ""
126
125
 
@@ -130,7 +129,6 @@ msgid "Add redirect"
130
129
  msgstr ""
131
130
 
132
131
  #: templates/wagtailredirects/add.html:19
133
- #: templates/wagtailredirects/edit.html:19
134
132
  msgid "Save"
135
133
  msgstr ""
136
134
 
@@ -141,7 +139,7 @@ msgstr ""
141
139
 
142
140
  #: templates/wagtailredirects/choose_import_file.html:6
143
141
  #: templates/wagtailredirects/confirm_import.html:6
144
- #: templates/wagtailredirects/import_summary.html:5 views.py:116
142
+ #: templates/wagtailredirects/import_summary.html:5 views.py:130
145
143
  msgid "Import redirects"
146
144
  msgstr ""
147
145
 
@@ -191,19 +189,6 @@ msgstr ""
191
189
  msgid "Preview"
192
190
  msgstr ""
193
191
 
194
- #: templates/wagtailredirects/edit.html:3
195
- #, python-format
196
- msgid "Editing %(title)s"
197
- msgstr ""
198
-
199
- #: templates/wagtailredirects/edit.html:5
200
- msgid "Editing"
201
- msgstr ""
202
-
203
- #: templates/wagtailredirects/edit.html:21
204
- msgid "Delete redirect"
205
- msgstr ""
206
-
207
192
  #: templates/wagtailredirects/import_summary.html:3
208
193
  #: templates/wagtailredirects/import_summary.html:6
209
194
  msgid "Summary"
@@ -215,14 +200,11 @@ msgid ""
215
200
  "Found %(total)s redirects, created %(successes)s and found %(errors)s errors."
216
201
  msgstr ""
217
202
 
218
- #: templates/wagtailredirects/import_summary.html:17
219
- #: templates/wagtailredirects/list.html:12
220
- #: templates/wagtailredirects/list.html:15 views.py:84 views.py:463
203
+ #: templates/wagtailredirects/import_summary.html:17 views.py:84 views.py:116
221
204
  msgid "From"
222
205
  msgstr ""
223
206
 
224
- #: templates/wagtailredirects/import_summary.html:18
225
- #: templates/wagtailredirects/list.html:19 views.py:96 views.py:465
207
+ #: templates/wagtailredirects/import_summary.html:18 views.py:96 views.py:118
226
208
  msgid "To"
227
209
  msgstr ""
228
210
 
@@ -246,76 +228,59 @@ msgid ""
246
228
  "href=\"%(wagtailredirects_add_redirect_url)s\">add one</a>?"
247
229
  msgstr ""
248
230
 
249
- #: templates/wagtailredirects/list.html:18 views.py:90 views.py:464
231
+ #: views.py:90 views.py:117
250
232
  msgid "Site"
251
233
  msgstr ""
252
234
 
253
- #: templates/wagtailredirects/list.html:27
254
- msgid "Edit this redirect"
255
- msgstr ""
256
-
257
- #: templates/wagtailredirects/reports/redirects_report.html:8
258
- #: templates/wagtailredirects/reports/redirects_report.html:13
259
- msgid "No redirects found."
260
- msgstr ""
261
-
262
- #: views.py:122
263
- msgid "Export redirects"
235
+ #: views.py:148
236
+ msgid "The redirect could not be saved due to errors."
264
237
  msgstr ""
265
238
 
266
- #: views.py:147
239
+ #: views.py:153
267
240
  #, python-format
268
241
  msgid "Redirect '%(redirect_title)s' updated."
269
242
  msgstr ""
270
243
 
271
- #: views.py:152 views.py:220
272
- msgid "Edit"
273
- msgstr ""
274
-
275
- #: views.py:158
276
- msgid "The redirect could not be saved due to errors."
277
- msgstr ""
278
-
279
- #: views.py:190
244
+ #: views.py:173
280
245
  #, python-format
281
246
  msgid "Redirect '%(redirect_title)s' deleted."
282
247
  msgstr ""
283
248
 
284
- #: views.py:215
249
+ #: views.py:198
285
250
  #, python-format
286
251
  msgid "Redirect '%(redirect_title)s' added."
287
252
  msgstr ""
288
253
 
289
- #: views.py:227
254
+ #: views.py:203
255
+ msgid "Edit"
256
+ msgstr ""
257
+
258
+ #: views.py:210
290
259
  msgid "The redirect could not be created due to errors."
291
260
  msgstr ""
292
261
 
293
- #: views.py:266
262
+ #: views.py:249
294
263
  msgid "Search redirects"
295
264
  msgstr ""
296
265
 
297
- #: views.py:280
266
+ #: views.py:263
298
267
  #, python-format
299
268
  msgid "File format of type \"%(extension)s\" is not supported"
300
269
  msgstr ""
301
270
 
302
- #: views.py:297
271
+ #: views.py:280
303
272
  #, python-format
304
273
  msgid "Imported file has a wrong encoding: %(error_message)s"
305
274
  msgstr ""
306
275
 
307
- #: views.py:304
276
+ #: views.py:287
308
277
  #, python-format
309
278
  msgid "%(error)s encountered while trying to read file: %(filename)s"
310
279
  msgstr ""
311
280
 
312
- #: views.py:395
281
+ #: views.py:378
313
282
  #, python-format
314
283
  msgid "Imported %(total)d redirect"
315
284
  msgid_plural "Imported %(total)d redirects"
316
285
  msgstr[0] ""
317
286
  msgstr[1] ""
318
-
319
- #: views.py:451
320
- msgid "Export Redirects"
321
- msgstr ""
@@ -2,6 +2,7 @@ from urllib.parse import urlparse
2
2
 
3
3
  from django.db import models
4
4
  from django.urls import Resolver404
5
+ from django.utils.functional import cached_property
5
6
  from django.utils.translation import gettext_lazy as _
6
7
 
7
8
  from wagtail.models import Page
@@ -63,10 +64,10 @@ class Redirect(models.Model):
63
64
  def __str__(self):
64
65
  return self.title
65
66
 
66
- @property
67
+ @cached_property
67
68
  def link(self):
68
69
  if self.redirect_page:
69
- page = self.redirect_page.specific
70
+ page = self.redirect_page.specific_deferred
70
71
  base_url = page.url
71
72
  if not self.redirect_page_route_path:
72
73
  return base_url
@@ -145,7 +146,7 @@ class Redirect(models.Model):
145
146
  url_parsed = urlparse(url)
146
147
 
147
148
  # Path must start with / but not end with /
148
- path = url_parsed[2]
149
+ path = url_parsed.path
149
150
  if not path.startswith("/"):
150
151
  path = "/" + path
151
152
 
@@ -153,12 +154,12 @@ class Redirect(models.Model):
153
154
  path = path[:-1]
154
155
 
155
156
  # Parameters must be sorted alphabetically
156
- parameters = url_parsed[3]
157
+ parameters = url_parsed.params
157
158
  parameters_components = parameters.split(";")
158
159
  parameters = ";".join(sorted(parameters_components))
159
160
 
160
161
  # Query string components must be sorted alphabetically
161
- query_string = url_parsed[4]
162
+ query_string = url_parsed.query
162
163
  query_string_components = query_string.split("&")
163
164
  query_string = "&".join(sorted(query_string_components))
164
165
 
@@ -1,38 +1 @@
1
- {% extends "wagtailadmin/base.html" %}
2
- {% load i18n wagtailadmin_tags %}
3
- {% block titletag %}{% blocktrans trimmed with title=redirect.title %}Editing {{ title }}{% endblocktrans %}{% endblock %}
4
- {% block content %}
5
- {% trans "Editing" as editing_str %}
6
- {% include "wagtailadmin/shared/header.html" with title=editing_str subtitle=redirect.title icon="redirect" %}
7
-
8
- {% include "wagtailadmin/shared/non_field_errors.html" %}
9
-
10
- <form action="{% url 'wagtailredirects:edit' redirect.id %}" method="POST" class="nice-padding" novalidate>
11
- {% csrf_token %}
12
-
13
- <ul class="fields">
14
- {% for field in form.visible_fields %}
15
- <li>{% formattedfield field %}</li>
16
- {% endfor %}
17
-
18
- <li>
19
- <input type="submit" value="{% trans 'Save' %}" class="button" />
20
- {% if user_can_delete %}
21
- <a href="{% url 'wagtailredirects:delete' redirect.id %}" class="button no">{% trans "Delete redirect" %}</a>
22
- {% endif %}
23
- </li>
24
- </ul>
25
- </form>
26
-
27
- {% endblock %}
28
-
29
- {% block extra_js %}
30
- {{ block.super }}
31
- {% include "wagtailadmin/pages/_editor_js.html" %}
32
- {{ form.media.js }}
33
- {% endblock %}
34
-
35
- {% block extra_css %}
36
- {{ block.super }}
37
- {{ form.media.css }}
38
- {% endblock %}
1
+ {% extends "wagtailadmin/generic/edit.html" %}
@@ -1,6 +1,10 @@
1
+ from io import BytesIO
2
+
1
3
  from django.conf import settings
4
+ from django.contrib.auth.models import Permission
2
5
  from django.test import TestCase, override_settings
3
6
  from django.urls import reverse
7
+ from openpyxl.reader.excel import load_workbook
4
8
 
5
9
  from wagtail.admin.admin_url_finder import AdminURLFinder
6
10
  from wagtail.contrib.redirects import models
@@ -592,7 +596,14 @@ class TestRedirects(TestCase):
592
596
  self.assertIs(redirect.is_permanent, True)
593
597
 
594
598
 
599
+ @override_settings(
600
+ CACHES={"default": {"BACKEND": "django.core.cache.backends.locmem.LocMemCache"}}
601
+ )
595
602
  class TestRedirectsIndexView(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
603
+ @classmethod
604
+ def setUpTestData(cls):
605
+ cls.site = Site.objects.first()
606
+
596
607
  def setUp(self):
597
608
  self.login()
598
609
 
@@ -607,6 +618,7 @@ class TestRedirectsIndexView(AdminTemplateTestUtils, WagtailTestUtils, TestCase)
607
618
  [{"url": "", "label": "Redirects"}],
608
619
  response.content,
609
620
  )
621
+ self.assertContains(response, "No redirects have been created")
610
622
 
611
623
  def test_search(self):
612
624
  models.Redirect.objects.create(
@@ -692,6 +704,94 @@ class TestRedirectsIndexView(AdminTemplateTestUtils, WagtailTestUtils, TestCase)
692
704
  (ordering,),
693
705
  )
694
706
 
707
+ def test_filtering_by_type(self):
708
+ temp_redirect = models.Redirect.add_redirect("/from", "/to", False)
709
+ perm_redirect = models.Redirect.add_redirect("/cat", "/dog", True)
710
+
711
+ response = self.get(params={"is_permanent": "True"})
712
+
713
+ self.assertContains(response, perm_redirect.old_path)
714
+ self.assertNotContains(response, temp_redirect.old_path)
715
+
716
+ def test_filtering_by_site(self):
717
+ site_redirect = models.Redirect.add_redirect("/cat", "/dog")
718
+ site_redirect.site = self.site
719
+ site_redirect.save()
720
+ nosite_redirect = models.Redirect.add_redirect("/from", "/to")
721
+
722
+ response = self.get(params={"site": self.site.pk})
723
+
724
+ self.assertContains(response, site_redirect.old_path)
725
+ self.assertNotContains(response, nosite_redirect.old_path)
726
+
727
+ def test_csv_export(self):
728
+ models.Redirect.add_redirect("/from", "/to", False)
729
+
730
+ # Session, User, UserProfile, Redirects
731
+ with self.assertNumQueries(4):
732
+ response = self.get(params={"export": "csv"})
733
+
734
+ csv_data = response.getvalue().decode().split("\n")
735
+
736
+ self.assertEqual(response.status_code, 200)
737
+ csv_header = csv_data[0]
738
+ csv_entries = csv_data[1:]
739
+ csv_entries = csv_entries[:-1] # Drop empty last line
740
+
741
+ self.assertEqual(csv_header, "From,To,Type,Site\r")
742
+ self.assertEqual(len(csv_entries), 1)
743
+ self.assertEqual(csv_entries[0], "/from,/to,temporary,\r")
744
+
745
+ def test_xlsx_export(self):
746
+ models.Redirect.add_redirect("/from", "/to", True)
747
+
748
+ # Session, User, UserProfile, Redirects
749
+ with self.assertNumQueries(4):
750
+ response = self.get(params={"export": "xlsx"})
751
+ workbook_data = response.getvalue()
752
+
753
+ self.assertEqual(response.status_code, 200)
754
+
755
+ worksheet = load_workbook(filename=BytesIO(workbook_data))["Sheet1"]
756
+ cell_array = [[cell.value for cell in row] for row in worksheet.rows]
757
+
758
+ self.assertEqual(cell_array[0], ["From", "To", "Type", "Site"])
759
+ self.assertEqual(len(cell_array), 2)
760
+ self.assertEqual(cell_array[1], ["/from", "/to", "permanent", None])
761
+
762
+ def test_num_queries_in_export(self):
763
+ page = Page.objects.get(id=2)
764
+ for i in range(3):
765
+ models.Redirect.add_redirect(f"/from{i}", "/to", False)
766
+ models.Redirect.add_redirect(f"/from-site{i}", "/to", False, site=self.site)
767
+ models.Redirect.add_redirect(f"/to-page{i}", page, False)
768
+
769
+ response = self.get(params={"export": "csv"})
770
+ csv_data = response.getvalue().decode().strip().split("\n")
771
+ # Session, User, UserProfile, Redirects
772
+ with self.assertNumQueries(4):
773
+ response = self.get(params={"export": "csv"})
774
+ csv_data = response.getvalue().decode().strip().split("\n")
775
+
776
+ self.assertEqual(len(csv_data), 10)
777
+
778
+ def test_redirect_page_filter_only_includes_relevant_pages(self):
779
+ """
780
+ The redirect_page filter should only include pages referenced by Redirect objects.
781
+ """
782
+ response = self.get()
783
+ request = response.context["request"]
784
+ qs = response.context["filters"].filters["redirect_page"].queryset(request)
785
+ self.assertQuerySetEqual(qs, Page.objects.none())
786
+
787
+ page = Page.objects.get(id=2)
788
+ models.Redirect.add_redirect("/to-page", page, False)
789
+
790
+ response = self.get()
791
+ request = response.context["request"]
792
+ qs = response.context["filters"].filters["redirect_page"].queryset(request)
793
+ self.assertQuerySetEqual(qs, Page.objects.filter(pk=2))
794
+
695
795
 
696
796
  class TestRedirectsAddView(WagtailTestUtils, TestCase):
697
797
  fixtures = ["test.json"]
@@ -849,7 +949,7 @@ class TestRedirectsAddView(WagtailTestUtils, TestCase):
849
949
  self.assertIsNone(redirects.first().site)
850
950
 
851
951
 
852
- class TestRedirectsEditView(WagtailTestUtils, TestCase):
952
+ class TestRedirectsEditView(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
853
953
  def setUp(self):
854
954
  # Create a redirect to edit
855
955
  self.redirect = models.Redirect(
@@ -876,6 +976,13 @@ class TestRedirectsEditView(WagtailTestUtils, TestCase):
876
976
  response = self.get()
877
977
  self.assertEqual(response.status_code, 200)
878
978
  self.assertTemplateUsed(response, "wagtailredirects/edit.html")
979
+ self.assertBreadcrumbsItemsRendered(
980
+ [
981
+ {"url": reverse("wagtailredirects:index"), "label": "Redirects"},
982
+ {"url": "", "label": "/test"},
983
+ ],
984
+ response.content,
985
+ )
879
986
 
880
987
  url_finder = AdminURLFinder(self.user)
881
988
  expected_url = "/admin/redirects/%d/" % self.redirect.id
@@ -957,6 +1064,39 @@ class TestRedirectsEditView(WagtailTestUtils, TestCase):
957
1064
  # Should not redirect to index
958
1065
  self.assertEqual(response.status_code, 200)
959
1066
 
1067
+ def test_get_with_no_permission(self, redirect_id=None):
1068
+ self.user.is_superuser = False
1069
+ self.user.save()
1070
+ # Only basic access_admin permission is given
1071
+ self.user.user_permissions.add(
1072
+ Permission.objects.get(
1073
+ content_type__app_label="wagtailadmin",
1074
+ codename="access_admin",
1075
+ )
1076
+ )
1077
+
1078
+ response = self.get()
1079
+ self.assertEqual(response.status_code, 302)
1080
+ self.assertRedirects(response, reverse("wagtailadmin_home"))
1081
+
1082
+ def test_get_with_edit_permission_only(self):
1083
+ self.user.is_superuser = False
1084
+ self.user.save()
1085
+ self.user.user_permissions.add(
1086
+ Permission.objects.get(
1087
+ content_type__app_label="wagtailadmin",
1088
+ codename="access_admin",
1089
+ ),
1090
+ Permission.objects.get(
1091
+ content_type__app_label="wagtailredirects",
1092
+ codename="change_redirect",
1093
+ ),
1094
+ )
1095
+
1096
+ response = self.get()
1097
+ self.assertEqual(response.status_code, 200)
1098
+ self.assertTemplateUsed(response, "wagtailredirects/edit.html")
1099
+
960
1100
 
961
1101
  class TestRedirectsDeleteView(WagtailTestUtils, TestCase):
962
1102
  def setUp(self):
@@ -7,9 +7,8 @@ urlpatterns = [
7
7
  path("", views.IndexView.as_view(), name="index"),
8
8
  path("results/", views.IndexView.as_view(results_only=True), name="index_results"),
9
9
  path("add/", views.add, name="add"),
10
- path("<int:redirect_id>/", views.edit, name="edit"),
10
+ path("<int:redirect_id>/", views.EditView.as_view(), name="edit"),
11
11
  path("<int:redirect_id>/delete/", views.delete, name="delete"),
12
12
  path("import/", views.start_import, name="start_import"),
13
13
  path("import/process/", views.process_import, name="process_import"),
14
- path("report", views.RedirectsReportView.as_view(), name="report"),
15
14
  ]