Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 38 additions & 1 deletion src/wagtailmedia/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
)
from wagtail.models import Collection

from wagtailmedia.models import Media
from wagtailmedia.models import Media, MediaType
from wagtailmedia.permissions import permission_policy as media_permission_policy
from wagtailmedia.settings import wagtailmedia_settings

Expand All @@ -29,6 +29,14 @@ def formfield_for_dbfield(db_field, **kwargs):
return db_field.formfield(**kwargs)


def format_extensions_for_accept_value(allowed_extensions: list[str]) -> str:
"""Returns the specified extensions in a format usable in the `accept=""` attribute of a `FileInput` widget.
This assumes the list of extensions are the bare extensions e.g., `["mp4", "webm"]` and prefixes each extension with
a ".".
"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return ",".join([f".{e}" for e in allowed_extensions])


class BaseMediaForm(BaseCollectionMemberForm):
class Meta:
widgets = {
Expand All @@ -42,12 +50,41 @@ class Meta:
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

if file_accept_value := self.get_file_accept_value(self.instance.type):
self.fields["file"].widget.attrs["accept"] = file_accept_value

if self.instance.type == "audio":
for name in ("width", "height"):
# these fields might be editable=False so verify before accessing
if name in self.fields:
del self.fields[name]

@staticmethod
def get_file_accept_value(media_type: MediaType) -> str | None:
"""Dynamically set the `accept` attribute on the file input based on the media type. If allowed extensions have
been configured in settings, this will restrict the file input to only those extensions. Otherwise, it will
fall back to allowing all video or audio file types.
See https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input/file#unique_file_type_specifiers
for more information on the `accept` attribute.
"""

if media_type == MediaType.VIDEO:
return (
format_extensions_for_accept_value(
wagtailmedia_settings.VIDEO_EXTENSIONS
)
or "video/*"
)
elif media_type == MediaType.AUDIO:
return (
format_extensions_for_accept_value(
wagtailmedia_settings.AUDIO_EXTENSIONS
)
or "audio/*"
)

return None


def get_media_base_form():
base_form_override = wagtailmedia_settings.MEDIA_FORM_BASE
Expand Down
44 changes: 44 additions & 0 deletions tests/test_form.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from django.test import TestCase, override_settings

from wagtailmedia.forms import format_extensions_for_accept_value, get_media_form
from wagtailmedia.models import MediaType, get_media_model
from wagtailmedia.settings import wagtailmedia_settings


class TestForm(TestCase):
def test_file_input_accept_attribute(self):
"""Tests that the file input widget only accepts the default file extensions per media type."""
Media = get_media_model()
MediaForm = get_media_form(Media)
media_type_to_extensions = {
MediaType.VIDEO: wagtailmedia_settings.VIDEO_EXTENSIONS,
MediaType.AUDIO: wagtailmedia_settings.AUDIO_EXTENSIONS,
}
for media_type, extensions in media_type_to_extensions.items():
media = Media(type=media_type)
form = MediaForm(instance=media)

self.assertIn(
f'accept="{format_extensions_for_accept_value(extensions)}"',
form["file"].as_widget(),
)

@override_settings(WAGTAILMEDIA={"VIDEO_EXTENSIONS": [], "AUDIO_EXTENSIONS": []})
def test_file_input_accept_attribute_all_extensions_allowed(self):
"""Tests that if `VIDEO_EXTENSIONS` and `AUDIO_EXTENSIONS` are set to empty lists, that the accept attribute
allows all file extensions for the given media type.
"""
Media = get_media_model()
MediaForm = get_media_form(Media)
media_type_to_extensions = {
MediaType.VIDEO: "video/*",
MediaType.AUDIO: "audio/*",
}
for media_type, accept_value in media_type_to_extensions.items():
media = Media(type=media_type)
form = MediaForm(instance=media)

self.assertIn(
f'accept="{accept_value}"',
form["file"].as_widget(),
)