feat!: Removes XML endpoint and adds fields for German and English tour details
This commit is contained in:
parent
b8deff0b68
commit
f5e32a6649
4 changed files with 119 additions and 229 deletions
|
|
@ -66,6 +66,12 @@ Development setup
|
||||||
Changelog
|
Changelog
|
||||||
---------
|
---------
|
||||||
|
|
||||||
|
2.0.0
|
||||||
|
~~~~~
|
||||||
|
|
||||||
|
- Removes XML endpoint (breaking)
|
||||||
|
- Replaces language section with "Hackertours Settings" section containing language of tour and links for English and German tour details
|
||||||
|
|
||||||
1.1.1
|
1.1.1
|
||||||
~~~~~
|
~~~~~
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,219 +5,13 @@ try:
|
||||||
from pretix.base.models import SubEventMetaValue
|
from pretix.base.models import SubEventMetaValue
|
||||||
except Exception: # pragma: no cover
|
except Exception: # pragma: no cover
|
||||||
SubEventMetaValue = None
|
SubEventMetaValue = None
|
||||||
import xml.etree.ElementTree as ET
|
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from datetime import timedelta
|
|
||||||
import uuid
|
import uuid
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from . import __version__
|
from . import __version__
|
||||||
import json
|
import json
|
||||||
|
|
||||||
class CongressScheduleXMLView(views.APIView):
|
|
||||||
def get(self, request, organizer, event, *args, **kwargs):
|
|
||||||
try:
|
|
||||||
ev = Event.objects.get(organizer__slug=organizer, slug=event)
|
|
||||||
except Event.DoesNotExist:
|
|
||||||
return HttpResponse(b'<?xml version="1.0"?><error>Event not found</error>', status=404, content_type='application/xml')
|
|
||||||
|
|
||||||
if not ev.has_subevents:
|
|
||||||
return HttpResponse(
|
|
||||||
b'<?xml version="1.0"?><error>Event is not an event-series: https://docs.pretix.eu/guides/event-series/?h=dates#how-to-create-an-event-series</error>',
|
|
||||||
status=400,
|
|
||||||
content_type='application/xml'
|
|
||||||
)
|
|
||||||
|
|
||||||
subs = SubEvent.objects.filter(event=ev).order_by('date_from')
|
|
||||||
|
|
||||||
root = ET.Element('schedule')
|
|
||||||
|
|
||||||
gen = ET.SubElement(root, 'generator')
|
|
||||||
gen.set('name', 'pretix-congressschedule')
|
|
||||||
gen.set('version', __version__)
|
|
||||||
|
|
||||||
try:
|
|
||||||
feed_url = request.build_absolute_uri()
|
|
||||||
ET.SubElement(root, 'url').text = feed_url
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# Version string – keep simple and stable per event
|
|
||||||
ET.SubElement(root, 'version').text = f"{ev.slug}-v1"
|
|
||||||
|
|
||||||
conf = ET.SubElement(root, 'conference')
|
|
||||||
conf_title = ev.name.localize(ev.settings.locale) if hasattr(ev.name, 'localize') else str(ev.name)
|
|
||||||
ET.SubElement(conf, 'title').text = conf_title or str(ev.slug)
|
|
||||||
acronym = f"{organizer}_{event}".lower()
|
|
||||||
ET.SubElement(conf, 'acronym').text = acronym
|
|
||||||
|
|
||||||
# start/end/days based on subevents if available, else fall back to event
|
|
||||||
all_starts = [se.date_from for se in subs if se.date_from]
|
|
||||||
all_ends = [se.date_to for se in subs if se.date_to]
|
|
||||||
|
|
||||||
if all_starts:
|
|
||||||
ET.SubElement(conf, 'start').text = min(all_starts).isoformat()
|
|
||||||
if all_ends:
|
|
||||||
ET.SubElement(conf, 'end').text = max(all_ends).isoformat()
|
|
||||||
|
|
||||||
# days count – unique calendar days from subevents
|
|
||||||
unique_days = sorted({(se.date_from.date() if se.date_from else None) for se in subs} - {None})
|
|
||||||
if unique_days:
|
|
||||||
ET.SubElement(conf, 'days').text = str(len(unique_days))
|
|
||||||
|
|
||||||
# time zone name – try Event.timezone or settings
|
|
||||||
tz_name = getattr(ev, 'timezone', None) or getattr(ev.settings, 'timezone', None)
|
|
||||||
if tz_name:
|
|
||||||
tz_text = tz_name if isinstance(tz_name, str) else str(tz_name)
|
|
||||||
ET.SubElement(conf, 'time_zone_name').text = tz_text
|
|
||||||
|
|
||||||
# Group subevents into days and rooms
|
|
||||||
# days: {date -> {room_name -> [subevents]}}
|
|
||||||
days: dict = defaultdict(lambda: defaultdict(list))
|
|
||||||
|
|
||||||
def get_room_name(se):
|
|
||||||
# Try SubEvent.location if present, else fallback to `Main`
|
|
||||||
loc = getattr(se, 'location', None)
|
|
||||||
if hasattr(loc, 'localize'):
|
|
||||||
try:
|
|
||||||
txt = loc.localize(ev.settings.locale)
|
|
||||||
except Exception:
|
|
||||||
txt = str(loc)
|
|
||||||
else:
|
|
||||||
txt = str(loc) if loc else ''
|
|
||||||
return (txt or 'Main').strip() or 'Main'
|
|
||||||
|
|
||||||
for se in subs:
|
|
||||||
if not se.date_from:
|
|
||||||
# Skip entries without a start
|
|
||||||
continue
|
|
||||||
day_key = se.date_from.date()
|
|
||||||
room = get_room_name(se)
|
|
||||||
days[day_key][room].append(se)
|
|
||||||
|
|
||||||
# Emit <day> elements in chronological order
|
|
||||||
for day_index, (day_date, rooms) in enumerate(sorted(days.items()), start=1):
|
|
||||||
# Compute day start/end from all events this day
|
|
||||||
starts = [se.date_from for r in rooms.values() for se in r if se.date_from]
|
|
||||||
ends = [se.date_to for r in rooms.values() for se in r if se.date_to]
|
|
||||||
day_start = min(starts) if starts else None
|
|
||||||
# If end is missing for any, approximate using +0 duration => start
|
|
||||||
if ends:
|
|
||||||
day_end = max(ends)
|
|
||||||
else:
|
|
||||||
day_end = (day_start + timedelta(minutes=0)) if day_start else None
|
|
||||||
|
|
||||||
day_el = ET.SubElement(root, 'day')
|
|
||||||
if day_date:
|
|
||||||
day_el.set('date', day_date.isoformat())
|
|
||||||
if day_start:
|
|
||||||
day_el.set('start', day_start.isoformat())
|
|
||||||
if day_end:
|
|
||||||
day_el.set('end', day_end.isoformat())
|
|
||||||
day_el.set('index', str(day_index))
|
|
||||||
|
|
||||||
# Emit <room> containers
|
|
||||||
for room_name, events_in_room in sorted(rooms.items(), key=lambda x: x[0].lower()):
|
|
||||||
room_el = ET.SubElement(day_el, 'room')
|
|
||||||
room_el.set('name', room_name)
|
|
||||||
# Optional guid on room – stable UUID5 based on names
|
|
||||||
room_el.set('guid', str(uuid.uuid5(uuid.NAMESPACE_DNS, f"room:{organizer}:{event}:{room_name}")))
|
|
||||||
|
|
||||||
# Emit each <event> in chronological order within the room
|
|
||||||
for se in sorted(events_in_room, key=lambda s: s.date_from or 0):
|
|
||||||
ev_el = ET.SubElement(room_el, 'event')
|
|
||||||
ev_el.set('id', str(se.pk))
|
|
||||||
ev_el.set('guid', str(uuid.uuid5(uuid.NAMESPACE_DNS, f"subevent:{ev.pk}:{se.pk}")))
|
|
||||||
|
|
||||||
# Helper: localize strings
|
|
||||||
def _localize(val):
|
|
||||||
if hasattr(val, 'localize'):
|
|
||||||
try:
|
|
||||||
return val.localize(ev.settings.locale)
|
|
||||||
except Exception:
|
|
||||||
return str(val)
|
|
||||||
return str(val) if val is not None else ''
|
|
||||||
|
|
||||||
# Required children according to schema
|
|
||||||
ET.SubElement(ev_el, 'room').text = room_name
|
|
||||||
title = _localize(se.name)
|
|
||||||
ET.SubElement(ev_el, 'title').text = title
|
|
||||||
ET.SubElement(ev_el, 'subtitle').text = ''
|
|
||||||
ET.SubElement(ev_el, 'type').text = 'subevent'
|
|
||||||
|
|
||||||
# date (full datetime with TZ)
|
|
||||||
if se.date_from:
|
|
||||||
ET.SubElement(ev_el, 'date').text = se.date_from.isoformat()
|
|
||||||
|
|
||||||
# start (HH:MM or HH:MM:SS)
|
|
||||||
if se.date_from:
|
|
||||||
ET.SubElement(ev_el, 'start').text = se.date_from.strftime('%H:%M')
|
|
||||||
|
|
||||||
# duration from date_to - date_from
|
|
||||||
dur_txt = '00:00'
|
|
||||||
if se.date_from and se.date_to and se.date_to >= se.date_from:
|
|
||||||
delta: timedelta = se.date_to - se.date_from
|
|
||||||
total_seconds = int(delta.total_seconds())
|
|
||||||
hours = total_seconds // 3600
|
|
||||||
minutes = (total_seconds % 3600) // 60
|
|
||||||
seconds = total_seconds % 60
|
|
||||||
# prefer HH:MM if no seconds, else HH:MM:SS
|
|
||||||
if seconds == 0:
|
|
||||||
dur_txt = f"{hours:02d}:{minutes:02d}"
|
|
||||||
else:
|
|
||||||
dur_txt = f"{hours:02d}:{minutes:02d}:{seconds:02d}"
|
|
||||||
ET.SubElement(ev_el, 'duration').text = dur_txt
|
|
||||||
|
|
||||||
ET.SubElement(ev_el, 'abstract').text = ''
|
|
||||||
|
|
||||||
# slug (pattern: "[a-z0-9_]{4,}-[a-z0-9\-_]{4,}")
|
|
||||||
def slugify(text: str) -> str:
|
|
||||||
text = (text or '').lower()
|
|
||||||
text = re.sub(r'\s+', '-', text)
|
|
||||||
text = re.sub(r'[^a-z0-9\-_]', '', text)
|
|
||||||
text = text.strip('-_')
|
|
||||||
return text or 'item'
|
|
||||||
|
|
||||||
base = f"{organizer}_{event}".lower()
|
|
||||||
second = slugify(title)
|
|
||||||
if len(second) < 4:
|
|
||||||
second = f"{second}-{se.pk}"
|
|
||||||
ET.SubElement(ev_el, 'slug').text = f"{base}-{second}"
|
|
||||||
|
|
||||||
# track – use room name as a simple track assignment
|
|
||||||
ET.SubElement(ev_el, 'track').text = slugify(room_name) or 'general'
|
|
||||||
|
|
||||||
# Optional elements: language – per subevent via SubEventMetaValue
|
|
||||||
def _get_lang(subevent: SubEvent) -> str:
|
|
||||||
if SubEventMetaValue is not None:
|
|
||||||
try:
|
|
||||||
v = (
|
|
||||||
SubEventMetaValue.objects
|
|
||||||
.filter(subevent=subevent, key='congressschedule_language')
|
|
||||||
.values_list('value', flat=True)
|
|
||||||
.first()
|
|
||||||
)
|
|
||||||
return (v or 'deen').strip() or 'deen'
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
# Fallbacks for environments without pretix DB access
|
|
||||||
md = getattr(subevent, 'meta_data', None) or {}
|
|
||||||
if isinstance(md, dict) and 'congressschedule_language' in md:
|
|
||||||
return (md.get('congressschedule_language') or 'deen')
|
|
||||||
se_settings = getattr(subevent, 'settings', None)
|
|
||||||
try:
|
|
||||||
return se_settings.get('congressschedule_language', 'deen') if se_settings is not None else 'deen'
|
|
||||||
except Exception:
|
|
||||||
return 'deen'
|
|
||||||
|
|
||||||
lang = _get_lang(se)
|
|
||||||
ET.SubElement(ev_el, 'language').text = str(lang or 'deen')
|
|
||||||
|
|
||||||
# Leave optional complex children (persons, recording, links, attachments) empty for now
|
|
||||||
|
|
||||||
xml_bytes = ET.tostring(root, encoding='utf-8', xml_declaration=True)
|
|
||||||
return HttpResponse(xml_bytes, content_type='application/xml')
|
|
||||||
|
|
||||||
class CongressScheduleJSONView(views.APIView):
|
class CongressScheduleJSONView(views.APIView):
|
||||||
def get(self, request, organizer, event):
|
def get(self, request, organizer, event):
|
||||||
|
|
||||||
|
|
@ -313,7 +107,7 @@ class CongressScheduleJSONView(views.APIView):
|
||||||
text = text.strip('-_')
|
text = text.strip('-_')
|
||||||
return text or 'item'
|
return text or 'item'
|
||||||
|
|
||||||
def _get_lang(subevent: SubEvent) -> str:
|
def _get_language(subevent: SubEvent) -> str:
|
||||||
if SubEventMetaValue is not None:
|
if SubEventMetaValue is not None:
|
||||||
try:
|
try:
|
||||||
v = (
|
v = (
|
||||||
|
|
@ -333,6 +127,48 @@ class CongressScheduleJSONView(views.APIView):
|
||||||
return se_settings.get('congressschedule_language', 'deen') if se_settings is not None else 'deen'
|
return se_settings.get('congressschedule_language', 'deen') if se_settings is not None else 'deen'
|
||||||
except Exception:
|
except Exception:
|
||||||
return 'deen'
|
return 'deen'
|
||||||
|
|
||||||
|
def _get_websiteDE(subevent: SubEvent) -> str:
|
||||||
|
if SubEventMetaValue is not None:
|
||||||
|
try:
|
||||||
|
v = (
|
||||||
|
SubEventMetaValue.objects
|
||||||
|
.filter(subevent=subevent, key='congressschedule_website_de')
|
||||||
|
.values_list('value', flat=True)
|
||||||
|
.first()
|
||||||
|
)
|
||||||
|
return (v or '').strip()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
md = getattr(subevent, 'meta_data', None) or {}
|
||||||
|
if isinstance(md, dict) and 'congressschedule_website_de' in md:
|
||||||
|
return (md.get('congressschedule_website_de') or '').strip()
|
||||||
|
se_settings = getattr(subevent, 'settings', None)
|
||||||
|
try:
|
||||||
|
return se_settings.get('congressschedule_website_de', '') if se_settings is not None else ''
|
||||||
|
except Exception:
|
||||||
|
return ''
|
||||||
|
|
||||||
|
def _get_websiteEN(subevent: SubEvent) -> str:
|
||||||
|
if SubEventMetaValue is not None:
|
||||||
|
try:
|
||||||
|
v = (
|
||||||
|
SubEventMetaValue.objects
|
||||||
|
.filter(subevent=subevent, key='congressschedule_website_en')
|
||||||
|
.values_list('value', flat=True)
|
||||||
|
.first()
|
||||||
|
)
|
||||||
|
return (v or '').strip()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
md = getattr(subevent, 'meta_data', None) or {}
|
||||||
|
if isinstance(md, dict) and 'congressschedule_website_en' in md:
|
||||||
|
return (md.get('congressschedule_website_en') or '').strip()
|
||||||
|
se_settings = getattr(subevent, 'settings', None)
|
||||||
|
try:
|
||||||
|
return se_settings.get('congressschedule_website_en', '') if se_settings is not None else ''
|
||||||
|
except Exception:
|
||||||
|
return ''
|
||||||
|
|
||||||
for day_index, (day_date, rooms) in enumerate(sorted(days.items()), start=1):
|
for day_index, (day_date, rooms) in enumerate(sorted(days.items()), start=1):
|
||||||
starts = [se.date_from for r in rooms.values() for se in r if se.date_from]
|
starts = [se.date_from for r in rooms.values() for se in r if se.date_from]
|
||||||
|
|
@ -369,7 +205,9 @@ class CongressScheduleJSONView(views.APIView):
|
||||||
if len(second) < 4:
|
if len(second) < 4:
|
||||||
second = f"{second}-{se.pk}"
|
second = f"{second}-{se.pk}"
|
||||||
|
|
||||||
lang = _get_lang(se)
|
language = _get_language(se)
|
||||||
|
websiteDE = _get_websiteDE(se)
|
||||||
|
websiteEN = _get_websiteEN(se)
|
||||||
|
|
||||||
ev_obj = {
|
ev_obj = {
|
||||||
"id": se.pk,
|
"id": se.pk,
|
||||||
|
|
@ -384,13 +222,17 @@ class CongressScheduleJSONView(views.APIView):
|
||||||
"subtitle": "",
|
"subtitle": "",
|
||||||
"track": "Hackertours",
|
"track": "Hackertours",
|
||||||
"type": "Tour",
|
"type": "Tour",
|
||||||
"language": str(lang or "de, en"),
|
"language": str(language or "de, en"),
|
||||||
"abstract": se.frontpage_text.localize(ev.settings.locale) if hasattr(se.frontpage_text, 'localize') else str(se.frontpage_text) if se.frontpage_text else "",
|
"abstract": se.frontpage_text.localize(ev.settings.locale) if hasattr(se.frontpage_text, 'localize') else str(se.frontpage_text) if se.frontpage_text else "",
|
||||||
"persons": [],
|
"persons": [],
|
||||||
"links": [
|
"links": [
|
||||||
{
|
{
|
||||||
"url": "TODO",
|
"url": str(websiteDE),
|
||||||
"title": "TODO",
|
"title": title + " (DE)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": str(websiteEN),
|
||||||
|
"title": title + " (DE)",
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ except Exception: # pragma: no cover - during docs build or without pretix
|
||||||
SubEventMetaValue = None
|
SubEventMetaValue = None
|
||||||
|
|
||||||
|
|
||||||
class SubEventLanguageForm(forms.Form):
|
class SubEventHackertoursForm(forms.Form):
|
||||||
language = forms.ChoiceField(
|
language = forms.ChoiceField(
|
||||||
label=_("Language"),
|
label=_("Language"),
|
||||||
required=False,
|
required=False,
|
||||||
|
|
@ -18,6 +18,16 @@ class SubEventLanguageForm(forms.Form):
|
||||||
('en', _("English")),
|
('en', _("English")),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
website_en = forms.URLField(
|
||||||
|
label=_("Website (English)"),
|
||||||
|
required=False,
|
||||||
|
help_text=_("Link to the English tour details on https://hackertours.hamburg.ccc.de/en/"),
|
||||||
|
)
|
||||||
|
website_de = forms.URLField(
|
||||||
|
label=_("Website (German)"),
|
||||||
|
required=False,
|
||||||
|
help_text=_("Link to the German tour details on https://hackertours.hamburg.ccc.de/de/"),
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.event = kwargs.pop('event')
|
self.event = kwargs.pop('event')
|
||||||
|
|
@ -25,45 +35,83 @@ class SubEventLanguageForm(forms.Form):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
# Pre-fill from subevent meta if available
|
# Pre-fill from subevent meta if available
|
||||||
if self.subevent:
|
if self.subevent:
|
||||||
val = (
|
languageValue = (
|
||||||
SubEventMetaValue.objects
|
SubEventMetaValue.objects
|
||||||
.filter(subevent=self.subevent, property__name='congressschedule_language')
|
.filter(subevent=self.subevent, property__name='congressschedule_language')
|
||||||
.values_list('value', flat=True)
|
.values_list('value', flat=True)
|
||||||
.first()
|
.first()
|
||||||
)
|
)
|
||||||
self.fields['language'].initial = val or ''
|
self.fields['language'].initial = languageValue or ''
|
||||||
|
websiteENValue = (
|
||||||
|
SubEventMetaValue.objects
|
||||||
|
.filter(subevent=self.subevent, property__name='congressschedule_website_en')
|
||||||
|
.values_list('value', flat=True)
|
||||||
|
.first()
|
||||||
|
)
|
||||||
|
self.fields['website_en'].initial = websiteENValue or ''
|
||||||
|
websiteDEValue = (
|
||||||
|
SubEventMetaValue.objects
|
||||||
|
.filter(subevent=self.subevent, property__name='congressschedule_website_de')
|
||||||
|
.values_list('value', flat=True)
|
||||||
|
.first()
|
||||||
|
)
|
||||||
|
self.fields['website_de'].initial = websiteDEValue or ''
|
||||||
elif self.subevent and hasattr(self.subevent, 'settings'):
|
elif self.subevent and hasattr(self.subevent, 'settings'):
|
||||||
# Fallback (older pretix): might be event-wide, keep as last resort
|
# Fallback (older pretix): might be event-wide, keep as last resort
|
||||||
self.fields['language'].initial = "deen"
|
self.fields['language'].initial = "deen"
|
||||||
|
self.fields['website_en'].initial = ""
|
||||||
|
self.fields['website_de'].initial = ""
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def title(self):
|
def title(self):
|
||||||
return _("Language")
|
return _("Hackertours Settings")
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
if not self.subevent:
|
if not self.subevent:
|
||||||
return
|
return
|
||||||
val = (self.cleaned_data.get('language') or '').strip() or 'deen'
|
languageValue = (self.cleaned_data.get('language') or '').strip() or 'deen'
|
||||||
|
websiteENValue = (self.cleaned_data.get('website_en') or '').strip()
|
||||||
|
websiteDEValue = (self.cleaned_data.get('website_de') or '').strip()
|
||||||
# Persist as real subevent meta value so it's scoped per subevent
|
# Persist as real subevent meta value so it's scoped per subevent
|
||||||
from pretix.base.models import EventMetaProperty
|
from pretix.base.models import EventMetaProperty
|
||||||
|
|
||||||
property_obj, _ = EventMetaProperty.objects.get_or_create(
|
language_property_obj, _ = EventMetaProperty.objects.get_or_create(
|
||||||
name='congressschedule_language',
|
name='congressschedule_language',
|
||||||
defaults={'default': '', 'organizer': self.event.organizer}
|
defaults={'default': '', 'organizer': self.event.organizer}
|
||||||
)
|
)
|
||||||
SubEventMetaValue.objects.update_or_create(
|
SubEventMetaValue.objects.update_or_create(
|
||||||
subevent=self.subevent,
|
subevent=self.subevent,
|
||||||
property=property_obj,
|
property=language_property_obj,
|
||||||
defaults={'value': val},
|
defaults={'value': languageValue},
|
||||||
|
)
|
||||||
|
|
||||||
|
website_en_property_obj, _ = EventMetaProperty.objects.get_or_create(
|
||||||
|
name='congressschedule_website_en',
|
||||||
|
defaults={'default': '', 'organizer': self.event.organizer}
|
||||||
|
)
|
||||||
|
SubEventMetaValue.objects.update_or_create(
|
||||||
|
subevent=self.subevent,
|
||||||
|
property=website_en_property_obj,
|
||||||
|
defaults={'value': websiteENValue},
|
||||||
|
)
|
||||||
|
|
||||||
|
website_de_property_obj, _ = EventMetaProperty.objects.get_or_create(
|
||||||
|
name='congressschedule_website_de',
|
||||||
|
defaults={'default': '', 'organizer': self.event.organizer}
|
||||||
|
)
|
||||||
|
SubEventMetaValue.objects.update_or_create(
|
||||||
|
subevent=self.subevent,
|
||||||
|
property=website_de_property_obj,
|
||||||
|
defaults={'value': websiteDEValue},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def subevent_forms(sender, request, subevent, **kwargs):
|
def subevent_hackertours_forms(sender, request, subevent, **kwargs):
|
||||||
# Provide our additional subevent form
|
# Provide our additional subevent form
|
||||||
import logging
|
import logging
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
logger.debug("Providing congressschedule subevent form for event %s, subevent %s", sender.slug, getattr(subevent, 'name', 'no-subevent'))
|
logger.debug("Providing congressschedule subevent form for event %s, subevent %s", sender.slug, getattr(subevent, 'name', 'no-subevent'))
|
||||||
form = SubEventLanguageForm(
|
form = SubEventHackertoursForm(
|
||||||
data=request.POST if request.method == 'POST' else None,
|
data=request.POST if request.method == 'POST' else None,
|
||||||
event=sender,
|
event=sender,
|
||||||
subevent=subevent,
|
subevent=subevent,
|
||||||
|
|
@ -73,11 +121,10 @@ def subevent_forms(sender, request, subevent, **kwargs):
|
||||||
|
|
||||||
|
|
||||||
def connect_signals():
|
def connect_signals():
|
||||||
# Connect to pretix.control.signals.subevent_forms at import time
|
|
||||||
try:
|
try:
|
||||||
from pretix.control import signals as control_signals
|
from pretix.control import signals as control_signals
|
||||||
|
|
||||||
control_signals.subevent_forms.connect(subevent_forms, dispatch_uid='pretix_congressschedule_subevent_language')
|
control_signals.subevent_forms.connect(subevent_hackertours_forms, dispatch_uid='pretix_congressschedule_subevent_hackertours')
|
||||||
except Exception:
|
except Exception:
|
||||||
# Pretix not fully loaded in some contexts (e.g., docs build)
|
# Pretix not fully loaded in some contexts (e.g., docs build)
|
||||||
pass
|
pass
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,7 @@
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
from .api import CongressScheduleXMLView, CongressScheduleJSONView, HackertoursMarkdownView
|
from .api import CongressScheduleJSONView, HackertoursMarkdownView
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path(
|
|
||||||
'api/v1/event/<str:organizer>/<str:event>/schedule.xml',
|
|
||||||
CongressScheduleXMLView.as_view(),
|
|
||||||
name='schedule-xml',
|
|
||||||
),
|
|
||||||
path(
|
path(
|
||||||
'api/v1/event/<str:organizer>/<str:event>/schedule.json',
|
'api/v1/event/<str:organizer>/<str:event>/schedule.json',
|
||||||
CongressScheduleJSONView.as_view(),
|
CongressScheduleJSONView.as_view(),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue