Skip to content
Snippets Groups Projects
forms.py 6.59 KiB
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
            )