You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
521 lines
20 KiB
521 lines
20 KiB
from datetime import date
|
|
|
|
from crispy_forms.utils import flatatt
|
|
from django.db import models
|
|
import django.db.models.options as options
|
|
from django.utils.html import format_html, format_html_join
|
|
from wagtail.embeds.blocks import EmbedBlock
|
|
|
|
options.DEFAULT_NAMES = options.DEFAULT_NAMES + ('description',)
|
|
from django.urls import reverse
|
|
from django.contrib import messages
|
|
|
|
from wagtailcaptcha.models import WagtailCaptchaEmailForm
|
|
from crispy_forms.helper import FormHelper
|
|
from django_extensions.db.models import TimeStampedModel
|
|
|
|
from modelcluster.fields import ParentalKey
|
|
from wagtail import blocks
|
|
from wagtail.documents import get_document_model
|
|
from wagtail.images import get_image_model
|
|
from wagtail.models import Page
|
|
from wagtail.fields import RichTextField, StreamField
|
|
from wagtail.admin.panels import (
|
|
MultiFieldPanel, PageChooserPanel, InlinePanel, FieldPanel)
|
|
from wagtail.images.blocks import ImageChooserBlock
|
|
from wagtail.documents.blocks import DocumentChooserBlock
|
|
from wagtail.contrib.forms.models import AbstractEmailForm, AbstractFormField
|
|
from wagtailmedia.edit_handlers import MediaChooserPanel
|
|
|
|
from wagtailmedia.blocks import AbstractMediaChooserBlock
|
|
|
|
|
|
class MediaBlock(AbstractMediaChooserBlock):
|
|
def render_basic(self, value, context=None):
|
|
if not value:
|
|
return ''
|
|
|
|
if value.type == 'video':
|
|
player_code = '''
|
|
<div>
|
|
<video width="720" controls>
|
|
{0}
|
|
Your browser does not support the video tag.
|
|
</video>
|
|
</div>
|
|
'''
|
|
else:
|
|
player_code = '''
|
|
<div>
|
|
<audio controls>
|
|
{0}
|
|
Your browser does not support the audio element.
|
|
</audio>
|
|
</div>
|
|
'''
|
|
|
|
return format_html(player_code, format_html_join(
|
|
'\n', "<source{0}>",
|
|
[[flatatt(s)] for s in value.sources]
|
|
))
|
|
|
|
|
|
class HomePage(Page):
|
|
block1 = RichTextField(blank=True)
|
|
|
|
# revolution slider
|
|
slide1_img = models.ForeignKey(
|
|
get_image_model(),
|
|
null=True,
|
|
blank=True,
|
|
on_delete=models.SET_NULL,
|
|
related_name='+'
|
|
)
|
|
slide1_headline = models.CharField(max_length=512, blank=True)
|
|
slide1_subline = models.CharField(max_length=512, blank=True)
|
|
slide1_link_url = models.URLField(blank=True)
|
|
slide1_link_text = models.CharField(max_length=64, blank=True)
|
|
slide2_img = models.ForeignKey(
|
|
get_image_model(),
|
|
null=True,
|
|
blank=True,
|
|
on_delete=models.SET_NULL,
|
|
related_name='+'
|
|
)
|
|
slide2_headline = models.CharField(max_length=512, blank=True)
|
|
slide2_subline = models.CharField(max_length=512, blank=True)
|
|
slide2_link_url = models.URLField(blank=True)
|
|
slide2_link_text = models.CharField(max_length=64, blank=True)
|
|
slide3_img = models.ForeignKey(
|
|
get_image_model(),
|
|
null=True,
|
|
blank=True,
|
|
on_delete=models.SET_NULL,
|
|
related_name='+'
|
|
)
|
|
slide3_headline = models.CharField(max_length=512, blank=True)
|
|
slide3_subline = models.CharField(max_length=512, blank=True)
|
|
slide3_link_url = models.URLField(blank=True)
|
|
slide3_link_text = models.CharField(max_length=64, blank=True)
|
|
|
|
thumbnail1_img = models.ForeignKey(
|
|
get_image_model(),
|
|
null=True,
|
|
blank=True,
|
|
on_delete=models.SET_NULL,
|
|
related_name='+'
|
|
)
|
|
thumbnail1_more_page = models.ForeignKey(
|
|
'wagtailcore.Page',
|
|
null=True,
|
|
blank=True,
|
|
on_delete=models.SET_NULL,
|
|
related_name='+',
|
|
)
|
|
thumbnail1_more_text = models.CharField(max_length=64, blank=True)
|
|
thumbnail1_title = models.CharField(max_length=128, blank=True)
|
|
thumbnail1_text = RichTextField(blank=True)
|
|
|
|
thumbnail2_img = models.ForeignKey(
|
|
get_image_model(),
|
|
null=True,
|
|
blank=True,
|
|
on_delete=models.SET_NULL,
|
|
related_name='+'
|
|
)
|
|
thumbnail2_more_page = models.ForeignKey(
|
|
'wagtailcore.Page',
|
|
null=True,
|
|
blank=True,
|
|
on_delete=models.SET_NULL,
|
|
related_name='+',
|
|
)
|
|
thumbnail2_more_text = models.CharField(max_length=64, blank=True)
|
|
thumbnail2_title = models.CharField(max_length=128, blank=True)
|
|
thumbnail2_text = RichTextField(blank=True)
|
|
|
|
thumbnail3_img = models.ForeignKey(
|
|
get_image_model(),
|
|
null=True,
|
|
blank=True,
|
|
on_delete=models.SET_NULL,
|
|
related_name='+'
|
|
)
|
|
thumbnail3_more_page = models.ForeignKey(
|
|
'wagtailcore.Page',
|
|
null=True,
|
|
blank=True,
|
|
on_delete=models.SET_NULL,
|
|
related_name='+',
|
|
)
|
|
thumbnail3_more_text = models.CharField(max_length=64, blank=True)
|
|
thumbnail3_title = models.CharField(max_length=128, blank=True)
|
|
thumbnail3_text = RichTextField(blank=True)
|
|
|
|
|
|
REVOLUTION_SLIDER_FIELDS = [
|
|
MultiFieldPanel([
|
|
FieldPanel('slide1_img'),
|
|
FieldPanel('slide1_headline', classname="full"),
|
|
FieldPanel('slide1_subline', classname="full"),
|
|
FieldPanel('slide1_link_url', classname="full"),
|
|
FieldPanel('slide1_link_text', classname="full"),
|
|
], heading='Slide 1', classname="collapsible"),
|
|
|
|
MultiFieldPanel([
|
|
FieldPanel('slide2_img'),
|
|
FieldPanel('slide2_headline', classname="full"),
|
|
FieldPanel('slide2_subline', classname="full"),
|
|
FieldPanel('slide2_link_url', classname="full"),
|
|
FieldPanel('slide2_link_text', classname="full"),
|
|
], heading='Slide 2', classname="collapsible"),
|
|
|
|
MultiFieldPanel([
|
|
FieldPanel('slide3_img'),
|
|
FieldPanel('slide3_headline', classname="full"),
|
|
FieldPanel('slide3_subline', classname="full"),
|
|
FieldPanel('slide3_link_url', classname="full"),
|
|
FieldPanel('slide3_link_text', classname="full"),
|
|
], heading='Slide 3'),
|
|
]
|
|
|
|
HOME_THUMBNAIL_FIELDS = [
|
|
MultiFieldPanel([
|
|
FieldPanel('thumbnail1_img'),
|
|
PageChooserPanel('thumbnail1_more_page'),
|
|
FieldPanel('thumbnail1_more_text', classname="full"),
|
|
FieldPanel('thumbnail1_title', classname="full"),
|
|
FieldPanel('thumbnail1_text', classname="full"),
|
|
], heading='Thumbnail 1', classname="collapsible"),
|
|
MultiFieldPanel([
|
|
FieldPanel('thumbnail2_img'),
|
|
PageChooserPanel('thumbnail2_more_page'),
|
|
FieldPanel('thumbnail2_more_text', classname="full"),
|
|
FieldPanel('thumbnail2_title', classname="full"),
|
|
FieldPanel('thumbnail2_text', classname="full"),
|
|
], heading='Thumbnail 2', classname="collapsible"),
|
|
MultiFieldPanel([
|
|
FieldPanel('thumbnail3_img'),
|
|
PageChooserPanel('thumbnail3_more_page'),
|
|
FieldPanel('thumbnail3_more_text', classname="full"),
|
|
FieldPanel('thumbnail3_title', classname="full"),
|
|
FieldPanel('thumbnail3_text', classname="full"),
|
|
], heading='Thumbnail 3', classname="collapsible"),
|
|
]
|
|
|
|
HomePage.content_panels = [
|
|
FieldPanel('title', classname="full title"),
|
|
MultiFieldPanel(REVOLUTION_SLIDER_FIELDS, heading='Slider elements', classname="collapsible collapsed"),
|
|
FieldPanel('block1', classname="full"),
|
|
MultiFieldPanel(HOME_THUMBNAIL_FIELDS, heading='Thumbnail elements', classname="collapsible collapsed"),
|
|
]
|
|
|
|
|
|
class SimpleOneColumnPage(Page):
|
|
featured_media = models.ForeignKey(
|
|
'wagtailmedia.Media',
|
|
null=True,
|
|
blank=True,
|
|
on_delete=models.SET_NULL,
|
|
related_name='+'
|
|
)
|
|
content = RichTextField(blank=True)
|
|
|
|
|
|
SimpleOneColumnPage.content_panels = [
|
|
FieldPanel('title', classname="full title"),
|
|
FieldPanel('featured_media'),
|
|
FieldPanel('content', classname="full"),
|
|
]
|
|
|
|
|
|
class BlogPage(Page):
|
|
posts = StreamField([
|
|
('post', blocks.StructBlock([
|
|
('images', blocks.ListBlock(ImageChooserBlock())),
|
|
('title', blocks.CharBlock(max_length=200)),
|
|
('author', blocks.CharBlock(max_length=64, default="Marion Schauf", required=False)),
|
|
('date', blocks.DateBlock()),
|
|
('text', blocks.RichTextBlock()),
|
|
('url', blocks.URLBlock(required=False)),
|
|
])),
|
|
], null=True, blank=True, use_json_field=True)
|
|
|
|
|
|
BlogPage.content_panels = [
|
|
FieldPanel('title', classname="full title"),
|
|
FieldPanel('posts'),
|
|
]
|
|
|
|
|
|
class EventIndexPage(Page):
|
|
subpage_types = ['core.EventPage']
|
|
|
|
def get_events(self):
|
|
return EventPage.objects.live().filter(show_in_event_calendar=True, path__startswith=self.path).order_by('start_date')
|
|
|
|
class Meta:
|
|
description = "Displays all events on EventPages below in an overview. Use this as parent page for events."
|
|
|
|
|
|
class EventPage(AbstractEmailForm):
|
|
parent_page_types = ['core.EventIndexPage', 'core.EventHistoryPage']
|
|
subtitle = models.CharField(max_length=512, null=True, blank=True)
|
|
description = RichTextField(blank=True)
|
|
|
|
# revolution slider
|
|
slide1_img = models.ForeignKey(
|
|
get_image_model(),
|
|
null=True,
|
|
blank=True,
|
|
on_delete=models.SET_NULL,
|
|
related_name='+'
|
|
)
|
|
slide1_headline = models.CharField(max_length=512, blank=True)
|
|
slide1_subline = models.CharField(max_length=512, blank=True)
|
|
slide1_link_url = models.URLField(blank=True)
|
|
slide1_link_text = models.CharField(max_length=64, blank=True)
|
|
slide2_img = models.ForeignKey(
|
|
get_image_model(),
|
|
null=True,
|
|
blank=True,
|
|
on_delete=models.SET_NULL,
|
|
related_name='+'
|
|
)
|
|
slide2_headline = models.CharField(max_length=512, blank=True)
|
|
slide2_subline = models.CharField(max_length=512, blank=True)
|
|
slide2_link_url = models.URLField(blank=True)
|
|
slide2_link_text = models.CharField(max_length=64, blank=True)
|
|
slide3_img = models.ForeignKey(
|
|
get_image_model(),
|
|
null=True,
|
|
blank=True,
|
|
on_delete=models.SET_NULL,
|
|
related_name='+'
|
|
)
|
|
slide3_headline = models.CharField(max_length=512, blank=True)
|
|
slide3_subline = models.CharField(max_length=512, blank=True)
|
|
slide3_link_url = models.URLField(blank=True)
|
|
slide3_link_text = models.CharField(max_length=64, blank=True)
|
|
|
|
img1_img = models.ForeignKey(
|
|
get_image_model(),
|
|
null=True,
|
|
blank=True,
|
|
on_delete=models.SET_NULL,
|
|
related_name='+'
|
|
)
|
|
img1_caption = models.CharField(max_length=64, blank=True)
|
|
img2_img = models.ForeignKey(
|
|
get_image_model(),
|
|
null=True,
|
|
blank=True,
|
|
on_delete=models.SET_NULL,
|
|
related_name='+'
|
|
)
|
|
img2_caption = models.CharField(max_length=64, blank=True)
|
|
|
|
start_date = models.DateField()
|
|
end_date = models.DateField(null=True, blank=True)
|
|
location_name = models.CharField(
|
|
max_length=256, help_text="Name of the location (first line of address)", blank=True)
|
|
location_street = models.CharField(max_length=256, help_text="Street and house number", blank=True)
|
|
location_city = models.CharField(max_length=256, help_text="Zip code and city", blank=True)
|
|
flyer = models.ForeignKey(
|
|
get_document_model(),
|
|
null=True,
|
|
blank=True,
|
|
on_delete=models.SET_NULL,
|
|
related_name='+'
|
|
)
|
|
downloads = StreamField([
|
|
('download', blocks.StructBlock([
|
|
('title', blocks.CharBlock(max_length=128, label='Name (Button-Beschriftung)')),
|
|
('file', DocumentChooserBlock(label='Datei')),
|
|
])),
|
|
], null=True, blank=True, use_json_field=True)
|
|
tabs = StreamField([
|
|
('sponsor_tab', blocks.StructBlock([
|
|
('title', blocks.CharBlock(max_length=64)),
|
|
('sponsors', blocks.StreamBlock([
|
|
('sponsor', blocks.StructBlock([
|
|
('name', blocks.CharBlock(max_length=64)),
|
|
('logo', ImageChooserBlock(required=False)),
|
|
('url', blocks.URLBlock(required=False)),
|
|
])),
|
|
('headline', blocks.CharBlock(max_length=64)),
|
|
])),
|
|
])),
|
|
('richtext_tab', blocks.StructBlock([
|
|
('title', blocks.CharBlock(max_length=64)),
|
|
('content', blocks.RichTextBlock()),
|
|
])),
|
|
('media_tab', blocks.StructBlock([
|
|
('title', blocks.CharBlock(max_length=64)),
|
|
('pre_content', blocks.RichTextBlock(required=False)),
|
|
('media_file', MediaBlock(template='core/blocks/media_block.html')),
|
|
('autoplay', blocks.BooleanBlock(label='Automatisch abspielen', required=False)),
|
|
('muted', blocks.BooleanBlock(label='Stummgeschaltet starten', required=False)),
|
|
('post_content', blocks.RichTextBlock(required=False)),
|
|
])),
|
|
], null=True, blank=True, use_json_field=True)
|
|
|
|
registration_url = models.URLField(max_length=512, blank=True, help_text="URL der Anmeldeseite (leer lassen um klassische Anmeldung zu verwenden)")
|
|
pretix_slug = models.CharField(max_length=512, blank=True, help_text="Slug von Pretix (leer lassen, um klassische Anmeldung zu verwenden)")
|
|
registration_start_date = models.DateField(
|
|
null=True, blank=True, help_text="When does the registration open? Leave empty to disable registration")
|
|
registration_end_date = models.DateField(
|
|
null=True, blank=True,
|
|
help_text="Last day where the registration will be available. Leave empty to enable registration permanently"
|
|
"after start date")
|
|
show_in_event_calendar = models.BooleanField(default=True, help_text='Event in Eventliste und im Kalender anzeigen?')
|
|
is_free = models.BooleanField(default=False, help_text='If this is checked the send button under the registration'
|
|
'form will be labeled "verbindlich anmelden" instead of "kostenpflichtig anmelden"')
|
|
external_registration_code = models.TextField(
|
|
blank=True, null=True,
|
|
help_text='Put code e.g. from Xing here. If this field is filled out there will be no registration form displayed.')
|
|
|
|
vimeo_id = models.TextField(blank=True, help_text='Vimeo Event ID (aus Vimeo-Link: https://vimeo.com/<hier-ist-die-id> )')
|
|
|
|
def is_registration_active(self):
|
|
return self.registration_start_date and self.registration_start_date <= date.today() and\
|
|
(not self.registration_end_date or self.registration_end_date >= date.today())
|
|
|
|
@property
|
|
def pretix_url(self):
|
|
if self.pretix_slug:
|
|
return 'https://tickets.feo.gmbh/' + self.pretix_slug + '/'
|
|
|
|
return None
|
|
|
|
def get_form_helper(self):
|
|
helper = FormHelper()
|
|
helper.label_class = 'col-lg-3'
|
|
helper.field_class = 'col-lg-9'
|
|
helper.form_tag = False
|
|
return helper
|
|
|
|
class Meta:
|
|
ordering = ['-start_date']
|
|
|
|
|
|
class EventRegistrationField(AbstractFormField):
|
|
page = ParentalKey('EventPage', related_name='form_fields')
|
|
|
|
|
|
EventPage.content_panels = [
|
|
MultiFieldPanel(REVOLUTION_SLIDER_FIELDS, heading='Slider elements', classname="collapsible collapsed"),
|
|
FieldPanel('title', classname="full title"),
|
|
FieldPanel('subtitle', classname="full"),
|
|
FieldPanel('description', classname="full"),
|
|
FieldPanel('img1_img'),
|
|
FieldPanel('img1_caption', classname="full"),
|
|
FieldPanel('img2_img'),
|
|
FieldPanel('img2_caption', classname="full"),
|
|
FieldPanel('start_date', classname="full"),
|
|
FieldPanel('end_date', classname="full"),
|
|
FieldPanel('tabs'),
|
|
FieldPanel('location_name', classname="full"),
|
|
FieldPanel('location_street', classname="full"),
|
|
FieldPanel('location_city', classname="full"),
|
|
FieldPanel('flyer'),
|
|
FieldPanel('downloads'),
|
|
MultiFieldPanel([
|
|
FieldPanel('show_in_event_calendar', classname="full"),
|
|
FieldPanel('is_free', classname="full"),
|
|
FieldPanel('pretix_slug', classname="full"),
|
|
FieldPanel('registration_url', classname="full"),
|
|
FieldPanel('vimeo_id', classname="full"),
|
|
], heading="Settings", classname="collapsible collapsed"),
|
|
FieldPanel('external_registration_code', classname="full"),
|
|
MultiFieldPanel([
|
|
InlinePanel('form_fields', label="Form fields"),
|
|
FieldPanel('registration_start_date', classname="full"),
|
|
FieldPanel('registration_end_date', classname="full"),
|
|
MultiFieldPanel([
|
|
FieldPanel('to_address', classname="full"),
|
|
FieldPanel('from_address', classname="full"),
|
|
FieldPanel('subject', classname="full"),
|
|
], "Email"),
|
|
], heading="Registration Form", classname="collapsible collapsed"),
|
|
]
|
|
|
|
|
|
class EventHistoryPage(Page):
|
|
events = StreamField([
|
|
('event', blocks.StructBlock([
|
|
('title', blocks.CharBlock(max_length=512, required=False)),
|
|
('subtitle', blocks.CharBlock(max_length=512, required=False)),
|
|
('start_date', blocks.DateBlock()),
|
|
('end_date', blocks.DateBlock(required=False, help_text="Leave empty for single day events")),
|
|
('location_name', blocks.CharBlock(
|
|
max_length=256, help_text="Name of the location (first line of address)", required=False)),
|
|
('location_city', blocks.CharBlock(max_length=256, help_text="Zip code and city", required=False)),
|
|
('image', ImageChooserBlock(required=False)),
|
|
('flyer', DocumentChooserBlock(required=False)),
|
|
('additional_info_btn_label', blocks.CharBlock(max_length=128, required=False, label='Zusatzinfo Button Text')),
|
|
('additional_info_target', blocks.PageChooserBlock(required=False, label='Zusatzinfo Zielseite')),
|
|
])),
|
|
], null=True, blank=True, use_json_field=True)
|
|
|
|
|
|
EventHistoryPage.content_panels = [
|
|
FieldPanel('title', classname="full title"),
|
|
FieldPanel('events'),
|
|
]
|
|
|
|
|
|
class ContactFormField(AbstractFormField):
|
|
page = ParentalKey('ContactFormPage', related_name='form_fields')
|
|
|
|
|
|
class ContactFormPage(WagtailCaptchaEmailForm):
|
|
form_title = models.CharField(max_length=128, blank=True)
|
|
person_img = models.ForeignKey(
|
|
get_image_model(),
|
|
null=True,
|
|
blank=True,
|
|
on_delete=models.SET_NULL,
|
|
related_name='+'
|
|
)
|
|
person_name = models.CharField(max_length=128, blank=True)
|
|
person_position = models.CharField(max_length=128, blank=True)
|
|
address = models.CharField(max_length=128, blank=True)
|
|
mail_address = models.CharField(max_length=128, blank=True)
|
|
phone = models.CharField(max_length=128, blank=True)
|
|
web_address = models.URLField(blank=True)
|
|
thank_you_text = RichTextField(blank=True)
|
|
|
|
|
|
ContactFormPage.content_panels = [
|
|
FieldPanel('title', classname="full title"),
|
|
FieldPanel('form_title', classname="full"),
|
|
FieldPanel('person_img'),
|
|
FieldPanel('person_name', classname="full"),
|
|
FieldPanel('person_position', classname="full"),
|
|
FieldPanel('address', classname="full"),
|
|
FieldPanel('mail_address', classname="full"),
|
|
FieldPanel('phone', classname="full"),
|
|
FieldPanel('web_address', classname="full"),
|
|
InlinePanel('form_fields', label="Form fields"),
|
|
FieldPanel('thank_you_text', classname="full"),
|
|
MultiFieldPanel([
|
|
FieldPanel('to_address', classname="full"),
|
|
FieldPanel('from_address', classname="full"),
|
|
FieldPanel('subject', classname="full"),
|
|
], "Email")
|
|
]
|
|
|
|
|
|
class UploadedScript(TimeStampedModel):
|
|
name = models.CharField(max_length=512, verbose_name='Ihr Name')
|
|
script = models.FileField(upload_to='scripts', verbose_name='Skript')
|
|
|
|
def get_delete_url(self):
|
|
return reverse('delete_script', kwargs={'pk': self.pk})
|
|
|
|
def delete(self, *args, **kwargs):
|
|
storage, path = self.script.storage, self.script.path
|
|
out = super().delete(*args, **kwargs)
|
|
storage.delete(path)
|
|
return out
|
|
|