réorganisation des forms en module
This commit is contained in:
		
							
								
								
									
										9
									
								
								src/agenda_culturel/forms/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/agenda_culturel/forms/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
from .utils import *
 | 
			
		||||
from .user import *
 | 
			
		||||
from .category import *
 | 
			
		||||
from .tag import *
 | 
			
		||||
from .event import *
 | 
			
		||||
from .place import *
 | 
			
		||||
from .message import *
 | 
			
		||||
from .imports import *
 | 
			
		||||
from .special_period import *
 | 
			
		||||
							
								
								
									
										57
									
								
								src/agenda_culturel/forms/category.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/agenda_culturel/forms/category.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
			
		||||
import logging
 | 
			
		||||
 | 
			
		||||
from django.forms import (
 | 
			
		||||
    BooleanField,
 | 
			
		||||
    CharField,
 | 
			
		||||
    Form,
 | 
			
		||||
    HiddenInput,
 | 
			
		||||
    ModelForm,
 | 
			
		||||
)
 | 
			
		||||
from django.utils.translation import gettext_lazy as _
 | 
			
		||||
 | 
			
		||||
from ..models import (
 | 
			
		||||
    CategorisationRule,
 | 
			
		||||
    Event,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
logger = logging.getLogger(__name__)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CategorisationRuleImportForm(ModelForm):
 | 
			
		||||
    required_css_class = "required"
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = CategorisationRule
 | 
			
		||||
        fields = "__all__"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CategorisationForm(Form):
 | 
			
		||||
    required_css_class = "required"
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        if "events" in kwargs:
 | 
			
		||||
            events = kwargs.pop("events", None)
 | 
			
		||||
        else:
 | 
			
		||||
            events = []
 | 
			
		||||
            for f in args[0]:
 | 
			
		||||
                if "_" not in f:
 | 
			
		||||
                    if f + "_cat" in args[0]:
 | 
			
		||||
                        events.append(
 | 
			
		||||
                            (Event.objects.get(pk=int(f)), args[0][f + "_cat"])
 | 
			
		||||
                        )
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
 | 
			
		||||
        for e, c in events:
 | 
			
		||||
            self.fields[str(e.pk)] = BooleanField(
 | 
			
		||||
                initial=False,
 | 
			
		||||
                label=_("Apply category {} to the event {}").format(c, e.title),
 | 
			
		||||
                required=False,
 | 
			
		||||
            )
 | 
			
		||||
            self.fields[str(e.pk) + "_cat"] = CharField(initial=c, widget=HiddenInput())
 | 
			
		||||
 | 
			
		||||
    def get_validated(self):
 | 
			
		||||
        return [
 | 
			
		||||
            (e, self.cleaned_data.get(e + "_cat"))
 | 
			
		||||
            for e in self.fields
 | 
			
		||||
            if "_" not in e and self.cleaned_data.get(e)
 | 
			
		||||
        ]
 | 
			
		||||
@@ -1,285 +1,43 @@
 | 
			
		||||
import logging
 | 
			
		||||
import os
 | 
			
		||||
from string import ascii_uppercase as auc
 | 
			
		||||
 | 
			
		||||
from django.conf import settings
 | 
			
		||||
from django.core.files import File
 | 
			
		||||
from django.forms import (
 | 
			
		||||
    BooleanField,
 | 
			
		||||
    CharField,
 | 
			
		||||
    ChoiceField,
 | 
			
		||||
    EmailField,
 | 
			
		||||
    Form,
 | 
			
		||||
    HiddenInput,
 | 
			
		||||
    ModelChoiceField,
 | 
			
		||||
    ModelForm,
 | 
			
		||||
    MultipleChoiceField,
 | 
			
		||||
    MultipleHiddenInput,
 | 
			
		||||
    RadioSelect,
 | 
			
		||||
    Textarea,
 | 
			
		||||
    TextInput,
 | 
			
		||||
    URLField,
 | 
			
		||||
    ValidationError,
 | 
			
		||||
    FileField,
 | 
			
		||||
    formset_factory,
 | 
			
		||||
)
 | 
			
		||||
from django.utils.formats import localize
 | 
			
		||||
from django.utils.safestring import mark_safe
 | 
			
		||||
from django.utils.translation import gettext_lazy as _
 | 
			
		||||
from django_better_admin_arrayfield.forms.widgets import DynamicArrayWidget
 | 
			
		||||
 | 
			
		||||
from .models import (
 | 
			
		||||
    CategorisationRule,
 | 
			
		||||
from . import (
 | 
			
		||||
    GroupFormMixin,
 | 
			
		||||
    MultipleChoiceFieldAcceptAll,
 | 
			
		||||
    DynamicArrayWidgetTags,
 | 
			
		||||
    DynamicArrayWidgetURLs,
 | 
			
		||||
    SimpleContactForm,
 | 
			
		||||
)
 | 
			
		||||
from ..models import (
 | 
			
		||||
    Category,
 | 
			
		||||
    Event,
 | 
			
		||||
    Message,
 | 
			
		||||
    Place,
 | 
			
		||||
    RecurrentImport,
 | 
			
		||||
    Tag,
 | 
			
		||||
    UserProfile,
 | 
			
		||||
    SpecialPeriod,
 | 
			
		||||
)
 | 
			
		||||
from .templatetags.event_extra import event_field_verbose_name, field_to_html
 | 
			
		||||
from .templatetags.utils_extra import int_to_abc
 | 
			
		||||
 | 
			
		||||
from .models.constants import (
 | 
			
		||||
from ..models.constants import (
 | 
			
		||||
    TITLE_ISSUE_DATE_IMPORTATION,
 | 
			
		||||
    TITLE_ISSUE_TIME_IMPORTATION,
 | 
			
		||||
    PUBLICATION_ISSUE,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
logger = logging.getLogger(__name__)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class GroupFormMixin:
 | 
			
		||||
    template_name = "agenda_culturel/forms/div_group.html"
 | 
			
		||||
 | 
			
		||||
    class FieldGroup:
 | 
			
		||||
        def __init__(
 | 
			
		||||
            self,
 | 
			
		||||
            id,
 | 
			
		||||
            label,
 | 
			
		||||
            display_label=False,
 | 
			
		||||
            maskable=False,
 | 
			
		||||
            default_masked=True,
 | 
			
		||||
        ):
 | 
			
		||||
            self.id = id
 | 
			
		||||
            self.label = label
 | 
			
		||||
            self.display_label = display_label
 | 
			
		||||
            self.maskable = maskable
 | 
			
		||||
            self.default_masked = default_masked
 | 
			
		||||
 | 
			
		||||
        def toggle_field_name(self):
 | 
			
		||||
            return "group_" + self.id
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        self.groups = []
 | 
			
		||||
 | 
			
		||||
    def add_group(self, *args, **kwargs):
 | 
			
		||||
        self.groups.append(GroupFormMixin.FieldGroup(*args, **kwargs))
 | 
			
		||||
        if self.groups[-1].maskable:
 | 
			
		||||
            self.fields[self.groups[-1].toggle_field_name()] = BooleanField(
 | 
			
		||||
                required=False
 | 
			
		||||
            )
 | 
			
		||||
            self.fields[self.groups[-1].toggle_field_name()].toggle_group = True
 | 
			
		||||
 | 
			
		||||
    def get_fields_in_group(self, g):
 | 
			
		||||
        return [
 | 
			
		||||
            f
 | 
			
		||||
            for f in self.visible_fields()
 | 
			
		||||
            if not hasattr(f.field, "toggle_group")
 | 
			
		||||
            and hasattr(f.field, "group_id")
 | 
			
		||||
            and f.field.group_id == g.id
 | 
			
		||||
        ]
 | 
			
		||||
 | 
			
		||||
    def get_no_group_fields(self):
 | 
			
		||||
        return [
 | 
			
		||||
            f
 | 
			
		||||
            for f in self.visible_fields()
 | 
			
		||||
            if not hasattr(f.field, "toggle_group")
 | 
			
		||||
            and (not hasattr(f.field, "group_id") or f.field.group_id is None)
 | 
			
		||||
        ]
 | 
			
		||||
 | 
			
		||||
    def fields_by_group(self):
 | 
			
		||||
        return [(g, self.get_fields_in_group(g)) for g in self.groups] + [
 | 
			
		||||
            (
 | 
			
		||||
                GroupFormMixin.FieldGroup("other", _("Other")),
 | 
			
		||||
                self.get_no_group_fields(),
 | 
			
		||||
            )
 | 
			
		||||
        ]
 | 
			
		||||
 | 
			
		||||
    def clean(self):
 | 
			
		||||
        result = super().clean()
 | 
			
		||||
 | 
			
		||||
        if result:
 | 
			
		||||
            data = dict(self.data)
 | 
			
		||||
            # for each masked group, we remove data
 | 
			
		||||
            for g in self.groups:
 | 
			
		||||
                if g.maskable and g.toggle_field_name() not in data:
 | 
			
		||||
                    fields = self.get_fields_in_group(g)
 | 
			
		||||
                    for f in fields:
 | 
			
		||||
                        self.cleaned_data[f.name] = None
 | 
			
		||||
 | 
			
		||||
        return result
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TagForm(ModelForm):
 | 
			
		||||
    required_css_class = "required"
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = Tag
 | 
			
		||||
        fields = [
 | 
			
		||||
            "name",
 | 
			
		||||
            "description",
 | 
			
		||||
            "message",
 | 
			
		||||
            "in_included_suggestions",
 | 
			
		||||
            "in_excluded_suggestions",
 | 
			
		||||
            "principal",
 | 
			
		||||
        ]
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        if "name" in kwargs["initial"]:
 | 
			
		||||
            self.fields["name"].widget = HiddenInput()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TagRenameForm(Form):
 | 
			
		||||
    required_css_class = "required"
 | 
			
		||||
 | 
			
		||||
    name = CharField(label=_("Name of new tag"), required=True)
 | 
			
		||||
 | 
			
		||||
    force = BooleanField(
 | 
			
		||||
        label=_(
 | 
			
		||||
            "Force renaming despite the existence of events already using the chosen tag."
 | 
			
		||||
        ),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        force = kwargs.pop("force", False)
 | 
			
		||||
        name = kwargs.pop("name", None)
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        if not (force or (not len(args) == 0 and "force" in args[0])):
 | 
			
		||||
            del self.fields["force"]
 | 
			
		||||
        if name is not None and self.fields["name"].initial is None:
 | 
			
		||||
            self.fields["name"].initial = name
 | 
			
		||||
 | 
			
		||||
    def is_force(self):
 | 
			
		||||
        return "force" in self.fields and self.cleaned_data["force"] is True
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SimpleContactForm(GroupFormMixin, Form):
 | 
			
		||||
    email = EmailField(
 | 
			
		||||
        label=_("Your email"),
 | 
			
		||||
        help_text=_("Your email address"),
 | 
			
		||||
        max_length=254,
 | 
			
		||||
        required=False,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    comments = CharField(
 | 
			
		||||
        label=_("Comments"),
 | 
			
		||||
        help_text=_(
 | 
			
		||||
            "Your message for the moderation team (comments, clarifications, requests...)"
 | 
			
		||||
        ),
 | 
			
		||||
        widget=Textarea,
 | 
			
		||||
        max_length=2048,
 | 
			
		||||
        required=False,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        is_authenticated = "is_authenticated" in kwargs and kwargs["is_authenticated"]
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
 | 
			
		||||
        if not is_authenticated:
 | 
			
		||||
            self.add_group(
 | 
			
		||||
                "communication",
 | 
			
		||||
                _(
 | 
			
		||||
                    "Receive notification of publication or leave a message for moderation"
 | 
			
		||||
                ),
 | 
			
		||||
                maskable=True,
 | 
			
		||||
                default_masked=True,
 | 
			
		||||
            )
 | 
			
		||||
            self.fields["email"].group_id = "communication"
 | 
			
		||||
            self.fields["comments"].group_id = "communication"
 | 
			
		||||
        else:
 | 
			
		||||
            del self.fields["email"]
 | 
			
		||||
            del self.fields["comments"]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class URLSubmissionSimpleForm(Form):
 | 
			
		||||
    url = URLField(max_length=512)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class URLSubmissionForm(GroupFormMixin, Form):
 | 
			
		||||
    required_css_class = "required"
 | 
			
		||||
 | 
			
		||||
    url = URLField(max_length=512)
 | 
			
		||||
    category = ModelChoiceField(
 | 
			
		||||
        label=_("Category"),
 | 
			
		||||
        queryset=Category.objects.all().order_by("name"),
 | 
			
		||||
        initial=None,
 | 
			
		||||
        required=False,
 | 
			
		||||
    )
 | 
			
		||||
    tags = MultipleChoiceField(
 | 
			
		||||
        label=_("Tags"), initial=None, choices=[], required=False
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        kwargs.pop("is_authenticated", False)
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        self.fields["tags"].choices = Tag.get_tag_groups(all=True)
 | 
			
		||||
 | 
			
		||||
        self.add_group("event", _("Event"))
 | 
			
		||||
        self.fields["url"].group_id = "event"
 | 
			
		||||
        self.fields["category"].group_id = "event"
 | 
			
		||||
        self.fields["tags"].group_id = "event"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class URLSubmissionFormWithContact(SimpleContactForm, URLSubmissionForm):
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
URLSubmissionFormSet = formset_factory(URLSubmissionForm, extra=9, min_num=1)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DynamicArrayWidgetURLs(DynamicArrayWidget):
 | 
			
		||||
    template_name = "agenda_culturel/widgets/widget-urls.html"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DynamicArrayWidgetTags(DynamicArrayWidget):
 | 
			
		||||
    template_name = "agenda_culturel/widgets/widget-tags.html"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class RecurrentImportForm(ModelForm):
 | 
			
		||||
    required_css_class = "required"
 | 
			
		||||
 | 
			
		||||
    defaultTags = MultipleChoiceField(
 | 
			
		||||
        label=_("Tags"), initial=None, choices=[], required=False
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = RecurrentImport
 | 
			
		||||
        fields = "__all__"
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        self.fields["defaultTags"].choices = Tag.get_tag_groups(all=True)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CategorisationRuleImportForm(ModelForm):
 | 
			
		||||
    required_css_class = "required"
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = CategorisationRule
 | 
			
		||||
        fields = "__all__"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MultipleChoiceFieldAcceptAll(MultipleChoiceField):
 | 
			
		||||
    def validate(self, value):
 | 
			
		||||
        # check if each element is without "/"
 | 
			
		||||
        for item in value:
 | 
			
		||||
            if "/" in item:
 | 
			
		||||
                raise ValidationError(_("The '/' character is not allowed."))
 | 
			
		||||
from ..templatetags.event_extra import event_field_verbose_name, field_to_html
 | 
			
		||||
from ..templatetags.utils_extra import int_to_abc
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class EventForm(GroupFormMixin, ModelForm):
 | 
			
		||||
@@ -570,131 +328,6 @@ class EventModerateForm(ModelForm):
 | 
			
		||||
        self.cleaned_data["tags"] = list(set(self.cleaned_data["tags"]))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class BatchImportationForm(Form):
 | 
			
		||||
    required_css_class = "required"
 | 
			
		||||
 | 
			
		||||
    data = CharField(
 | 
			
		||||
        label=_("Data"),
 | 
			
		||||
        widget=Textarea(attrs={"rows": "10"}),
 | 
			
		||||
        help_text=_("Supported formats: json, html."),
 | 
			
		||||
        required=True,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    category = ModelChoiceField(
 | 
			
		||||
        label=_("Category"),
 | 
			
		||||
        queryset=Category.objects.all().order_by("name"),
 | 
			
		||||
        help_text=_("Used only if data is html."),
 | 
			
		||||
        initial=None,
 | 
			
		||||
        required=False,
 | 
			
		||||
    )
 | 
			
		||||
    tags = MultipleChoiceField(
 | 
			
		||||
        label=_("Tags"),
 | 
			
		||||
        initial=None,
 | 
			
		||||
        choices=[],
 | 
			
		||||
        help_text=_("Used only if data is html."),
 | 
			
		||||
        required=False,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        self.fields["tags"].choices = Tag.get_tag_groups(all=True)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class FixDuplicates(Form):
 | 
			
		||||
    required_css_class = "required"
 | 
			
		||||
 | 
			
		||||
    action = ChoiceField()
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        edup = kwargs.pop("edup", None)
 | 
			
		||||
        events = edup.get_duplicated()
 | 
			
		||||
        len(events)
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
 | 
			
		||||
        choices = []
 | 
			
		||||
        initial = None
 | 
			
		||||
        for i, e in enumerate(events):
 | 
			
		||||
            if e.status != Event.STATUS.TRASH or e.modified():
 | 
			
		||||
                msg = ""
 | 
			
		||||
                if e.local_version():
 | 
			
		||||
                    msg = _(" (locally modified version)")
 | 
			
		||||
                    if e.status != Event.STATUS.TRASH:
 | 
			
		||||
                        initial = "Select-" + str(e.pk)
 | 
			
		||||
                if e.pure_import():
 | 
			
		||||
                    msg = _(" (synchronized on import version)")
 | 
			
		||||
                choices += [
 | 
			
		||||
                    (
 | 
			
		||||
                        "Select-" + str(e.pk),
 | 
			
		||||
                        _("Select {} as representative version.").format(auc[i] + msg),
 | 
			
		||||
                    )
 | 
			
		||||
                ]
 | 
			
		||||
 | 
			
		||||
        for i, e in enumerate(events):
 | 
			
		||||
            if e.status != Event.STATUS.TRASH and e.local_version():
 | 
			
		||||
                choices += [
 | 
			
		||||
                    (
 | 
			
		||||
                        "Update-" + str(e.pk),
 | 
			
		||||
                        _(
 | 
			
		||||
                            "Update {} using some fields from other versions (interactive mode)."
 | 
			
		||||
                        ).format(auc[i]),
 | 
			
		||||
                    )
 | 
			
		||||
                ]
 | 
			
		||||
 | 
			
		||||
        extra = ""
 | 
			
		||||
        if edup.has_local_version():
 | 
			
		||||
            extra = _(" Warning: a version is already locally modified.")
 | 
			
		||||
 | 
			
		||||
        if initial is None:
 | 
			
		||||
            initial = "Merge"
 | 
			
		||||
        choices += [
 | 
			
		||||
            (
 | 
			
		||||
                "Merge",
 | 
			
		||||
                _("Create a new version by merging (interactive mode).") + extra,
 | 
			
		||||
            )
 | 
			
		||||
        ]
 | 
			
		||||
        for i, e in enumerate(events):
 | 
			
		||||
            if e.status != Event.STATUS.TRASH:
 | 
			
		||||
                choices += [
 | 
			
		||||
                    (
 | 
			
		||||
                        "Remove-" + str(e.pk),
 | 
			
		||||
                        _("Make {} independent.").format(auc[i]),
 | 
			
		||||
                    )
 | 
			
		||||
                ]
 | 
			
		||||
        choices += [("NotDuplicates", _("Make all versions independent."))]
 | 
			
		||||
 | 
			
		||||
        self.fields["action"].choices = choices
 | 
			
		||||
        self.fields["action"].initial = initial
 | 
			
		||||
 | 
			
		||||
    def is_action_no_duplicates(self):
 | 
			
		||||
        return self.cleaned_data["action"] == "NotDuplicates"
 | 
			
		||||
 | 
			
		||||
    def is_action_select(self):
 | 
			
		||||
        return self.cleaned_data["action"].startswith("Select")
 | 
			
		||||
 | 
			
		||||
    def is_action_update(self):
 | 
			
		||||
        return self.cleaned_data["action"].startswith("Update")
 | 
			
		||||
 | 
			
		||||
    def is_action_remove(self):
 | 
			
		||||
        return self.cleaned_data["action"].startswith("Remove")
 | 
			
		||||
 | 
			
		||||
    def get_selected_event_code(self):
 | 
			
		||||
        if (
 | 
			
		||||
            self.is_action_select()
 | 
			
		||||
            or self.is_action_remove()
 | 
			
		||||
            or self.is_action_update()
 | 
			
		||||
        ):
 | 
			
		||||
            return int(self.cleaned_data["action"].split("-")[-1])
 | 
			
		||||
        else:
 | 
			
		||||
            return None
 | 
			
		||||
 | 
			
		||||
    def get_selected_event(self, edup):
 | 
			
		||||
        selected = self.get_selected_event_code()
 | 
			
		||||
        for e in edup.get_duplicated():
 | 
			
		||||
            if e.pk == selected:
 | 
			
		||||
                return e
 | 
			
		||||
        return None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SelectEventInList(Form):
 | 
			
		||||
    required_css_class = "required"
 | 
			
		||||
 | 
			
		||||
@@ -888,190 +521,96 @@ class MergeDuplicates(Form):
 | 
			
		||||
                return None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CategorisationForm(Form):
 | 
			
		||||
class FixDuplicates(Form):
 | 
			
		||||
    required_css_class = "required"
 | 
			
		||||
 | 
			
		||||
    action = ChoiceField()
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        if "events" in kwargs:
 | 
			
		||||
            events = kwargs.pop("events", None)
 | 
			
		||||
        else:
 | 
			
		||||
            events = []
 | 
			
		||||
            for f in args[0]:
 | 
			
		||||
                if "_" not in f:
 | 
			
		||||
                    if f + "_cat" in args[0]:
 | 
			
		||||
                        events.append(
 | 
			
		||||
                            (Event.objects.get(pk=int(f)), args[0][f + "_cat"])
 | 
			
		||||
                        )
 | 
			
		||||
        edup = kwargs.pop("edup", None)
 | 
			
		||||
        events = edup.get_duplicated()
 | 
			
		||||
        len(events)
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
 | 
			
		||||
        for e, c in events:
 | 
			
		||||
            self.fields[str(e.pk)] = BooleanField(
 | 
			
		||||
                initial=False,
 | 
			
		||||
                label=_("Apply category {} to the event {}").format(c, e.title),
 | 
			
		||||
                required=False,
 | 
			
		||||
        choices = []
 | 
			
		||||
        initial = None
 | 
			
		||||
        for i, e in enumerate(events):
 | 
			
		||||
            if e.status != Event.STATUS.TRASH or e.modified():
 | 
			
		||||
                msg = ""
 | 
			
		||||
                if e.local_version():
 | 
			
		||||
                    msg = _(" (locally modified version)")
 | 
			
		||||
                    if e.status != Event.STATUS.TRASH:
 | 
			
		||||
                        initial = "Select-" + str(e.pk)
 | 
			
		||||
                if e.pure_import():
 | 
			
		||||
                    msg = _(" (synchronized on import version)")
 | 
			
		||||
                choices += [
 | 
			
		||||
                    (
 | 
			
		||||
                        "Select-" + str(e.pk),
 | 
			
		||||
                        _("Select {} as representative version.").format(auc[i] + msg),
 | 
			
		||||
                    )
 | 
			
		||||
                ]
 | 
			
		||||
 | 
			
		||||
        for i, e in enumerate(events):
 | 
			
		||||
            if e.status != Event.STATUS.TRASH and e.local_version():
 | 
			
		||||
                choices += [
 | 
			
		||||
                    (
 | 
			
		||||
                        "Update-" + str(e.pk),
 | 
			
		||||
                        _(
 | 
			
		||||
                            "Update {} using some fields from other versions (interactive mode)."
 | 
			
		||||
                        ).format(auc[i]),
 | 
			
		||||
                    )
 | 
			
		||||
                ]
 | 
			
		||||
 | 
			
		||||
        extra = ""
 | 
			
		||||
        if edup.has_local_version():
 | 
			
		||||
            extra = _(" Warning: a version is already locally modified.")
 | 
			
		||||
 | 
			
		||||
        if initial is None:
 | 
			
		||||
            initial = "Merge"
 | 
			
		||||
        choices += [
 | 
			
		||||
            (
 | 
			
		||||
                "Merge",
 | 
			
		||||
                _("Create a new version by merging (interactive mode).") + extra,
 | 
			
		||||
            )
 | 
			
		||||
            self.fields[str(e.pk) + "_cat"] = CharField(initial=c, widget=HiddenInput())
 | 
			
		||||
 | 
			
		||||
    def get_validated(self):
 | 
			
		||||
        return [
 | 
			
		||||
            (e, self.cleaned_data.get(e + "_cat"))
 | 
			
		||||
            for e in self.fields
 | 
			
		||||
            if "_" not in e and self.cleaned_data.get(e)
 | 
			
		||||
        ]
 | 
			
		||||
        for i, e in enumerate(events):
 | 
			
		||||
            if e.status != Event.STATUS.TRASH:
 | 
			
		||||
                choices += [
 | 
			
		||||
                    (
 | 
			
		||||
                        "Remove-" + str(e.pk),
 | 
			
		||||
                        _("Make {} independent.").format(auc[i]),
 | 
			
		||||
                    )
 | 
			
		||||
                ]
 | 
			
		||||
        choices += [("NotDuplicates", _("Make all versions independent."))]
 | 
			
		||||
 | 
			
		||||
        self.fields["action"].choices = choices
 | 
			
		||||
        self.fields["action"].initial = initial
 | 
			
		||||
 | 
			
		||||
class EventAddPlaceForm(Form):
 | 
			
		||||
    required_css_class = "required"
 | 
			
		||||
    def is_action_no_duplicates(self):
 | 
			
		||||
        return self.cleaned_data["action"] == "NotDuplicates"
 | 
			
		||||
 | 
			
		||||
    place = ModelChoiceField(
 | 
			
		||||
        label=_("Place"),
 | 
			
		||||
        queryset=Place.objects.all().order_by("name"),
 | 
			
		||||
        empty_label=_("Create a missing place"),
 | 
			
		||||
        required=False,
 | 
			
		||||
    )
 | 
			
		||||
    add_alias = BooleanField(initial=True, required=False)
 | 
			
		||||
    def is_action_select(self):
 | 
			
		||||
        return self.cleaned_data["action"].startswith("Select")
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        self.instance = kwargs.pop("instance", False)
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        if self.instance.location:
 | 
			
		||||
            self.fields["add_alias"].label = _(
 | 
			
		||||
                'Add "{}" to the aliases of the place'
 | 
			
		||||
            ).format(self.instance.location)
 | 
			
		||||
    def is_action_update(self):
 | 
			
		||||
        return self.cleaned_data["action"].startswith("Update")
 | 
			
		||||
 | 
			
		||||
    def is_action_remove(self):
 | 
			
		||||
        return self.cleaned_data["action"].startswith("Remove")
 | 
			
		||||
 | 
			
		||||
    def get_selected_event_code(self):
 | 
			
		||||
        if (
 | 
			
		||||
            self.is_action_select()
 | 
			
		||||
            or self.is_action_remove()
 | 
			
		||||
            or self.is_action_update()
 | 
			
		||||
        ):
 | 
			
		||||
            return int(self.cleaned_data["action"].split("-")[-1])
 | 
			
		||||
        else:
 | 
			
		||||
            self.fields.pop("add_alias")
 | 
			
		||||
        if self.instance.exact_location:
 | 
			
		||||
            self.fields["place"].initial = self.instance.exact_location
 | 
			
		||||
            self.fields["add_alias"].initial = False
 | 
			
		||||
            return None
 | 
			
		||||
 | 
			
		||||
    def modified_event(self):
 | 
			
		||||
        return self.cleaned_data.get("place")
 | 
			
		||||
 | 
			
		||||
    def save(self):
 | 
			
		||||
        if self.cleaned_data.get("place"):
 | 
			
		||||
            place = self.cleaned_data.get("place")
 | 
			
		||||
            self.instance.exact_location = place
 | 
			
		||||
            self.instance.save(update_fields=["exact_location"])
 | 
			
		||||
            if self.cleaned_data.get("add_alias"):
 | 
			
		||||
                if place.aliases:
 | 
			
		||||
                    place.aliases.append(self.instance.location.strip())
 | 
			
		||||
                else:
 | 
			
		||||
                    place.aliases = [self.instance.location.strip()]
 | 
			
		||||
                place.save()
 | 
			
		||||
 | 
			
		||||
        return self.instance
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class PlaceForm(GroupFormMixin, ModelForm):
 | 
			
		||||
    required_css_class = "required"
 | 
			
		||||
 | 
			
		||||
    apply_to_all = BooleanField(
 | 
			
		||||
        initial=True,
 | 
			
		||||
        label=_(
 | 
			
		||||
            "On saving, use aliases to detect all matching events with missing place"
 | 
			
		||||
        ),
 | 
			
		||||
        required=False,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = Place
 | 
			
		||||
        fields = "__all__"
 | 
			
		||||
        widgets = {"location": TextInput()}
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
 | 
			
		||||
        self.add_group("header", _("Header"))
 | 
			
		||||
        self.fields["name"].group_id = "header"
 | 
			
		||||
 | 
			
		||||
        self.add_group("address", _("Address"))
 | 
			
		||||
        self.fields["address"].group_id = "address"
 | 
			
		||||
        self.fields["postcode"].group_id = "address"
 | 
			
		||||
        self.fields["city"].group_id = "address"
 | 
			
		||||
        self.fields["location"].group_id = "address"
 | 
			
		||||
 | 
			
		||||
        self.add_group("meta", _("Meta"))
 | 
			
		||||
        self.fields["aliases"].group_id = "meta"
 | 
			
		||||
 | 
			
		||||
        self.add_group("information", _("Information"))
 | 
			
		||||
        self.fields["description"].group_id = "information"
 | 
			
		||||
 | 
			
		||||
    def as_grid(self):
 | 
			
		||||
        result = (
 | 
			
		||||
            '<div class="grid"><div>'
 | 
			
		||||
            + super().as_p()
 | 
			
		||||
            + """</div><div><div class="map-widget">
 | 
			
		||||
            <div id="map_location"></div>
 | 
			
		||||
            <p>Cliquez pour ajuster la position GPS</p></div>
 | 
			
		||||
            <input type="checkbox" role="switch" id="lock_position">Verrouiller la position</lock>
 | 
			
		||||
            <script>
 | 
			
		||||
                document.getElementById("lock_position").onclick = function() {
 | 
			
		||||
                    const field = document.getElementById("id_location");
 | 
			
		||||
                    if (this.checked)
 | 
			
		||||
                        field.setAttribute("readonly", true);
 | 
			
		||||
                    else
 | 
			
		||||
                        field.removeAttribute("readonly");
 | 
			
		||||
                }
 | 
			
		||||
            </script>
 | 
			
		||||
            </div></div>"""
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        return mark_safe(result)
 | 
			
		||||
 | 
			
		||||
    def apply(self):
 | 
			
		||||
        return self.cleaned_data.get("apply_to_all")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MessageForm(ModelForm):
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = Message
 | 
			
		||||
        fields = ["subject", "name", "email", "message", "related_event"]
 | 
			
		||||
        widgets = {"related_event": HiddenInput(), "user": HiddenInput()}
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        self.event = kwargs.pop("event", False)
 | 
			
		||||
        self.internal = kwargs.pop("internal", False)
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        self.fields["related_event"].required = False
 | 
			
		||||
        if self.internal:
 | 
			
		||||
            self.fields.pop("name")
 | 
			
		||||
            self.fields.pop("email")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MessageEventForm(ModelForm):
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = Message
 | 
			
		||||
        fields = ["message"]
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        self.fields["message"].label = _("Add a comment")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class UserProfileForm(ModelForm):
 | 
			
		||||
 | 
			
		||||
    user = CharField(widget=HiddenInput())
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = UserProfile
 | 
			
		||||
        fields = "__all__"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SpecialPeriodForm(ModelForm):
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = SpecialPeriod
 | 
			
		||||
        fields = "__all__"
 | 
			
		||||
        widgets = {
 | 
			
		||||
            "start_date": TextInput(attrs={"type": "date"}),
 | 
			
		||||
            "end_date": TextInput(attrs={"type": "date"}),
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SpecialPeriodFileForm(Form):
 | 
			
		||||
    periodtype = ChoiceField(
 | 
			
		||||
        label=_("Period type"),
 | 
			
		||||
        required=True,
 | 
			
		||||
        choices=SpecialPeriod.PERIODTYPE.choices,
 | 
			
		||||
    )
 | 
			
		||||
    file = FileField(label=_("ICAL file"), required=True)
 | 
			
		||||
    def get_selected_event(self, edup):
 | 
			
		||||
        selected = self.get_selected_event_code()
 | 
			
		||||
        for e in edup.get_duplicated():
 | 
			
		||||
            if e.pk == selected:
 | 
			
		||||
                return e
 | 
			
		||||
        return None
 | 
			
		||||
							
								
								
									
										61
									
								
								src/agenda_culturel/forms/imports.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/agenda_culturel/forms/imports.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,61 @@
 | 
			
		||||
from django.forms import (
 | 
			
		||||
    CharField,
 | 
			
		||||
    Form,
 | 
			
		||||
    ModelChoiceField,
 | 
			
		||||
    ModelForm,
 | 
			
		||||
    MultipleChoiceField,
 | 
			
		||||
    Textarea,
 | 
			
		||||
)
 | 
			
		||||
from django.utils.translation import gettext_lazy as _
 | 
			
		||||
 | 
			
		||||
from ..models import (
 | 
			
		||||
    Category,
 | 
			
		||||
    RecurrentImport,
 | 
			
		||||
    Tag,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class BatchImportationForm(Form):
 | 
			
		||||
    required_css_class = "required"
 | 
			
		||||
 | 
			
		||||
    data = CharField(
 | 
			
		||||
        label=_("Data"),
 | 
			
		||||
        widget=Textarea(attrs={"rows": "10"}),
 | 
			
		||||
        help_text=_("Supported formats: json, html."),
 | 
			
		||||
        required=True,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    category = ModelChoiceField(
 | 
			
		||||
        label=_("Category"),
 | 
			
		||||
        queryset=Category.objects.all().order_by("name"),
 | 
			
		||||
        help_text=_("Used only if data is html."),
 | 
			
		||||
        initial=None,
 | 
			
		||||
        required=False,
 | 
			
		||||
    )
 | 
			
		||||
    tags = MultipleChoiceField(
 | 
			
		||||
        label=_("Tags"),
 | 
			
		||||
        initial=None,
 | 
			
		||||
        choices=[],
 | 
			
		||||
        help_text=_("Used only if data is html."),
 | 
			
		||||
        required=False,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        self.fields["tags"].choices = Tag.get_tag_groups(all=True)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class RecurrentImportForm(ModelForm):
 | 
			
		||||
    required_css_class = "required"
 | 
			
		||||
 | 
			
		||||
    defaultTags = MultipleChoiceField(
 | 
			
		||||
        label=_("Tags"), initial=None, choices=[], required=False
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = RecurrentImport
 | 
			
		||||
        fields = "__all__"
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        self.fields["defaultTags"].choices = Tag.get_tag_groups(all=True)
 | 
			
		||||
							
								
								
									
										35
									
								
								src/agenda_culturel/forms/message.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/agenda_culturel/forms/message.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
			
		||||
from django.forms import (
 | 
			
		||||
    HiddenInput,
 | 
			
		||||
    ModelForm,
 | 
			
		||||
)
 | 
			
		||||
from django.utils.translation import gettext_lazy as _
 | 
			
		||||
 | 
			
		||||
from ..models import (
 | 
			
		||||
    Message,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MessageForm(ModelForm):
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = Message
 | 
			
		||||
        fields = ["subject", "name", "email", "message", "related_event"]
 | 
			
		||||
        widgets = {"related_event": HiddenInput(), "user": HiddenInput()}
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        self.event = kwargs.pop("event", False)
 | 
			
		||||
        self.internal = kwargs.pop("internal", False)
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        self.fields["related_event"].required = False
 | 
			
		||||
        if self.internal:
 | 
			
		||||
            self.fields.pop("name")
 | 
			
		||||
            self.fields.pop("email")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MessageEventForm(ModelForm):
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = Message
 | 
			
		||||
        fields = ["message"]
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        self.fields["message"].label = _("Add a comment")
 | 
			
		||||
							
								
								
									
										116
									
								
								src/agenda_culturel/forms/place.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								src/agenda_culturel/forms/place.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,116 @@
 | 
			
		||||
from django.forms import (
 | 
			
		||||
    BooleanField,
 | 
			
		||||
    Form,
 | 
			
		||||
    ModelChoiceField,
 | 
			
		||||
    ModelForm,
 | 
			
		||||
    TextInput,
 | 
			
		||||
)
 | 
			
		||||
from django.utils.safestring import mark_safe
 | 
			
		||||
from django.utils.translation import gettext_lazy as _
 | 
			
		||||
 | 
			
		||||
from . import GroupFormMixin
 | 
			
		||||
from ..models import (
 | 
			
		||||
    Place,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class EventAddPlaceForm(Form):
 | 
			
		||||
    required_css_class = "required"
 | 
			
		||||
 | 
			
		||||
    place = ModelChoiceField(
 | 
			
		||||
        label=_("Place"),
 | 
			
		||||
        queryset=Place.objects.all().order_by("name"),
 | 
			
		||||
        empty_label=_("Create a missing place"),
 | 
			
		||||
        required=False,
 | 
			
		||||
    )
 | 
			
		||||
    add_alias = BooleanField(initial=True, required=False)
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        self.instance = kwargs.pop("instance", False)
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        if self.instance.location:
 | 
			
		||||
            self.fields["add_alias"].label = _(
 | 
			
		||||
                'Add "{}" to the aliases of the place'
 | 
			
		||||
            ).format(self.instance.location)
 | 
			
		||||
        else:
 | 
			
		||||
            self.fields.pop("add_alias")
 | 
			
		||||
        if self.instance.exact_location:
 | 
			
		||||
            self.fields["place"].initial = self.instance.exact_location
 | 
			
		||||
            self.fields["add_alias"].initial = False
 | 
			
		||||
 | 
			
		||||
    def modified_event(self):
 | 
			
		||||
        return self.cleaned_data.get("place")
 | 
			
		||||
 | 
			
		||||
    def save(self):
 | 
			
		||||
        if self.cleaned_data.get("place"):
 | 
			
		||||
            place = self.cleaned_data.get("place")
 | 
			
		||||
            self.instance.exact_location = place
 | 
			
		||||
            self.instance.save(update_fields=["exact_location"])
 | 
			
		||||
            if self.cleaned_data.get("add_alias"):
 | 
			
		||||
                if place.aliases:
 | 
			
		||||
                    place.aliases.append(self.instance.location.strip())
 | 
			
		||||
                else:
 | 
			
		||||
                    place.aliases = [self.instance.location.strip()]
 | 
			
		||||
                place.save()
 | 
			
		||||
 | 
			
		||||
        return self.instance
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class PlaceForm(GroupFormMixin, ModelForm):
 | 
			
		||||
    required_css_class = "required"
 | 
			
		||||
 | 
			
		||||
    apply_to_all = BooleanField(
 | 
			
		||||
        initial=True,
 | 
			
		||||
        label=_(
 | 
			
		||||
            "On saving, use aliases to detect all matching events with missing place"
 | 
			
		||||
        ),
 | 
			
		||||
        required=False,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = Place
 | 
			
		||||
        fields = "__all__"
 | 
			
		||||
        widgets = {"location": TextInput()}
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
 | 
			
		||||
        self.add_group("header", _("Header"))
 | 
			
		||||
        self.fields["name"].group_id = "header"
 | 
			
		||||
 | 
			
		||||
        self.add_group("address", _("Address"))
 | 
			
		||||
        self.fields["address"].group_id = "address"
 | 
			
		||||
        self.fields["postcode"].group_id = "address"
 | 
			
		||||
        self.fields["city"].group_id = "address"
 | 
			
		||||
        self.fields["location"].group_id = "address"
 | 
			
		||||
 | 
			
		||||
        self.add_group("meta", _("Meta"))
 | 
			
		||||
        self.fields["aliases"].group_id = "meta"
 | 
			
		||||
 | 
			
		||||
        self.add_group("information", _("Information"))
 | 
			
		||||
        self.fields["description"].group_id = "information"
 | 
			
		||||
 | 
			
		||||
    def as_grid(self):
 | 
			
		||||
        result = (
 | 
			
		||||
            '<div class="grid"><div>'
 | 
			
		||||
            + super().as_p()
 | 
			
		||||
            + """</div><div><div class="map-widget">
 | 
			
		||||
            <div id="map_location"></div>
 | 
			
		||||
            <p>Cliquez pour ajuster la position GPS</p></div>
 | 
			
		||||
            <input type="checkbox" role="switch" id="lock_position">Verrouiller la position</lock>
 | 
			
		||||
            <script>
 | 
			
		||||
                document.getElementById("lock_position").onclick = function() {
 | 
			
		||||
                    const field = document.getElementById("id_location");
 | 
			
		||||
                    if (this.checked)
 | 
			
		||||
                        field.setAttribute("readonly", true);
 | 
			
		||||
                    else
 | 
			
		||||
                        field.removeAttribute("readonly");
 | 
			
		||||
                }
 | 
			
		||||
            </script>
 | 
			
		||||
            </div></div>"""
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        return mark_safe(result)
 | 
			
		||||
 | 
			
		||||
    def apply(self):
 | 
			
		||||
        return self.cleaned_data.get("apply_to_all")
 | 
			
		||||
							
								
								
									
										32
									
								
								src/agenda_culturel/forms/special_period.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/agenda_culturel/forms/special_period.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
from django.forms import (
 | 
			
		||||
    ChoiceField,
 | 
			
		||||
    Form,
 | 
			
		||||
    ModelForm,
 | 
			
		||||
    TextInput,
 | 
			
		||||
    FileField,
 | 
			
		||||
)
 | 
			
		||||
from django.utils.translation import gettext_lazy as _
 | 
			
		||||
 | 
			
		||||
from ..models import (
 | 
			
		||||
    SpecialPeriod,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SpecialPeriodForm(ModelForm):
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = SpecialPeriod
 | 
			
		||||
        fields = "__all__"
 | 
			
		||||
        widgets = {
 | 
			
		||||
            "start_date": TextInput(attrs={"type": "date"}),
 | 
			
		||||
            "end_date": TextInput(attrs={"type": "date"}),
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SpecialPeriodFileForm(Form):
 | 
			
		||||
    periodtype = ChoiceField(
 | 
			
		||||
        label=_("Period type"),
 | 
			
		||||
        required=True,
 | 
			
		||||
        choices=SpecialPeriod.PERIODTYPE.choices,
 | 
			
		||||
    )
 | 
			
		||||
    file = FileField(label=_("ICAL file"), required=True)
 | 
			
		||||
							
								
								
									
										56
									
								
								src/agenda_culturel/forms/tag.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								src/agenda_culturel/forms/tag.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,56 @@
 | 
			
		||||
from django.forms import (
 | 
			
		||||
    BooleanField,
 | 
			
		||||
    CharField,
 | 
			
		||||
    Form,
 | 
			
		||||
    HiddenInput,
 | 
			
		||||
    ModelForm,
 | 
			
		||||
)
 | 
			
		||||
from django.utils.translation import gettext_lazy as _
 | 
			
		||||
 | 
			
		||||
from ..models import (
 | 
			
		||||
    Tag,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TagForm(ModelForm):
 | 
			
		||||
    required_css_class = "required"
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = Tag
 | 
			
		||||
        fields = [
 | 
			
		||||
            "name",
 | 
			
		||||
            "description",
 | 
			
		||||
            "message",
 | 
			
		||||
            "in_included_suggestions",
 | 
			
		||||
            "in_excluded_suggestions",
 | 
			
		||||
            "principal",
 | 
			
		||||
        ]
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        if "name" in kwargs["initial"]:
 | 
			
		||||
            self.fields["name"].widget = HiddenInput()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TagRenameForm(Form):
 | 
			
		||||
    required_css_class = "required"
 | 
			
		||||
 | 
			
		||||
    name = CharField(label=_("Name of new tag"), required=True)
 | 
			
		||||
 | 
			
		||||
    force = BooleanField(
 | 
			
		||||
        label=_(
 | 
			
		||||
            "Force renaming despite the existence of events already using the chosen tag."
 | 
			
		||||
        ),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        force = kwargs.pop("force", False)
 | 
			
		||||
        name = kwargs.pop("name", None)
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        if not (force or (not len(args) == 0 and "force" in args[0])):
 | 
			
		||||
            del self.fields["force"]
 | 
			
		||||
        if name is not None and self.fields["name"].initial is None:
 | 
			
		||||
            self.fields["name"].initial = name
 | 
			
		||||
 | 
			
		||||
    def is_force(self):
 | 
			
		||||
        return "force" in self.fields and self.cleaned_data["force"] is True
 | 
			
		||||
							
								
								
									
										18
									
								
								src/agenda_culturel/forms/user.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/agenda_culturel/forms/user.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
from django.forms import (
 | 
			
		||||
    CharField,
 | 
			
		||||
    HiddenInput,
 | 
			
		||||
    ModelForm,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
from ..models import (
 | 
			
		||||
    UserProfile,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class UserProfileForm(ModelForm):
 | 
			
		||||
 | 
			
		||||
    user = CharField(widget=HiddenInput())
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = UserProfile
 | 
			
		||||
        fields = "__all__"
 | 
			
		||||
							
								
								
									
										182
									
								
								src/agenda_culturel/forms/utils.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										182
									
								
								src/agenda_culturel/forms/utils.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,182 @@
 | 
			
		||||
from django.forms import (
 | 
			
		||||
    BooleanField,
 | 
			
		||||
    CharField,
 | 
			
		||||
    EmailField,
 | 
			
		||||
    Form,
 | 
			
		||||
    ModelChoiceField,
 | 
			
		||||
    MultipleChoiceField,
 | 
			
		||||
    Textarea,
 | 
			
		||||
    URLField,
 | 
			
		||||
    ValidationError,
 | 
			
		||||
    formset_factory,
 | 
			
		||||
)
 | 
			
		||||
from django.utils.translation import gettext_lazy as _
 | 
			
		||||
from django_better_admin_arrayfield.forms.widgets import DynamicArrayWidget
 | 
			
		||||
 | 
			
		||||
from ..models import (
 | 
			
		||||
    Category,
 | 
			
		||||
    Tag,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class GroupFormMixin:
 | 
			
		||||
    template_name = "agenda_culturel/forms/div_group.html"
 | 
			
		||||
 | 
			
		||||
    class FieldGroup:
 | 
			
		||||
        def __init__(
 | 
			
		||||
            self,
 | 
			
		||||
            id,
 | 
			
		||||
            label,
 | 
			
		||||
            display_label=False,
 | 
			
		||||
            maskable=False,
 | 
			
		||||
            default_masked=True,
 | 
			
		||||
        ):
 | 
			
		||||
            self.id = id
 | 
			
		||||
            self.label = label
 | 
			
		||||
            self.display_label = display_label
 | 
			
		||||
            self.maskable = maskable
 | 
			
		||||
            self.default_masked = default_masked
 | 
			
		||||
 | 
			
		||||
        def toggle_field_name(self):
 | 
			
		||||
            return "group_" + self.id
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        self.groups = []
 | 
			
		||||
 | 
			
		||||
    def add_group(self, *args, **kwargs):
 | 
			
		||||
        self.groups.append(GroupFormMixin.FieldGroup(*args, **kwargs))
 | 
			
		||||
        if self.groups[-1].maskable:
 | 
			
		||||
            self.fields[self.groups[-1].toggle_field_name()] = BooleanField(
 | 
			
		||||
                required=False
 | 
			
		||||
            )
 | 
			
		||||
            self.fields[self.groups[-1].toggle_field_name()].toggle_group = True
 | 
			
		||||
 | 
			
		||||
    def get_fields_in_group(self, g):
 | 
			
		||||
        return [
 | 
			
		||||
            f
 | 
			
		||||
            for f in self.visible_fields()
 | 
			
		||||
            if not hasattr(f.field, "toggle_group")
 | 
			
		||||
            and hasattr(f.field, "group_id")
 | 
			
		||||
            and f.field.group_id == g.id
 | 
			
		||||
        ]
 | 
			
		||||
 | 
			
		||||
    def get_no_group_fields(self):
 | 
			
		||||
        return [
 | 
			
		||||
            f
 | 
			
		||||
            for f in self.visible_fields()
 | 
			
		||||
            if not hasattr(f.field, "toggle_group")
 | 
			
		||||
            and (not hasattr(f.field, "group_id") or f.field.group_id is None)
 | 
			
		||||
        ]
 | 
			
		||||
 | 
			
		||||
    def fields_by_group(self):
 | 
			
		||||
        return [(g, self.get_fields_in_group(g)) for g in self.groups] + [
 | 
			
		||||
            (
 | 
			
		||||
                GroupFormMixin.FieldGroup("other", _("Other")),
 | 
			
		||||
                self.get_no_group_fields(),
 | 
			
		||||
            )
 | 
			
		||||
        ]
 | 
			
		||||
 | 
			
		||||
    def clean(self):
 | 
			
		||||
        result = super().clean()
 | 
			
		||||
 | 
			
		||||
        if result:
 | 
			
		||||
            data = dict(self.data)
 | 
			
		||||
            # for each masked group, we remove data
 | 
			
		||||
            for g in self.groups:
 | 
			
		||||
                if g.maskable and g.toggle_field_name() not in data:
 | 
			
		||||
                    fields = self.get_fields_in_group(g)
 | 
			
		||||
                    for f in fields:
 | 
			
		||||
                        self.cleaned_data[f.name] = None
 | 
			
		||||
 | 
			
		||||
        return result
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SimpleContactForm(GroupFormMixin, Form):
 | 
			
		||||
    email = EmailField(
 | 
			
		||||
        label=_("Your email"),
 | 
			
		||||
        help_text=_("Your email address"),
 | 
			
		||||
        max_length=254,
 | 
			
		||||
        required=False,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    comments = CharField(
 | 
			
		||||
        label=_("Comments"),
 | 
			
		||||
        help_text=_(
 | 
			
		||||
            "Your message for the moderation team (comments, clarifications, requests...)"
 | 
			
		||||
        ),
 | 
			
		||||
        widget=Textarea,
 | 
			
		||||
        max_length=2048,
 | 
			
		||||
        required=False,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        is_authenticated = "is_authenticated" in kwargs and kwargs["is_authenticated"]
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
 | 
			
		||||
        if not is_authenticated:
 | 
			
		||||
            self.add_group(
 | 
			
		||||
                "communication",
 | 
			
		||||
                _(
 | 
			
		||||
                    "Receive notification of publication or leave a message for moderation"
 | 
			
		||||
                ),
 | 
			
		||||
                maskable=True,
 | 
			
		||||
                default_masked=True,
 | 
			
		||||
            )
 | 
			
		||||
            self.fields["email"].group_id = "communication"
 | 
			
		||||
            self.fields["comments"].group_id = "communication"
 | 
			
		||||
        else:
 | 
			
		||||
            del self.fields["email"]
 | 
			
		||||
            del self.fields["comments"]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class URLSubmissionSimpleForm(Form):
 | 
			
		||||
    url = URLField(max_length=512)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class URLSubmissionForm(GroupFormMixin, Form):
 | 
			
		||||
    required_css_class = "required"
 | 
			
		||||
 | 
			
		||||
    url = URLField(max_length=512)
 | 
			
		||||
    category = ModelChoiceField(
 | 
			
		||||
        label=_("Category"),
 | 
			
		||||
        queryset=Category.objects.all().order_by("name"),
 | 
			
		||||
        initial=None,
 | 
			
		||||
        required=False,
 | 
			
		||||
    )
 | 
			
		||||
    tags = MultipleChoiceField(
 | 
			
		||||
        label=_("Tags"), initial=None, choices=[], required=False
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        kwargs.pop("is_authenticated", False)
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        self.fields["tags"].choices = Tag.get_tag_groups(all=True)
 | 
			
		||||
 | 
			
		||||
        self.add_group("event", _("Event"))
 | 
			
		||||
        self.fields["url"].group_id = "event"
 | 
			
		||||
        self.fields["category"].group_id = "event"
 | 
			
		||||
        self.fields["tags"].group_id = "event"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class URLSubmissionFormWithContact(SimpleContactForm, URLSubmissionForm):
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
URLSubmissionFormSet = formset_factory(URLSubmissionForm, extra=9, min_num=1)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DynamicArrayWidgetURLs(DynamicArrayWidget):
 | 
			
		||||
    template_name = "agenda_culturel/widgets/widget-urls.html"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DynamicArrayWidgetTags(DynamicArrayWidget):
 | 
			
		||||
    template_name = "agenda_culturel/widgets/widget-tags.html"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MultipleChoiceFieldAcceptAll(MultipleChoiceField):
 | 
			
		||||
    def validate(self, value):
 | 
			
		||||
        # check if each element is without "/"
 | 
			
		||||
        for item in value:
 | 
			
		||||
            if "/" in item:
 | 
			
		||||
                raise ValidationError(_("The '/' character is not allowed."))
 | 
			
		||||
		Reference in New Issue
	
	Block a user