def is_plugin_available_for_organizer(organizer): individually_activated = str( organizer.id) in GlobalSettingsObject().settings.get( 'enable_landingpage_individually') globally_activated = GlobalSettingsObject().settings.get( 'enable_landingpage_for_all_organizers') return individually_activated or globally_activated
def contextprocessor(request): """ Adds data to all template contexts """ if request.path.startswith('/control'): return {} ctx = { 'css_file': None, 'DEBUG': settings.DEBUG, } _html_head = [] _footer = [] if hasattr(request, 'event'): pretix_settings = request.event.settings elif hasattr(request, 'organizer'): pretix_settings = request.organizer.settings else: pretix_settings = GlobalSettingsObject().settings text = pretix_settings.get('footer_text', as_type=LazyI18nString) link = pretix_settings.get('footer_link', as_type=LazyI18nString) if text: if link: _footer.append({'url': str(link), 'label': str(text)}) else: ctx['footer_text'] = str(text) if hasattr(request, 'event'): for receiver, response in html_head.send(request.event, request=request): _html_head.append(response) for receiver, response in footer_link.send(request.event, request=request): if isinstance(response, list): _footer += response else: _footer.append(response) if request.event.settings.presale_css_file: ctx['css_file'] = default_storage.url( request.event.settings.presale_css_file) ctx['event_logo'] = request.event.settings.get('logo_image', as_type=str, default='')[7:] ctx['event'] = request.event ctx['html_head'] = "".join(_html_head) ctx['footer'] = _footer ctx['site_url'] = settings.SITE_URL return ctx
def test_default_page_is_shown_if_inactive(env, client): r = client.get("/FB9000/") assert r.status_code == 200 assert 'pretixpresale/organizers/index.html' == r.context_data[ 'view'].template_name gs = GlobalSettingsObject().settings gs.enable_landingpage_for_all_organizers = False gs.flush() env[3].active = True env[3].save() r = client.get("/FB9000/") assert r.status_code == 200 assert 'pretixpresale/organizers/index.html' == r.context_data[ 'view'].template_name
def _use_mapquest(self, q): gs = GlobalSettingsObject() try: r = requests.get( 'http://www.mapquestapi.com/geocoding/v1/address?location={}&key={}'.format( quote(q), gs.settings.mapquest_apikey ) ) r.raise_for_status() except IOError: logger.exception("Geocoding failed") return JsonResponse({ 'success': False, 'results': [] }, status=200) else: d = r.json() res = [ { 'formatted': q, 'lat': r['locations'][0]['latLng']['lat'], 'lon': r['locations'][0]['latLng']['lng'], } for r in d['results'] ] return res
def _use_opencage(self, q): gs = GlobalSettingsObject() try: r = requests.get( 'https://api.opencagedata.com/geocode/v1/json?q={}&key={}'.format( quote(q), gs.settings.opencagedata_apikey ) ) r.raise_for_status() except IOError: logger.exception("Geocoding failed") return JsonResponse({ 'success': False, 'results': [] }, status=200) else: d = r.json() res = [ { 'formatted': r['formatted'], 'lat': r['geometry']['lat'], 'lon': r['geometry']['lng'], } for r in d['results'] ] return res
def get(self, request, *args, **kwargs): q = self.request.GET.get('q') cd = cache.get('geocode:{}'.format(q)) if cd: return JsonResponse({ 'success': True, 'results': cd }, status=200) gs = GlobalSettingsObject() if gs.settings.opencagedata_apikey: res = self._use_opencage(q) if gs.settings.mapquest_apikey: res = self._use_mapquest(q) else: return JsonResponse({ 'success': False, 'results': [] }, status=200) cache.set('geocode:{}'.format(q), res, timeout=3600 * 6) return JsonResponse({ 'success': True, 'results': res }, status=200)
def __init__(self, *args, **kwargs): self.obj = GlobalSettingsObject() super().__init__(*args, obj=self.obj, **kwargs) self.fields = OrderedDict([ ('footer_text', I18nFormField( widget=I18nTextInput, required=False, label=_("Additional footer text"), help_text= _("Will be included as additional text in the footer, site-wide." ))), ('footer_link', I18nFormField( widget=I18nTextInput, required=False, label=_("Additional footer link"), help_text= _("Will be included as the link in the additional footer text." ))) ]) responses = register_global_settings.send(self) for r, response in responses: for key, value in response.items(): # We need to be this explicit, since OrderedDict.update does not retain ordering self.fields[key] = value
def test_organizer_not_allowed_to_use_plugin(env, client): gs = GlobalSettingsObject().settings gs.enable_landingpage_for_all_organizers = False gs.flush() __login_as_admin(env, client, False) r = client.get('/control/organizer/FB9000/landingpage/') assert r.status_code == 404 available = _("This page is unavailable for the selected organizer") assert bytes(available, 'utf-8') in r.content r2 = client.post('/control/organizer/FB9000/landingpage/', data={'active': 'on'}) assert r2.status_code == 404 available = _("This page is unavailable for the selected organizer") assert bytes(available, 'utf-8') in r2.content
def get(self, request, *args, **kwargs): gs = GlobalSettingsObject() if not gs.settings.opencagedata_apikey: return JsonResponse({'success': False, 'results': []}, status=200) q = request.GET.get('q') cd = cache.get('geocode:{}'.format(q)) if cd: return JsonResponse({'success': True, 'results': cd}, status=200) try: r = requests.get( 'https://api.opencagedata.com/geocode/v1/json?q={}&key={}'. format(quote(q), gs.settings.opencagedata_apikey)) r.raise_for_status() except IOError: logger.exception("Geocoding failed") return JsonResponse({'success': False, 'results': []}, status=200) else: d = r.json() res = [{ 'formatted': r['formatted'], 'lat': r['geometry']['lat'], 'lon': r['geometry']['lng'], } for r in d['results']] cache.set('geocode:{}'.format(q), res, timeout=3600 * 6) return JsonResponse({'success': True, 'results': res}, status=200)
def handle(self, *args, **options): for es in Organizer_SettingsStore.objects.filter( key="presale_css_file"): regenerate_organizer_css.apply_async(args=(es.object_id, )) for es in Event_SettingsStore.objects.filter( key="presale_css_file").order_by('-object__date_from'): regenerate_css.apply_async(args=(es.object_id, )) gs = GlobalSettingsObject() for lc, ll in settings.LANGUAGES: data = generate_widget_js(lc).encode() checksum = hashlib.sha1(data).hexdigest() fname = gs.settings.get('widget_file_{}'.format(lc)) if not fname or gs.settings.get('widget_checksum_{}'.format(lc), '') != checksum: newname = default_storage.save( 'pub/widget/widget.{}.{}.js'.format(lc, checksum), ContentFile(data)) gs.settings.set('widget_file_{}'.format(lc), 'file://' + newname) gs.settings.set('widget_checksum_{}'.format(lc), checksum) if fname: if isinstance(fname, File): default_storage.delete(fname.name) else: default_storage.delete(fname)
def get_powered_by(request, safelink=True): gs = GlobalSettingsObject() d = gs.settings.license_check_input if d.get('poweredby_name'): if d.get('poweredby_url'): n = '<a href="{}" target="_blank" rel="noopener">{}</a>'.format( sl(d['poweredby_url']) if safelink else d['poweredby_url'], d['poweredby_name']) else: n = d['poweredby_name'] msg = gettext( 'powered by {name} based on <a {a_attr}>pretix</a>').format( name=n, a_attr='href="{}" target="_blank" rel="noopener"'.format( sl('https://pretix.eu') if safelink else 'https://pretix.eu', )) else: msg = gettext('<a %(a_attr)s>ticketing powered by pretix</a>') % { 'a_attr': 'href="{}" target="_blank" rel="noopener"'.format( sl('https://pretix.eu') if safelink else 'https://pretix.eu', ) } if d.get('base_license') == 'agpl': msg += ' (<a href="{}" target="_blank" rel="noopener">{}</a>)'.format( request.build_absolute_uri(reverse('source')), gettext('source code')) return mark_safe(msg)
def test_reverse_charge_foreign_currency_data_too_old(env): event, order = env gs = GlobalSettingsObject() gs.settings.ecb_rates_date = date.today() - timedelta(days=14) tr = event.tax_rules.first() tr.eu_reverse_charge = True tr.home_country = Country('DE') tr.save() event.settings.set('invoice_language', 'en') InvoiceAddress.objects.create(company='Acme Company', street='221B Baker Street', zipcode='12345', city='Warsaw', country=Country('PL'), vat_id='PL123456780', vat_id_validated=True, order=order, is_business=True) ocm = OrderChangeManager(order, None) ocm.recalculate_taxes() ocm.commit() assert not order.positions.filter(tax_value__gt=0).exists() inv = generate_invoice(order) assert "reverse charge" in inv.additional_text.lower() assert inv.foreign_currency_rate is None assert inv.foreign_currency_rate_date is None
def refresh_mollie_tokens(sender, **kwargs): seen = set() gs = GlobalSettingsObject() for es in Event_SettingsStore.objects.filter(key='payment_mollie_expires'): if time.time() - float(es.object.settings.payment_mollie_expires) < 600: rt = es.object.settings.payment_mollie_refresh_token if rt not in seen: try: resp = requests.post('https://api.mollie.com/oauth2/tokens', auth=( gs.settings.payment_mollie_connect_client_id, gs.settings.payment_mollie_connect_client_secret ), data={ 'grant_type': 'refresh_token', 'refresh_token': es.object.settings.payment_mollie_refresh_token, 'redirect_uri': build_absolute_uri('plugins:pretix_mollie:oauth.return') }) except: logger.exception('Unable to refresh mollie token') if float(es.object.settings.payment_mollie_expires) > time.time() and not \ es.object.settings.payment_mollie_api_key: es.object.settings.payment_mollie__enabled = False es.object.log_action('pretix_mollie.event.disabled') else: if resp.status_code == 200: data = resp.json() for ev in Event_SettingsStore.objects.filter(key='payment_mollie_refresh_token', value=rt): ev.object.settings.payment_mollie_access_token = data['access_token'] ev.object.settings.payment_mollie_refresh_token = data['refresh_token'] ev.object.settings.payment_mollie_expires = time.time() + data['expires_in'] seen.add(rt)
def run_update_check(sender, **kwargs): gs = GlobalSettingsObject() if not gs.settings.update_check_perform: return if not gs.settings.update_check_last or now() - gs.settings.update_check_last > timedelta(hours=23): update_check.apply_async()
def widget_js(request, lang, **kwargs): if lang not in [lc for lc, ll in settings.LANGUAGES]: raise Http404() cached_js = cache.get('widget_js_data_{}'.format(lang)) if cached_js and not settings.DEBUG: return HttpResponse(cached_js, content_type='text/javascript') gs = GlobalSettingsObject() fname = gs.settings.get('widget_file_{}'.format(lang)) resp = None if fname and not settings.DEBUG: if isinstance(fname, File): fname = fname.name try: data = default_storage.open(fname).read() resp = HttpResponse(data, content_type='text/javascript') cache.set('widget_js_data_{}'.format(lang), data, 3600 * 4) except: logger.exception('Failed to open widget.js') if not resp: data = generate_widget_js(lang).encode() checksum = hashlib.sha1(data).hexdigest() if not settings.DEBUG: newname = default_storage.save( 'widget/widget.{}.{}.js'.format(lang, checksum), ContentFile(data)) gs.settings.set('widget_file_{}'.format(lang), 'file://' + newname) gs.settings.set('widget_checksum_{}'.format(lang), checksum) cache.set('widget_js_data_{}'.format(lang), data, 3600 * 4) resp = HttpResponse(data, content_type='text/javascript') return resp
def settings(self) -> SettingsProxy: """ Returns an object representing this organizer's settings """ from pretix.base.settings import GlobalSettingsObject return SettingsProxy(self, type=OrganizerSetting, parent=GlobalSettingsObject())
def contextprocessor(request): """ Adds data to all template contexts """ if request.path.startswith('/control'): return {} ctx = { 'css_file': None, 'DEBUG': settings.DEBUG, } _html_head = [] _footer = [] if hasattr(request, 'event'): pretix_settings = request.event.settings elif hasattr(request, 'organizer'): pretix_settings = request.organizer.settings else: pretix_settings = GlobalSettingsObject().settings text = pretix_settings.get('footer_text', as_type=LazyI18nString) link = pretix_settings.get('footer_link', as_type=LazyI18nString) if text: if link: _footer.append({'url': str(link), 'label': str(text)}) else: ctx['footer_text'] = str(text) if hasattr(request, 'event'): for receiver, response in html_head.send(request.event, request=request): _html_head.append(response) for receiver, response in footer_link.send(request.event, request=request): _footer.append(response) if request.event.settings.presale_css_file: ctx['css_file'] = default_storage.url(request.event.settings.presale_css_file) ctx['event_logo'] = request.event.settings.get('logo_image', as_type=str, default='')[7:] ctx['event'] = request.event ctx['html_head'] = "".join(_html_head) ctx['footer'] = _footer ctx['site_url'] = settings.SITE_URL return ctx
def get_source(request): gs = GlobalSettingsObject() d = gs.settings.license_check_input if d.get('base_license') == 'agpl': n = d.get('source_notice', '') return render(request, 'source.html', {'notice': n}) else: raise Http404(f'Not used under AGPL ({d.get("base_license")})')
def contextprocessor(request): """ Adds data to all template contexts """ try: url = resolve(request.path_info) except Resolver404: return {} if not request.path.startswith(get_script_prefix() + 'control'): return {} ctx = { 'url_name': url.url_name, 'settings': settings, 'DEBUG': settings.DEBUG, } _html_head = [] if hasattr(request, 'event'): for receiver, response in html_head.send(request.event, request=request): _html_head.append(response) ctx['html_head'] = "".join(_html_head) _js_payment_weekdays_disabled = '[]' _nav_event = [] if hasattr(request, 'event'): for receiver, response in nav_event.send(request.event, request=request): _nav_event += response if request.event.settings.get('payment_term_weekdays'): _js_payment_weekdays_disabled = '[0,6]' ctx['js_payment_weekdays_disabled'] = _js_payment_weekdays_disabled ctx['nav_event'] = _nav_event _nav_topbar = [] for receiver, response in nav_topbar.send(request, request=request): _nav_topbar += response ctx['nav_topbar'] = _nav_topbar ctx['js_datetime_format'] = get_javascript_format('DATETIME_INPUT_FORMATS') ctx['js_date_format'] = get_javascript_format('DATE_INPUT_FORMATS') ctx['js_locale'] = get_moment_locale() if settings.DEBUG and 'runserver' not in sys.argv: ctx['debug_warning'] = True elif 'runserver' in sys.argv: ctx['development_warning'] = True ctx['warning_update_available'] = False ctx['warning_update_check_active'] = False if request.user.is_superuser: gs = GlobalSettingsObject() if gs.settings.update_check_result_warning: ctx['warning_update_available'] = True if not gs.settings.update_check_ack and 'runserver' not in sys.argv: ctx['warning_update_check_active'] = True return ctx
def test_organizer_allowed_to_use_plugin(env, client): gs = GlobalSettingsObject().settings gs.enable_landingpage_for_all_organizers = True gs.flush() __login_as_admin(env, client, False) r = client.get('/control/organizer/FB9000/landingpage/') assert r.status_code == 200 gs.enable_landingpage_for_all_organizers = False gs.enable_landingpage_individually = ['1'] gs.flush() r = client.get('/control/organizer/FB9000/landingpage/') assert r.status_code == 200
def get_class_id(event: Event): gs = GlobalSettingsObject() if not gs.settings.get('update_check_id'): gs.settings.set('update_check_id', uuid.uuid4().hex) issuer_id = event.settings.get('googlepaypasses_issuer_id') return "%s.pretix-%s-%s-%s" % (issuer_id, gs.settings.get('update_check_id'), event.organizer.slug, event.slug)
def __init__(self, *args, **kwargs): self.obj = GlobalSettingsObject() super().__init__(*args, obj=self.obj, **kwargs) self.fields = OrderedDict(list(self.fields.items()) + [ ('footer_text', I18nFormField( widget=I18nTextInput, required=False, label=_("Additional footer text"), help_text=_("Will be included as additional text in the footer, site-wide.") )), ('footer_link', I18nFormField( widget=I18nTextInput, required=False, label=_("Additional footer link"), help_text=_("Will be included as the link in the additional footer text.") )), ('banner_message', I18nFormField( widget=I18nTextarea, required=False, label=_("Global message banner"), )), ('banner_message_detail', I18nFormField( widget=I18nTextarea, required=False, label=_("Global message banner detail text"), )), ('opencagedata_apikey', SecretKeySettingsField( required=False, label=_("OpenCage API key for geocoding"), )), ('mapquest_apikey', SecretKeySettingsField( required=False, label=_("MapQuest API key for geocoding"), )), ('leaflet_tiles', forms.CharField( required=False, label=_("Leaflet tiles URL pattern"), help_text=_("e.g. {sample}").format(sample="https://a.tile.openstreetmap.org/{z}/{x}/{y}.png") )), ('leaflet_tiles_attribution', forms.CharField( required=False, label=_("Leaflet tiles attribution"), help_text=_("e.g. {sample}").format(sample='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors') )), ]) responses = register_global_settings.send(self) for r, response in sorted(responses, key=lambda r: str(r[0])): for key, value in response.items(): # We need to be this explicit, since OrderedDict.update does not retain ordering self.fields[key] = value self.fields['banner_message'].widget.attrs['rows'] = '2' self.fields['banner_message_detail'].widget.attrs['rows'] = '3'
def test_update_check_disabled(): gs = GlobalSettingsObject() gs.settings.update_check_perform = False responses.add_callback( responses.POST, 'https://pretix.eu/.update_check/', callback=request_callback_disallowed, content_type='application/json', ) update_check.update_check.apply(throw=True)
def get_object_id(op: OrderPosition): gs = GlobalSettingsObject() if not gs.settings.get('update_check_id'): gs.settings.set('update_check_id', uuid.uuid4().hex) issuer_id = op.order.event.settings.get('googlepaypasses_issuer_id') return "%s.pretix-%s-%s-%s-%s-%s-%s" % ( issuer_id, gs.settings.get('update_check_id'), op.order.event.organizer.slug, op.order.event.slug, op.order.code, op.positionid, uuid.uuid4().hex)
def env(): o = Organizer.objects.create(name='Dummy', slug='dummy') event = Event.objects.create( organizer=o, name='Dummy', slug='dummy', date_from=now(), plugins='pretix.plugins.banktransfer' ) o = Order.objects.create( code='FOO', event=event, email='*****@*****.**', status=Order.STATUS_PENDING, datetime=now(), expires=now() + timedelta(days=10), total=0, locale='en' ) tr = event.tax_rules.create(rate=Decimal('19.00')) o.fees.create(fee_type=OrderFee.FEE_TYPE_PAYMENT, value=Decimal('0.25'), tax_rate=Decimal('19.00'), tax_value=Decimal('0.05'), tax_rule=tr) ticket = Item.objects.create(event=event, name='Early-bird ticket', category=None, default_price=23, tax_rule=tr, admission=True) t_shirt = Item.objects.create(event=event, name='T-Shirt', category=None, default_price=42, tax_rule=tr, admission=True) variation = ItemVariation.objects.create(value='M', item=t_shirt) OrderPosition.objects.create( order=o, item=ticket, variation=None, price=Decimal("23.00"), positionid=1, ) OrderPosition.objects.create( order=o, item=t_shirt, variation=variation, price=Decimal("42.00"), positionid=2, ) gs = GlobalSettingsObject() gs.settings.ecb_rates_date = date.today() gs.settings.ecb_rates_dict = json.dumps({ "USD": "1.1648", "RON": "4.5638", "CZK": "26.024", "BGN": "1.9558", "HRK": "7.4098", "EUR": "1.0000", "NOK": "9.3525", "HUF": "305.15", "DKK": "7.4361", "PLN": "4.2408", "GBP": "0.89350", "SEK": "9.5883" }, cls=DjangoJSONEncoder) return event, o
def test_update_check_sent_updates(): responses.add_callback( responses.POST, 'https://pretix.eu/.update_check/', callback=request_callback_updatable, content_type='application/json', ) update_check.update_check.apply(throw=True) gs = GlobalSettingsObject() assert gs.settings.update_check_result_warning storeddata = gs.settings.update_check_result assert storeddata['version']['updatable']
def test_update_check_disabled(): gs = GlobalSettingsObject() gs.settings.update_check_perform = False responses.add_callback( responses.POST, 'https://pretix.eu/.update_check/', callback=request_callback_disallowed, content_type='application/json', match_querystring= None, # https://github.com/getsentry/responses/issues/464 ) update_check.update_check.apply(throw=True)
def _use_mapquest(self, q): gs = GlobalSettingsObject() r = requests.get( 'https://www.mapquestapi.com/geocoding/v1/address?location={}&key={}' .format(quote(q), gs.settings.mapquest_apikey)) r.raise_for_status() d = r.json() res = [{ 'formatted': q, 'lat': r['locations'][0]['latLng']['lat'], 'lon': r['locations'][0]['latLng']['lng'], } for r in d['results']] return res
def fetch_ecb_rates(sender, **kwargs): if not settings.FETCH_ECB_RATES: return gs = GlobalSettingsObject() if gs.settings.ecb_rates_date == now().strftime("%Y-%m-%d"): return try: date, rates = vat_moss.exchange_rates.fetch() gs.settings.ecb_rates_date = date gs.settings.ecb_rates_dict = json.dumps(rates, cls=DjangoJSONEncoder) except urllib.error.URLError: logger.exception('Could not retrieve rates from ECB')
def test_update_check_sent_no_updates(): responses.add_callback( responses.POST, 'https://pretix.eu/.update_check/', callback=request_callback_not_updatable, content_type='application/json', match_querystring= None, # https://github.com/getsentry/responses/issues/464 ) update_check.update_check.apply(throw=True) gs = GlobalSettingsObject() assert not gs.settings.update_check_result_warning storeddata = gs.settings.update_check_result assert not storeddata['version']['updatable']
def handle(self, *args, **options): call_command('compilemessages', verbosity=1, interactive=False) call_command('compilejsi18n', verbosity=1, interactive=False) call_command('collectstatic', verbosity=1, interactive=False) call_command('compress', verbosity=1, interactive=False) try: gs = GlobalSettingsObject() del gs.settings.update_check_last del gs.settings.update_check_result del gs.settings.update_check_result_warning except: # Fails when this is executed without a valid database configuration. # We don't care. pass
def contextprocessor(request): """ Adds data to all template contexts """ if request.path.startswith('/control'): return {} ctx = { 'css_file': None, 'DEBUG': settings.DEBUG, } _html_head = [] _html_page_header = [] _html_foot = [] _footer = [] if hasattr(request, 'event'): pretix_settings = request.event.settings elif hasattr(request, 'organizer'): pretix_settings = request.organizer.settings else: pretix_settings = GlobalSettingsObject().settings text = pretix_settings.get('footer_text', as_type=LazyI18nString) link = pretix_settings.get('footer_link', as_type=LazyI18nString) if text: if link: _footer.append({'url': str(link), 'label': str(text)}) else: ctx['footer_text'] = str(text) if hasattr(request, 'event'): for receiver, response in html_head.send(request.event, request=request): _html_head.append(response) for receiver, response in html_page_header.send(request.event, request=request): _html_page_header.append(response) for receiver, response in html_footer.send(request.event, request=request): _html_foot.append(response) for receiver, response in footer_link.send(request.event, request=request): if isinstance(response, list): _footer += response else: _footer.append(response) if request.event.settings.presale_css_file: ctx['css_file'] = default_storage.url(request.event.settings.presale_css_file) ctx['event_logo'] = request.event.settings.get('logo_image', as_type=str, default='')[7:] ctx['event'] = request.event ctx['languages'] = [get_language_info(code) for code in request.event.settings.locales] if request.resolver_match: ctx['cart_namespace'] = request.resolver_match.kwargs.get('cart_namespace', '') elif hasattr(request, 'organizer'): ctx['languages'] = [get_language_info(code) for code in request.organizer.settings.locales] if hasattr(request, 'organizer'): if request.organizer.settings.presale_css_file and not hasattr(request, 'event'): ctx['css_file'] = default_storage.url(request.organizer.settings.presale_css_file) ctx['organizer_logo'] = request.organizer.settings.get('organizer_logo_image', as_type=str, default='')[7:] ctx['organizer_homepage_text'] = request.organizer.settings.get('organizer_homepage_text', as_type=LazyI18nString) ctx['organizer'] = request.organizer ctx['html_head'] = "".join(_html_head) ctx['html_foot'] = "".join(_html_foot) ctx['html_page_header'] = "".join(_html_page_header) ctx['footer'] = _footer ctx['site_url'] = settings.SITE_URL ctx['js_datetime_format'] = get_javascript_format_without_seconds('DATETIME_INPUT_FORMATS') ctx['js_date_format'] = get_javascript_format_without_seconds('DATE_INPUT_FORMATS') ctx['js_time_format'] = get_javascript_format_without_seconds('TIME_INPUT_FORMATS') ctx['js_locale'] = get_moment_locale() ctx['settings'] = pretix_settings ctx['django_settings'] = settings return ctx