from django import forms from django.utils.html import conditional_escape, mark_safe from django.utils.translation import gettext, gettext_lazy as _ from mptt.forms import TreeNodeChoiceField from ...themes.models import Theme from ..forms import YesNoSwitch from .assets import create_css, create_image class ThemeChoiceField(TreeNodeChoiceField): level_indicator = "- - " def __init__(self, *args, **kwargs): kwargs.setdefault("queryset", Theme.objects.all()) kwargs.setdefault("empty_label", _("No parent")) super().__init__(*args, **kwargs) class ThemeForm(forms.ModelForm): name = forms.CharField(label=_("Name")) parent = ThemeChoiceField(label=_("Parent"), required=False) version = forms.CharField(label=_("Version"), required=False) author = forms.CharField(label=_("Author(s)"), required=False) url = forms.URLField(label=_("Url"), required=False) class Meta: model = Theme fields = ["name", "parent", "version", "author", "url"] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.limit_parent_choices() def limit_parent_choices(self): if not self.instance or not self.instance.pk: return self.fields["parent"].queryset = Theme.objects.exclude( tree_id=self.instance.tree_id, lft__gte=self.instance.lft, rght__lte=self.instance.rght, ) class UploadAssetsForm(forms.Form): allowed_content_types = [] allowed_extensions = [] assets = forms.FileField( widget=forms.ClearableFileInput(attrs={"multiple": True}), error_messages={"required": _("No files have been uploaded.")}, ) def __init__(self, *args, instance=None): self.instance = instance super().__init__(*args) def clean_assets(self): assets = [] for asset in self.files.getlist("assets"): try: if self.allowed_content_types: self.validate_asset_content_type(asset) if self.allowed_extensions: self.validate_asset_extension(asset) except forms.ValidationError as e: self.add_error("assets", e) else: assets.append(asset) return assets def validate_asset_content_type(self, asset): if asset.content_type in self.allowed_content_types: return message = gettext( 'File "%(file)s" content type "%(content_type)s" is not allowed.' ) details = {"file": asset.name, "content_type": asset.content_type} raise forms.ValidationError(message % details) def validate_asset_extension(self, asset): filename = asset.name.lower() for extension in self.allowed_extensions: if filename.endswith(".%s" % extension): return message = gettext('File "%(file)s" extension is invalid.') details = {"file": asset.name} raise forms.ValidationError(message % details) def save(self): for asset in self.cleaned_data["assets"]: self.save_asset(asset) class UploadCssForm(UploadAssetsForm): allowed_content_types = ["text/css"] allowed_extensions = ["css"] def save_asset(self, asset): create_css(self.instance, asset) class UploadImagesForm(UploadAssetsForm): assets = forms.ImageField(widget=forms.ClearableFileInput(attrs={"multiple": True})) def save_asset(self, asset): create_image(self.instance, asset)