191 lines
6.4 KiB
Python
191 lines
6.4 KiB
Python
|
from datetime import date
|
||
|
from decimal import Decimal
|
||
|
from itertools import chain
|
||
|
|
||
|
from catalog.models import Comment, SiteConfig
|
||
|
from django import forms
|
||
|
from django.db import models
|
||
|
from django.utils.translation import gettext_lazy as _
|
||
|
from modelcluster.fields import ParentalKey
|
||
|
from wagtail.admin.edit_handlers import (FieldPanel, InlinePanel,StreamFieldPanel)
|
||
|
from wagtail.contrib.forms.forms import FormBuilder
|
||
|
from wagtail.contrib.forms.models import (FORM_FIELD_CHOICES, AbstractForm,
|
||
|
AbstractFormField)
|
||
|
from wagtail.core import blocks
|
||
|
from wagtail.core.fields import RichTextField, StreamField
|
||
|
from wagtail.core.models import Page
|
||
|
from wagtail.embeds.blocks import EmbedBlock
|
||
|
|
||
|
from .blocks import ImageListBlock, ModalBlock, YellowStripBlock, NewsletterBlock
|
||
|
from .utils import get_current_site, TranslatedField, get_language_codes
|
||
|
|
||
|
|
||
|
class CustomFormBuilder(FormBuilder):
|
||
|
def __init__(self, fields):
|
||
|
super().__init__(fields)
|
||
|
|
||
|
def create_file_field(self, field, options):
|
||
|
return forms.FileField(**options)
|
||
|
|
||
|
def create_multiselect_field(self, field, options):
|
||
|
return super().create_checkboxes_field(field, options)
|
||
|
|
||
|
|
||
|
class CustomPageMixin(Page):
|
||
|
class Meta:
|
||
|
abstract = True
|
||
|
|
||
|
menu_link_text = models.CharField(
|
||
|
max_length=255, blank=True
|
||
|
)
|
||
|
promote_panels = Page.promote_panels + [
|
||
|
FieldPanel("menu_link_text")
|
||
|
]
|
||
|
|
||
|
preview_modes = []
|
||
|
|
||
|
class ImageGallery(Page):
|
||
|
template = "pages/image_gallery.html"
|
||
|
preview_modes = []
|
||
|
|
||
|
|
||
|
class InfoPage(CustomPageMixin):
|
||
|
template = "pages/info.html"
|
||
|
body = StreamField([
|
||
|
("header_video", EmbedBlock()),
|
||
|
("paragraph", blocks.RichTextBlock()),
|
||
|
("medium_text", blocks.RichTextBlock()),
|
||
|
("h1_big_text", blocks.TextBlock()),
|
||
|
("image_list", ImageListBlock()),
|
||
|
("yellow_strip", YellowStripBlock())
|
||
|
])
|
||
|
footer = StreamField([("modal", ModalBlock())], blank=True)
|
||
|
newsletter_strip = StreamField([("Newletter", NewsletterBlock())], max_num=1, blank=True)
|
||
|
content_panels = CustomPageMixin.content_panels + [
|
||
|
StreamFieldPanel("body"),
|
||
|
StreamFieldPanel("footer"),
|
||
|
StreamFieldPanel("newsletter_strip")
|
||
|
]
|
||
|
|
||
|
def get_context(self, request, *args, **kwargs):
|
||
|
context = super().get_context(request, *args, **kwargs)
|
||
|
site_config = SiteConfig.objects.get(site=get_current_site(request))
|
||
|
context["site_config"] = site_config
|
||
|
return context
|
||
|
|
||
|
class GenericPage(CustomPageMixin):
|
||
|
template = "pages/generic.html"
|
||
|
body = StreamField([
|
||
|
("paragraph", blocks.RichTextBlock()),
|
||
|
("medium_text", blocks.RichTextBlock()),
|
||
|
("h1_big_text", blocks.TextBlock()),
|
||
|
("image_list", ImageListBlock()),
|
||
|
("modal", ModalBlock())
|
||
|
])
|
||
|
content_panels = CustomPageMixin.content_panels + [
|
||
|
StreamFieldPanel("body")
|
||
|
]
|
||
|
|
||
|
class CustomAbstractForm(CustomPageMixin, AbstractForm):
|
||
|
class Meta:
|
||
|
abstract = True
|
||
|
|
||
|
|
||
|
TRANSLATED_FIELDS = {
|
||
|
'help_text': models.CharField(verbose_name=_('help text'), max_length=255, blank=True),
|
||
|
'choices': models.TextField(
|
||
|
verbose_name='choices',
|
||
|
blank=True,
|
||
|
help_text=_('Comma separated list of choices. Only applicable in checkboxes, radio and dropdown.')
|
||
|
)
|
||
|
}
|
||
|
|
||
|
class ContributeField(AbstractFormField):
|
||
|
CHOICES = FORM_FIELD_CHOICES + (('file', 'Upload File'),)
|
||
|
|
||
|
page = ParentalKey("ContributePage", on_delete=models.CASCADE, related_name="form_fields")
|
||
|
|
||
|
field_type = models.CharField(
|
||
|
verbose_name='field type',
|
||
|
max_length=16,
|
||
|
choices=CHOICES
|
||
|
)
|
||
|
choices = TranslatedField("choices")
|
||
|
help_text = TranslatedField("help_text")
|
||
|
|
||
|
|
||
|
AbstractFormField.panels = [
|
||
|
field
|
||
|
for field in AbstractFormField.panels
|
||
|
if field.field_name not in TRANSLATED_FIELDS.keys()
|
||
|
]
|
||
|
|
||
|
panels = AbstractFormField.panels + list(
|
||
|
chain.from_iterable([
|
||
|
[
|
||
|
FieldPanel(f"{field}_{language_code}")
|
||
|
for language_code in get_language_codes()
|
||
|
]
|
||
|
for field in TRANSLATED_FIELDS.keys()
|
||
|
])
|
||
|
)
|
||
|
|
||
|
for field in TRANSLATED_FIELDS:
|
||
|
for language_code in get_language_codes():
|
||
|
_, path, args, kwargs = TRANSLATED_FIELDS[field].deconstruct()
|
||
|
kwargs['verbose_name'] = f"{kwargs['verbose_name']} ({language_code})"
|
||
|
ContributeField.add_to_class(
|
||
|
f"{field}_{language_code}",
|
||
|
TRANSLATED_FIELDS[field].__class__(*args, **kwargs)
|
||
|
)
|
||
|
|
||
|
class ContributePage(CustomAbstractForm):
|
||
|
template = "pages/contribute.html"
|
||
|
landing_page_template = "pages/contribute_landing.html"
|
||
|
form_builder = CustomFormBuilder
|
||
|
|
||
|
details = RichTextField(blank=True)
|
||
|
bottom_details = StreamField([
|
||
|
("paragraph", blocks.RichTextBlock()),
|
||
|
("medium_text", blocks.RichTextBlock()),
|
||
|
("h1_big_text", blocks.TextBlock()),
|
||
|
("image_list", ImageListBlock()),
|
||
|
("modal", ModalBlock())
|
||
|
], blank=True)
|
||
|
content_panels = CustomAbstractForm.content_panels + [
|
||
|
FieldPanel("details", classname="full"),
|
||
|
InlinePanel("form_fields", label="Form Fields"),
|
||
|
FieldPanel("bottom_details", classname="full")
|
||
|
]
|
||
|
|
||
|
def get_context(self, request, *args, **kwargs):
|
||
|
context = super().get_context(request, *args, **kwargs)
|
||
|
site_config = SiteConfig.objects.get(site=get_current_site(request))
|
||
|
context["site_config"] = site_config
|
||
|
return context
|
||
|
|
||
|
def process_form_submission(self, form):
|
||
|
"""
|
||
|
Processes the form submission, if an Image upload is found, pull out the
|
||
|
files data, create an actual Wgtail Image and reference its ID only in the
|
||
|
stored form response.
|
||
|
"""
|
||
|
|
||
|
cleaned_data = form.cleaned_data
|
||
|
|
||
|
matching_fields = map(lambda f: f.name, Comment._meta.get_fields()) & cleaned_data.keys()
|
||
|
non_matching_fields = cleaned_data.keys() - matching_fields
|
||
|
for field in non_matching_fields:
|
||
|
if isinstance(cleaned_data[field], date):
|
||
|
cleaned_data[field] = str(cleaned_data[field])
|
||
|
elif isinstance(cleaned_data[field], Decimal):
|
||
|
cleaned_data[field] = float(cleaned_data[field])
|
||
|
|
||
|
submission = Comment(
|
||
|
**{k: cleaned_data[k] for k in matching_fields},
|
||
|
site=get_current_site(form.page.url),
|
||
|
misc_data={k: cleaned_data[k] for k in non_matching_fields}
|
||
|
)
|
||
|
submission.save()
|
||
|
return submission
|