import os import tempfile from django import forms from django.core.exceptions import ValidationError from shared.forms import ArticlesPageForm as SharedArticlesPageForm from shared.forms import JekyllImportForm as SharedJekyllImportForm from .tasks import import_jekyll_articles class MultipleFileInput(forms.ClearableFileInput): allow_multiple_selected = True class MultipleFileField(forms.FileField): def __init__(self, *args, **kwargs): kwargs.setdefault("widget", MultipleFileInput()) super().__init__(*args, **kwargs) TOTAL_MAX_FILE_SIZE = 5 * 1024 * 1024 # 5 MB def clean(self, data, initial=None): single_file_clean = super().clean if isinstance(data, (list, tuple)): total_size = 0 for file in data: total_size += file.size if total_size > self.TOTAL_MAX_FILE_SIZE: raise ValidationError( "Celková velikost nahraných souborů je příliš velká." ) result = [single_file_clean(d, initial) for d in data] else: result = [single_file_clean(data, initial)] return result # Allowed MIME types ALLOWED_FILE_TYPES = [ "application/pdf", # PDF "application/msword", # DOC "application/vnd.openxmlformats-officedocument.wordprocessingml.document", # DOCX "image/png", # PNG "application/vnd.oasis.opendocument.text", # ODT ] def validate_file_type(file): if file.content_type not in ALLOWED_FILE_TYPES: raise ValidationError( f"Chybný formát souboru: {file.content_type}. Povolené jsou pouze PDF, DOC, DOCX, PNG, and ODT." ) def validate_file_size(file, max_size=5 * 1024 * 1024): # Default: 5 MB if file.size > max_size: raise ValidationError( f"Soubory mohou být max. {max_size / (1024 * 1024)} MB velké." ) class CareerSubmissionForm(forms.Form): name = forms.CharField( min_length=1, max_length=256, required=True, widget=forms.TextInput( attrs={ "placeholder": "Jméno", "class": "lg:w-auto w-full", "value": "", "autocomplete": "", } ), ) surname = forms.CharField( min_length=1, max_length=256, required=True, widget=forms.TextInput( attrs={ "placeholder": "Příjmení", "class": "lg:w-auto w-full", "value": "", "autocomplete": "", } ), ) email = forms.EmailField( min_length=1, max_length=256, required=True, widget=forms.EmailInput( attrs={ "placeholder": "Email", "class": "w-full", "value": "", "autocomplete": "", } ), ) phone = forms.IntegerField( required=True, widget=forms.NumberInput( attrs={ "type": "tel", "placeholder": "Telefon", "class": "w-full", "value": "", "autocomplete": "", } ), ) own_text = forms.CharField( widget=forms.Textarea( attrs={ "placeholder": "Vlastní text (nepovinný)", "class": "w-full", "rows": 3, } ), max_length=65535, required=False, ) cv_file = forms.FileField( required=True, validators=[validate_file_type, validate_file_size], widget=forms.FileInput( attrs={ "class": "max-w-64 mr-auto overflow-hidden break-words", "accept": ".pdf,.doc,.docx,.png,.odt", } ), ) cover_letter_file = forms.FileField( required=True, validators=[validate_file_type, validate_file_size], widget=forms.FileInput( attrs={ "class": "max-w-64 mr-auto overflow-hidden break-words", "accept": ".pdf,.doc,.docx,.png,.odt", } ), ) other_files = MultipleFileField( required=False, validators=[validate_file_type, validate_file_size], widget=MultipleFileInput( attrs={ "class": "max-w-64 mr-auto overflow-hidden break-words", "accept": ".pdf,.doc,.docx,.png,.odt", } ), ) personal_data_agreement = forms.BooleanField(required=True) other_offers_agreement = forms.BooleanField(required=False) class JekyllImportForm(SharedJekyllImportForm): def handle_import(self): lock_file_name = os.path.join( tempfile.gettempdir(), f".{self.instance.id}.articles-import-lock" ) if os.path.isfile(lock_file_name): return open(lock_file_name, "w").close() import_jekyll_articles.delay( article_parent_page_id=self.instance.id, collection_id=self.cleaned_data["collection"].id, url=self.cleaned_data["jekyll_repo_url"], dry_run=self.cleaned_data["dry_run"], use_git=True, ) class MainArticlesPageForm(SharedArticlesPageForm, JekyllImportForm): def __init__(self, *args, **kwargs): from shared.models import SharedTag from .models import MainArticleTag super().__init__(*args, **kwargs) self.fields["shared_tags"].queryset = SharedTag.objects.order_by("name") if self.instance.pk: valid_tag_ids = ( MainArticleTag.objects.filter( content_object__in=self.instance.get_children().specific() ) .values_list("tag_id", flat=True) .distinct() ) valid_shared_tag_ids = ( self.instance.shared_tags.values_list("id", flat=True).distinct().all() ) self.fields["displayed_tags"].queryset = ( MainArticleTag.objects.filter(id__in=valid_tag_ids) .order_by("tag__name") .distinct("tag__name") ) self.fields["displayed_shared_tags"].queryset = ( SharedTag.objects.filter(id__in=valid_shared_tag_ids) .order_by("name") .distinct("name") ) else: self.fields["displayed_tags"].queryset = MainArticleTag.objects.filter( id=-1 ) self.fields["displayed_shared_tags"].queryset = SharedTag.objects.filter( id=-1 )