# This file is part of photo21 # Copyright (C) 2022 Amicale des élèves de l'ENS Paris-Saclay # SPDX-License-Identifier: GPL-3.0-or-later import datetime from crispy_forms.helper import FormHelper from crispy_forms.layout import Div, Layout, Submit from django import forms from django.utils.text import slugify from django.utils.translation import gettext_lazy as _ from django_select2.forms import ModelSelect2MultipleWidget from .models import Gallery, Tag class MultipleFileInput(forms.ClearableFileInput): allow_multiple_selected = True class MultipleFileField(forms.FileField): allowed_extensions = [ "jpg", "jpeg", "png", "gif", "tiff", ] # Specify allowed extensions here def __init__(self, *args, **kwargs): kwargs.setdefault( "widget", MultipleFileInput( attrs={ "accept": "image/*", "class": "mb-3", } ), ) super().__init__(*args, **kwargs) def clean(self, data, initial=None): single_file_clean = super().clean if isinstance(data, (list, tuple)): result = [self.validate_file(d, single_file_clean, initial) for d in data] else: result = self.validate_file(data, single_file_clean, initial) return result def validate_file(self, file, single_file_clean, initial): # Perform the default clean cleaned_file = single_file_clean(file, initial) # Check the file extension extension = file.name.split(".")[-1].lower() if extension not in self.allowed_extensions: raise forms.ValidationError( f"{file.name} has an invalid file extension. " f"Allowed extensions are: {', '.join(self.allowed_extensions)}" ) return cleaned_file class UploadForm(forms.Form): file_field = MultipleFileField(label="") gallery = forms.ModelChoiceField( Gallery.objects.all(), label=_("Gallery"), required=False, empty_label=_("-- Create a new gallery --"), help_text=_( "Select a gallery to add these images to. Leave this empty to " "create a new gallery from the supplied title." ), ) new_gallery_title = forms.CharField( label=_("New gallery title"), max_length=250, required=False, ) new_gallery_date_start = forms.DateField( label=_("New gallery event start date"), initial=datetime.date.today, required=False, widget=forms.DateInput(attrs={"type":"date"}) ) new_gallery_date_end = forms.DateField( label=_("New gallery event end date"), initial=datetime.date.today, required=False, widget=forms.DateInput(attrs={"type":"date"}) ) new_gallery_description = forms.CharField( widget=forms.Textarea(attrs={"rows": 4}), label=_("Description"), required=False, ) new_gallery_tags = forms.ModelMultipleChoiceField( Tag.objects.all(), label=_("New gallery tags"), required=False, widget=ModelSelect2MultipleWidget( model=Tag, search_fields=['name__icontains'], attrs = { 'data-minimum-input-length': 0, 'data-placeholder': 'Select tags', } ) ) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.helper = FormHelper() self.helper.use_custom_control = False self.helper.layout = Layout( "file_field", "gallery", "new_gallery_title", Div( Div("new_gallery_date_start", css_class="col"), Div("new_gallery_date_end", css_class="col"), css_class="row", ), "new_gallery_description", "new_gallery_tags", Submit("submit", _("Upload"), css_class="btn btn-success mt-2"), ) def clean(self): cleaned_data = super().clean() # Check that either an existing gallery is chosen, or new_gallery_title is filled if not ( bool(cleaned_data["gallery"]) ^ bool(cleaned_data.get("new_gallery_title", None)) ): raise forms.ValidationError( _("Select an existing gallery, or enter a title for a new gallery.") ) return cleaned_data def get_or_create_gallery(self): """ Get or create gallery """ gallery = self.cleaned_data["gallery"] if not gallery: # Create new gallery title = self.cleaned_data.get("new_gallery_title") base_slug = slugify(title) slug = base_slug counter = 2 while Gallery.objects.filter(slug=slug).exists(): slug = f"{base_slug}-{counter}" counter += 1 gallery = Gallery.objects.create( title=title, slug=slug, date_start=self.cleaned_data["new_gallery_date_start"], date_end=self.cleaned_data["new_gallery_date_end"], description=self.cleaned_data["new_gallery_description"], ) for tag in self.cleaned_data["new_gallery_tags"]: gallery.tags.add(tag) return gallery