Compare commits
1 Commits
main
...
419_Réorga
Author | SHA1 | Date | |
---|---|---|---|
![]() |
2afafc1338 |
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."))
|
Loading…
x
Reference in New Issue
Block a user