import glob import os import re import sys THEME_REPO_URL = "https://git.falkenthal.me/falkenthal/pretix-falkenthal-theme" PLATFORM_IMPRINT_URL = "https://tickets.falkenthal.me/impressum" PLATFORM_PRIVACY_URL = "https://tickets.falkenthal.me/datenschutz" ASSET_VERSION = "1.8.4" control_files = [ '/pretix/src/pretix/control/templates/pretixcontrol/base.html', '/pretix/src/pretix/control/templates/pretixcontrol/auth/base.html', ] platform_footer_html = ( '
' '
' 'Technischer Plattformbetrieb: FALKENTHAL' '·' f'Plattform-Impressum' '·' f'Plattform-Datenschutz' '·' f'Theme & Quellcode (AGPLv3)' '
' '
' '' ) # 1. Control & Auth Templates patchen (Plattform-Backend: immer Falkenthal-Branding) for p in control_files: if not os.path.exists(p): print(f"ERROR: Expected template not found: {p}", file=sys.stderr) sys.exit(1) with open(p, 'r', encoding='utf-8') as f: c = f.read() # Standard-Pretix-Favicon im Backend durch Falkenthal-Favicon ersetzen c = re.sub(r']*rel=[\"\'](shortcut )?icon[\"\'][^>]*>', '', c, flags=re.I) # Eindeutige Body-Klasse für Auth/Login-Seiten setzen (verhindert CSS-Leaks im normalen Backend) if p.endswith('auth/base.html') and 'falkenthal-auth-body' not in c: if ']*)class=["\']([^"\']*)["\']', r'' not in c: print(f"ERROR: tag not found in {p}", file=sys.stderr) sys.exit(1) c = c.replace( '', f'' f'' f'' ) if 'falkenthal-platform-bar' not in c: if '' not in c: print(f"ERROR: tag not found in {p}", file=sys.stderr) sys.exit(1) c = c.replace('', platform_footer_html) with open(p, 'w', encoding='utf-8') as f: f.write(c) # 2. Presale Template patchen (Ticketshop: Veranstalter-Favicons respektieren, Fallback = Falkenthal) presale_file = '/pretix/src/pretix/presale/templates/pretixpresale/base.html' if not os.path.exists(presale_file): print(f"ERROR: Expected template not found: {presale_file}", file=sys.stderr) sys.exit(1) with open(presale_file, 'r', encoding='utf-8') as f: c = f.read() # Nur die statischen Standard-Pretix-Favicon-Fallbacks ersetzen, damit individuelle # Veranstalter-/Event-Favicons ({% if request.event.settings.favicon %}) erhalten bleiben! c = re.sub( r']*rel=[\"\'](shortcut )?icon[\"\'][^>]*static\s+[\"\']pretixbase/img/favicon[^\"\']*[\"\'][^>]*>', '', c, flags=re.I, ) # Falls in einem {% else %}-Zweig der Standard-Favicon-Block nun leer wäre oder direkt vor : if '/static/whitelabel/presale.css' not in c: if '' not in c: print(f"ERROR: tag not found in {presale_file}", file=sys.stderr) sys.exit(1) presale_head_inject = ( '{% if not request.event or not request.event.settings.favicon %}' f'' f'' '{% endif %}' f'' ) c = c.replace('', presale_head_inject) if 'falkenthal-platform-bar' not in c: if '' not in c: print(f"ERROR: tag not found in {presale_file}", file=sys.stderr) sys.exit(1) c = c.replace('', platform_footer_html) with open(presale_file, 'w', encoding='utf-8') as f: f.write(c) # 3. Globale Fehlerseiten (400, 403, 404, 500, 503) mit Plattform-Rechtstexten ausstatten error_templates_dir = '/pretix/src/pretix/base/templates' for err_name in ['400.html', '403.html', '403_csrf.html', '404.html', '500.html', '503.html']: err_path = os.path.join(error_templates_dir, err_name) if os.path.exists(err_path): with open(err_path, 'r', encoding='utf-8') as f: ec = f.read() if 'falkenthal-platform-bar' not in ec and '' in ec: error_footer = ( '
' 'Technischer Plattformbetrieb: FALKENTHAL' ' · ' f'Plattform-Impressum' ' · ' f'Plattform-Datenschutz' ' · ' f'Theme & Quellcode (AGPLv3)' '
' ) ec = ec.replace('', error_footer) with open(err_path, 'w', encoding='utf-8') as f: f.write(ec) # 4. Eingebettetes Pretix-Widget (widget.js / v1.*.js): # Einheitliche Plattform-Pflichtangaben auch direkt unter dem Inline-Widget auf externen Veranstalter-Websites! widget_platform_bar_js = r""" ;(function(){ if (typeof document === 'undefined' || window.__falkenthalWidgetPatched) return; window.__falkenthalWidgetPatched = true; var BAR_HTML = 'Technischer Plattformbetrieb: FALKENTHAL' + ' · Plattform-Impressum' + ' · Plattform-Datenschutz' + ' · Theme & Quellcode (AGPLv3)'; function injectWidgetBar() { var footers = document.querySelectorAll('.pretix-widget-attribution'); for (var i = 0; i < footers.length; i++) { var el = footers[i]; if (!el.getAttribute('data-falkenthal-bar')) { el.setAttribute('data-falkenthal-bar', '1'); var bar = document.createElement('div'); bar.className = 'pretix-widget-falkenthal-bar'; bar.style.cssText = 'margin-top:6px;padding-top:6px;border-top:1px solid rgba(128,128,128,0.2);font-size:11px;line-height:1.5;text-align:center;opacity:0.85;'; bar.innerHTML = BAR_HTML; el.appendChild(bar); } } } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', injectWidgetBar); } else { injectWidgetBar(); } if (typeof MutationObserver !== 'undefined') { var obs = new MutationObserver(function() { injectWidgetBar(); }); var startObs = function() { if (document.body) obs.observe(document.body, { childList: true, subtree: true }); }; if (document.body) startObs(); else document.addEventListener('DOMContentLoaded', startObs); } setInterval(injectWidgetBar, 1500); })(); """ widget_js_candidates = ( glob.glob('/pretix/src/pretix/presale/static/pretixpresale/js/widget/*.js') + glob.glob('/pretix/src/pretix/static.dist/**/widget/*.js', recursive=True) ) for wjs in widget_js_candidates: if os.path.isfile(wjs): with open(wjs, 'r', encoding='utf-8') as f: wc = f.read() if '__falkenthalWidgetPatched' not in wc: with open(wjs, 'a', encoding='utf-8') as f: f.write('\n' + widget_platform_bar_js) print(f"Pretix templates and widget assets patched and verified successfully (v{ASSET_VERSION}).")