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 = '''
''' else: player_code = '''
''' return format_html(player_code, format_html_join( '\n', "", [[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/ )') 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