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
 | 
					import os
 | 
				
			||||||
from string import ascii_uppercase as auc
 | 
					from string import ascii_uppercase as auc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from django.conf import settings
 | 
					from django.conf import settings
 | 
				
			||||||
from django.core.files import File
 | 
					from django.core.files import File
 | 
				
			||||||
from django.forms import (
 | 
					from django.forms import (
 | 
				
			||||||
    BooleanField,
 | 
					 | 
				
			||||||
    CharField,
 | 
					    CharField,
 | 
				
			||||||
    ChoiceField,
 | 
					    ChoiceField,
 | 
				
			||||||
    EmailField,
 | 
					 | 
				
			||||||
    Form,
 | 
					    Form,
 | 
				
			||||||
    HiddenInput,
 | 
					    HiddenInput,
 | 
				
			||||||
    ModelChoiceField,
 | 
					 | 
				
			||||||
    ModelForm,
 | 
					    ModelForm,
 | 
				
			||||||
    MultipleChoiceField,
 | 
					    MultipleChoiceField,
 | 
				
			||||||
    MultipleHiddenInput,
 | 
					    MultipleHiddenInput,
 | 
				
			||||||
    RadioSelect,
 | 
					    RadioSelect,
 | 
				
			||||||
    Textarea,
 | 
					 | 
				
			||||||
    TextInput,
 | 
					    TextInput,
 | 
				
			||||||
    URLField,
 | 
					 | 
				
			||||||
    ValidationError,
 | 
					    ValidationError,
 | 
				
			||||||
    FileField,
 | 
					 | 
				
			||||||
    formset_factory,
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from django.utils.formats import localize
 | 
					from django.utils.formats import localize
 | 
				
			||||||
from django.utils.safestring import mark_safe
 | 
					from django.utils.safestring import mark_safe
 | 
				
			||||||
from django.utils.translation import gettext_lazy as _
 | 
					from django.utils.translation import gettext_lazy as _
 | 
				
			||||||
from django_better_admin_arrayfield.forms.widgets import DynamicArrayWidget
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .models import (
 | 
					from . import (
 | 
				
			||||||
    CategorisationRule,
 | 
					    GroupFormMixin,
 | 
				
			||||||
 | 
					    MultipleChoiceFieldAcceptAll,
 | 
				
			||||||
 | 
					    DynamicArrayWidgetTags,
 | 
				
			||||||
 | 
					    DynamicArrayWidgetURLs,
 | 
				
			||||||
 | 
					    SimpleContactForm,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					from ..models import (
 | 
				
			||||||
    Category,
 | 
					    Category,
 | 
				
			||||||
    Event,
 | 
					    Event,
 | 
				
			||||||
    Message,
 | 
					 | 
				
			||||||
    Place,
 | 
					 | 
				
			||||||
    RecurrentImport,
 | 
					 | 
				
			||||||
    Tag,
 | 
					    Tag,
 | 
				
			||||||
    UserProfile,
 | 
					 | 
				
			||||||
    SpecialPeriod,
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from .templatetags.event_extra import event_field_verbose_name, field_to_html
 | 
					from ..models.constants import (
 | 
				
			||||||
from .templatetags.utils_extra import int_to_abc
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from .models.constants import (
 | 
					 | 
				
			||||||
    TITLE_ISSUE_DATE_IMPORTATION,
 | 
					    TITLE_ISSUE_DATE_IMPORTATION,
 | 
				
			||||||
    TITLE_ISSUE_TIME_IMPORTATION,
 | 
					    TITLE_ISSUE_TIME_IMPORTATION,
 | 
				
			||||||
    PUBLICATION_ISSUE,
 | 
					    PUBLICATION_ISSUE,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					from ..templatetags.event_extra import event_field_verbose_name, field_to_html
 | 
				
			||||||
logger = logging.getLogger(__name__)
 | 
					from ..templatetags.utils_extra import int_to_abc
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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."))
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class EventForm(GroupFormMixin, ModelForm):
 | 
					class EventForm(GroupFormMixin, ModelForm):
 | 
				
			||||||
@@ -570,131 +328,6 @@ class EventModerateForm(ModelForm):
 | 
				
			|||||||
        self.cleaned_data["tags"] = list(set(self.cleaned_data["tags"]))
 | 
					        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):
 | 
					class SelectEventInList(Form):
 | 
				
			||||||
    required_css_class = "required"
 | 
					    required_css_class = "required"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -888,190 +521,96 @@ class MergeDuplicates(Form):
 | 
				
			|||||||
                return None
 | 
					                return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CategorisationForm(Form):
 | 
					class FixDuplicates(Form):
 | 
				
			||||||
    required_css_class = "required"
 | 
					    required_css_class = "required"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    action = ChoiceField()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, *args, **kwargs):
 | 
					    def __init__(self, *args, **kwargs):
 | 
				
			||||||
        if "events" in kwargs:
 | 
					        edup = kwargs.pop("edup", None)
 | 
				
			||||||
            events = kwargs.pop("events", None)
 | 
					        events = edup.get_duplicated()
 | 
				
			||||||
        else:
 | 
					        len(events)
 | 
				
			||||||
            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)
 | 
					        super().__init__(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for e, c in events:
 | 
					        choices = []
 | 
				
			||||||
            self.fields[str(e.pk)] = BooleanField(
 | 
					        initial = None
 | 
				
			||||||
                initial=False,
 | 
					        for i, e in enumerate(events):
 | 
				
			||||||
                label=_("Apply category {} to the event {}").format(c, e.title),
 | 
					            if e.status != Event.STATUS.TRASH or e.modified():
 | 
				
			||||||
                required=False,
 | 
					                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):
 | 
					    def is_action_no_duplicates(self):
 | 
				
			||||||
    required_css_class = "required"
 | 
					        return self.cleaned_data["action"] == "NotDuplicates"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    place = ModelChoiceField(
 | 
					    def is_action_select(self):
 | 
				
			||||||
        label=_("Place"),
 | 
					        return self.cleaned_data["action"].startswith("Select")
 | 
				
			||||||
        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):
 | 
					    def is_action_update(self):
 | 
				
			||||||
        self.instance = kwargs.pop("instance", False)
 | 
					        return self.cleaned_data["action"].startswith("Update")
 | 
				
			||||||
        super().__init__(*args, **kwargs)
 | 
					
 | 
				
			||||||
        if self.instance.location:
 | 
					    def is_action_remove(self):
 | 
				
			||||||
            self.fields["add_alias"].label = _(
 | 
					        return self.cleaned_data["action"].startswith("Remove")
 | 
				
			||||||
                'Add "{}" to the aliases of the place'
 | 
					
 | 
				
			||||||
            ).format(self.instance.location)
 | 
					    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:
 | 
					        else:
 | 
				
			||||||
            self.fields.pop("add_alias")
 | 
					            return None
 | 
				
			||||||
        if self.instance.exact_location:
 | 
					 | 
				
			||||||
            self.fields["place"].initial = self.instance.exact_location
 | 
					 | 
				
			||||||
            self.fields["add_alias"].initial = False
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def modified_event(self):
 | 
					    def get_selected_event(self, edup):
 | 
				
			||||||
        return self.cleaned_data.get("place")
 | 
					        selected = self.get_selected_event_code()
 | 
				
			||||||
 | 
					        for e in edup.get_duplicated():
 | 
				
			||||||
    def save(self):
 | 
					            if e.pk == selected:
 | 
				
			||||||
        if self.cleaned_data.get("place"):
 | 
					                return e
 | 
				
			||||||
            place = self.cleaned_data.get("place")
 | 
					        return None
 | 
				
			||||||
            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)
 | 
					 | 
				
			||||||
							
								
								
									
										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