Same approach as 4023a90d6e for images - define an UploadedDocument model to hold the uploaded file up to the point where the required metadata has been supplied.
Boto3 has been around for a long time now. Adding a Boto-specific parameter in a tutorial is confusing (it was for me) as people are likely to install Boto3 directly and skip Boto. The `AWS_HEADERS` parameter was replaced by the `AWS_S3_OBJECT_PARAMETERS` parameter in Boto3 and the parameter that controls the access control list specifically is the `ACL`.
By the way, are the instructions on line 50 still relevant today?
Signal receivers must accept `**kwargs`, otherwise one runs into this:
```
File "/lib/python3.8/site-packages/django/dispatch/dispatcher.py", line 94, in connect
raise ValueError("Signal receivers must accept keyword arguments (**kwargs).")
ValueError: Signal receivers must accept keyword arguments (**kwargs).
```
This PR adds the 'choose' permission discussed in #4488. It limits Image and Document choosers to showing only those Collections (and their contents) for which the current user has the Choose permission.
It grants Choose permissions to the Root Collection to every existing Group that has the "Can access Wagtail admin" perm, via data migration. So there will be no change in behavior unless the user goes in and alters the Choose perms for their site's groups.
This PR has no effect on anything except choosers. The Image and Document index pages are still controlled solely by the 'add' and 'change' permissions, as those are only accessible by users who have those permissions in the first place. This means that it's now possible to configure a Group to allow its members to choose images from existing Collections when editing pages, *without* them being able to edit said images or add new ones.
This avoids separate lookups during render_html and render_js_init, and means that shared logic such as building the edit-view URL can be accessed outside of template rendering (so that we can pass it to chooser.setState in the Javascript chooser API, for example).
Passing the model instance means that logic such as rendering thumbnails and generating URLs to edit pages ends up on the template. This is bad because we're going to want to populate these widgets through mechanisms other than rendering the template (e.g. setState on the widget's Javascript API), and that would end up duplicating the logic on the template.
This will make them easier to manage when they need to be passed through additional levels of indirection between the Python widget code and the eventual call to createPageChooser, e.g. in PageChooserBlock.
It's a really small thing, but I honestly feel like Cynthia did most of the work of taking my workaround to production quality code and pushing it over the finish line. So she should be first here.