wagtail 6.0.2__py3-none-any.whl → 6.1rc1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (355) hide show
  1. wagtail/__init__.py +1 -1
  2. wagtail/admin/checks.py +51 -0
  3. wagtail/admin/compare.py +1 -1
  4. wagtail/admin/filters.py +70 -1
  5. wagtail/admin/forms/account.py +1 -1
  6. wagtail/admin/forms/collections.py +15 -0
  7. wagtail/admin/forms/pages.py +49 -0
  8. wagtail/admin/locale/de/LC_MESSAGES/django.mo +0 -0
  9. wagtail/admin/locale/de/LC_MESSAGES/django.po +5 -5
  10. wagtail/admin/locale/en/LC_MESSAGES/django.po +474 -385
  11. wagtail/admin/locale/en/LC_MESSAGES/djangojs.po +3 -3
  12. wagtail/admin/locale/pt_PT/LC_MESSAGES/django.mo +0 -0
  13. wagtail/admin/locale/pt_PT/LC_MESSAGES/django.po +73 -2
  14. wagtail/admin/locale/ro/LC_MESSAGES/django.mo +0 -0
  15. wagtail/admin/locale/ro/LC_MESSAGES/django.po +3 -3
  16. wagtail/admin/panels/comment_panel.py +1 -1
  17. wagtail/admin/panels/field_panel.py +1 -1
  18. wagtail/admin/rich_text/converters/editor_html.py +3 -1
  19. wagtail/admin/rich_text/editors/draftail/__init__.py +28 -2
  20. wagtail/admin/static/wagtailadmin/css/core.css +1 -1
  21. wagtail/admin/static/wagtailadmin/css/panels/draftail.css +1 -1
  22. wagtail/admin/static/wagtailadmin/images/favicon.ico +0 -0
  23. wagtail/admin/static/wagtailadmin/js/bulk-actions.js +1 -1
  24. wagtail/admin/static/wagtailadmin/js/chooser-modal.js +1 -1
  25. wagtail/admin/static/wagtailadmin/js/chooser-widget-telepath.js +1 -1
  26. wagtail/admin/static/wagtailadmin/js/chooser-widget.js +1 -1
  27. wagtail/admin/static/wagtailadmin/js/comments.js +1 -1
  28. wagtail/admin/static/wagtailadmin/js/core.js +1 -1
  29. wagtail/admin/static/wagtailadmin/js/core.js.LICENSE.txt +1 -1
  30. wagtail/admin/static/wagtailadmin/js/date-time-chooser.js +1 -1
  31. wagtail/admin/static/wagtailadmin/js/draftail.js +1 -1
  32. wagtail/admin/static/wagtailadmin/js/expanding-formset.js +1 -1
  33. wagtail/admin/static/wagtailadmin/js/filtered-select.js +1 -1
  34. wagtail/admin/static/wagtailadmin/js/modal-workflow.js +1 -1
  35. wagtail/admin/static/wagtailadmin/js/page-chooser-modal.js +1 -1
  36. wagtail/admin/static/wagtailadmin/js/page-chooser-telepath.js +1 -1
  37. wagtail/admin/static/wagtailadmin/js/page-chooser.js +1 -1
  38. wagtail/admin/static/wagtailadmin/js/preview-panel.js +1 -1
  39. wagtail/admin/static/wagtailadmin/js/privacy-switch.js +1 -1
  40. wagtail/admin/static/wagtailadmin/js/sidebar.js +1 -1
  41. wagtail/admin/static/wagtailadmin/js/task-chooser-modal.js +1 -1
  42. wagtail/admin/static/wagtailadmin/js/task-chooser.js +1 -1
  43. wagtail/admin/static/wagtailadmin/js/telepath/blocks.js +1 -1
  44. wagtail/admin/static/wagtailadmin/js/telepath/telepath.js +1 -1
  45. wagtail/admin/static/wagtailadmin/js/telepath/widgets.js +1 -1
  46. wagtail/admin/static/wagtailadmin/js/userbar.js +1 -1
  47. wagtail/admin/static/wagtailadmin/js/vendor.js +1 -1
  48. wagtail/admin/static/wagtailadmin/js/vendor.js.LICENSE.txt +4 -4
  49. wagtail/admin/static/wagtailadmin/js/wagtailadmin.js +1 -1
  50. wagtail/admin/static/wagtailadmin/js/workflow-action.js +1 -1
  51. wagtail/admin/staticfiles.py +1 -0
  52. wagtail/admin/templates/wagtailadmin/base.html +1 -0
  53. wagtail/admin/templates/wagtailadmin/collection_privacy/set_privacy.html +3 -1
  54. wagtail/admin/templates/wagtailadmin/collections/index_results.html +10 -0
  55. wagtail/admin/templates/wagtailadmin/generic/base.html +1 -9
  56. wagtail/admin/templates/wagtailadmin/generic/form.html +3 -2
  57. wagtail/admin/templates/wagtailadmin/generic/history/action_cell.html +27 -0
  58. wagtail/admin/templates/wagtailadmin/home/workflow_objects_to_moderate.html +3 -3
  59. wagtail/admin/templates/wagtailadmin/icons/keyboard.svg +1 -0
  60. wagtail/admin/templates/wagtailadmin/page_privacy/set_privacy.html +3 -1
  61. wagtail/admin/templates/wagtailadmin/pages/_editor_js.html +0 -14
  62. wagtail/admin/templates/wagtailadmin/pages/action_menu/save_draft.html +3 -1
  63. wagtail/admin/templates/wagtailadmin/pages/choose_parent.html +17 -0
  64. wagtail/admin/templates/wagtailadmin/pages/explorable_index.html +8 -0
  65. wagtail/admin/templates/wagtailadmin/pages/history.html +1 -61
  66. wagtail/admin/templates/wagtailadmin/pages/index.html +1 -3
  67. wagtail/admin/templates/wagtailadmin/pages/listing/_locked_indicator.html +2 -2
  68. wagtail/admin/templates/wagtailadmin/pages/listing/_page_title_column_header.html +25 -27
  69. wagtail/admin/templates/wagtailadmin/pages/page_listing_header.html +2 -1
  70. wagtail/admin/templates/wagtailadmin/panels/multi_field_panel_child.html +1 -1
  71. wagtail/admin/templates/wagtailadmin/panels/publishing/schedule_publishing_panel.html +3 -1
  72. wagtail/admin/templates/wagtailadmin/panels/tabbed_interface.html +1 -1
  73. wagtail/admin/templates/wagtailadmin/shared/active_filters.html +2 -1
  74. wagtail/admin/templates/wagtailadmin/shared/breadcrumbs.html +8 -0
  75. wagtail/admin/templates/wagtailadmin/shared/forms/single_checkbox.html +1 -1
  76. wagtail/admin/templates/wagtailadmin/shared/headers/page_edit_header.html +1 -1
  77. wagtail/admin/templates/wagtailadmin/shared/headers/slim_header.html +21 -9
  78. wagtail/admin/templates/wagtailadmin/shared/human_readable_date.html +1 -1
  79. wagtail/admin/templates/wagtailadmin/shared/keyboard_shortcuts_dialog.html +29 -0
  80. wagtail/admin/templates/wagtailadmin/shared/side_panel_toggle.html +2 -1
  81. wagtail/admin/templates/wagtailadmin/skeleton.html +2 -1
  82. wagtail/admin/templates/wagtailadmin/tables/related_objects_cell.html +9 -0
  83. wagtail/admin/templates/wagtailadmin/tables/title_cell.html +9 -7
  84. wagtail/admin/templates/wagtailadmin/widgets/draftail_rich_text_area.html +1 -1
  85. wagtail/admin/templates/wagtailadmin/workflows/create.html +6 -23
  86. wagtail/admin/templates/wagtailadmin/workflows/create_task.html +6 -15
  87. wagtail/admin/templates/wagtailadmin/workflows/edit.html +6 -23
  88. wagtail/admin/templates/wagtailadmin/workflows/edit_task.html +6 -13
  89. wagtail/admin/templates/wagtailadmin/workflows/includes/task_usage_cell.html +4 -4
  90. wagtail/admin/templates/wagtailadmin/workflows/includes/workflow_tasks_cell.html +18 -0
  91. wagtail/admin/templates/wagtailadmin/workflows/includes/workflow_title_cell.html +7 -0
  92. wagtail/admin/templates/wagtailadmin/workflows/includes/workflow_used_by_cell.html +25 -0
  93. wagtail/admin/templates/wagtailadmin/workflows/index.html +0 -99
  94. wagtail/admin/templates/wagtailadmin/workflows/index_results.html +10 -0
  95. wagtail/admin/templates/wagtailadmin/workflows/task_index.html +0 -30
  96. wagtail/admin/templates/wagtailadmin/workflows/task_index_results.html +10 -0
  97. wagtail/admin/templates/wagtailadmin/workflows/usage.html +1 -1
  98. wagtail/admin/templatetags/wagtailadmin_tags.py +116 -39
  99. wagtail/admin/tests/pages/test_create_page.py +10 -4
  100. wagtail/admin/tests/pages/test_custom_listing.py +37 -0
  101. wagtail/admin/tests/pages/test_edit_page.py +6 -6
  102. wagtail/admin/tests/pages/test_explorer_view.py +19 -18
  103. wagtail/admin/tests/pages/test_move_page.py +1 -1
  104. wagtail/admin/tests/pages/test_page_usage.py +50 -2
  105. wagtail/admin/tests/pages/test_parent_page_chooser_view.py +119 -0
  106. wagtail/admin/tests/pages/test_preview.py +18 -4
  107. wagtail/admin/tests/test_account_management.py +20 -1
  108. wagtail/admin/tests/test_audit_log.py +172 -5
  109. wagtail/admin/tests/test_checks.py +92 -0
  110. wagtail/admin/tests/test_collections_views.py +19 -5
  111. wagtail/admin/tests/test_compare.py +6 -6
  112. wagtail/admin/tests/test_dashboard.py +404 -0
  113. wagtail/admin/tests/test_dbwhitelister.py +4 -5
  114. wagtail/admin/tests/test_edit_handlers.py +2 -2
  115. wagtail/admin/tests/test_keyboard_shortcuts.py +84 -0
  116. wagtail/admin/tests/test_page_chooser.py +31 -18
  117. wagtail/admin/tests/test_privacy.py +36 -2
  118. wagtail/admin/tests/test_rich_text.py +168 -23
  119. wagtail/admin/tests/test_templatetags.py +411 -43
  120. wagtail/admin/tests/test_views.py +4 -2
  121. wagtail/admin/tests/test_workflows.py +531 -9
  122. wagtail/admin/tests/tests.py +3 -1
  123. wagtail/admin/tests/ui/test_tables.py +48 -1
  124. wagtail/admin/tests/viewsets/test_model_viewset.py +126 -29
  125. wagtail/admin/ui/side_panels.py +3 -1
  126. wagtail/admin/ui/tables/__init__.py +13 -1
  127. wagtail/admin/ui/tables/pages.py +17 -6
  128. wagtail/admin/urls/__init__.py +8 -3
  129. wagtail/admin/urls/pages.py +5 -0
  130. wagtail/admin/urls/workflows.py +10 -0
  131. wagtail/admin/views/chooser.py +20 -24
  132. wagtail/admin/views/collections.py +17 -1
  133. wagtail/admin/views/generic/base.py +31 -4
  134. wagtail/admin/views/generic/history.py +220 -51
  135. wagtail/admin/views/generic/mixins.py +7 -4
  136. wagtail/admin/views/generic/models.py +54 -38
  137. wagtail/admin/views/generic/multiple_upload.py +17 -8
  138. wagtail/admin/views/generic/usage.py +17 -11
  139. wagtail/admin/views/home.py +15 -12
  140. wagtail/admin/views/mixins.py +30 -0
  141. wagtail/admin/views/pages/choose_parent.py +73 -0
  142. wagtail/admin/views/pages/history.py +54 -66
  143. wagtail/admin/views/pages/listing.py +187 -106
  144. wagtail/admin/views/pages/usage.py +6 -1
  145. wagtail/admin/views/pages/utils.py +70 -1
  146. wagtail/admin/views/workflows.py +150 -21
  147. wagtail/admin/viewsets/model.py +2 -2
  148. wagtail/admin/viewsets/pages.py +77 -0
  149. wagtail/admin/wagtail_hooks.py +40 -2
  150. wagtail/admin/widgets/button.py +10 -9
  151. wagtail/api/v2/filters.py +1 -1
  152. wagtail/api/v2/tests/test_pages.py +1 -1
  153. wagtail/blocks/base.py +18 -9
  154. wagtail/blocks/field_block.py +9 -7
  155. wagtail/blocks/list_block.py +16 -6
  156. wagtail/blocks/static_block.py +3 -0
  157. wagtail/blocks/stream_block.py +58 -23
  158. wagtail/blocks/struct_block.py +15 -9
  159. wagtail/contrib/forms/locale/en/LC_MESSAGES/django.po +39 -47
  160. wagtail/contrib/forms/models.py +5 -5
  161. wagtail/contrib/forms/templates/wagtailforms/list_submissions.html +44 -33
  162. wagtail/contrib/forms/templates/wagtailforms/submissions_index.html +2 -63
  163. wagtail/contrib/forms/tests/test_models.py +26 -0
  164. wagtail/contrib/forms/urls.py +6 -0
  165. wagtail/contrib/forms/views.py +52 -49
  166. wagtail/contrib/redirects/locale/ca/LC_MESSAGES/django.mo +0 -0
  167. wagtail/contrib/redirects/locale/ca/LC_MESSAGES/django.po +3 -3
  168. wagtail/contrib/redirects/locale/en/LC_MESSAGES/django.po +34 -42
  169. wagtail/contrib/redirects/signal_handlers.py +1 -1
  170. wagtail/contrib/redirects/templates/wagtailredirects/index.html +1 -36
  171. wagtail/contrib/redirects/templates/wagtailredirects/index_results.html +18 -0
  172. wagtail/contrib/redirects/templates/wagtailredirects/redirect_target_cell.html +8 -0
  173. wagtail/contrib/redirects/tests/test_import_command.py +1 -1
  174. wagtail/contrib/redirects/tests/test_redirects.py +79 -8
  175. wagtail/contrib/redirects/urls.py +2 -1
  176. wagtail/contrib/redirects/views.py +85 -55
  177. wagtail/contrib/search_promotions/admin_urls.py +2 -1
  178. wagtail/contrib/search_promotions/locale/en/LC_MESSAGES/django.po +41 -64
  179. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/index.html +1 -16
  180. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/index_results.html +11 -0
  181. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/list.html +0 -51
  182. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/results.html +3 -16
  183. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/search_promotion_column.html +15 -0
  184. wagtail/contrib/search_promotions/tests.py +122 -9
  185. wagtail/contrib/search_promotions/views.py +66 -65
  186. wagtail/contrib/settings/locale/en/LC_MESSAGES/django.po +3 -3
  187. wagtail/contrib/settings/registry.py +10 -5
  188. wagtail/contrib/settings/tests/generic/test_admin.py +9 -0
  189. wagtail/contrib/settings/tests/site_specific/test_admin.py +10 -1
  190. wagtail/contrib/settings/tests/site_specific/test_model.py +3 -3
  191. wagtail/contrib/settings/tests/site_specific/test_templates.py +1 -1
  192. wagtail/contrib/settings/views.py +3 -1
  193. wagtail/contrib/simple_translation/locale/en/LC_MESSAGES/django.po +1 -1
  194. wagtail/contrib/simple_translation/tests/test_wagtail_hooks.py +2 -2
  195. wagtail/contrib/styleguide/locale/en/LC_MESSAGES/django.po +7 -7
  196. wagtail/contrib/table_block/blocks.py +1 -1
  197. wagtail/contrib/table_block/locale/en/LC_MESSAGES/django.po +1 -1
  198. wagtail/contrib/table_block/static/table_block/js/table.js +1 -1
  199. wagtail/contrib/typed_table_block/locale/en/LC_MESSAGES/django.po +1 -1
  200. wagtail/contrib/typed_table_block/static/typed_table_block/js/typed_table_block.js +1 -1
  201. wagtail/coreutils.py +3 -2
  202. wagtail/documents/admin_urls.py +2 -2
  203. wagtail/documents/locale/en/LC_MESSAGES/django.po +22 -22
  204. wagtail/documents/migrations/0013_delete_uploadeddocument.py +16 -0
  205. wagtail/documents/models.py +1 -20
  206. wagtail/documents/rich_text/__init__.py +11 -7
  207. wagtail/documents/static/wagtaildocs/js/document-chooser-modal.js +1 -1
  208. wagtail/documents/static/wagtaildocs/js/document-chooser-telepath.js +1 -1
  209. wagtail/documents/static/wagtaildocs/js/document-chooser.js +1 -1
  210. wagtail/documents/templates/wagtaildocs/documents/index.html +0 -16
  211. wagtail/documents/tests/test_admin_views.py +155 -23
  212. wagtail/documents/tests/test_collection_privacy.py +55 -1
  213. wagtail/documents/tests/test_rich_text.py +14 -0
  214. wagtail/documents/views/documents.py +25 -22
  215. wagtail/documents/views/multiple.py +6 -7
  216. wagtail/documents/views/serve.py +16 -1
  217. wagtail/documents/wagtail_hooks.py +20 -15
  218. wagtail/embeds/blocks.py +5 -0
  219. wagtail/embeds/locale/en/LC_MESSAGES/django.po +2 -2
  220. wagtail/embeds/rich_text/__init__.py +1 -1
  221. wagtail/embeds/tests/test_rich_text.py +14 -0
  222. wagtail/embeds/wagtail_hooks.py +4 -14
  223. wagtail/fields.py +3 -48
  224. wagtail/images/admin_urls.py +2 -2
  225. wagtail/images/check_files/wagtail.jpg +0 -0
  226. wagtail/images/check_files/wagtail.png +0 -0
  227. wagtail/images/fields.py +2 -0
  228. wagtail/images/image_operations.py +1 -1
  229. wagtail/images/locale/en/LC_MESSAGES/django.po +33 -45
  230. wagtail/images/locale/pt_PT/LC_MESSAGES/django.mo +0 -0
  231. wagtail/images/locale/pt_PT/LC_MESSAGES/django.po +4 -0
  232. wagtail/images/migrations/0026_delete_uploadedimage.py +16 -0
  233. wagtail/images/models.py +49 -43
  234. wagtail/images/rich_text/__init__.py +18 -8
  235. wagtail/images/static/wagtailimages/js/image-chooser-modal.js +1 -1
  236. wagtail/images/static/wagtailimages/js/image-chooser-telepath.js +1 -1
  237. wagtail/images/static/wagtailimages/js/image-chooser.js +1 -1
  238. wagtail/images/templates/wagtailimages/images/image_listing_header.html +6 -0
  239. wagtail/images/templates/wagtailimages/images/index.html +11 -51
  240. wagtail/images/tests/test_admin_views.py +119 -62
  241. wagtail/images/tests/test_image_operations.py +10 -0
  242. wagtail/images/tests/test_models.py +35 -33
  243. wagtail/images/tests/test_rich_text.py +14 -0
  244. wagtail/images/tests/utils.py +1 -1
  245. wagtail/images/views/images.py +35 -64
  246. wagtail/images/views/multiple.py +6 -7
  247. wagtail/images/wagtail_hooks.py +4 -14
  248. wagtail/locale/en/LC_MESSAGES/django.po +150 -136
  249. wagtail/locales/locale/en/LC_MESSAGES/django.po +1 -1
  250. wagtail/locales/tests.py +18 -3
  251. wagtail/locales/views.py +0 -1
  252. wagtail/management/commands/rebuild_references_index.py +3 -1
  253. wagtail/migrations/0092_alter_collectionviewrestriction_password_and_more.py +33 -0
  254. wagtail/migrations/0093_uploadedfile.py +53 -0
  255. wagtail/models/__init__.py +147 -32
  256. wagtail/models/i18n.py +1 -1
  257. wagtail/models/{collections.py → media.py} +33 -2
  258. wagtail/models/reference_index.py +1 -1
  259. wagtail/models/view_restrictions.py +10 -3
  260. wagtail/project_template/project_name/settings/base.py +6 -0
  261. wagtail/project_template/requirements.txt +1 -1
  262. wagtail/rich_text/__init__.py +25 -8
  263. wagtail/rich_text/pages.py +19 -8
  264. wagtail/rich_text/rewriters.py +140 -68
  265. wagtail/search/backends/database/mysql/mysql.py +3 -3
  266. wagtail/search/backends/database/postgres/postgres.py +3 -3
  267. wagtail/search/backends/database/sqlite/sqlite.py +2 -2
  268. wagtail/search/backends/elasticsearch7.py +4 -0
  269. wagtail/search/locale/en/LC_MESSAGES/django.po +3 -3
  270. wagtail/search/tests/test_postgres_backend.py +50 -0
  271. wagtail/sites/locale/en/LC_MESSAGES/django.po +8 -8
  272. wagtail/sites/tests.py +35 -9
  273. wagtail/sites/views.py +3 -1
  274. wagtail/snippets/locale/de/LC_MESSAGES/django.mo +0 -0
  275. wagtail/snippets/locale/de/LC_MESSAGES/django.po +5 -6
  276. wagtail/snippets/locale/en/LC_MESSAGES/django.po +16 -56
  277. wagtail/snippets/static/wagtailsnippets/js/snippet-chooser-telepath.js +1 -1
  278. wagtail/snippets/static/wagtailsnippets/js/snippet-chooser.js +1 -1
  279. wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/publish.html +3 -1
  280. wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/save.html +3 -1
  281. wagtail/snippets/templates/wagtailsnippets/snippets/create.html +1 -1
  282. wagtail/snippets/templates/wagtailsnippets/snippets/edit.html +1 -1
  283. wagtail/snippets/tests/test_preview.py +13 -2
  284. wagtail/snippets/tests/test_snippets.py +41 -16
  285. wagtail/snippets/tests/test_viewset.py +63 -18
  286. wagtail/snippets/tests/test_workflows.py +12 -0
  287. wagtail/snippets/views/snippets.py +1 -40
  288. wagtail/templatetags/wagtailcore_tags.py +1 -1
  289. wagtail/test/demosite/models.py +1 -1
  290. wagtail/test/middleware.py +14 -1
  291. wagtail/test/testapp/fixtures/test.json +20 -0
  292. wagtail/test/testapp/migrations/0001_squashed_0073_revisablechildmodel_secret_text.py +8 -8
  293. wagtail/test/testapp/migrations/0023_snippetchoosermodel_full_featured.py +1 -0
  294. wagtail/test/testapp/migrations/0034_custompermissionmodel.py +44 -0
  295. wagtail/test/testapp/migrations/0035_modelwithcustommanager.py +30 -0
  296. wagtail/test/testapp/migrations/0036_complexdefaultstreampage.py +28 -0
  297. wagtail/test/testapp/models.py +79 -2
  298. wagtail/test/testapp/templates/tests/custom_docs_password_required.html +10 -0
  299. wagtail/test/testapp/templates/tests/custom_page_password_required.html +10 -0
  300. wagtail/test/testapp/views.py +24 -2
  301. wagtail/test/testapp/wagtail_hooks.py +19 -0
  302. wagtail/test/utils/wagtail_tests.py +2 -2
  303. wagtail/tests/test_blocks.py +262 -1
  304. wagtail/tests/test_migrations.py +1 -1
  305. wagtail/tests/test_page_model.py +77 -0
  306. wagtail/tests/test_page_privacy.py +18 -1
  307. wagtail/tests/test_rich_text.py +95 -5
  308. wagtail/tests/test_streamfield.py +43 -0
  309. wagtail/tests/test_utils.py +8 -2
  310. wagtail/tests/test_views.py +52 -1
  311. wagtail/tests/test_whitelist.py +7 -7
  312. wagtail/users/forms.py +3 -1
  313. wagtail/users/locale/en/LC_MESSAGES/django.po +124 -96
  314. wagtail/users/migrations/0013_userprofile_density.py +23 -0
  315. wagtail/users/models.py +14 -3
  316. wagtail/users/templates/wagtailusers/groups/create.html +1 -7
  317. wagtail/users/templates/wagtailusers/groups/edit.html +1 -13
  318. wagtail/users/templates/wagtailusers/groups/includes/formatted_permissions.html +46 -2
  319. wagtail/users/templates/wagtailusers/groups/includes/group_form_js.html +0 -2
  320. wagtail/users/templates/wagtailusers/users/create.html +1 -9
  321. wagtail/users/templates/wagtailusers/users/edit.html +1 -9
  322. wagtail/users/templates/wagtailusers/users/index.html +2 -5
  323. wagtail/users/templates/wagtailusers/users/index_results.html +3 -13
  324. wagtail/users/templates/wagtailusers/users/user_cell.html +9 -0
  325. wagtail/users/templatetags/wagtailusers_tags.py +107 -20
  326. wagtail/users/tests/test_admin_views.py +669 -90
  327. wagtail/users/views/groups.py +58 -61
  328. wagtail/users/views/users.py +211 -92
  329. wagtail/users/wagtail_hooks.py +6 -38
  330. wagtail/users/widgets.py +3 -5
  331. wagtail/utils/text.py +1 -1
  332. wagtail/views.py +5 -9
  333. wagtail/whitelist.py +1 -1
  334. {wagtail-6.0.2.dist-info → wagtail-6.1rc1.dist-info}/METADATA +4 -5
  335. {wagtail-6.0.2.dist-info → wagtail-6.1rc1.dist-info}/RECORD +339 -320
  336. wagtail/admin/static/wagtailadmin/js/page-editor.js +0 -1
  337. wagtail/admin/static/wagtailadmin/js/vendor/mousetrap.min.js +0 -1
  338. wagtail/admin/static/wagtailadmin/js/vendor/urlify.js +0 -1
  339. wagtail/admin/static/wagtailadmin/js/vendor/xregexp.min.js +0 -1
  340. wagtail/admin/templates/wagtailadmin/collections/index.html +0 -34
  341. wagtail/admin/templates/wagtailadmin/pages/revisions/_actions.html +0 -22
  342. wagtail/admin/templates/wagtailadmin/shared/page_breadcrumbs.html +0 -55
  343. wagtail/admin/tests/pages/test_dashboard.py +0 -172
  344. wagtail/contrib/redirects/templates/wagtailredirects/results.html +0 -23
  345. wagtail/documents/templates/wagtaildocs/documents/list.html +0 -2
  346. wagtail/search/tests/test_postgres_stemming.py +0 -40
  347. wagtail/sites/templates/wagtailsites/create.html +0 -6
  348. wagtail/sites/templates/wagtailsites/edit.html +0 -6
  349. wagtail/snippets/templates/wagtailsnippets/snippets/revisions/_actions.html +0 -36
  350. wagtail/users/templates/wagtailusers/users/list.html +0 -62
  351. wagtail/users/urls/users.py +0 -12
  352. {wagtail-6.0.2.dist-info → wagtail-6.1rc1.dist-info}/LICENSE +0 -0
  353. {wagtail-6.0.2.dist-info → wagtail-6.1rc1.dist-info}/WHEEL +0 -0
  354. {wagtail-6.0.2.dist-info → wagtail-6.1rc1.dist-info}/entry_points.txt +0 -0
  355. {wagtail-6.0.2.dist-info → wagtail-6.1rc1.dist-info}/top_level.txt +0 -0
@@ -2,6 +2,7 @@ import json
2
2
  from unittest import mock
3
3
 
4
4
  from django.contrib.auth.models import Group, Permission
5
+ from django.contrib.contenttypes.models import ContentType
5
6
  from django.core.files.uploadedfile import SimpleUploadedFile
6
7
  from django.test import TestCase, TransactionTestCase
7
8
  from django.test.utils import override_settings
@@ -12,7 +13,13 @@ from django.utils.http import urlencode
12
13
  from wagtail.admin.admin_url_finder import AdminURLFinder
13
14
  from wagtail.documents import get_document_model, models
14
15
  from wagtail.documents.tests.utils import get_test_document_file
15
- from wagtail.models import Collection, GroupCollectionPermission, Page, ReferenceIndex
16
+ from wagtail.models import (
17
+ Collection,
18
+ GroupCollectionPermission,
19
+ Page,
20
+ ReferenceIndex,
21
+ UploadedFile,
22
+ )
16
23
  from wagtail.test.testapp.models import (
17
24
  CustomDocument,
18
25
  CustomDocumentWithAuthor,
@@ -86,6 +93,9 @@ class TestDocumentIndexView(WagtailTestUtils, TestCase):
86
93
  response = self.get()
87
94
  self.assertNotContains(response, "<th>Collection</th>", html=True)
88
95
  self.assertNotContains(response, "<td>Root</td>", html=True)
96
+ soup = self.get_soup(response.content)
97
+ collection_select = soup.select_one('select[name="collection_id"]')
98
+ self.assertIsNone(collection_select)
89
99
 
90
100
  def test_index_with_collection(self):
91
101
  root_collection = Collection.get_first_root_node()
@@ -97,8 +107,18 @@ class TestDocumentIndexView(WagtailTestUtils, TestCase):
97
107
  response = self.get()
98
108
  self.assertContains(response, "<th>Collection</th>", html=True)
99
109
  self.assertContains(response, "<td>Root</td>", html=True)
110
+
111
+ response = self.get()
112
+ soup = self.get_soup(response.content)
113
+ collection_options = soup.select(
114
+ 'select[name="collection_id"] option[value]:not(option[value=""])'
115
+ )
116
+
100
117
  self.assertEqual(
101
- [collection.name for collection in response.context["collections"]],
118
+ [
119
+ collection.get_text(strip=True).lstrip("↳ ")
120
+ for collection in collection_options
121
+ ],
102
122
  ["Root", "Evil plans", "Good plans"],
103
123
  )
104
124
 
@@ -162,7 +182,7 @@ class TestDocumentIndexView(WagtailTestUtils, TestCase):
162
182
  def test_search_form_rendered(self):
163
183
  response = self.get()
164
184
  html = response.content.decode()
165
- search_url = reverse("wagtaildocs:index")
185
+ search_url = reverse("wagtaildocs:index_results")
166
186
 
167
187
  # Search form in the header should be rendered.
168
188
  self.assertTagInHTML(
@@ -172,6 +192,101 @@ class TestDocumentIndexView(WagtailTestUtils, TestCase):
172
192
  allow_extra_attrs=True,
173
193
  )
174
194
 
195
+ def test_tags(self):
196
+ document_two_tags = models.Document.objects.create(
197
+ title="Test document with two tags"
198
+ )
199
+ document_two_tags.tags.add("one", "two")
200
+
201
+ response = self.get()
202
+ self.assertEqual(response.status_code, 200)
203
+
204
+ soup = self.get_soup(response.content)
205
+ current_tags = soup.select("input[name=tag][checked]")
206
+ self.assertFalse(current_tags)
207
+
208
+ tags = soup.select("#id_tag label")
209
+ self.assertCountEqual(
210
+ [tags.get_text(strip=True) for tags in tags],
211
+ ["one", "two"],
212
+ )
213
+
214
+ def test_tag_filtering(self):
215
+ models.Document.objects.create(title="Test document with no tags")
216
+
217
+ document_one_tag = models.Document.objects.create(
218
+ title="Test document with one tag"
219
+ )
220
+ document_one_tag.tags.add("one")
221
+
222
+ document_two_tags = models.Document.objects.create(
223
+ title="Test document with two tags"
224
+ )
225
+ document_two_tags.tags.add("one", "two")
226
+
227
+ document_unrelated_tag = models.Document.objects.create(
228
+ title="Test document with a different tag"
229
+ )
230
+ document_unrelated_tag.tags.add("unrelated")
231
+
232
+ # no filtering
233
+ response = self.get()
234
+ # four documents created above
235
+ self.assertEqual(response.context["page_obj"].paginator.count, 4)
236
+
237
+ # filter all documents with tag 'one'
238
+ response = self.get({"tag": "one"})
239
+ self.assertEqual(response.context["page_obj"].paginator.count, 2)
240
+
241
+ # filter all documents with tag 'two'
242
+ response = self.get({"tag": "two"})
243
+ self.assertEqual(response.context["page_obj"].paginator.count, 1)
244
+
245
+ # filter all documents with tag 'one' or 'unrelated'
246
+ response = self.get({"tag": ["one", "unrelated"]})
247
+ self.assertEqual(response.context["page_obj"].paginator.count, 3)
248
+
249
+ soup = self.get_soup(response.content)
250
+
251
+ # Should check the 'one' and 'unrelated' tags checkboxes
252
+ tags = soup.select("#id_tag label")
253
+ self.assertCountEqual(
254
+ [
255
+ tag.get_text(strip=True)
256
+ for tag in tags
257
+ if tag.select_one("input[checked]") is not None
258
+ ],
259
+ ["one", "unrelated"],
260
+ )
261
+
262
+ # Should render the active filter pills separately for each tag
263
+ active_filters = soup.select('[data-w-active-filter-id="id_tag"]')
264
+ self.assertCountEqual(
265
+ [filter.get_text(separator=" ", strip=True) for filter in active_filters],
266
+ ["Tag: one", "Tag: unrelated"],
267
+ )
268
+
269
+ def test_tag_filtering_preserves_other_params(self):
270
+ for i in range(1, 130):
271
+ document = models.Document.objects.create(title="Test document %i" % i)
272
+ if i % 2 != 0:
273
+ document.tags.add("even")
274
+ document.save()
275
+
276
+ response = self.get({"tag": "even", "p": 2})
277
+ self.assertEqual(response.status_code, 200)
278
+
279
+ response_body = response.content.decode("utf8")
280
+
281
+ # prev link should exist and include tag
282
+ self.assertTrue(
283
+ "?p=1&amp;tag=even" in response_body or "?tag=even&amp;p=1" in response_body
284
+ )
285
+ # next link should exist and include tag
286
+ self.assertTrue(
287
+ "?p=3&amp;tag=even" in response_body or "?tag=even&amp;p=3" in response_body
288
+ )
289
+
175
290
 
176
291
  class TestDocumentIndexViewSearch(WagtailTestUtils, TransactionTestCase):
177
292
  def setUp(self):
@@ -225,6 +340,24 @@ class TestDocumentIndexViewSearch(WagtailTestUtils, TransactionTestCase):
225
340
  self.assertTemplateUsed(response, "wagtaildocs/documents/index.html")
226
341
  self.assertContains(response, "There are 50 matches")
227
342
 
343
+ def test_tag_filtering_with_search_term(self):
344
+ models.Document.objects.create(title="Test document with no tags")
345
+
346
+ document_one_tag = models.Document.objects.create(
347
+ title="Test document with one tag"
348
+ )
349
+ document_one_tag.tags.add("one")
350
+
351
+ document_two_tags = models.Document.objects.create(
352
+ title="Test document with two tags"
353
+ )
354
+ document_two_tags.tags.add("one", "two")
355
+
356
+ # The tag shouldn't be ignored, so the result should be the documents
357
+ # that have the "one" tag and "test" in the title.
358
+ response = self.get({"tag": "one", "q": "test"})
359
+ self.assertEqual(response.context["page_obj"].paginator.count, 2)
360
+
228
361
 
229
362
  class TestDocumentIndexResultsView(WagtailTestUtils, TransactionTestCase):
230
363
  def setUp(self):
@@ -1277,15 +1410,16 @@ class TestMultipleCustomDocumentUploaderWithRequiredField(TestMultipleDocumentUp
1277
1410
  def setUp(self):
1278
1411
  super().setUp()
1279
1412
 
1280
- # Create an UploadedDocument for running tests on
1281
- self.uploaded_document = models.UploadedDocument.objects.create(
1413
+ # Create an UploadedFile for running tests on
1414
+ self.uploaded_document = UploadedFile.objects.create(
1415
+ for_content_type=ContentType.objects.get_for_model(get_document_model()),
1282
1416
  file=get_test_document_file(),
1283
1417
  uploaded_by_user=self.user,
1284
1418
  )
1285
1419
 
1286
1420
  def test_add_post(self):
1287
1421
  """
1288
- This tests that a POST request to the add view saves the document as an UploadedDocument
1422
+ This tests that a POST request to the add view saves the document as an UploadedFile
1289
1423
  and returns an edit form
1290
1424
  """
1291
1425
  response = self.client.post(
@@ -1326,11 +1460,11 @@ class TestMultipleCustomDocumentUploaderWithRequiredField(TestMultipleDocumentUp
1326
1460
 
1327
1461
  # Check JSON
1328
1462
  response_json = json.loads(response.content.decode())
1329
- self.assertIn("uploaded_document_id", response_json)
1463
+ self.assertIn("uploaded_file_id", response_json)
1330
1464
  self.assertIn("form", response_json)
1331
1465
  self.assertIn("success", response_json)
1332
1466
  self.assertEqual(
1333
- response_json["uploaded_document_id"],
1467
+ response_json["uploaded_file_id"],
1334
1468
  response.context["uploaded_document"].id,
1335
1469
  )
1336
1470
  self.assertTrue(response_json["success"])
@@ -1363,10 +1497,10 @@ class TestMultipleCustomDocumentUploaderWithRequiredField(TestMultipleDocumentUp
1363
1497
 
1364
1498
  # Check JSON
1365
1499
  response_json = json.loads(response.content.decode())
1366
- self.assertIn("uploaded_document_id", response_json)
1500
+ self.assertIn("uploaded_file_id", response_json)
1367
1501
  self.assertIn("form", response_json)
1368
1502
  self.assertEqual(
1369
- response_json["uploaded_document_id"],
1503
+ response_json["uploaded_file_id"],
1370
1504
  response.context["uploaded_document"].id,
1371
1505
  )
1372
1506
  self.assertTrue(response_json["success"])
@@ -1419,11 +1553,11 @@ class TestMultipleCustomDocumentUploaderWithRequiredField(TestMultipleDocumentUp
1419
1553
 
1420
1554
  # Check JSON
1421
1555
  response_json = json.loads(response.content.decode())
1422
- self.assertIn("uploaded_document_id", response_json)
1556
+ self.assertIn("uploaded_file_id", response_json)
1423
1557
  self.assertIn("form", response_json)
1424
1558
  self.assertIn("success", response_json)
1425
1559
  self.assertEqual(
1426
- response_json["uploaded_document_id"],
1560
+ response_json["uploaded_file_id"],
1427
1561
  response.context["uploaded_document"].id,
1428
1562
  )
1429
1563
  self.assertTrue(response_json["success"])
@@ -1438,10 +1572,10 @@ class TestMultipleCustomDocumentUploaderWithRequiredField(TestMultipleDocumentUp
1438
1572
  def test_create_from_upload_invalid_post(self):
1439
1573
  """
1440
1574
  Posting an invalid form to the create_from_uploaded_document view throws a validation error
1441
- and leaves the UploadedDocument intact
1575
+ and leaves the UploadedFile intact
1442
1576
  """
1443
1577
  doc_count_before = CustomDocumentWithAuthor.objects.count()
1444
- uploaded_doc_count_before = models.UploadedDocument.objects.count()
1578
+ uploaded_doc_count_before = UploadedFile.objects.count()
1445
1579
 
1446
1580
  # Send request
1447
1581
  response = self.client.post(
@@ -1459,9 +1593,9 @@ class TestMultipleCustomDocumentUploaderWithRequiredField(TestMultipleDocumentUp
1459
1593
  )
1460
1594
 
1461
1595
  doc_count_after = CustomDocumentWithAuthor.objects.count()
1462
- uploaded_doc_count_after = models.UploadedDocument.objects.count()
1596
+ uploaded_doc_count_after = UploadedFile.objects.count()
1463
1597
 
1464
- # no changes to document / UploadedDocument count
1598
+ # no changes to document / UploadedFile count
1465
1599
  self.assertEqual(doc_count_after, doc_count_before)
1466
1600
  self.assertEqual(uploaded_doc_count_after, uploaded_doc_count_before)
1467
1601
 
@@ -1497,7 +1631,7 @@ class TestMultipleCustomDocumentUploaderWithRequiredField(TestMultipleDocumentUp
1497
1631
  Posting a valid form to the create_from_uploaded_document view will create the document
1498
1632
  """
1499
1633
  doc_count_before = CustomDocumentWithAuthor.objects.count()
1500
- uploaded_doc_count_before = models.UploadedDocument.objects.count()
1634
+ uploaded_doc_count_before = UploadedFile.objects.count()
1501
1635
 
1502
1636
  # Send request
1503
1637
  response = self.client.post(
@@ -1519,7 +1653,7 @@ class TestMultipleCustomDocumentUploaderWithRequiredField(TestMultipleDocumentUp
1519
1653
  )
1520
1654
 
1521
1655
  doc_count_after = CustomDocumentWithAuthor.objects.count()
1522
- uploaded_doc_count_after = models.UploadedDocument.objects.count()
1656
+ uploaded_doc_count_after = UploadedFile.objects.count()
1523
1657
 
1524
1658
  # Check response
1525
1659
  self.assertEqual(response.status_code, 200)
@@ -1530,7 +1664,7 @@ class TestMultipleCustomDocumentUploaderWithRequiredField(TestMultipleDocumentUp
1530
1664
  self.assertIn("doc_id", response_json)
1531
1665
  self.assertTrue(response_json["success"])
1532
1666
 
1533
- # Document should have been created, UploadedDocument deleted
1667
+ # Document should have been created, UploadedFile deleted
1534
1668
  self.assertEqual(doc_count_after, doc_count_before + 1)
1535
1669
  self.assertEqual(uploaded_doc_count_after, uploaded_doc_count_before - 1)
1536
1670
 
@@ -1544,7 +1678,7 @@ class TestMultipleCustomDocumentUploaderWithRequiredField(TestMultipleDocumentUp
1544
1678
 
1545
1679
  def test_delete_uploaded_document(self):
1546
1680
  """
1547
- This tests that a POST request to the delete view deletes the UploadedDocument
1681
+ This tests that a POST request to the delete view deletes the UploadedFile
1548
1682
  """
1549
1683
  # Send request
1550
1684
  response = self.client.post(
@@ -1559,9 +1693,7 @@ class TestMultipleCustomDocumentUploaderWithRequiredField(TestMultipleDocumentUp
1559
1693
 
1560
1694
  # Make sure the document is deleted
1561
1695
  self.assertFalse(
1562
- models.UploadedDocument.objects.filter(
1563
- id=self.uploaded_document.id
1564
- ).exists()
1696
+ UploadedFile.objects.filter(id=self.uploaded_document.id).exists()
1565
1697
  )
1566
1698
 
1567
1699
  # Check JSON
@@ -1,6 +1,6 @@
1
1
  from django.contrib.auth.models import Group
2
2
  from django.core.files.base import ContentFile
3
- from django.test import TestCase
3
+ from django.test import TestCase, override_settings
4
4
  from django.urls import reverse
5
5
 
6
6
  from wagtail.documents.models import Document
@@ -19,6 +19,7 @@ class TestCollectionPrivacyDocument(WagtailTestUtils, TestCase):
19
19
  def setUp(self):
20
20
  self.fake_file = ContentFile(b"A boring example document")
21
21
  self.fake_file.name = "test.txt"
22
+ self.collection = Collection.objects.get(id=2)
22
23
  self.password_collection = Collection.objects.get(name="Password protected")
23
24
  self.login_collection = Collection.objects.get(name="Login protected")
24
25
  self.group_collection = Collection.objects.get(name="Group protected")
@@ -106,6 +107,28 @@ class TestCollectionPrivacyDocument(WagtailTestUtils, TestCase):
106
107
  )
107
108
  self.assertRedirects(response, "/")
108
109
 
110
+ @override_settings(
111
+ WAGTAILDOCS_PASSWORD_REQUIRED_TEMPLATE="tests/custom_docs_password_required.html"
112
+ )
113
+ def test_anonymous_user_must_authenticate_with_custom_password_required_template(
114
+ self
115
+ ):
116
+ secret_document = Document.objects.create(
117
+ title="Test document",
118
+ file=self.fake_file,
119
+ collection=self.password_collection,
120
+ )
121
+ doc_url = reverse(
122
+ "wagtaildocs_serve", args=(secret_document.id, secret_document.filename)
123
+ )
124
+ response = self.client.get(doc_url)
125
+ self.assertNotEqual(
126
+ response.templates[0].name, "wagtaildocs/password_required.html"
127
+ )
128
+ self.assertEqual(
129
+ response.templates[0].name, "tests/custom_docs_password_required.html"
130
+ )
131
+
109
132
  def test_group_restriction_with_anonymous_user(self):
110
133
  response, url = self.get_document(self.group_collection)
111
134
  self.assertRedirects(response, f"/_util/login/?next={url}")
@@ -133,3 +156,34 @@ class TestCollectionPrivacyDocument(WagtailTestUtils, TestCase):
133
156
  self.login(username="eventmoderator", password="password")
134
157
  response, url = self.get_document(self.login_collection)
135
158
  self.assertEqual(response.status_code, 200)
159
+
160
+ def test_set_shared_password_with_logged_in_user(self):
161
+ self.login()
162
+ response = self.client.get(
163
+ reverse("wagtailadmin_collections:set_privacy", args=(self.collection.id,)),
164
+ )
165
+
166
+ input_el = self.get_soup(response.content).select_one("[data-field-input]")
167
+ self.assertEqual(response.status_code, 200)
168
+
169
+ # check that input option for password is visible
170
+ self.assertIn("password", response.context["form"].fields)
171
+
172
+ # check that the option for password is visible
173
+ self.assertIsNotNone(input_el)
174
+
175
+ @override_settings(
176
+ WAGTAILDOCS_PRIVATE_COLLECTION_OPTIONS={"SHARED_PASSWORD": False}
177
+ )
178
+ def test_unset_shared_password_with_logged_in_user(self):
179
+ self.login()
180
+ response = self.client.get(
181
+ reverse("wagtailadmin_collections:set_privacy", args=(self.collection.id,)),
182
+ )
183
+ self.assertEqual(response.status_code, 200)
184
+ self.assertNotIn("password", response.context["form"].fields)
185
+ self.assertFalse(
186
+ response.context["form"]
187
+ .fields["restriction_type"]
188
+ .valid_value(CollectionViewRestriction.PASSWORD)
189
+ )
@@ -1,4 +1,5 @@
1
1
  from django.test import TestCase
2
+ from django.urls import reverse_lazy
2
3
 
3
4
  from wagtail.documents import get_document_model
4
5
  from wagtail.documents.rich_text import (
@@ -8,6 +9,7 @@ from wagtail.documents.rich_text.editor_html import (
8
9
  DocumentLinkHandler as EditorHtmlDocumentLinkHandler,
9
10
  )
10
11
  from wagtail.fields import RichTextField
12
+ from wagtail.rich_text.feature_registry import FeatureRegistry
11
13
  from wagtail.test.utils import WagtailTestUtils
12
14
 
13
15
 
@@ -60,3 +62,15 @@ class TestFrontendDocumentLinkHandler(TestCase):
60
62
  ),
61
63
  [(get_document_model(), "1", "", "")],
62
64
  )
65
+
66
+
67
+ class TestEntityFeatureChooserUrls(TestCase):
68
+ def test_chooser_urls_exist(self):
69
+ features = FeatureRegistry()
70
+ document = features.get_editor_plugin("draftail", "document-link")
71
+
72
+ self.assertIsNotNone(document.data.get("chooserUrls"))
73
+ self.assertEqual(
74
+ document.data["chooserUrls"]["documentChooser"],
75
+ reverse_lazy("wagtaildocs_chooser:choose"),
76
+ )
@@ -12,6 +12,7 @@ from django.utils.translation import gettext_lazy, ngettext
12
12
 
13
13
  from wagtail.admin import messages
14
14
  from wagtail.admin.auth import PermissionPolicyChecker
15
+ from wagtail.admin.filters import BaseMediaFilterSet
15
16
  from wagtail.admin.ui.tables import (
16
17
  BulkActionsCheckboxColumn,
17
18
  Column,
@@ -25,9 +26,9 @@ from wagtail.admin.views import generic
25
26
  from wagtail.documents import get_document_model
26
27
  from wagtail.documents.forms import get_document_form
27
28
  from wagtail.documents.permissions import permission_policy
28
- from wagtail.models import Collection
29
29
 
30
30
  permission_checker = PermissionPolicyChecker(permission_policy)
31
+ Document = get_document_model()
31
32
 
32
33
 
33
34
  class BulkActionsColumn(BulkActionsCheckboxColumn):
@@ -49,6 +50,14 @@ class DocumentTable(Table):
49
50
  return context
50
51
 
51
52
 
53
+ class DocumentsFilterSet(BaseMediaFilterSet):
54
+ permission_policy = permission_policy
55
+
56
+ class Meta:
57
+ model = Document
58
+ fields = []
59
+
60
+
52
61
  class IndexView(generic.IndexView):
53
62
  permission_policy = permission_policy
54
63
  any_permission_required = ["add", "change", "delete"]
@@ -65,9 +74,11 @@ class IndexView(generic.IndexView):
65
74
  results_template_name = "wagtaildocs/documents/index_results.html"
66
75
  default_ordering = "title"
67
76
  table_class = DocumentTable
77
+ filterset_class = DocumentsFilterSet
68
78
  model = get_document_model()
69
79
  add_item_label = gettext_lazy("Add a document")
70
80
  show_other_searches = True
81
+ _show_breadcrumbs = True
71
82
 
72
83
  def get_base_queryset(self):
73
84
  # Get documents (filtered by user permission)
@@ -75,17 +86,10 @@ class IndexView(generic.IndexView):
75
86
  self.request.user, ["change", "delete"]
76
87
  ).select_related("collection")
77
88
 
78
- def filter_queryset(self, queryset):
79
- self.current_collection = None
80
- collection_id = self.request.GET.get("collection_id")
81
- if collection_id:
82
- try:
83
- self.current_collection = Collection.objects.get(id=collection_id)
84
- queryset = queryset.filter(collection=self.current_collection)
85
- except (ValueError, Collection.DoesNotExist):
86
- pass
87
-
88
- return queryset
89
+ @cached_property
90
+ def current_collection(self):
91
+ # Upon validation, the cleaned data is a Collection instance
92
+ return self.filters and self.filters.form.cleaned_data.get("collection_id")
89
93
 
90
94
  @cached_property
91
95
  def columns(self):
@@ -106,7 +110,7 @@ class IndexView(generic.IndexView):
106
110
  width="16%",
107
111
  ),
108
112
  ]
109
- if self.collections:
113
+ if self.filters and "collection_id" in self.filters.filters:
110
114
  columns.insert(
111
115
  3,
112
116
  Column("collection", label=_("Collection"), accessor="collection.name"),
@@ -130,10 +134,10 @@ class IndexView(generic.IndexView):
130
134
  return next_url
131
135
 
132
136
  def get_add_url(self):
133
- # Pass the query string so that the collection filter is preserved
137
+ # Pass the collection filter to prefill the add form's collection field
134
138
  return set_query_params(
135
139
  super().get_add_url(),
136
- self.request.GET.copy(),
140
+ {"collection_id": self.current_collection and self.current_collection.pk},
137
141
  )
138
142
 
139
143
  def get_edit_url(self, instance):
@@ -142,15 +146,14 @@ class IndexView(generic.IndexView):
142
146
  {"next": self.get_next_url()},
143
147
  )
144
148
 
149
+ def get_filterset_kwargs(self):
150
+ kwargs = super().get_filterset_kwargs()
151
+ kwargs["is_searching"] = self.is_searching
152
+ return kwargs
153
+
145
154
  def get_context_data(self, **kwargs):
146
155
  context = super().get_context_data(**kwargs)
147
-
148
- context.update(
149
- {
150
- "collections": self.collections,
151
- "current_collection": self.current_collection,
152
- }
153
- )
156
+ context["current_collection"] = self.current_collection
154
157
  return context
155
158
 
156
159
 
@@ -12,14 +12,12 @@ from wagtail.admin.views.generic.multiple_upload import EditView as BaseEditView
12
12
 
13
13
  from .. import get_document_model
14
14
  from ..forms import get_document_form, get_document_multi_form
15
- from ..models import UploadedDocument
16
15
  from ..permissions import permission_policy
17
16
 
18
17
 
19
18
  class AddView(BaseAddView):
20
19
  permission_policy = permission_policy
21
20
  template_name = "wagtaildocs/multiple/add.html"
22
- upload_model = UploadedDocument
23
21
 
24
22
  edit_object_url_name = "wagtaildocs:edit_multiple"
25
23
  delete_object_url_name = "wagtaildocs:delete_multiple"
@@ -31,7 +29,7 @@ class AddView(BaseAddView):
31
29
  delete_upload_url_name = "wagtaildocs:delete_upload_multiple"
32
30
  edit_upload_form_prefix = "uploaded-document"
33
31
  context_upload_name = "uploaded_document"
34
- context_upload_id_name = "uploaded_document_id"
32
+ context_upload_id_name = "uploaded_file_id"
35
33
 
36
34
  def get_model(self):
37
35
  return get_document_model()
@@ -90,8 +88,7 @@ class DeleteView(BaseDeleteView):
90
88
  class CreateFromUploadedDocumentView(BaseCreateFromUploadView):
91
89
  edit_upload_url_name = "wagtaildocs:create_multiple_from_uploaded_document"
92
90
  delete_upload_url_name = "wagtaildocs:delete_upload_multiple"
93
- upload_model = UploadedDocument
94
- upload_pk_url_kwarg = "uploaded_document_id"
91
+ upload_pk_url_kwarg = "uploaded_file_id"
95
92
  edit_upload_form_prefix = "uploaded-document"
96
93
  context_object_id_name = "doc_id"
97
94
  context_upload_name = "uploaded_document"
@@ -118,5 +115,7 @@ class CreateFromUploadedDocumentView(BaseCreateFromUploadView):
118
115
 
119
116
 
120
117
  class DeleteUploadView(BaseDeleteUploadView):
121
- upload_model = UploadedDocument
122
- upload_pk_url_kwarg = "uploaded_document_id"
118
+ upload_pk_url_kwarg = "uploaded_file_id"
119
+
120
+ def get_model(self):
121
+ return get_document_model()
@@ -1,3 +1,5 @@
1
+ from warnings import warn
2
+
1
3
  from django.conf import settings
2
4
  from django.http import FileResponse, Http404, HttpResponse
3
5
  from django.shortcuts import get_object_or_404, redirect
@@ -12,6 +14,7 @@ from wagtail.documents.models import document_served
12
14
  from wagtail.forms import PasswordViewRestrictionForm
13
15
  from wagtail.models import CollectionViewRestriction
14
16
  from wagtail.utils import sendfile_streaming_backend
17
+ from wagtail.utils.deprecation import RemovedInWagtail70Warning
15
18
  from wagtail.utils.sendfile import sendfile
16
19
 
17
20
 
@@ -135,9 +138,21 @@ def authenticate_with_password(request, restriction_id):
135
138
 
136
139
  password_required_template = getattr(
137
140
  settings,
138
- "DOCUMENT_PASSWORD_REQUIRED_TEMPLATE",
141
+ "WAGTAILDOCS_PASSWORD_REQUIRED_TEMPLATE",
139
142
  "wagtaildocs/password_required.html",
140
143
  )
141
144
 
145
+ if hasattr(settings, "DOCUMENT_PASSWORD_REQUIRED_TEMPLATE"):
146
+ warn(
147
+ "The `DOCUMENT_PASSWORD_REQUIRED_TEMPLATE` setting is deprecated - use `WAGTAILDOCS_PASSWORD_REQUIRED_TEMPLATE` instead.",
148
+ category=RemovedInWagtail70Warning,
149
+ )
150
+
151
+ password_required_template = getattr(
152
+ settings,
153
+ "DOCUMENT_PASSWORD_REQUIRED_TEMPLATE",
154
+ password_required_template,
155
+ )
156
+
142
157
  context = {"form": form, "action_url": action_url}
143
158
  return TemplateResponse(request, password_required_template, context)