mirror of
https://github.com/mediacms-io/mediacms.git
synced 2025-07-25 15:03:22 +00:00

By default, Django uses type=text for the date input, which respects the locale settings. However, when changing the input type to date, it should only accept YYYY-MM-DD format so the input field can be properly handled.
258 lines
10 KiB
Python
258 lines
10 KiB
Python
from crispy_forms.bootstrap import FormActions
|
|
from crispy_forms.helper import FormHelper
|
|
from crispy_forms.layout import Field, Layout, Submit
|
|
from django import forms
|
|
from django.conf import settings
|
|
|
|
from .methods import get_next_state, is_mediacms_editor
|
|
from .models import MEDIA_STATES, Category, Media, Subtitle
|
|
|
|
|
|
class CustomField(Field):
|
|
template = 'cms/crispy_custom_field.html'
|
|
|
|
|
|
class MultipleSelect(forms.CheckboxSelectMultiple):
|
|
input_type = "checkbox"
|
|
|
|
|
|
class MediaMetadataForm(forms.ModelForm):
|
|
new_tags = forms.CharField(label="Tags", help_text="a comma separated list of tags.", required=False)
|
|
|
|
class Meta:
|
|
model = Media
|
|
fields = (
|
|
"friendly_token",
|
|
"title",
|
|
"new_tags",
|
|
"add_date",
|
|
"uploaded_poster",
|
|
"description",
|
|
"enable_comments",
|
|
"thumbnail_time",
|
|
)
|
|
|
|
widgets = {
|
|
"new_tags": MultipleSelect(),
|
|
"description": forms.Textarea(attrs={'rows': 4}),
|
|
"add_date": forms.DateInput(attrs={'type': 'date'}, format='%Y-%m-%d'),
|
|
"thumbnail_time": forms.NumberInput(attrs={'min': 0, 'step': 0.1}),
|
|
}
|
|
labels = {
|
|
"friendly_token": "Slug",
|
|
"uploaded_poster": "Poster Image",
|
|
"thumbnail_time": "Thumbnail Time (seconds)",
|
|
}
|
|
help_texts = {
|
|
"title": "",
|
|
"friendly_token": "Media URL slug",
|
|
"thumbnail_time": "Select the time in seconds for the video thumbnail",
|
|
"uploaded_poster": "Maximum file size: 5MB",
|
|
}
|
|
|
|
def __init__(self, user, *args, **kwargs):
|
|
self.user = user
|
|
super(MediaMetadataForm, self).__init__(*args, **kwargs)
|
|
if not getattr(settings, 'ALLOW_CUSTOM_MEDIA_URLS', False):
|
|
self.fields.pop("friendly_token")
|
|
if self.instance.media_type != "video":
|
|
self.fields.pop("thumbnail_time")
|
|
if self.instance.media_type == "image":
|
|
self.fields.pop("uploaded_poster")
|
|
|
|
self.fields["new_tags"].initial = ", ".join([tag.title for tag in self.instance.tags.all()])
|
|
|
|
self.helper = FormHelper()
|
|
self.helper.form_tag = True
|
|
self.helper.form_class = 'post-form'
|
|
self.helper.form_method = 'post'
|
|
self.helper.form_enctype = "multipart/form-data"
|
|
self.helper.form_show_errors = False
|
|
self.helper.layout = Layout(
|
|
CustomField('title'),
|
|
CustomField('new_tags'),
|
|
CustomField('add_date'),
|
|
CustomField('description'),
|
|
CustomField('uploaded_poster'),
|
|
CustomField('enable_comments'),
|
|
)
|
|
|
|
if self.instance.media_type == "video":
|
|
self.helper.layout.append(CustomField('thumbnail_time'))
|
|
if getattr(settings, 'ALLOW_CUSTOM_MEDIA_URLS', False):
|
|
self.helper.layout.insert(0, CustomField('friendly_token'))
|
|
|
|
self.helper.layout.append(FormActions(Submit('submit', 'Update Media', css_class='primaryAction')))
|
|
|
|
def clean_friendly_token(self):
|
|
token = self.cleaned_data.get("friendly_token", "").strip()
|
|
|
|
if token:
|
|
if not all(c.isalnum() or c in "-_" for c in token):
|
|
raise forms.ValidationError("Slug can only contain alphanumeric characters, underscores, or hyphens.")
|
|
|
|
if Media.objects.filter(friendly_token=token).exclude(pk=self.instance.pk).exists():
|
|
raise forms.ValidationError("This slug is already in use. Please choose a different one.")
|
|
return token
|
|
|
|
def clean_uploaded_poster(self):
|
|
image = self.cleaned_data.get("uploaded_poster", False)
|
|
if image:
|
|
if image.size > 5 * 1024 * 1024:
|
|
raise forms.ValidationError("Image file too large ( > 5mb )")
|
|
return image
|
|
|
|
def save(self, *args, **kwargs):
|
|
data = self.cleaned_data # noqa
|
|
|
|
media = super(MediaMetadataForm, self).save(*args, **kwargs)
|
|
return media
|
|
|
|
|
|
class MediaPublishForm(forms.ModelForm):
|
|
confirm_state = forms.BooleanField(required=False, initial=False, label="Acknowledge sharing status", help_text="")
|
|
|
|
class Meta:
|
|
model = Media
|
|
fields = (
|
|
"category",
|
|
"state",
|
|
"featured",
|
|
"reported_times",
|
|
"is_reviewed",
|
|
"allow_download",
|
|
)
|
|
|
|
widgets = {
|
|
"category": MultipleSelect(),
|
|
}
|
|
|
|
def __init__(self, user, *args, **kwargs):
|
|
self.user = user
|
|
super(MediaPublishForm, self).__init__(*args, **kwargs)
|
|
if not is_mediacms_editor(user):
|
|
for field in ["featured", "reported_times", "is_reviewed"]:
|
|
self.fields[field].disabled = True
|
|
self.fields[field].widget.attrs['class'] = 'read-only-field'
|
|
self.fields[field].widget.attrs['title'] = "This field can only be modified by MediaCMS admins or editors"
|
|
|
|
if settings.PORTAL_WORKFLOW not in ["public"]:
|
|
valid_states = ["unlisted", "private"]
|
|
if self.instance.state and self.instance.state not in valid_states:
|
|
valid_states.append(self.instance.state)
|
|
self.fields["state"].choices = [(state, dict(MEDIA_STATES).get(state, state)) for state in valid_states]
|
|
|
|
if getattr(settings, 'USE_RBAC', False) and 'category' in self.fields:
|
|
if is_mediacms_editor(user):
|
|
pass
|
|
else:
|
|
self.fields['category'].initial = self.instance.category.all()
|
|
|
|
non_rbac_categories = Category.objects.filter(is_rbac_category=False)
|
|
rbac_categories = user.get_rbac_categories_as_contributor()
|
|
combined_category_ids = list(non_rbac_categories.values_list('id', flat=True)) + list(rbac_categories.values_list('id', flat=True))
|
|
|
|
if self.instance.pk:
|
|
instance_category_ids = list(self.instance.category.all().values_list('id', flat=True))
|
|
combined_category_ids = list(set(combined_category_ids + instance_category_ids))
|
|
|
|
self.fields['category'].queryset = Category.objects.filter(id__in=combined_category_ids).order_by('title')
|
|
|
|
self.helper = FormHelper()
|
|
self.helper.form_tag = True
|
|
self.helper.form_class = 'post-form'
|
|
self.helper.form_method = 'post'
|
|
self.helper.form_enctype = "multipart/form-data"
|
|
self.helper.form_show_errors = False
|
|
self.helper.layout = Layout(
|
|
CustomField('category'),
|
|
CustomField('state'),
|
|
CustomField('featured'),
|
|
CustomField('reported_times'),
|
|
CustomField('is_reviewed'),
|
|
CustomField('allow_download'),
|
|
)
|
|
|
|
self.helper.layout.append(FormActions(Submit('submit', 'Publish Media', css_class='primaryAction')))
|
|
|
|
def clean(self):
|
|
cleaned_data = super().clean()
|
|
state = cleaned_data.get("state")
|
|
categories = cleaned_data.get("category")
|
|
|
|
if getattr(settings, 'USE_RBAC', False) and 'category' in self.fields:
|
|
rbac_categories = categories.filter(is_rbac_category=True).values_list('title', flat=True)
|
|
|
|
if rbac_categories and state in ['private', 'unlisted']:
|
|
# Make the confirm_state field visible and add it to the layout
|
|
self.fields['confirm_state'].widget = forms.CheckboxInput()
|
|
|
|
# add it after the state field
|
|
state_index = None
|
|
for i, layout_item in enumerate(self.helper.layout):
|
|
if isinstance(layout_item, CustomField) and layout_item.fields[0] == 'state':
|
|
state_index = i
|
|
break
|
|
|
|
if state_index:
|
|
layout_items = list(self.helper.layout)
|
|
layout_items.insert(state_index + 1, CustomField('confirm_state'))
|
|
self.helper.layout = Layout(*layout_items)
|
|
|
|
if not cleaned_data.get('confirm_state'):
|
|
error_message = f"I understand that although media state is {state}, the media is also shared with users that have access to the following categories: {', '.join(rbac_categories)}"
|
|
self.add_error('confirm_state', error_message)
|
|
|
|
return cleaned_data
|
|
|
|
def save(self, *args, **kwargs):
|
|
data = self.cleaned_data
|
|
state = data.get("state")
|
|
if state != self.initial["state"]:
|
|
self.instance.state = get_next_state(self.user, self.initial["state"], self.instance.state)
|
|
|
|
media = super(MediaPublishForm, self).save(*args, **kwargs)
|
|
|
|
return media
|
|
|
|
|
|
class SubtitleForm(forms.ModelForm):
|
|
class Meta:
|
|
model = Subtitle
|
|
fields = ["language", "subtitle_file"]
|
|
|
|
def __init__(self, media_item, *args, **kwargs):
|
|
super(SubtitleForm, self).__init__(*args, **kwargs)
|
|
self.instance.media = media_item
|
|
self.fields["subtitle_file"].help_text = "SubRip (.srt) and WebVTT (.vtt) are supported file formats."
|
|
self.fields["subtitle_file"].label = "Subtitle or Closed Caption File"
|
|
|
|
def save(self, *args, **kwargs):
|
|
self.instance.user = self.instance.media.user
|
|
media = super(SubtitleForm, self).save(*args, **kwargs)
|
|
return media
|
|
|
|
|
|
class EditSubtitleForm(forms.Form):
|
|
subtitle = forms.CharField(widget=forms.Textarea, required=True)
|
|
|
|
def __init__(self, subtitle, *args, **kwargs):
|
|
super(EditSubtitleForm, self).__init__(*args, **kwargs)
|
|
self.fields["subtitle"].initial = subtitle.subtitle_file.read().decode("utf-8")
|
|
|
|
|
|
class ContactForm(forms.Form):
|
|
from_email = forms.EmailField(required=True)
|
|
name = forms.CharField(required=False)
|
|
message = forms.CharField(widget=forms.Textarea, required=True)
|
|
|
|
def __init__(self, user, *args, **kwargs):
|
|
super(ContactForm, self).__init__(*args, **kwargs)
|
|
self.fields["name"].label = "Your name:"
|
|
self.fields["from_email"].label = "Your email:"
|
|
self.fields["message"].label = "Please add your message here and submit:"
|
|
self.user = user
|
|
if user.is_authenticated:
|
|
self.fields.pop("name")
|
|
self.fields.pop("from_email")
|