Compare commits

..
Author SHA1 Message Date
Richard Schreiber 7d2695e4d3 Widget: add beta-flag to URL 2026-07-03 11:31:54 +02:00
Raphael Michel 120317a8f2 Fix linter issue 2026-07-03 11:00:48 +02:00
Raphael Michel 7d5b00a610 Fix linter issues 2026-07-03 10:54:44 +02:00
Raphael Michel 83612c7d65 Merge branch 'security/harden-staffsession' into 'master'
Harden StaffSession handling

See merge request pretix/pretix!42
2026-07-03 10:41:39 +02:00
Mira Weller 7a5f96369a Harden StaffSession handling 2026-07-03 10:41:39 +02:00
Raphael Michel 7fd6bf41f9 Merge branch 'csp-refactor' into 'master'
CSP refactor

See merge request pretix/pretix!35
2026-07-03 10:33:35 +02:00
Mira Weller 458c3d4b83 CSP refactor 2026-07-03 10:33:35 +02:00
Raphael Michel d10d061e45 Merge branch 'check-csp' into 'master'
Check CSP components before rendering, prevent format string traversal

See merge request pretix/pretix!33
2026-07-03 10:26:23 +02:00
Mira Weller d30bca50f7 Check CSP components before rendering, prevent format string traversal 2026-07-03 10:26:23 +02:00
Phin Wolkwitz 3903aca7c9 Add Thai translations to community languages (Z#23239401) (#6334) 2026-07-02 17:44:28 +02:00
Raphael Michel 493c920aba Install django-querytagger (#6332)
* Install django-querytagger

* Update pyproject.toml
2026-07-02 14:40:02 +02:00
Raphael Michel 09b7bc00b0 Organizer calendar: Respect event_calendar_future_only (Z#23238776) (#6326)
We initially didn't do this for two reasons:

- Performance implications of calling the settings store for every event
  that shows up in the calendar. As of d43e85da, we need that anyways.
- Performance implications of filtering in Python except SQL but... it
  can't really be worse than not filtering at all.
- We don't easily know if it's valid for all events so we can't stop
  rendering the unused calendar rows. That's an acceptable issue for
  now, still better than nothing. We can always optimize later.

So we might as well implement it.
2026-07-02 14:31:44 +02:00
dependabot[bot] 2e195c0274 Update sentry-sdk requirement from ==2.63.* to ==2.64.*
Updates the requirements on [sentry-sdk](https://github.com/getsentry/sentry-python) to permit the latest version.
- [Release notes](https://github.com/getsentry/sentry-python/releases)
- [Changelog](https://github.com/getsentry/sentry-python/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-python/compare/2.63.0...2.64.0)

---
updated-dependencies:
- dependency-name: sentry-sdk
  dependency-version: 2.64.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-02 13:53:33 +02:00
Raphael Michel 18cb9c1816 Drop line numbers from gettext .po files (#6330)
Knowing what file a string comes from is useful, but the line number is less
useful and changes a lot, causing very unreadable diffs of translation
files. I propose we drop them and only include the file names
2026-07-02 10:21:09 +02:00
Richard Schreiber c3e0120f9f Improve calendar explorability for VoiceOver on iOS 2026-07-02 08:13:09 +02:00
Raphael Michel 67f7fec134 Fix flake8 issue 2026-07-01 18:01:50 +02:00
Raphael Michel c2c97f31ca Bump version to 2026.7.0.dev0 2026-07-01 16:33:10 +02:00
25 changed files with 388 additions and 1710 deletions
-202
View File
@@ -1,202 +0,0 @@
Führe den vollständigen Upstream-Merge-Workflow für pretix_cgo durch. Gehe dabei strikt Schritt für Schritt vor und warte an den markierten Stellen auf Bestätigung.
---
## Schritt 1 Master aktualisieren
```bash
git checkout master
git pull
```
---
## Schritt 2 Upstream-Tags holen & neuesten Tag ermitteln
```bash
git fetch upstream --tags
```
Bestimme danach den neuesten upstream-Tag (Format `vYYYY.M.P`, **ohne** das `.0`-Suffix unserer eigenen Tags):
```bash
git tag --sort=-version:refname | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | head -1
```
Merke dir diesen Tag als `UPSTREAM_TAG` (z.B. `v2026.5.0`) und leite daraus den Branch-Namen ab: `upstream/2026.5.0` (ohne führendes `v`).
---
## Schritt 3 Branch erstellen
```bash
git checkout -b upstream/<VERSION> tags/<UPSTREAM_TAG>
# Beispiel: git checkout -b upstream/2026.5.0 tags/v2026.5.0
```
---
## Schritt 4 Master mergen (immer, nicht optional)
```bash
git merge master
```
Bei Merge-Konflikten: Konflikte anzeigen und gemeinsam mit dem Nutzer lösen, bevor es weitergeht.
---
## Schritt 5 Branch pushen & MR anlegen
Push mit Push Option, damit Gitea direkt einen MR anlegt:
```bash
git push --set-upstream origin upstream/<VERSION> -o merge_request.create
```
---
## Schritt 6 Gender-Prüfung in den deutschen Übersetzungen
**Erst nach dem Merge mit master** die folgenden vier Dateien auf gegenderte Sprache prüfen:
- `src/pretix/locale/de/LC_MESSAGES/django.po`
- `src/pretix/locale/de/LC_MESSAGES/djangojs.po`
- `src/pretix/locale/de_Informal/LC_MESSAGES/django.po`
- `src/pretix/locale/de_Informal/LC_MESSAGES/djangojs.po`
Suche in den `msgstr`-Zeilen (und den zugehörigen `msgid`-Zeilen für Kontext) nach folgenden Mustern:
| Muster | Beispiele |
|--------|-----------|
| Binneni mit `*` | `Teilnehmer*in`, `Käufer*innen` |
| Binneni mit `:` | `Teilnehmer:in`, `Käufer:innen` |
| Binneni mit `_` | `Teilnehmer_in`, `Käufer_innen` |
| Binneni mit `(in)` | `Teilnehmer(in)`, `Käufer(innen)` |
| Partizip-Plural auf `-enden` | `Teilnehmenden`, `Helfenden`, `Organisierenden`, `Bestellenden`, `Buchenden`, `Zahlenden` |
**Ausgabe der Befunde:** Zeige für jeden Treffer:
1. Datei + Zeilennummer
2. Den vollständigen `msgstr`-Block (mehrzeilig wenn nötig) als Kontext
3. Den konkreten Vorschlag für die Ersetzung (z.B. `Teilnehmer*in``Teilnehmer`, `Teilnehmenden``Teilnehmer`)
Warte dann auf Freigabe durch den Nutzer, bevor Änderungen vorgenommen werden.
Nach Freigabe: Korrekturen direkt in den Dateien vornehmen und committen:
```bash
git add src/pretix/locale/de/ src/pretix/locale/de_Informal/
git commit -m "Remove gendered language from de/de_Informal translations"
git push
```
---
## Schritt 7 Warten auf Merge-Bestätigung
**Hier pausieren.** Den Nutzer auffordern zu bestätigen, sobald der MR auf Gitea gemergt wurde.
---
## Schritt 8 Master aktualisieren und neuen Tag vergeben
Nach Bestätigung:
```bash
git checkout master
git pull
```
Den neuen Tag ableiten: `<UPSTREAM_TAG>.0` **ohne führendes `v`** (z.B. `v2026.5.0``2026.5.0.0`):
```bash
git tag <VERSION>.0
# Beispiel: git tag 2026.5.0.0
git push origin <VERSION>.0
```
Ausgabe: Bestätigung mit dem neuen Tag und kurzem Status.
---
## Schritt 9 Warten auf Build-Pipeline
Nutze den Gitea MCP Server, um den Pipeline-Lauf für den soeben gepushten Tag zu überwachen:
- **Repo:** `CGM_Public` / `pretix_cgo`
- **Methode:** `mcp__gitea__actions_run_read` mit `method: list_runs`
- Warte, bis ein Run mit dem passenden Ref (`refs/tags/<NEUER_TAG>`) den Status `success` erreicht.
- Prüfe alle ~30 Sekunden erneut und zeige dem Nutzer den aktuellen Status (running / success / failure).
- Bei `failure`: sofort stoppen und dem Nutzer melden.
Erst wenn der Build erfolgreich (`success`) abgeschlossen ist, weitermachen.
---
## Schritt 10 cgm72 GitOps-Update
Im GitOps-Repo unter `../OrtlerstrasseGitOps/` (liegt immer neben dem pretix_cgo-Repo):
1. In `pretix-cgm72/pretix-deployment.yaml` den Image-Tag aktualisieren:
- Suche: `cr.ortlerstrasse.de/cgo/pretix:<ALTER_TAG>`
- Ersetze mit: `cr.ortlerstrasse.de/cgo/pretix:<NEUER_TAG>` (= der in Schritt 8 gesetzte Git-Tag, z.B. `2026.5.0.0`)
2. Committen und pushen (im OrtlerstrasseGitOps-Verzeichnis):
```bash
git -C ../OrtlerstrasseGitOps add pretix-cgm72/pretix-deployment.yaml
git -C ../OrtlerstrasseGitOps commit -m "Update pretix-cgm72 to <NEUER_TAG>"
git -C ../OrtlerstrasseGitOps push
```
Der GitOps-Operator wendet das YAML automatisch via `kubectl apply` an und rollt den Container neu aus.
---
## Schritt 11 cgm72: Container-Neustart abwarten und Loginseite prüfen
Warte, bis der Container neu gestartet ist, und prüfe dann die Loginseite:
- **URL:** `https://anmeldung.christliche-gemeinde.de/`
- **Prüfung:** HTTP 200 und die Seite enthält typische Pretix-Inhalte (z.B. Stichwort „pretix" oder ein Login-Formular im Body)
Methode: Nutze `mcp__claude_ai_Simon_Fetch__fetch_page` (oder `curl -sI`), um die URL alle ~30 Sekunden abzurufen. Erwarte einen kurzen Ausfall während des Neustarts warte danach auf eine erfolgreiche Antwort.
Zeige dem Nutzer das Ergebnis (Status-Code + kurzen Seitenausschnitt als Bestätigung).
---
## Schritt 12 Manuelle Bestätigung für cgm72
**Hier pausieren.** Den Nutzer auffordern zu bestätigen, dass cgm72 korrekt funktioniert (`https://anmeldung.christliche-gemeinde.de/`), bevor mit sola fortgefahren wird.
---
## Schritt 13 sola GitOps-Update
Im GitOps-Repo unter `../OrtlerstrasseGitOps/` (liegt immer neben dem pretix_cgo-Repo):
1. In `pretix-sola/pretix-deployment.yaml` den Image-Tag aktualisieren:
- Suche: `cr.ortlerstrasse.de/cgo/pretix:<ALTER_TAG>`
- Ersetze mit: `cr.ortlerstrasse.de/cgo/pretix:<NEUER_TAG>`
2. Committen und pushen:
```bash
git -C ../OrtlerstrasseGitOps add pretix-sola/pretix-deployment.yaml
git -C ../OrtlerstrasseGitOps commit -m "Update pretix-sola to <NEUER_TAG>"
git -C ../OrtlerstrasseGitOps push
```
---
## Schritt 14 sola: Container-Neustart abwarten und Loginseite prüfen
Warte, bis der Container neu gestartet ist, und prüfe dann die Loginseite:
- **URL:** `https://anmeldung.sola-muenchen.de`
- **Prüfung:** HTTP 200 und die Seite enthält typische Pretix-Inhalte
Methode: wie in Schritt 11.
Ausgabe: Bestätigung mit kurzem Abschluss-Status des gesamten Workflows.
-31
View File
@@ -1,31 +0,0 @@
name: Build Deploy email notification tool
run-name: ${{ gitea.actor }} building new version of the email notification tool
on:
push: # Baut bei jedem Push (Branches + Tags)
workflow_dispatch:
jobs:
Apply-Kubernetes-Resources:
runs-on: podman
steps:
- name: Check out repository code
uses: actions/checkout@v3
- name: Login to Docker Registry
run: podman login -u ${{ secrets.REGISTRY_USERNAME }} -p ${{ secrets.REGISTRY_TOKEN }} cr.ortlerstrasse.de
- name: Set Docker Image Tag
run: |
if [[ "${{ gitea.ref }}" == refs/tags/* ]]; then
echo "TAG_NAME=${{ gitea.ref_name }}" >> $GITHUB_ENV
else
echo "TAG_NAME=latest" >> $GITHUB_ENV
fi
- name: Build Docker image
run: podman build -t cr.ortlerstrasse.de/cgo/pretix:${{ env.TAG_NAME }} .
- name: Push Docker image
run: |
podman push cr.ortlerstrasse.de/cgo/pretix:${{ env.TAG_NAME }}
echo "Image pushed successfully: cr.ortlerstrasse.de/cgo/pretix:${{ env.TAG_NAME }}"
+1 -2
View File
@@ -61,8 +61,7 @@ RUN pip3 install -U \
cd /pretix && \
PRETIX_DOCKER_BUILD=TRUE pip3 install \
-e ".[memcached]" \
gunicorn django-extensions ipython \
pretix-oidc && \
gunicorn django-extensions ipython && \
rm -rf ~/.cache/pip
RUN chmod +x /usr/local/bin/pretix && \
+2 -1
View File
@@ -53,6 +53,7 @@ dependencies = [
"django-oauth-toolkit==2.3.*",
"django-otp==1.7.*",
"django-phonenumber-field==8.4.*",
"django-querytagger==0.0.2",
"django-redis==6.0.*",
"django-scopes==2.0.*",
"django-statici18n==2.7.*",
@@ -93,7 +94,7 @@ dependencies = [
"redis==7.4.*",
"reportlab==4.5.*",
"requests==2.32.*",
"sentry-sdk==2.63.*",
"sentry-sdk==2.64.*",
"sepaxml==2.7.*",
"stripe==7.9.*",
"text-unidecode==1.*",
+2 -2
View File
@@ -6,8 +6,8 @@ localecompile:
./manage.py compilemessages
localegen:
./manage.py makemessages --keep-pot --ignore "pretix/static/npm_dir/*" $(LNGS)
./manage.py makemessages --keep-pot -e js,ts,vue -d djangojs --ignore "pretix/static/npm_dir/*" --ignore "pretix/helpers/*" --ignore "pretix/static/jsi18n/*" --ignore "pretix/static/jsi18n/*" --ignore "pretix/static.dist/*" --ignore "data/*" --ignore "pretix/static/rrule/*" --ignore "build/*" $(LNGS)
./manage.py makemessages --keep-pot --add-location file --ignore "pretix/static/npm_dir/*" $(LNGS)
./manage.py makemessages --keep-pot --add-location file -e js,ts,vue -d djangojs --ignore "pretix/static/npm_dir/*" --ignore "pretix/helpers/*" --ignore "pretix/static/jsi18n/*" --ignore "pretix/static/jsi18n/*" --ignore "pretix/static.dist/*" --ignore "data/*" --ignore "pretix/static/rrule/*" --ignore "build/*" $(LNGS)
staticfiles: npminstall npmbuild jsi18n
./manage.py collectstatic --noinput
+1 -1
View File
@@ -19,4 +19,4 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
__version__ = "2026.6.0"
__version__ = "2026.7.0.dev0"
+1
View File
@@ -118,6 +118,7 @@ ALL_LANGUAGES = [
('sv', _('Swedish')),
('es', _('Spanish')),
('es-419', _('Spanish (Latin America)')),
('th', _('Thai')),
('tr', _('Turkish')),
('uk', _('Ukrainian')),
]
-1
View File
@@ -28,6 +28,5 @@ from .items import * # noqa
from .json import * # noqa
from .mail import * # noqa
from .orderlist import * # noqa
from .relevant_orderlist import * # noqa
from .reusablemedia import * # noqa
from .waitinglist import * # noqa
+1 -1
View File
@@ -89,7 +89,7 @@ class OrderListExporter(MultiSheetListExporter):
description = gettext_lazy('Download a spreadsheet of all orders. The spreadsheet will include three sheets, one '
'with a line for every order, one with a line for every order position, and one with '
'a line for every additional fee charged in an order.')
featured = False
featured = True
repeatable_read = False
@cached_property
File diff suppressed because it is too large Load Diff
+76 -46
View File
@@ -19,6 +19,8 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
import logging
import re
from collections import OrderedDict
from urllib.parse import urlparse, urlsplit
from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
@@ -43,6 +45,8 @@ from pretix.multidomain.urlreverse import (
)
from pretix.presale.style import get_fonts
logger = logging.getLogger(__name__)
_supported = None
@@ -223,7 +227,26 @@ def _parse_csp(header):
return h
VALID_CSP_DIRECTIVES = [
"child-src", "connect-src", "default-src", "fenced-frame-src", "font-src", "form-action", "frame-src", "img-src",
"manifest-src", "media-src", "object-src", "prefetch-src", "report-uri", "script-src", "script-src-elem",
"script-src-attr", "style-src", "style-src-elem", "style-src-attr", "worker-src",
]
CSP_ILLEGAL_CHARS = re.compile(r'[\s,;]')
def _sanitize_csp(h):
for k, v in h.items():
if k not in VALID_CSP_DIRECTIVES:
raise ValueError("Invalid CSP directive " + k)
if any(CSP_ILLEGAL_CHARS.search(el) for el in v):
logger.warning("Stripping invalid component from CSP: %r", h)
h[k] = [el for el in v if not CSP_ILLEGAL_CHARS.search(el)]
def _render_csp(h):
_sanitize_csp(h)
return "; ".join(k + ' ' + ' '.join(v) for k, v in h.items() if v)
@@ -243,21 +266,7 @@ def _merge_csp(a, b):
class SecurityMiddleware(MiddlewareMixin):
CSP_EXEMPT = (
'/api/v1/docs/',
)
def process_response(self, request, resp):
def nested_dict_values(d):
for v in d.values():
if isinstance(v, dict):
yield from nested_dict_values(v)
else:
if isinstance(v, str):
yield v
url = resolve(request.path_info)
if settings.DEBUG and resp.status_code >= 400:
# Don't use CSP on debug error page as it breaks of Django's fancy error
# pages
@@ -268,18 +277,15 @@ class SecurityMiddleware(MiddlewareMixin):
# https://github.com/pretix/pretix/issues/765
resp['P3P'] = 'CP=\"ALL DSP COR CUR ADM TAI OUR IND COM NAV INT\"'
img_src = []
gs = global_settings_object(request)
if gs.settings.leaflet_tiles:
img_src.append(gs.settings.leaflet_tiles[:gs.settings.leaflet_tiles.index("/", 10)].replace("{s}", "*"))
if not getattr(resp, '_csp_ignore', False):
resp['Content-Security-Policy'] = _render_csp(self._build_csp(request, resp))
elif 'Content-Security-Policy' in resp:
del resp['Content-Security-Policy']
font_src = set()
if hasattr(request, 'event'):
for font in get_fonts(request.event, pdf_support_required=False).values():
for path in list(nested_dict_values(font)):
font_location = urlparse(path)
if font_location.scheme and font_location.netloc:
font_src.add('{}://{}'.format(font_location.scheme, font_location.netloc))
return resp
def _build_csp(self, request, resp):
url = resolve(request.path_info)
h = {
'default-src': ["{static}"],
@@ -288,8 +294,8 @@ class SecurityMiddleware(MiddlewareMixin):
'frame-src': ['{static}'],
'style-src': ["{static}", "{media}"],
'connect-src': ["{dynamic}", "{media}"],
'img-src': ["{static}", "{media}", "data:"] + img_src,
'font-src': ["{static}"] + list(font_src),
'img-src': ["{static}", "{media}", "data:"],
'font-src': ["{static}"],
'media-src': ["{static}", "data:"],
# form-action is not only used to match on form actions, but also on URLs
# form-actions redirect to. In the context of e.g. payment providers or
@@ -298,6 +304,13 @@ class SecurityMiddleware(MiddlewareMixin):
'form-action': ["{dynamic}", "https:"] + (['http:'] if settings.SITE_URL.startswith('http://') else []),
}
gs = global_settings_object(request)
if gs.settings.leaflet_tiles:
h['img-src'].append(gs.settings.leaflet_tiles[:gs.settings.leaflet_tiles.index("/", 10)].replace("{s}", "*"))
if hasattr(request, 'event'):
h['font-src'] += list(self._get_font_origins(request.event))
if settings.VITE_DEV_MODE:
h['script-src'] += ["http://localhost:5173", "ws://localhost:5173"]
h['style-src'] += ["'unsafe-inline'"]
@@ -309,6 +322,7 @@ class SecurityMiddleware(MiddlewareMixin):
if not settings.VITE_DEV_MODE:
# can't have 'unsafe-inline' and nonce at the same time
h['style-src'].append(nonce)
# Only include pay.google.com for wallet detection purposes on the Payment selection page
if (
url.url_name == "event.order.pay.change" or
@@ -317,27 +331,32 @@ class SecurityMiddleware(MiddlewareMixin):
h['script-src'].append('https://pay.google.com')
h['frame-src'].append('https://pay.google.com')
h['connect-src'].append('https://google.com/pay')
if settings.LOG_CSP:
h['report-uri'] = ["/csp_report/"]
if 'Content-Security-Policy' in resp:
_merge_csp(h, _parse_csp(resp['Content-Security-Policy']))
if settings.CSP_ADDITIONAL_HEADER:
_merge_csp(h, _parse_csp(settings.CSP_ADDITIONAL_HEADER))
staticdomain = "'self'"
dynamicdomain = "'self'"
mediadomain = "'self'"
placeholders = {
"{static}": ["'self'"],
"{dynamic}": ["'self'"],
"{media}": ["'self'"],
}
if settings.MEDIA_URL.startswith('http'):
mediadomain += " " + settings.MEDIA_URL[:settings.MEDIA_URL.find('/', 9)]
placeholders["{media}"].append(settings.MEDIA_URL[:settings.MEDIA_URL.find('/', 9)])
if settings.STATIC_URL.startswith('http'):
staticdomain += " " + settings.STATIC_URL[:settings.STATIC_URL.find('/', 9)]
placeholders["{static}"].append(settings.STATIC_URL[:settings.STATIC_URL.find('/', 9)])
if settings.SITE_URL.startswith('http'):
if settings.SITE_URL.find('/', 9) > 0:
staticdomain += " " + settings.SITE_URL[:settings.SITE_URL.find('/', 9)]
dynamicdomain += " " + settings.SITE_URL[:settings.SITE_URL.find('/', 9)]
placeholders["{static}"].append(settings.SITE_URL[:settings.SITE_URL.find('/', 9)])
placeholders["{dynamic}"].append(settings.SITE_URL[:settings.SITE_URL.find('/', 9)])
else:
staticdomain += " " + settings.SITE_URL
dynamicdomain += " " + settings.SITE_URL
placeholders["{static}"].append(settings.SITE_URL)
placeholders["{dynamic}"].append(settings.SITE_URL)
if hasattr(request, 'organizer') and request.organizer:
if hasattr(request, 'event') and request.event:
@@ -348,18 +367,29 @@ class SecurityMiddleware(MiddlewareMixin):
siteurlsplit = urlsplit(settings.SITE_URL)
if siteurlsplit.port and siteurlsplit.port not in (80, 443):
domain = '%s:%d' % (domain, siteurlsplit.port)
dynamicdomain += " " + domain
placeholders["{dynamic}"].append(domain)
if request.path not in self.CSP_EXEMPT and not getattr(resp, '_csp_ignore', False):
resp['Content-Security-Policy'] = _render_csp(h).format(static=staticdomain, dynamic=dynamicdomain,
media=mediadomain)
for k, v in h.items():
h[k] = sorted(set(' '.join(v).format(static=staticdomain, dynamic=dynamicdomain, media=mediadomain).split(' ')))
resp['Content-Security-Policy'] = _render_csp(h)
elif 'Content-Security-Policy' in resp:
del resp['Content-Security-Policy']
for k, v in h.items():
h[k] = sorted(set(result for part in v for result in placeholders.get(part, [part])))
return resp
return h
def _get_font_origins(self, event):
def nested_dict_values(d):
for v in d.values():
if isinstance(v, dict):
yield from nested_dict_values(v)
else:
if isinstance(v, str):
yield v
font_src = set()
for font in get_fonts(event, pdf_support_required=False).values():
for path in list(nested_dict_values(font)):
font_location = urlparse(path)
if font_location.scheme and font_location.netloc:
font_src.add('{}://{}'.format(font_location.scheme, font_location.netloc))
return font_src
class RejectInvalidInputMiddleware(MiddlewareMixin):
+6 -9
View File
@@ -647,25 +647,22 @@ class User(AbstractBaseUser, PermissionsMixin, LoggingMixin):
id__in=self.teams.filter(TeamQuerySet.organizer_permission_q(permission)).values_list('organizer', flat=True)
)
def has_active_staff_session(self, session_key=None):
def has_active_staff_session(self, session_key):
"""
Returns whether or not a user has an active staff session (formerly known as superuser session)
with the given session key.
"""
return self.get_active_staff_session(session_key) is not None
def get_active_staff_session(self, session_key=None):
if not self.is_staff:
def get_active_staff_session(self, session_key):
if not self.is_staff or not session_key:
return None
if not hasattr(self, '_staff_session_cache'):
self._staff_session_cache = {}
if session_key not in self._staff_session_cache:
qs = StaffSession.objects.filter(
user=self, date_end__isnull=True
)
if session_key:
qs = qs.filter(session_key=session_key)
sess = qs.first()
sess = StaffSession.objects.filter(
user=self, date_end__isnull=True, session_key=session_key
).first()
if sess:
if sess.date_start < now() - timedelta(seconds=settings.PRETIX_SESSION_TIMEOUT_ABSOLUTE):
sess.date_end = now()
-2
View File
@@ -1924,8 +1924,6 @@ DEFAULTS = {
'serializer_class': serializers.BooleanField,
'form_kwargs': dict(
label=_("Hide all past dates from calendar"),
help_text=_("This option currently only affects the calendar of this event series, not the organizer-wide "
"calendar.")
)
},
'allow_modifications': {
@@ -42,8 +42,6 @@ from bleach import DEFAULT_CALLBACKS, html5lib_shim
from bleach.linkifier import build_email_re
from django import template
from django.conf import settings
from django.core import signing
from django.urls import reverse
from django.utils.functional import SimpleLazyObject
from django.utils.html import escape
from django.utils.http import url_has_allowed_host_and_scheme
+10 -6
View File
@@ -36,6 +36,7 @@ from urllib.parse import quote, urljoin, urlparse
from django.conf import settings
from django.contrib.auth import REDIRECT_FIELD_NAME, logout
from django.contrib.auth.views import redirect_to_login
from django.http import Http404
from django.shortcuts import get_object_or_404, resolve_url
from django.template.response import TemplateResponse
@@ -214,12 +215,15 @@ class AuditLogMiddleware:
hijack_history = request.session.get('hijack_history', False)
hijacker = get_object_or_404(User, pk=hijack_history[0]["user"])
ss = hijacker.get_active_staff_session(request.session.get('hijacker_session'))
if ss:
ss.logs.create(
url=request.path,
method=request.method,
impersonating=request.user
)
if not ss:
# Staff session expired or not found
logout(request)
return redirect_to_login(request.get_full_path())
ss.logs.create(
url=request.path,
method=request.method,
impersonating=request.user
)
else:
ss = request.user.get_active_staff_session(request.session.session_key)
if ss:
+27 -11
View File
@@ -31,6 +31,7 @@ from django.contrib.auth import (
)
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.views import redirect_to_login
from django.core.exceptions import PermissionDenied
from django.db import transaction
from django.shortcuts import get_object_or_404, redirect
from django.urls import reverse
@@ -221,11 +222,13 @@ class UserImpersonateView(AdministratorPermissionRequiredMixin, RecentAuthentica
def post(self, request, *args, **kwargs):
self.object = get_object_or_404(User, pk=self.kwargs.get("id"))
staff_session = request.user.get_active_staff_session(request.session.session_key)
self.request.user.log_action('pretix.control.auth.user.impersonated',
user=request.user,
data={
'other': self.kwargs.get("id"),
'other_email': self.object.email
'other_email': self.object.email,
'staff_session': staff_session.pk,
})
oldkey = request.session.session_key
@@ -249,6 +252,12 @@ class UserImpersonateView(AdministratorPermissionRequiredMixin, RecentAuthentica
with signals.no_update_last_login(), keep_session_age(request.session):
login(request, hijacked, backend=backend)
request.session.save()
staff_session.logs.create(
method='(NOTE)',
url=f'Begin impersonating user #{hijacked.pk} (request session {oldkey[:8]} -> {request.session.session_key[:8]})',
)
request.session["hijack_history"] = hijack_history
signals.hijack_started.send(
@@ -265,13 +274,15 @@ class UserImpersonateView(AdministratorPermissionRequiredMixin, RecentAuthentica
class UserImpersonateStopView(LoginRequiredMixin, View):
def post(self, request, *args, **kwargs):
impersonated = request.user
hijs = request.session['hijacker_session']
staff_session_key = request.session['hijacker_session']
prev_session_key = request.session.session_key
hijack_history = request.session.get("hijack_history", [])
hijacked = request.user
prev_session = hijack_history.pop()
hijacker = get_object_or_404(get_user_model(), pk=prev_session["user"])
staff_session = hijacker.get_active_staff_session(staff_session_key)
if not staff_session:
raise PermissionDenied
expected_hash = salted_hmac(
key_salt=b"hijack-history-hash",
@@ -299,17 +310,22 @@ class UserImpersonateStopView(LoginRequiredMixin, View):
hijacked=hijacked,
)
ss = request.user.get_active_staff_session(hijs)
if ss:
request.session.save()
ss.session_key = request.session.session_key
ss.save()
request.session.save()
staff_session.session_key = request.session.session_key
staff_session.save()
staff_session.logs.create(
method='(NOTE)',
url=f'Stop impersonating user #{hijacked.pk} (request session {prev_session_key[:8]}, '
f'staff session {staff_session_key[:8]} -> {request.session.session_key[:8]})',
)
request.user.log_action('pretix.control.auth.user.impersonate_stopped',
user=request.user,
data={
'other': impersonated.pk,
'other_email': impersonated.email
'other': hijacked.pk,
'other_email': hijacked.email,
'staff_session': staff_session.pk,
})
return redirect(reverse('control:index'))
+77 -93
View File
@@ -898,7 +898,7 @@ msgstr "Details der Bestellposition"
#: pretix/base/datasync/sourcefields.py:129
msgid "Attendee details"
msgstr "Details Teilnehmer"
msgstr "Details Teilnehmer*in"
#: pretix/base/datasync/sourcefields.py:130 pretix/base/exporters/answers.py:66
#: pretix/base/models/items.py:1777 pretix/control/navigation.py:185
@@ -960,13 +960,13 @@ msgstr "Veranstaltungs- oder Termininformationen"
#: pretix/presale/templates/pretixpresale/organizers/customer_membership.html:50
#: pretix/presale/templates/pretixpresale/organizers/customer_memberships.html:36
msgid "Attendee name"
msgstr "Name Teilnehmer"
msgstr "Name Teilnehmer*in"
#: pretix/base/datasync/sourcefields.py:187
#: pretix/base/datasync/sourcefields.py:604
#: pretix/base/datasync/sourcefields.py:628
msgid "Attendee"
msgstr "Teilnehmer"
msgstr "Teilnehmer*in"
#: pretix/base/datasync/sourcefields.py:207
#: pretix/base/exporters/orderlist.py:648 pretix/base/forms/questions.py:713
@@ -977,11 +977,11 @@ msgstr "Teilnehmer"
#: pretix/presale/templates/pretixpresale/event/fragment_cart.html:172
#: pretix/presale/templates/pretixpresale/event/fragment_cart.html:175
msgid "Attendee email"
msgstr "E-Mail Teilnehmer"
msgstr "E-Mail Teilnehmer*in"
#: pretix/base/datasync/sourcefields.py:219
msgid "Attendee or order email"
msgstr "E-Mail Teilnehmer oder Bestellung"
msgstr "E-Mail Teilnehmer*in oder Bestellung"
#: pretix/base/datasync/sourcefields.py:232
#: pretix/base/exporters/orderlist.py:649 pretix/base/pdf.py:188
@@ -991,23 +991,23 @@ msgstr "E-Mail Teilnehmer oder Bestellung"
#: pretix/presale/templates/pretixpresale/event/fragment_cart.html:182
#: pretix/presale/templates/pretixpresale/event/fragment_cart.html:185
msgid "Attendee company"
msgstr "Teilnehmer-Firma"
msgstr "Teilnehmer*innen-Firma"
#: pretix/base/datasync/sourcefields.py:241
msgid "Attendee address street"
msgstr "Teilnehmer-Adresse: Straße"
msgstr "Teilnehmer*innen-Adresse: Straße"
#: pretix/base/datasync/sourcefields.py:250
msgid "Attendee address ZIP code"
msgstr "Teilnehmer-Adresse: PLZ"
msgstr "Teilnehmer*innen-Adresse: PLZ"
#: pretix/base/datasync/sourcefields.py:259
msgid "Attendee address city"
msgstr "Teilnehmer-Adresse: Stadt"
msgstr "Teilnehmer*innen-Adresse: Stadt"
#: pretix/base/datasync/sourcefields.py:268
msgid "Attendee address country"
msgstr "Teilnehmer-Adresse: Land"
msgstr "Teilnehmer*innen-Adresse: Land"
#: pretix/base/datasync/sourcefields.py:279
#: pretix/base/exporters/orderlist.py:691 pretix/base/pdf.py:346
@@ -1286,7 +1286,7 @@ msgid ""
"Download a ZIP file including all files that have been uploaded by your "
"customers while creating an order."
msgstr ""
"ZIP-Datei mit allen Dateien, die von Kunden im Bestellprozess als "
"ZIP-Datei mit allen Dateien, die von Kund*innen im Bestellprozess als "
"Antwort auf eine Frage hochgeladen wurden."
#: pretix/base/exporters/answers.py:76 pretix/base/exporters/orderlist.py:629
@@ -2256,10 +2256,6 @@ msgstr "Ohne gültige Mitgliedschaft verstecken"
msgid "Order data"
msgstr "Bestelldaten"
#: pretix/base/exporters/relevant_orderlist.py:86
msgid "Order data (sorted by relevance)"
msgstr "Bestelldaten (nach Relevanz sortiert)"
#: pretix/base/exporters/json.py:53
msgid ""
"Download a structured JSON representation of all orders. This might be "
@@ -2277,8 +2273,8 @@ msgid ""
"Download a text file with all email addresses collected either from buyers "
"or from ticket holders."
msgstr ""
"Textdatei mit allen E-Mail-Adressen, die von Käufern und "
"Ticketinhaber eingesammelt wurden."
"Textdatei mit allen E-Mail-Adressen, die von Käufer*innen und "
"Ticketinhaber*innen eingesammelt wurden."
#: pretix/base/exporters/mail.py:76 pretix/plugins/reports/exporters.py:502
#: pretix/plugins/reports/exporters.py:685
@@ -2296,18 +2292,6 @@ msgstr ""
"Bestellposition und das dritte eine Zeile für jede zusätzlich erhobene "
"Gebühr."
#: pretix/base/exporters/relevant_orderlist.py:88
msgid ""
"Download a spreadsheet of all orders. The spreadsheet will include three "
"sheets, one with a line for every order, one with a line for every order "
"position, and one with a line for every additional fee charged in an "
"order. The most relevant data is in the first columns of the tables."
msgstr ""
"Tabelle (Excel oder CSV) mit allen Bestellungen. Das erste Tabellenblatt "
"enthält eine Zeile für jede Bestellung, das zweite eine Zeile für jede "
"Bestellposition und das dritte eine Zeile für jede zusätzlich erhobene "
"Gebühr. Die relevantesten Daten sind in den ersten Spalten der Tabellen."
#: pretix/base/exporters/orderlist.py:102 pretix/base/models/orders.py:336
#: pretix/base/permissions.py:228 pretix/control/navigation.py:267
#: pretix/control/navigation.py:387
@@ -4279,7 +4263,7 @@ msgstr "Bitte wählen Sie einen gültigen Staat aus."
#: pretix/base/modelimport_orders.py:359 pretix/control/forms/filter.py:688
msgid "Attendee email address"
msgstr "Teilnehmer-E-Mail-Adresse"
msgstr "Teilnehmer*innen-E-Mail-Adresse"
#: pretix/base/modelimport_orders.py:375 pretix/base/modelimport_orders.py:386
#: pretix/base/modelimport_orders.py:397 pretix/base/modelimport_orders.py:408
@@ -4291,7 +4275,7 @@ msgstr "Teilnehmer-E-Mail-Adresse"
#: pretix/presale/templates/pretixpresale/event/fragment_cart.html:193
#: pretix/presale/templates/pretixpresale/event/fragment_cart.html:196
msgid "Attendee address"
msgstr "Teilnehmer-Adresse"
msgstr "Teilnehmer*innen-Adresse"
#: pretix/base/modelimport_orders.py:468
msgid "Calculate from product"
@@ -5830,8 +5814,8 @@ msgid ""
"needs to be checked."
msgstr ""
"Wenn diese Option gesetzt ist, wird die Check-in-Anwendung melden, dass "
"dieses Ticket besondere Behandlung braucht. Das ist z.B. für Studenten "
"nützlich, deren Studentenausweis noch geprüft werden soll."
"dieses Ticket besondere Behandlung braucht. Das ist z.B. für Studierende "
"nützlich, deren Studierendenausweis noch geprüft werden soll."
#: pretix/base/models/items.py:670 pretix/base/models/items.py:1261
msgid ""
@@ -6734,8 +6718,8 @@ msgid ""
"cases."
msgstr ""
"Wenn diese Option gesetzt ist, wird die Check-in-Anwendung melden, dass "
"dieses Ticket besondere Behandlung braucht. Das ist z.B. für Studenten "
"nützlich, deren Studentenausweis noch geprüft werden soll."
"dieses Ticket besondere Behandlung braucht. Das ist z.B. für Studierende "
"nützlich, deren Studierendenausweis noch geprüft werden soll."
#: pretix/base/models/orders.py:290
msgid ""
@@ -8225,7 +8209,7 @@ msgstr "Musterfirma GmbH"
#: pretix/base/pdf.py:193
msgid "Full attendee address"
msgstr "Volle Teilnehmer-Adresse"
msgstr "Volle Teilnehmer*innen-Adresse"
#: pretix/base/pdf.py:194
msgid ""
@@ -8243,23 +8227,23 @@ msgstr ""
#: pretix/base/pdf.py:198
msgid "Attendee street"
msgstr "Teilnehmer-Straße"
msgstr "Teilnehmer*innen-Straße"
#: pretix/base/pdf.py:203
msgid "Attendee ZIP code"
msgstr "Teilnehmer-PLZ"
msgstr "Teilnehmer*innen-PLZ"
#: pretix/base/pdf.py:208
msgid "Attendee city"
msgstr "Teilnehmer-Stadt"
msgstr "Teilnehmer*innen-Stadt"
#: pretix/base/pdf.py:213
msgid "Attendee state"
msgstr "Teilnehmer-Bundesstaat"
msgstr "Teilnehmer*innen-Bundesstaat"
#: pretix/base/pdf.py:218
msgid "Attendee country"
msgstr "Teilnehmer-Land"
msgstr "Teilnehmer*innen-Land"
#: pretix/base/pdf.py:230
msgid "Pseudonymization ID (lead scanning)"
@@ -8565,7 +8549,7 @@ msgstr "Herr Mustermann"
#: pretix/plugins/ticketoutputpdf/exporters.py:99
#, python-brace-format
msgid "Attendee name: {part}"
msgstr "Teilnehmername: {part}"
msgstr "Teilnehmer*innenname: {part}"
#: pretix/base/pdf.py:700
msgid "Invoice address name for salutation"
@@ -9491,7 +9475,7 @@ msgstr "Veranstaltungsort: {location}"
#, python-brace-format
msgctxt "invoice"
msgid "Attendee: {name}"
msgstr "Teilnehmer: {name}"
msgstr "Teilnehmer*in: {name}"
#: pretix/base/services/invoices.py:293 pretix/plugins/reports/exporters.py:308
#, python-brace-format
@@ -10421,7 +10405,7 @@ msgstr ""
#: pretix/base/settings.py:375
msgid "Hide prices on attendee ticket page"
msgstr "Preise auf Teilnehmer-Ticket-Seite verstecken"
msgstr "Preise auf Teilnehmer*innen-Ticket-Seite verstecken"
#: pretix/base/settings.py:376
msgid ""
@@ -10431,13 +10415,13 @@ msgid ""
"price."
msgstr ""
"Wenn eine Person mehrere Tickets erwirbt und E-Mails an alle "
"Teilnehmer verschickt werden, wird mit dieser Option der Ticketpreis "
"auf der Ticket-Seite der einzelnen Teilnehmer versteckt. Nur die "
"Teilnehmer*innen verschickt werden, wird mit dieser Option der Ticketpreis "
"auf der Ticket-Seite der einzelnen Teilnehmer*innen versteckt. Nur die "
"Person, welche die Tickets kauft, sieht den Preis."
#: pretix/base/settings.py:394
msgid "Ask for attendee names"
msgstr "Namen der Teilnehmer erfragen"
msgstr "Namen der Teilnehmer*innen erfragen"
#: pretix/base/settings.py:395
msgid "Ask for a name for all personalized tickets."
@@ -10446,11 +10430,11 @@ msgstr ""
#: pretix/base/settings.py:404
msgid "Require attendee names"
msgstr "Namen der Teilnehmer erfordern"
msgstr "Namen der Teilnehmer*innen erfordern"
#: pretix/base/settings.py:405
msgid "Require customers to fill in the names of all attendees."
msgstr "Erfordere die Eingabe aller Teilnehmer-Namen."
msgstr "Erfordere die Eingabe aller Teilnehmer*innen-Namen."
#: pretix/base/settings.py:415
msgid "Ask for email addresses per ticket"
@@ -10981,8 +10965,8 @@ msgid ""
"but no indication of missing payment will be visible on the ticket pages of "
"attendees who did not buy the ticket themselves."
msgstr ""
"Die Box mit Zahlungsinstruktionen wird Ticketkäufern weiter angezeigt, "
"aber Teilnehmern, die ihr Ticket nicht selbst gekauft haben, werden "
"Die Box mit Zahlungsinstruktionen wird Ticketkäufer*innen weiter angezeigt, "
"aber Teilnehmer*innen, die ihr Ticket nicht selbst gekauft haben, werden "
"keine Anzeichen des fehlenden Zahlungseingangs sehen."
#: pretix/base/settings.py:1120
@@ -11480,7 +11464,7 @@ msgstr ""
#: pretix/base/settings.py:1763
msgid "Show number of check-ins to customer"
msgstr "Zeige Anzahl der Check-ins für Kunden an"
msgstr "Zeige Anzahl der Check-ins für Kund*innen an"
#: pretix/base/settings.py:1764
msgid ""
@@ -11491,12 +11475,12 @@ msgid ""
"failed scans will not be counted, and the user will not see the different "
"check-in lists."
msgstr ""
"Wenn diese Option aktiv ist, können Kunden selbst sehen, wie oft sie die "
"Wenn diese Option aktiv ist, können Kund*innen selbst sehen, wie oft sie die "
"Veranstaltung betreten haben. Das ist normalerweise nicht nötig, aber kann "
"nützlich sein, wenn es Tickets gibt, die eine bestimmte Anzahl an Eintritten "
"erlauben, sodass Kunden die bisherige Nutzung des Tickets einsehen "
"erlauben, sodass Kund*innen die bisherige Nutzung des Tickets einsehen "
"können. Ausgänge oder fehlgeschlagene Scans werden nicht angezeigt und die "
"Kunden sehen keine Aufschlüsselung verschiedener Check-in-Listen."
"Kund*innen sehen keine Aufschlüsselung verschiedener Check-in-Listen."
#: pretix/base/settings.py:1777
msgid "Allow users to download tickets"
@@ -11677,7 +11661,7 @@ msgstr ""
#: pretix/base/settings.py:1940 pretix/base/settings.py:1949
msgid "Both the attendee and the person who ordered can make changes"
msgstr ""
"Sowohl Besteller als auch Teilnehmer können Änderungen vornehmen"
"Sowohl Besteller*in als auch Teilnehmer*innen können Änderungen vornehmen"
#: pretix/base/settings.py:1944
msgid "Allow customers to modify their information"
@@ -11785,7 +11769,7 @@ msgstr ""
#: pretix/base/settings.py:2050
msgid "Allow individual attendees to change their ticket"
msgstr "Erlaubt einzelnen Teilnehmern ihr Ticket zu ändern"
msgstr "Erlaubt einzelnen Teilnehmer*innen ihr Ticket zu ändern"
#: pretix/base/settings.py:2051
msgid ""
@@ -11797,7 +11781,7 @@ msgid ""
msgstr ""
"Standardmäßig kann nur die Person, welche die Tickets gekauft hat, "
"Änderungen an der Bestellung vornehmen. Wenn diese Option aktiv ist, können "
"auch einzelne Teilnehmer Änderungen vornehmen. Teilnehmer können "
"auch einzelne Teilnehmer*innen Änderungen vornehmen. Teilnehmer*innen können "
"jedoch immer nur Änderungen vornehmen, welche die Gesamtkosten der "
"Bestellung nicht verändern. Solche Änderungen können nur vom Ticketkäufer "
"vorgenommen werden."
@@ -12094,7 +12078,7 @@ msgid ""
"people."
msgstr ""
"Sie können dieses Feld benutzen, um zusätzliche Informationen mit Ihren "
"Teilnehmer zu teilen, wie z.B. Anreise-Informationen oder den Link zu "
"Teilnehmer*innen zu teilen, wie z.B. Anreise-Informationen oder den Link zu "
"einer digitalen Veranstaltung. Wenn das Feld leer ist, fügen wir automatisch "
"einen Link zum Ticketshop, die Einlass-Uhrzeit und den Veranstalter hier "
"ein. Es sind keine Platzhalter mit sensiblen personenbezogenen Daten "
@@ -12335,8 +12319,8 @@ msgstr ""
"Diese Datei wird an die erste E-Mail angehängt, die wir beim Eingang einer "
"neuen Bestellung verschicken. Sie kann daher mit den Textvorlagen "
"\"Getätigte Bestellung\", \"Kostenlose Bestellung\" oder \"Erhaltene "
"Bestellung\" von oben auftreten. Sie wird ggf. sowohl an Besteller als "
"auch Teilnehmer verschickt. Nicht geeignet zum Versand nicht-"
"Bestellung\" von oben auftreten. Sie wird ggf. sowohl an Besteller*innen als "
"auch Teilnehmer*innen verschickt. Nicht geeignet zum Versand nicht-"
"öffentlicher Informationen, da die Datei unabhängig davon verschickt wird, "
"ob die Bestellung bezahlt oder freigegeben ist. Um zu vermeiden, dass diese "
"wichtige E-Mail nicht ankommt, können nur PDF-Dateien mit maximal {size} MB "
@@ -15672,7 +15656,7 @@ msgstr "Check-in-Status"
#: pretix/control/forms/filter.py:2174
#: pretix/plugins/checkinlists/exporters.py:109
msgid "All attendees"
msgstr "Alle Teilnehmer"
msgstr "Alle Teilnehmer*innen"
#: pretix/control/forms/filter.py:2175
#: pretix/control/templates/pretixcontrol/checkin/index.html:183
@@ -16257,7 +16241,7 @@ msgid ""
"people over 65. This ticket includes access to all parts of the event, "
"except the VIP area."
msgstr ""
"z.B. Dieses reduzierte Ticket ist erhältlich für Vollzeitstudent, "
"z.B. Dieses reduzierte Ticket ist erhältlich für Vollzeitstudent*innen, "
"Arbeitslose und Menschen über 65. Das Ticket enthält Zugang zu allen Teilen "
"der Veranstaltung außer des VIP-Bereiches."
@@ -16571,7 +16555,7 @@ msgstr ""
#: pretix/control/forms/orders.py:167 pretix/control/forms/orders.py:226
#: pretix/control/forms/orders.py:240
msgid "Notify customer by email"
msgstr "Kunde per E-Mail benachrichtigen"
msgstr "Kund*in per E-Mail benachrichtigen"
#: pretix/control/forms/orders.py:174
msgid "Keep a cancellation fee of"
@@ -18130,7 +18114,7 @@ msgstr "Eine individuelle E-Mail wurde verschickt."
#: pretix/control/logdisplay.py:554
msgid "A custom email has been sent to an attendee."
msgstr "Eine individuelle E-Mail wurde an einen Teilnehmer verschickt."
msgstr "Eine individuelle E-Mail wurde an eine Teilnehmer*in verschickt."
#: pretix/control/logdisplay.py:555
msgid ""
@@ -19866,7 +19850,7 @@ msgstr "Terminal-ID"
#: pretix/control/templates/pretixcontrol/boxoffice/payment.html:104
msgid "Card holder"
msgstr "Karteninhaber"
msgstr "Karteninhaber*in"
#: pretix/control/templates/pretixcontrol/boxoffice/payment.html:108
msgid "Card expiration"
@@ -20177,7 +20161,7 @@ msgstr "CSV"
#: pretix/control/templates/pretixcontrol/checkin/index.html:73
msgid "No attendee record was found."
msgstr "Keine passenden Teilnehmer gefunden."
msgstr "Keine passenden Teilnehmer*innen gefunden."
#: pretix/control/templates/pretixcontrol/checkin/index.html:91
#: pretix/control/templates/pretixcontrol/datasync/failed_jobs.html:19
@@ -22988,7 +22972,7 @@ msgid ""
"Only purchases of such products will be considered \"attendees\" for most "
"statistical purposes or within some plugins."
msgstr ""
"Nur Käufe eines solchen Produkts werden als \"Teilnehmer\" gewertet, "
"Nur Käufe eines solchen Produkts werden als \"Teilnehmer*innen\" gewertet, "
"z.B. in Statistiken oder in Funktionen von Erweiterungen."
#: pretix/control/templates/pretixcontrol/item/create.html:39
@@ -23067,7 +23051,7 @@ msgid ""
"The system will not ask for a name or other attendee details. This only "
"affects system-provided fields, you can still add your own questions."
msgstr ""
"Das System wird nicht nach einem Namen oder anderen Teilnehmer-Daten "
"Das System wird nicht nach einem Namen oder anderen Teilnehmer*innen-Daten "
"fragen. Dies betrifft nur vom System bereitgestellte Felder, eigene Fragen "
"können trotzdem hinzugefügt werden."
@@ -25405,7 +25389,7 @@ msgstr "Sonstige Datenexporte"
#: pretix/control/templates/pretixcontrol/orders/export.html:107
#: pretix/control/templates/pretixcontrol/organizers/export.html:107
msgid "Recommended for new users"
msgstr "Empfohlen für neue Benutzer"
msgstr "Empfohlen für neue Benutzer*innen"
#: pretix/control/templates/pretixcontrol/orders/export.html:120
#: pretix/control/templates/pretixcontrol/organizers/export.html:120
@@ -26365,7 +26349,7 @@ msgstr "Domains"
#: pretix/control/templates/pretixcontrol/organizers/edit.html:321
msgid "This dialog is intended for advanced users."
msgstr "Dieser Dialog ist für fortgeschrittene Anwender gedacht."
msgstr "Dieser Dialog ist für fortgeschrittene Anwender*innen gedacht."
#: pretix/control/templates/pretixcontrol/organizers/edit.html:322
msgid ""
@@ -28814,7 +28798,7 @@ msgid ""
"customers. This way, customers will not be able to discover the waiting list."
msgstr ""
"Entsprechend Ihrer Veranstaltungseinstellungen werden ausverkaufte Produkte "
"nicht angezeigt. Dies führt dazu, dass Kunden die Warteliste nicht "
"nicht angezeigt. Dies führt dazu, dass Kund*innen die Warteliste nicht "
"finden können."
#: pretix/control/templates/pretixcontrol/waitinglist/index.html:38
@@ -29125,11 +29109,11 @@ msgstr "Das ausgewählte List wurde gelöscht."
#: pretix/control/views/dashboards.py:115
msgid "Attendees (ordered)"
msgstr "Teilnehmer (bestellt)"
msgstr "Teilnehmende (bestellt)"
#: pretix/control/views/dashboards.py:125
msgid "Attendees (paid)"
msgstr "Teilnehmer (bezahlt)"
msgstr "Teilnehmende (bezahlt)"
#: pretix/control/views/dashboards.py:137
#, python-brace-format
@@ -31213,7 +31197,7 @@ msgstr "PDF-Sammlungen"
#: pretix/plugins/badges/exporters.py:431
msgid "Download all attendee badges as one large PDF for printing."
msgstr "Alle Teilnehmer-Badges in einer großen PDF-Datei für den Druck."
msgstr "Alle Teilnehmer*innen-Badges in einer großen PDF-Datei für den Druck."
#: pretix/plugins/badges/exporters.py:452
#: pretix/plugins/ticketoutputpdf/exporters.py:80
@@ -31493,7 +31477,7 @@ msgstr "Anderes Bankkonto"
#: pretix/plugins/banktransfer/payment.py:85
msgid "Name of account holder"
msgstr "Kontoinhaber"
msgstr "Kontoinhaber*in"
#: pretix/plugins/banktransfer/payment.py:87
msgid ""
@@ -31635,7 +31619,7 @@ msgstr "Bitte überweisen Sie den vollen Betrag auf das folgende Bankkonto:"
#: pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_confirm.html:32
#: pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_confirm.html:35
msgid "Account holder"
msgstr "Kontoinhaber"
msgstr "Kontoinhaber*in"
#: pretix/plugins/banktransfer/payment.py:304
#: pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/checkout_payment_form.html:20
@@ -32230,7 +32214,7 @@ msgid ""
"Download a spreadsheet with all attendees that are included in a check-in "
"list."
msgstr ""
"Tabelle (Excel oder CSV) mit allen Teilnehmer, die in einer Check-in-"
"Tabelle (Excel oder CSV) mit allen Teilnehmer*innen, die in einer Check-in-"
"Liste zutrittsberechtigt sind."
#: pretix/plugins/checkinlists/exporters.py:500
@@ -33409,7 +33393,7 @@ msgstr "Geplante E-Mails"
#: pretix/plugins/sendmail/signals.py:122
msgid "Mass email was sent to customers or attendees."
msgstr "Rundmail wurde an Kunden oder Teilnehmer verschickt."
msgstr "Rundmail wurde an Kunden oder Teilnehmer*innen verschickt."
#: pretix/plugins/sendmail/signals.py:123
msgid "Mass email was sent to waiting list entries."
@@ -33441,7 +33425,7 @@ msgstr "Eine automatisierte E-Mail wurde an den Besteller verschickt"
#: pretix/plugins/sendmail/signals.py:142
msgid "A scheduled email was sent to a ticket holder"
msgstr "Eine automatisierte E-Mail wurde an eine Teilnehmer verschickt."
msgstr "Eine automatisierte E-Mail wurde an eine Teilnehmer*in verschickt."
#: pretix/plugins/sendmail/signals.py:143
msgid "An email rule was deleted"
@@ -33474,7 +33458,7 @@ msgstr "Alle nicht eingecheckten Kunden"
#: pretix/plugins/sendmail/templates/pretixplugins/sendmail/history_fragment_orders.html:23
msgid "Attendee contact addresses"
msgstr "Teilnehmer-E-Mail-Adressen"
msgstr "Teilnehmer*innen-E-Mail-Adressen"
#: pretix/plugins/sendmail/templates/pretixplugins/sendmail/history_fragment_orders.html:25
msgid "All contact addresses"
@@ -33633,14 +33617,14 @@ msgstr ""
#: pretix/plugins/sendmail/views.py:250
msgid "Orders or attendees"
msgstr "Bestellungen oder Teilnehmer"
msgstr "Bestellungen oder Teilnehmer*innen"
#: pretix/plugins/sendmail/views.py:251
msgid ""
"Send an email to every customer, or to every person a ticket has been "
"purchased for, or a combination of both."
msgstr ""
"Senden Sie eine E-Mail an alle Ticketkäufer, alle Ticketinhaber "
"Senden Sie eine E-Mail an alle Ticketkäufer*innen, alle Ticketinhaber*innen "
"oder eine Kombination aus beiden Gruppen."
#: pretix/plugins/sendmail/views.py:417
@@ -34214,23 +34198,23 @@ msgstr "SEPA-Lastschrift"
#: pretix/plugins/stripe/payment.py:1277
msgid "Account Holder Name"
msgstr "Kontoinhaber"
msgstr "Kontoinhaber*in"
#: pretix/plugins/stripe/payment.py:1282
msgid "Account Holder Street"
msgstr "Straße (Kontoinhaber)"
msgstr "Straße (Kontoinhaber*in)"
#: pretix/plugins/stripe/payment.py:1294
msgid "Account Holder Postal Code"
msgstr "PLZ (Kontoinhaber)"
msgstr "PLZ (Kontoinhaber*in)"
#: pretix/plugins/stripe/payment.py:1306
msgid "Account Holder City"
msgstr "Stadt (Kontoinhaber)"
msgstr "Stadt (Kontoinhaber*in)"
#: pretix/plugins/stripe/payment.py:1318
msgid "Account Holder Country"
msgstr "Land (Kontoinhaber)"
msgstr "Land (Kontoinhaber*in)"
#: pretix/plugins/stripe/payment.py:1362
msgid "Affirm via Stripe"
@@ -34681,7 +34665,7 @@ msgstr "MOTO"
#: pretix/plugins/stripe/templates/pretixplugins/stripe/control.html:64
#: pretix/plugins/stripe/templates/pretixplugins/stripe/control.html:67
msgid "Payer name"
msgstr "Name des Zahlers"
msgstr "Name des Zahlenden"
#: pretix/plugins/stripe/templates/pretixplugins/stripe/control.html:91
msgid "Payment receipt"
@@ -36076,7 +36060,7 @@ msgstr[1] "Das Ticket wurde %(count)s-mal eingelöst."
#: pretix/presale/templates/pretixpresale/event/fragment_cart.html:166
msgid "No attendee name provided"
msgstr "Name des Teilnehmenrs nicht angegeben"
msgstr "Name der teilnehmenden Person nicht angegeben"
#: pretix/presale/templates/pretixpresale/event/fragment_cart.html:219
msgid "The image you previously uploaded"
@@ -37838,12 +37822,12 @@ msgstr ""
#: pretix/presale/templates/pretixpresale/organizers/customer_profiles.html:11
#: pretix/presale/views/customer.py:388
msgid "Attendee profiles"
msgstr "Teilnehmer-Profile"
msgstr "Teilnehmer*innen-Profile"
#: pretix/presale/templates/pretixpresale/organizers/customer_profiles.html:37
msgid "You dont have any attendee profiles in your account yet."
msgstr ""
"In Ihrem Kundenkonto sind noch keine Teilnehmer-Profile gespeichert."
"In Ihrem Kundenkonto sind noch keine Teilnehmer*innen-Profile gespeichert."
#: pretix/presale/templates/pretixpresale/organizers/customer_registration.html:7
msgid "Registration"
@@ -39473,7 +39457,7 @@ msgstr "Kosovo"
#~ "This plugin allows you to generate badges or name tags for your attendees."
#~ msgstr ""
#~ "Diese Erweiterung erlaubt, Namensschilder oder Badges für die "
#~ "Teilnehmer zu erstellen."
#~ "Teilnehmer*innen zu erstellen."
#~ msgid "This plugin allows you to receive payments via PayPal"
#~ msgstr "Dieses Plugin erlaubt, Zahlungen über PayPal anzunehmen"
+2 -2
View File
@@ -162,12 +162,12 @@ msgstr "Bezahlte Bestellungen"
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:27
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:39
msgid "Attendees (ordered)"
msgstr "Teilnehmer (bestellt)"
msgstr "Teilnehmende (bestellt)"
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:27
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:39
msgid "Attendees (paid)"
msgstr "Teilnehmer (bezahlt)"
msgstr "Teilnehmende (bezahlt)"
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:51
msgid "Total revenue"
@@ -900,7 +900,7 @@ msgstr "Details der Bestellposition"
#: pretix/base/datasync/sourcefields.py:129
msgid "Attendee details"
msgstr "Details Teilnehmer"
msgstr "Details Teilnehmer*in"
#: pretix/base/datasync/sourcefields.py:130 pretix/base/exporters/answers.py:66
#: pretix/base/models/items.py:1777 pretix/control/navigation.py:185
@@ -962,13 +962,13 @@ msgstr "Veranstaltungs- oder Termininformationen"
#: pretix/presale/templates/pretixpresale/organizers/customer_membership.html:50
#: pretix/presale/templates/pretixpresale/organizers/customer_memberships.html:36
msgid "Attendee name"
msgstr "Name Teilnehmer"
msgstr "Name Teilnehmer*in"
#: pretix/base/datasync/sourcefields.py:187
#: pretix/base/datasync/sourcefields.py:604
#: pretix/base/datasync/sourcefields.py:628
msgid "Attendee"
msgstr "Teilnehmer"
msgstr "Teilnehmer*in"
#: pretix/base/datasync/sourcefields.py:207
#: pretix/base/exporters/orderlist.py:648 pretix/base/forms/questions.py:713
@@ -979,11 +979,11 @@ msgstr "Teilnehmer"
#: pretix/presale/templates/pretixpresale/event/fragment_cart.html:172
#: pretix/presale/templates/pretixpresale/event/fragment_cart.html:175
msgid "Attendee email"
msgstr "E-Mail Teilnehmer"
msgstr "E-Mail Teilnehmer*in"
#: pretix/base/datasync/sourcefields.py:219
msgid "Attendee or order email"
msgstr "E-Mail Teilnehmer oder Bestellung"
msgstr "E-Mail Teilnehmer*in oder Bestellung"
#: pretix/base/datasync/sourcefields.py:232
#: pretix/base/exporters/orderlist.py:649 pretix/base/pdf.py:188
@@ -993,23 +993,23 @@ msgstr "E-Mail Teilnehmer oder Bestellung"
#: pretix/presale/templates/pretixpresale/event/fragment_cart.html:182
#: pretix/presale/templates/pretixpresale/event/fragment_cart.html:185
msgid "Attendee company"
msgstr "Teilnehmer-Firma"
msgstr "Teilnehmer*innen-Firma"
#: pretix/base/datasync/sourcefields.py:241
msgid "Attendee address street"
msgstr "Teilnehmer-Adresse: Straße"
msgstr "Teilnehmer*innen-Adresse: Straße"
#: pretix/base/datasync/sourcefields.py:250
msgid "Attendee address ZIP code"
msgstr "Teilnehmer-Adresse: PLZ"
msgstr "Teilnehmer*innen-Adresse: PLZ"
#: pretix/base/datasync/sourcefields.py:259
msgid "Attendee address city"
msgstr "Teilnehmer-Adresse: Stadt"
msgstr "Teilnehmer*innen-Adresse: Stadt"
#: pretix/base/datasync/sourcefields.py:268
msgid "Attendee address country"
msgstr "Teilnehmer-Adresse: Land"
msgstr "Teilnehmer*innen-Adresse: Land"
#: pretix/base/datasync/sourcefields.py:279
#: pretix/base/exporters/orderlist.py:691 pretix/base/pdf.py:346
@@ -1288,7 +1288,7 @@ msgid ""
"Download a ZIP file including all files that have been uploaded by your "
"customers while creating an order."
msgstr ""
"ZIP-Datei mit allen Dateien, die von Kunden im Bestellprozess als "
"ZIP-Datei mit allen Dateien, die von Kund*innen im Bestellprozess als "
"Antwort auf eine Frage hochgeladen wurden."
#: pretix/base/exporters/answers.py:76 pretix/base/exporters/orderlist.py:629
@@ -2275,8 +2275,8 @@ msgid ""
"Download a text file with all email addresses collected either from buyers "
"or from ticket holders."
msgstr ""
"Textdatei mit allen E-Mail-Adressen, die von Käufer und "
"Ticketinhaber eingesammelt wurden."
"Textdatei mit allen E-Mail-Adressen, die von Käufer*innen und "
"Ticketinhaber*innen eingesammelt wurden."
#: pretix/base/exporters/mail.py:76 pretix/plugins/reports/exporters.py:502
#: pretix/plugins/reports/exporters.py:685
@@ -4265,7 +4265,7 @@ msgstr "Bitte wähle einen gültigen Staat aus."
#: pretix/base/modelimport_orders.py:359 pretix/control/forms/filter.py:688
msgid "Attendee email address"
msgstr "Teilnehmer-E-Mail-Adresse"
msgstr "Teilnehmer*innen-E-Mail-Adresse"
#: pretix/base/modelimport_orders.py:375 pretix/base/modelimport_orders.py:386
#: pretix/base/modelimport_orders.py:397 pretix/base/modelimport_orders.py:408
@@ -4277,7 +4277,7 @@ msgstr "Teilnehmer-E-Mail-Adresse"
#: pretix/presale/templates/pretixpresale/event/fragment_cart.html:193
#: pretix/presale/templates/pretixpresale/event/fragment_cart.html:196
msgid "Attendee address"
msgstr "Teilnehmer-Adresse"
msgstr "Teilnehmer*innen-Adresse"
#: pretix/base/modelimport_orders.py:468
msgid "Calculate from product"
@@ -5811,8 +5811,8 @@ msgid ""
"needs to be checked."
msgstr ""
"Wenn diese Option gesetzt ist, wird die Check-in-Anwendung melden, dass "
"dieses Ticket besondere Behandlung braucht. Das ist z.B. für Studenten "
"nützlich, deren Studentenausweis noch geprüft werden soll."
"dieses Ticket besondere Behandlung braucht. Das ist z.B. für Studierende "
"nützlich, deren Studierendenausweis noch geprüft werden soll."
#: pretix/base/models/items.py:670 pretix/base/models/items.py:1261
msgid ""
@@ -6715,8 +6715,8 @@ msgid ""
"cases."
msgstr ""
"Wenn diese Option gesetzt ist, wird die Check-in-Anwendung melden, dass "
"dieses Ticket besondere Behandlung braucht. Das ist z.B. für Studenten "
"nützlich, deren Studentenausweis noch geprüft werden soll."
"dieses Ticket besondere Behandlung braucht. Das ist z.B. für Studierende "
"nützlich, deren Studierendenausweis noch geprüft werden soll."
#: pretix/base/models/orders.py:290
msgid ""
@@ -8202,7 +8202,7 @@ msgstr "Musterfirma"
#: pretix/base/pdf.py:193
msgid "Full attendee address"
msgstr "Volle Teilnehmer-Adresse"
msgstr "Volle Teilnehmer*innen-Adresse"
#: pretix/base/pdf.py:194
msgid ""
@@ -8220,23 +8220,23 @@ msgstr ""
#: pretix/base/pdf.py:198
msgid "Attendee street"
msgstr "Teilnehmer-Straße"
msgstr "Teilnehmer*innen-Straße"
#: pretix/base/pdf.py:203
msgid "Attendee ZIP code"
msgstr "Teilnehmer-PLZ"
msgstr "Teilnehmer*innen-PLZ"
#: pretix/base/pdf.py:208
msgid "Attendee city"
msgstr "Teilnehmer-Stadt"
msgstr "Teilnehmer*innen-Stadt"
#: pretix/base/pdf.py:213
msgid "Attendee state"
msgstr "Teilnehmer-Bundesstaat"
msgstr "Teilnehmer*innen-Bundesstaat"
#: pretix/base/pdf.py:218
msgid "Attendee country"
msgstr "Teilnehmer-Land"
msgstr "Teilnehmer*innen-Land"
#: pretix/base/pdf.py:230
msgid "Pseudonymization ID (lead scanning)"
@@ -8542,7 +8542,7 @@ msgstr "Herr Mustermann"
#: pretix/plugins/ticketoutputpdf/exporters.py:99
#, python-brace-format
msgid "Attendee name: {part}"
msgstr "Teilnehmer: {part}"
msgstr "Teilnehmer*innenname: {part}"
#: pretix/base/pdf.py:700
msgid "Invoice address name for salutation"
@@ -9465,7 +9465,7 @@ msgstr "Veranstaltungsort: {location}"
#, python-brace-format
msgctxt "invoice"
msgid "Attendee: {name}"
msgstr "Teilnehmer: {name}"
msgstr "Teilnehmer*in: {name}"
#: pretix/base/services/invoices.py:293 pretix/plugins/reports/exporters.py:308
#, python-brace-format
@@ -10393,7 +10393,7 @@ msgstr ""
#: pretix/base/settings.py:375
msgid "Hide prices on attendee ticket page"
msgstr "Preise auf Teilnehmer-Ticket-Seite verstecken"
msgstr "Preise auf Teilnehmer*innen-Ticket-Seite verstecken"
#: pretix/base/settings.py:376
msgid ""
@@ -10403,13 +10403,13 @@ msgid ""
"price."
msgstr ""
"Wenn eine Person mehrere Tickets erwirbt und E-Mails an alle "
"Teilnehmer verschickt werden, wird mit dieser Option der Ticketpreis "
"auf der Ticket-Seite der einzelnen Teilnehmer versteckt. Nur die "
"Teilnehmer*innen verschickt werden, wird mit dieser Option der Ticketpreis "
"auf der Ticket-Seite der einzelnen Teilnehmer*innen versteckt. Nur die "
"Person, welche die Tickets kauft, sieht den Preis."
#: pretix/base/settings.py:394
msgid "Ask for attendee names"
msgstr "Namen der Teilnehmer erfragen"
msgstr "Namen der Teilnehmer*innen erfragen"
#: pretix/base/settings.py:395
msgid "Ask for a name for all personalized tickets."
@@ -10418,11 +10418,11 @@ msgstr ""
#: pretix/base/settings.py:404
msgid "Require attendee names"
msgstr "Namen der Teilnehmer erfordern"
msgstr "Namen der Teilnehmer*innen erfordern"
#: pretix/base/settings.py:405
msgid "Require customers to fill in the names of all attendees."
msgstr "Erfordere die Eingabe aller Teilnehmer-Namen."
msgstr "Erfordere die Eingabe aller Teilnehmer*innen-Namen."
#: pretix/base/settings.py:415
msgid "Ask for email addresses per ticket"
@@ -10444,7 +10444,7 @@ msgstr ""
"aktivierst, fragt das System zusätzlich nach einzelnen E-Mail-Adressen für "
"jedes personalisierte Ticket in der Bestellung. Dies könnte z.B. nützlich "
"sein, wenn du auch im Falle von Gruppenbestellungen individuelle Adressen "
"von jedem Teilnehmer benötigst. pretix sendet die Bestellbestätigung "
"von jeder Teilnehmer*in benötigst. pretix sendet die Bestellbestätigung "
"standardmäßig nach wie vor nur an die primäre Adresse, dies kann jedoch in "
"den E-Mail-Einstellungen angepasst werden."
@@ -10952,8 +10952,8 @@ msgid ""
"but no indication of missing payment will be visible on the ticket pages of "
"attendees who did not buy the ticket themselves."
msgstr ""
"Die Box mit Zahlungsinstruktionen wird Ticketkäufern weiter angezeigt, "
"aber Teilnehmer, die ihr Ticket nicht selbst gekauft haben, werden "
"Die Box mit Zahlungsinstruktionen wird Ticketkäufer*innen weiter angezeigt, "
"aber Teilnehmer*innen, die ihr Ticket nicht selbst gekauft haben, werden "
"keine Anzeichen des fehlenden Zahlungseingangs sehen."
#: pretix/base/settings.py:1120
@@ -11451,7 +11451,7 @@ msgstr ""
#: pretix/base/settings.py:1763
msgid "Show number of check-ins to customer"
msgstr "Zeige Anzahl der Check-ins für Kunden an"
msgstr "Zeige Anzahl der Check-ins für Kund*innen an"
#: pretix/base/settings.py:1764
msgid ""
@@ -11462,12 +11462,12 @@ msgid ""
"failed scans will not be counted, and the user will not see the different "
"check-in lists."
msgstr ""
"Wenn diese Option aktiv ist, können Kunden selbst sehen, wie oft sie die "
"Wenn diese Option aktiv ist, können Kund*innen selbst sehen, wie oft sie die "
"Veranstaltung betreten haben. Das ist normalerweise nicht nötig, aber kann "
"nützlich sein, wenn es Tickets gibt, die eine bestimmte Anzahl an Eintritten "
"erlauben, sodass Kunden die bisherige Nutzung des Tickets einsehen "
"erlauben, sodass Kund*innen die bisherige Nutzung des Tickets einsehen "
"können. Ausgänge oder fehlgeschlagene Scans werden nicht angezeigt und die "
"Kunden sehen keine Aufschlüsselung verschiedener Check-in-Listen."
"Kund*innen sehen keine Aufschlüsselung verschiedener Check-in-Listen."
#: pretix/base/settings.py:1777
msgid "Allow users to download tickets"
@@ -11648,7 +11648,7 @@ msgstr ""
#: pretix/base/settings.py:1940 pretix/base/settings.py:1949
msgid "Both the attendee and the person who ordered can make changes"
msgstr ""
"Sowohl Besteller als auch Teilnehmer können Änderungen vornehmen"
"Sowohl Besteller*in als auch Teilnehmer*innen können Änderungen vornehmen"
#: pretix/base/settings.py:1944
msgid "Allow customers to modify their information"
@@ -11756,7 +11756,7 @@ msgstr ""
#: pretix/base/settings.py:2050
msgid "Allow individual attendees to change their ticket"
msgstr "Erlaubt einzelnen Teilnehmer ihr Ticket zu ändern"
msgstr "Erlaubt einzelnen Teilnehmer*innen ihr Ticket zu ändern"
#: pretix/base/settings.py:2051
msgid ""
@@ -11768,7 +11768,7 @@ msgid ""
msgstr ""
"Standardmäßig kann nur die Person, welche die Tickets gekauft hat, "
"Änderungen an der Bestellung vornehmen. Wenn diese Option aktiv ist, können "
"auch einzelne Teilnehmer Änderungen vornehmen. Teilnehmer können "
"auch einzelne Teilnehmer*innen Änderungen vornehmen. Teilnehmer*innen können "
"jedoch immer nur Änderungen vornehmen, welche die Gesamtkosten der "
"Bestellung nicht verändern. Solche Änderungen können nur vom Ticketkäufer "
"vorgenommen werden."
@@ -11952,7 +11952,7 @@ msgstr "Kontakt-E-Mail"
#: pretix/base/settings.py:2286 pretix/control/forms/event.py:1900
msgid "We'll show this publicly to allow attendees to contact you."
msgstr ""
"Wir werden diese Adresse veröffentlichen um Teilnehmern zu ermöglichen, "
"Wir werden diese Adresse veröffentlichen um Teilnehmer*innen zu ermöglichen, "
"dich zu kontaktieren."
#: pretix/base/settings.py:2294 pretix/control/forms/event.py:1892
@@ -12064,7 +12064,7 @@ msgid ""
"people."
msgstr ""
"Du kannst dieses Feld benutzen um zusätzliche Informationen mit deinen "
"Teilnehmer zu teilen, wie z.B. Anreise-Informationen oder den Link zu "
"Teilnehmer*innen zu teilen, wie z.B. Anreise-Informationen oder den Link zu "
"einer digitalen Veranstaltung. Wenn das Feld leer ist, fügen wir automatisch "
"einen Link zum Ticketshop, die Einlass-Uhrzeit und den Veranstalter hier "
"ein. Es sind keine Platzhalter mit sensiblen personenbezogenen Daten "
@@ -12304,8 +12304,8 @@ msgstr ""
"Diese Datei wird an die erste E-Mail angehängt, die wir beim Eingang einer "
"neuen Bestellung verschicken. Sie kann daher mit den Textvorlagen "
"\"Getätigte Bestellung\", \"Kostenlose Bestellung\" oder \"Erhaltene "
"Bestellung\" von oben auftreten. Sie wird ggf. sowohl an Besteller als "
"auch Teilnehmer verschickt. Nicht geeignet zum Versand nicht-"
"Bestellung\" von oben auftreten. Sie wird ggf. sowohl an Besteller*innen als "
"auch Teilnehmer*innen verschickt. Nicht geeignet zum Versand nicht-"
"öffentlicher Informationen, da die Datei unabhängig davon verschickt wird, "
"ob die Bestellung bezahlt oder freigegeben ist. Um zu vermeiden, dass diese "
"wichtige E-Mail nicht ankommt, können nur PDF-Dateien mit maximal {size} MB "
@@ -13568,7 +13568,7 @@ msgstr ""
msgid ""
"You cannot require specifying attendee names if you do not ask for them."
msgstr ""
"Du kannst die Angabe von Teilnehmernamen nur erfordern, wenn auch nach "
"Du kannst die Angabe von Teilnehmer*innennamen nur erfordern, wenn auch nach "
"Namen gefragt wird."
#: pretix/base/settings.py:4146
@@ -15243,11 +15243,11 @@ msgstr "Ticket-Downloads"
#: pretix/control/forms/event.py:1882
msgid "Your customers will be able to download their tickets in PDF format."
msgstr ""
"Die Teilnehmer werden ihre Tickets im PDF-Format herunterladen können."
"Die Teilnehmer*innen werden ihre Tickets im PDF-Format herunterladen können."
#: pretix/control/forms/event.py:1886
msgid "Require all attendees to fill in their names"
msgstr "Erfordere, dass alle Teilnehmer ihre Namen ausfüllen"
msgstr "Erfordere, dass alle Teilnehmer*innen ihre Namen ausfüllen"
#: pretix/control/forms/event.py:1887
msgid ""
@@ -15283,7 +15283,7 @@ msgid ""
"then import your bank statements to process the payments within pretix, or "
"mark them as paid manually."
msgstr ""
"Deine Teilnehmer werden angewiesen, das Geld direkt auf dein Bankkonto "
"Deine Teilnehmer*innen werden angewiesen, das Geld direkt auf dein Bankkonto "
"zu überweisen. Du kannst dann deinen Kontoauszug in pretix importieren, um "
"Zahlungen zuzuweisen, oder die Bestellungen manuell als bezahlt markieren."
@@ -15632,7 +15632,7 @@ msgstr "Check-in-Status"
#: pretix/control/forms/filter.py:2174
#: pretix/plugins/checkinlists/exporters.py:109
msgid "All attendees"
msgstr "Alle Teilnehmer"
msgstr "Alle Teilnehmer*innen"
#: pretix/control/forms/filter.py:2175
#: pretix/control/templates/pretixcontrol/checkin/index.html:183
@@ -16217,7 +16217,7 @@ msgid ""
"people over 65. This ticket includes access to all parts of the event, "
"except the VIP area."
msgstr ""
"z.B. Dieses reduzierte Ticket ist erhältlich für Vollzeitstudenten, "
"z.B. Dieses reduzierte Ticket ist erhältlich für Vollzeitstudent*innen, "
"Arbeitslose und Menschen über 65. Das Ticket enthält Zugang zu allen Teilen "
"der Veranstaltung außer des VIP-Bereiches."
@@ -18090,7 +18090,7 @@ msgstr "Eine individuelle E-Mail wurde verschickt."
#: pretix/control/logdisplay.py:554
msgid "A custom email has been sent to an attendee."
msgstr "Eine individuelle E-Mail wurde an eine Teilnehmer verschickt."
msgstr "Eine individuelle E-Mail wurde an eine Teilnehmer*in verschickt."
#: pretix/control/logdisplay.py:555
msgid ""
@@ -19824,7 +19824,7 @@ msgstr "Terminal-ID"
#: pretix/control/templates/pretixcontrol/boxoffice/payment.html:104
msgid "Card holder"
msgstr "Karteninhaber"
msgstr "Karteninhaber*in"
#: pretix/control/templates/pretixcontrol/boxoffice/payment.html:108
msgid "Card expiration"
@@ -20135,7 +20135,7 @@ msgstr "CSV"
#: pretix/control/templates/pretixcontrol/checkin/index.html:73
msgid "No attendee record was found."
msgstr "Keine passenden Teilnehmer gefunden."
msgstr "Keine passenden Teilnehmer*innen gefunden."
#: pretix/control/templates/pretixcontrol/checkin/index.html:91
#: pretix/control/templates/pretixcontrol/datasync/failed_jobs.html:19
@@ -21962,7 +21962,7 @@ msgid ""
"provide ways for your attendees to contact you:"
msgstr ""
"Wenn irgendetwas schiefgeht oder unklar ist, empfehlen wir, dass du deinen "
"Teilnehmer die Möglichkeit gibst, dich zu benachrichtigen:"
"Teilnehmer*innen die Möglichkeit gibst, dich zu benachrichtigen:"
#: pretix/control/templates/pretixcontrol/event/settings.html:21
msgid "Basics"
@@ -22939,7 +22939,7 @@ msgid ""
"Only purchases of such products will be considered \"attendees\" for most "
"statistical purposes or within some plugins."
msgstr ""
"Nur Käufe eines solchen Produkts werden als \"Teilnehmer\" gewertet, "
"Nur Käufe eines solchen Produkts werden als \"Teilnehmer*innen\" gewertet, "
"z.B. in Statistiken oder in Funktionen von Erweiterungen."
#: pretix/control/templates/pretixcontrol/item/create.html:39
@@ -23018,7 +23018,7 @@ msgid ""
"The system will not ask for a name or other attendee details. This only "
"affects system-provided fields, you can still add your own questions."
msgstr ""
"Das System wird nicht nach einem Namen oder anderen Teilnehmer-Daten "
"Das System wird nicht nach einem Namen oder anderen Teilnehmer*innen-Daten "
"fragen. Dies betrifft nur vom System bereitgestellte Felder, eigene Fragen "
"können trotzdem hinzugefügt werden."
@@ -23715,9 +23715,9 @@ msgid ""
"ticket. If you provide food, one example might be to ask your users about "
"dietary requirements."
msgstr ""
"Fragen erlauben deinen Besucher, zusätzliche Informationen zu ihrem "
"Fragen erlauben deinen Besucher*innen, zusätzliche Informationen zu ihrem "
"Ticket auszufüllen. Wenn deine Veranstaltung Verpflegung beinhaltet, "
"könntest du z.B. nach Allergien deiner Teilnehmer fragen."
"könntest du z.B. nach Allergien deiner Teilnehmer*innen fragen."
#: pretix/control/templates/pretixcontrol/items/questions.html:15
msgid "Create a new question"
@@ -23882,7 +23882,7 @@ msgstr ""
"Um deine Produkte verfügbar zu machen, musst du Kontingente anlegen. "
"Kontingente definieren, wie oft ein Produkt verkauft werden darf. Auf diese "
"Art kannst du konfigurieren, ob deine Veranstaltung unbegrenzt viele "
"Teilnehmer aufnehmen kann oder ob die Anzahl begrenzt ist. Du kannst "
"Teilnehmer*innen aufnehmen kann oder ob die Anzahl begrenzt ist. Du kannst "
"ein Produkt zu mehreren Kontingenten hinzufügen, um komplexere Anforderungen "
"abzubilden, z.B. wenn du die Gesamtzahl der Tickets begrenzen willst, aber "
"einen speziellen Ticket-Typ noch stärker begrenzen willst."
@@ -25353,7 +25353,7 @@ msgstr "Sonstige Datenexporte"
#: pretix/control/templates/pretixcontrol/orders/export.html:107
#: pretix/control/templates/pretixcontrol/organizers/export.html:107
msgid "Recommended for new users"
msgstr "Empfohlen für neue Benutzer"
msgstr "Empfohlen für neue Benutzer*innen"
#: pretix/control/templates/pretixcontrol/orders/export.html:120
#: pretix/control/templates/pretixcontrol/organizers/export.html:120
@@ -26312,7 +26312,7 @@ msgstr "Domains"
#: pretix/control/templates/pretixcontrol/organizers/edit.html:321
msgid "This dialog is intended for advanced users."
msgstr "Dieser Dialog ist für fortgeschrittene Anwender gedacht."
msgstr "Dieser Dialog ist für fortgeschrittene Anwender*innen gedacht."
#: pretix/control/templates/pretixcontrol/organizers/edit.html:322
msgid ""
@@ -28756,7 +28756,7 @@ msgid ""
"customers. This way, customers will not be able to discover the waiting list."
msgstr ""
"Entsprechend deiner Veranstaltungseinstellungen werden ausverkaufte Produkte "
"nicht angezeigt. Dies führt dazu, dass Kunden die Warteliste nicht "
"nicht angezeigt. Dies führt dazu, dass Kund*innen die Warteliste nicht "
"finden können."
#: pretix/control/templates/pretixcontrol/waitinglist/index.html:38
@@ -29066,11 +29066,11 @@ msgstr "Das ausgewählte List wurde gelöscht."
#: pretix/control/views/dashboards.py:115
msgid "Attendees (ordered)"
msgstr "Teilnehmer (bestellt)"
msgstr "Teilnehmende (bestellt)"
#: pretix/control/views/dashboards.py:125
msgid "Attendees (paid)"
msgstr "Teilnehmer (bezahlt)"
msgstr "Teilnehmende (bezahlt)"
#: pretix/control/views/dashboards.py:137
#, python-brace-format
@@ -31150,7 +31150,7 @@ msgstr "PDF-Sammlungen"
#: pretix/plugins/badges/exporters.py:431
msgid "Download all attendee badges as one large PDF for printing."
msgstr "Alle Teilnehmer-Badges in einer großen PDF-Datei für den Druck."
msgstr "Alle Teilnehmer*innen-Badges in einer großen PDF-Datei für den Druck."
#: pretix/plugins/badges/exporters.py:452
#: pretix/plugins/ticketoutputpdf/exporters.py:80
@@ -31429,7 +31429,7 @@ msgstr "Anderes Bankkonto"
#: pretix/plugins/banktransfer/payment.py:85
msgid "Name of account holder"
msgstr "Kontoinhaber"
msgstr "Kontoinhaber*in"
#: pretix/plugins/banktransfer/payment.py:87
msgid ""
@@ -31571,7 +31571,7 @@ msgstr "Bitte überweise den vollen Betrag auf das folgende Bankkonto:"
#: pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_confirm.html:32
#: pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_confirm.html:35
msgid "Account holder"
msgstr "Kontoinhaber"
msgstr "Kontoinhaber*in"
#: pretix/plugins/banktransfer/payment.py:304
#: pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/checkout_payment_form.html:20
@@ -32167,7 +32167,7 @@ msgid ""
"Download a spreadsheet with all attendees that are included in a check-in "
"list."
msgstr ""
"Tabelle (Excel oder CSV) mit allen Teilnehmer, die in einer Check-in-"
"Tabelle (Excel oder CSV) mit allen Teilnehmer*innen, die in einer Check-in-"
"Liste zutrittsberechtigt sind."
#: pretix/plugins/checkinlists/exporters.py:500
@@ -33343,7 +33343,7 @@ msgstr "Geplante E-Mails"
#: pretix/plugins/sendmail/signals.py:122
msgid "Mass email was sent to customers or attendees."
msgstr "Rundmail wurde an Kunden oder Teilnehmer verschickt."
msgstr "Rundmail wurde an Kunden oder Teilnehmer*innen verschickt."
#: pretix/plugins/sendmail/signals.py:123
msgid "Mass email was sent to waiting list entries."
@@ -33375,7 +33375,7 @@ msgstr "Eine automatisierte E-Mail wurde an den Besteller verschickt"
#: pretix/plugins/sendmail/signals.py:142
msgid "A scheduled email was sent to a ticket holder"
msgstr "Eine automatisierte E-Mail wurde an einen Teilnehmer verschickt."
msgstr "Eine automatisierte E-Mail wurde an eine Teilnehmer*in verschickt."
#: pretix/plugins/sendmail/signals.py:143
msgid "An email rule was deleted"
@@ -33408,7 +33408,7 @@ msgstr "Alle nicht eingecheckten Kunden"
#: pretix/plugins/sendmail/templates/pretixplugins/sendmail/history_fragment_orders.html:23
msgid "Attendee contact addresses"
msgstr "Teilnehmer-E-Mail-Adressen"
msgstr "Teilnehmer*innen-E-Mail-Adressen"
#: pretix/plugins/sendmail/templates/pretixplugins/sendmail/history_fragment_orders.html:25
msgid "All contact addresses"
@@ -33569,14 +33569,14 @@ msgstr ""
#: pretix/plugins/sendmail/views.py:250
msgid "Orders or attendees"
msgstr "Bestellungen oder Teilnehmer"
msgstr "Bestellungen oder Teilnehmer*innen"
#: pretix/plugins/sendmail/views.py:251
msgid ""
"Send an email to every customer, or to every person a ticket has been "
"purchased for, or a combination of both."
msgstr ""
"Sende eine E-Mail an alle Ticketkäufer, alle Ticketinhaber oder "
"Sende eine E-Mail an alle Ticketkäufer*innen, alle Ticketinhaber*innen oder "
"eine Kombination aus beiden Gruppen."
#: pretix/plugins/sendmail/views.py:417
@@ -34148,23 +34148,23 @@ msgstr "SEPA-Lastschrift"
#: pretix/plugins/stripe/payment.py:1277
msgid "Account Holder Name"
msgstr "Kontoinhaber"
msgstr "Kontoinhaber*in"
#: pretix/plugins/stripe/payment.py:1282
msgid "Account Holder Street"
msgstr "Straße (Kontoinhaber)"
msgstr "Straße (Kontoinhaber*in)"
#: pretix/plugins/stripe/payment.py:1294
msgid "Account Holder Postal Code"
msgstr "PLZ (Kontoinhaber)"
msgstr "PLZ (Kontoinhaber*in)"
#: pretix/plugins/stripe/payment.py:1306
msgid "Account Holder City"
msgstr "Stadt (Kontoinhaber)"
msgstr "Stadt (Kontoinhaber*in)"
#: pretix/plugins/stripe/payment.py:1318
msgid "Account Holder Country"
msgstr "Land (Kontoinhaber)"
msgstr "Land (Kontoinhaber*in)"
#: pretix/plugins/stripe/payment.py:1362
msgid "Affirm via Stripe"
@@ -34613,7 +34613,7 @@ msgstr "MOTO"
#: pretix/plugins/stripe/templates/pretixplugins/stripe/control.html:64
#: pretix/plugins/stripe/templates/pretixplugins/stripe/control.html:67
msgid "Payer name"
msgstr "Name des Zahlers"
msgstr "Name des Zahlenden"
#: pretix/plugins/stripe/templates/pretixplugins/stripe/control.html:91
msgid "Payment receipt"
@@ -36003,7 +36003,7 @@ msgstr[1] "Das Ticket wurde %(count)s-mal eingelöst."
#: pretix/presale/templates/pretixpresale/event/fragment_cart.html:166
msgid "No attendee name provided"
msgstr "Name des Teilnehmenrs nicht angegeben"
msgstr "Name der teilnehmenden Person nicht angegeben"
#: pretix/presale/templates/pretixpresale/event/fragment_cart.html:219
msgid "The image you previously uploaded"
@@ -37763,12 +37763,12 @@ msgstr "Möchtest das folgende Profil wirklich aus deinem Kundenkonto löschen?"
#: pretix/presale/templates/pretixpresale/organizers/customer_profiles.html:11
#: pretix/presale/views/customer.py:388
msgid "Attendee profiles"
msgstr "Teilnehmer-Adresse"
msgstr "Teilnehmer*innen-Adresse"
#: pretix/presale/templates/pretixpresale/organizers/customer_profiles.html:37
msgid "You dont have any attendee profiles in your account yet."
msgstr ""
"In deinem Kundenkonto sind noch keine Teilnehmer-Profile gespeichert."
"In deinem Kundenkonto sind noch keine Teilnehmer*innen-Profile gespeichert."
#: pretix/presale/templates/pretixpresale/organizers/customer_registration.html:7
msgid "Registration"
@@ -39343,7 +39343,7 @@ msgstr "Kosovo"
#~ "This plugin allows you to generate badges or name tags for your attendees."
#~ msgstr ""
#~ "Diese Erweiterung erlaubt, Namensschilder oder Badges für die "
#~ "Teilnehmer zu erstellen."
#~ "Teilnehmer*innen zu erstellen."
#~ msgid "This plugin allows you to receive payments via PayPal"
#~ msgstr "Dieses Plugin erlaubt, Zahlungen über PayPal anzunehmen"
@@ -39921,7 +39921,7 @@ msgstr "Kosovo"
#~ msgstr "Biete Ticket-Download bereits vor Bezahlung einer Bestellung an"
#~ msgid "Attendee names"
#~ msgstr "Teilnehmername"
#~ msgstr "Teilnehmer*innennamen"
#~ msgid "Enable output"
#~ msgstr "Aktivieren"
@@ -40198,7 +40198,7 @@ msgstr "Kosovo"
#~ "If checked, users can cancel orders by themselves as long as they are not "
#~ "yet paid."
#~ msgstr ""
#~ "Wenn diese Option aktiviert ist, können Teilnehmer selbstständig "
#~ "Wenn diese Option aktiviert ist, können Teilnehmer*innen selbstständig "
#~ "Bestellungen stornieren solange sie nicht bezahlt wurden."
#~ msgid "Sales overview"
@@ -162,12 +162,12 @@ msgstr "Bezahlte Bestellungen"
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:27
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:39
msgid "Attendees (ordered)"
msgstr "Teilnehmer (bestellt)"
msgstr "Teilnehmende (bestellt)"
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:27
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:39
msgid "Attendees (paid)"
msgstr "Teilnehmer (bezahlt)"
msgstr "Teilnehmende (bezahlt)"
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:51
msgid "Total revenue"
@@ -21,22 +21,21 @@
data-date="{{ day.date|date_fast:"SHORT_DATE_FORMAT" }}">
<p>
{% if day.events %}
<a href="#selected-day" class="day-label event hidden-sm hidden-md hidden-lg">
<a href="#selected-day" class="day-label event hidden-sm hidden-md hidden-lg" aria-describedby="nr-of-events-{{ day.date|date_fast:"Y-m-d" }}">
<b aria-hidden="true">{{ day.day }}</b>
<time datetime="{{ day.date|date_fast:"Y-m-d" }}" class="sr-only">
{{ day.date|date_fast:"SHORT_DATE_FORMAT" }}
</time>
<span class="sr-only">
({% blocktrans trimmed count count=day.events|length %}
{{ count }} event
{% plural %}
{{ count }} events
{% endblocktrans %})
</span>
<span class="sr-only" id="nr-of-events-{{ day.date|date_fast:"Y-m-d" }}">{% blocktrans trimmed count count=day.events|length %}
{{ count }} event
{% plural %}
{{ count }} events
{% endblocktrans %}</span>
</a>
<time datetime="{{ day.date|date_fast:"Y-m-d" }}" class="hidden-xs">{{ day.day }}</time>
{% else %}
<time datetime="{{ day.date|date_fast:"Y-m-d" }}" class="day-label">{{ day.day }}</time>
<span class="sr-only">{% trans "No events" %}</span>
{% endif %}
</p>
<ul class="events">
+4
View File
@@ -650,6 +650,10 @@ def add_subevents_for_days(qs, before, after, ebd, timezones, sales_channel, eve
if hide:
continue
if s.event_calendar_future_only:
if (se.date_to or se.date_from) < time_machine_now():
continue
timezones.add(s.timezone)
tz = ZoneInfo(s.timezone)
datetime_from = se.date_from.astimezone(tz)
+1 -1
View File
@@ -123,7 +123,7 @@ def widget_css_etag(request, version, **kwargs):
def _use_vite(request):
if getattr(settings, 'PRETIX_WIDGET_VITE', False):
if getattr(settings, 'PRETIX_WIDGET_VITE', False) or "beta" in request.GET:
return True
origin = request.META.get('HTTP_ORIGIN', '')
gs = GlobalSettingsObject()
+2
View File
@@ -440,6 +440,7 @@ CSRF_COOKIE_NAME = 'pretix_csrftoken'
SESSION_COOKIE_HTTPONLY = True
INSTALLED_APPS += [ # noqa
'django_querytagger',
'django_filters',
'django_markup',
'django_otp',
@@ -505,6 +506,7 @@ MIDDLEWARE = [
'pretix.helpers.logs.RequestIdMiddleware',
'pretix.api.middleware.IdempotencyMiddleware',
'pretix.multidomain.middlewares.MultiDomainMiddleware',
'django_querytagger.middleware.SetTagMiddleware', # after MultiDomainMiddleware for correct url resolving
'pretix.base.middleware.CustomCommonMiddleware',
'pretix.multidomain.middlewares.SessionMiddleware',
'pretix.multidomain.middlewares.CsrfViewMiddleware',
+78
View File
@@ -126,3 +126,81 @@ class LocaleDeterminationTest(TestCase):
response = c.get('/dummy/dummy/')
language = response['Content-Language']
self.assertEqual(language, 'en')
def test_render_csp():
from pretix.base.middleware import _render_csp
assert _render_csp({}) == ""
assert _render_csp({'default-src': ["'self'"]}) == "default-src 'self'"
h = {
'default-src': ["'self'"],
'script-src': ["'self'"],
'object-src': ["'none'"],
'frame-src': ["'self'"],
'style-src': ["'self'", "'self'"],
'connect-src': ["'self'", "'self'"],
'img-src': ["'self'", "'self'", "data:"],
'font-src': ["'self'"],
'media-src': ["'self'", "data:"],
'form-action': ["'self'", "https:"],
}
assert _render_csp(h) == (
"default-src 'self'; script-src 'self'; object-src 'none'; frame-src 'self'; style-src 'self' 'self'; "
"connect-src 'self' 'self'; img-src 'self' 'self' data:; font-src 'self'; media-src 'self' data:; form-action 'self' https:"
)
def test_merge_csp():
from pretix.base.middleware import _merge_csp, _parse_csp, _render_csp
h = {
'default-src': ["'self'"],
'script-src': ["'self'"],
'style-src': ["'self'", "'self'"],
'form-action': ["'self'", "https:"],
'connect-src': ["'self'", "'self'"],
}
assert _render_csp(h) == (
"default-src 'self'; script-src 'self'; style-src 'self' 'self'; form-action 'self' https:; connect-src 'self' 'self'"
)
_merge_csp(h, _parse_csp("style-src 'unsafe-inline'; connect-src https://example.com"))
assert _render_csp(h) == (
"default-src 'self'; script-src 'self'; style-src 'self' 'self' 'unsafe-inline'; form-action 'self' "
"https:; connect-src 'self' 'self' https://example.com"
)
def test_roundtrip_csp():
from pretix.base.middleware import _merge_csp, _parse_csp, _render_csp
prod_csp = ("default-src 'self' https://pretix.eu https://static.pretix.cloud; script-src 'self' "
"'sha256-+tmFggeXIPOAC2UgcQ3LW/gPHTkwyWg3/D6FOJ5BHGo=' 'unsafe-eval' https://matomo.rami.io "
"https://pretix.eu https://static.pretix.cloud https://support.rami.io; object-src 'none'; "
"frame-src 'self' https://matomo.rami.io https://pretix.eu https://static.pretix.cloud "
"https://support.rami.io https://www.youtube-nocookie.com; style-src 'self' 'unsafe-inline' "
"data: https://cdn.pretix.cloud https://pretix.eu https://static.pretix…rt.rami.io; connect-src "
"'self' https://cdn.pretix.cloud https://matomo.rami.io https://pretix.eu https://static.pretix.cloud "
"https://support.rami.io ws://support.rami.io; img-src 'self' data: https://cdn.pretix.cloud "
"https://matomo.rami.io https://pretix.eu https://static.pretix.cloud https://support.rami.io; "
"font-src 'self' https://pretix.eu https://static.pretix.cloud; media-src 'self' data: "
"https://cdn.pretix.cloud https://pretix.eu https://static.pretix.cloud; form-action 'self' "
"https: https://pretix.eu")
h = _parse_csp(prod_csp)
_merge_csp(h, _parse_csp(prod_csp))
assert _render_csp(h) == prod_csp
def test_sanitize_csp():
from pretix.base.middleware import _render_csp
h = {
'style-src': ["'self'", "https://example.com", "https://example.org https://attack.example.net", "https://\fexample.org",
"https://\texample.org", "https://example.org;script-src https://example.org", ],
'script-src': ["'self'"],
}
assert _render_csp(h) == (
"style-src 'self' https://example.com; script-src 'self'"
)