Compare commits

...
Author SHA1 Message Date
Lukas Bockstaller addf94afe2 formatting 2026-11-11 12:16:31 +01:00
Lukas Bockstaller 0d828e439e adjust tests 2026-11-11 12:07:18 +01:00
Lukas Bockstaller 69108a1c20 change error serialization 2026-11-11 12:07:00 +01:00
Raphael Michel ceff9de5ee Customer step: Fix login URL for SSO in weird domain setup (#6687)
The current code links to a 404 page if the event has a custom domain
but the organizer uses the default system domain.
2026-11-10 14:44:48 +01:00
Lukas Bockstaller 38b467cef7 Add option to auto transmit invoices after modification by the customer (Z#23251416) (#6713)
* Add option to auto transmit invoices after modification by the customer

* Add caveat for peppol etc. to setting help text

* auto retransmit invoices after change

* code style
2026-11-10 14:41:19 +01:00
Raphael Michel ae95df7ea2 Merge branch 'ticketoutputpdf-security' into 'master'
[SECURITY] Fix missing permission check for ticket layout API (CVE-2026-125744)

See merge request pretix/pretix!60
2026-11-10 13:54:25 +01:00
d362f16417 Documentation for questionnaires API changes (#6704)
* Add docs pages, deprecation notes

* Add data field docs

* Items personalized deprecation

* Move paragraph

* fix indentation

* Document questionnaires resource

* Apply batched suggestions from code review

Co-authored-by: Raphael Michel <mail@raphaelmichel.de>
Co-authored-by: luelista <mira@teamwiki.de>

* rename to order_presale / position_presale

* _presale -> _purchase

* children -> rows

* change datafields API endpoint URLs

* removal of question change api endpoints

* update answers objects

* add print_on_invoice_label

* document restrictions

* Update personalized attribute

* fix inconsistent type

* Update doc/api/resources/datafields.rst

Co-authored-by: Raphael Michel <michel@pretix.eu>

* rename dependency_question -> dependency_datafield, document label/help_text fields for static text blocks

* add print_on_invoice_label to examples

* Add markers for new features

---------

Co-authored-by: Raphael Michel <mail@raphaelmichel.de>
Co-authored-by: Raphael Michel <michel@pretix.eu>
Co-authored-by: Raphael Michel <michel@rami.io>
2026-11-10 13:21:50 +01:00
Raphael Michel 7f1a0fd58f [SECURITY] Fix missing permission check for ticket layout API (CVE-2026-125744) 2026-11-10 13:13:31 +01:00
Martin Gross 6d05cfea8b Badges: Add Herma 9010 (Z#23253294) (#6759) 2026-11-10 12:29:47 +01:00
pajowu c1b8259075 Replace deprecated chained @classmethod (#6757) 2026-11-10 12:14:28 +01:00
pajowu e394054ae3 Fix duplicate default check in TicketLayoutSerializer (#6748) 2026-11-06 12:24:33 +01:00
Raphael Michel dda2a18fdf Week calendar: Fix navigation after dateutil 4.0 upgrade (#6746) 2026-11-06 10:03:55 +01:00
dependabot[bot] 68bd182f79 Bump arabic-reshaper from 3.0.1 to 3.1.0 (#6744)
Bumps [arabic-reshaper](https://github.com/mpcabd/python-arabic-reshaper) from 3.0.1 to 3.1.0.
- [Release notes](https://github.com/mpcabd/python-arabic-reshaper/releases)
- [Commits](https://github.com/mpcabd/python-arabic-reshaper/compare/v3.0.1...v3.1.0)

---
updated-dependencies:
- dependency-name: arabic-reshaper
  dependency-version: 3.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-11-05 20:03:54 +01:00
dependabot[bot] 2ee6ea7692 Update pytest-asyncio requirement from >=1.4.1 to >=1.4.1.post1 (#6743)
Updates the requirements on [pytest-asyncio](https://github.com/pytest-dev/pytest-asyncio) to permit the latest version.
- [Release notes](https://github.com/pytest-dev/pytest-asyncio/releases)
- [Commits](https://github.com/pytest-dev/pytest-asyncio/compare/v1.4.1...v1.4.1.post1)

---
updated-dependencies:
- dependency-name: pytest-asyncio
  dependency-version: 1.4.1.post1
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-11-05 20:03:22 +01:00
dependabot[bot] a37305f8f4 Update flake8 requirement from ==7.4.* to ==7.5.* (#6745)
Updates the requirements on [flake8](https://github.com/pycqa/flake8) to permit the latest version.
- [Commits](https://github.com/pycqa/flake8/compare/7.4.0...7.5.0)

---
updated-dependencies:
- dependency-name: flake8
  dependency-version: 7.5.0
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-11-05 20:02:57 +01:00
Richard Schreiber bd4b049c16 Fix parameters for localization of SeatProtected errors (#6740) 2026-11-05 15:39:03 +01:00
Phin Wolkwitz cb852a8fa7 Fix itemcount in list beneath cart in event series (Z#23251632) (#6727) 2026-11-05 13:03:44 +01:00
Richard Schreiber 86dd5619e0 Move JavaScript importmap to top (#6734) 2026-11-05 12:39:21 +01:00
pajowu b1a1d66156 ticketoutputpdf api: save background to permanent file (#6735) 2026-11-05 10:33:08 +01:00
pajowu e229697d2a Fix changing sold-out addons if hide_sold_out is set (#6714)
The old item was shown in the frontend and you could de-select it, but this change was never applied
2026-11-04 20:37:05 +01:00
dependabot[bot] f9c7378da7 Update fakeredis requirement from ==2.39.* to ==2.40.* (#6737)
Updates the requirements on [fakeredis](https://github.com/cunla/fakeredis-py) to permit the latest version.
- [Release notes](https://github.com/cunla/fakeredis-py/releases)
- [Commits](https://github.com/cunla/fakeredis-py/compare/v2.39.0...v2.40.0)

---
updated-dependencies:
- dependency-name: fakeredis
  dependency-version: 2.40.0
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-11-04 20:21:03 +01:00
dependabot[bot] 86152a182a Update python-dateutil requirement from ==3.0.* to ==4.0.* (#6736)
Updates the requirements on [python-dateutil](https://github.com/dateutil/dateutil) to permit the latest version.
- [Release notes](https://github.com/dateutil/dateutil/releases)
- [Changelog](https://github.com/dateutil/dateutil/blob/master/NEWS)
- [Commits](https://github.com/dateutil/dateutil/compare/3.0.0...4.0.0)

---
updated-dependencies:
- dependency-name: python-dateutil
  dependency-version: 4.0.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-11-04 20:20:12 +01:00
dependabot[bot] 76899600b0 Update pytest-asyncio requirement from >=1.4.0 to >=1.4.1 (#6739)
Updates the requirements on [pytest-asyncio](https://github.com/pytest-dev/pytest-asyncio) to permit the latest version.
- [Release notes](https://github.com/pytest-dev/pytest-asyncio/releases)
- [Commits](https://github.com/pytest-dev/pytest-asyncio/compare/v1.4.0...v1.4.1)

---
updated-dependencies:
- dependency-name: pytest-asyncio
  dependency-version: 1.4.1
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-11-04 20:17:40 +01:00
pajowu 04a0b009a6 Accept a list of sales_channels in (Sub)Event.annotated, filter_available (Z#23252067) (#6723) 2026-11-04 18:49:19 +01:00
pajowu 4e9d60d238 Fix tests loading local pretix.cfg (#6705)
test/sqlite.cfg does not exist, so pretix.testutils.settings never set PRETIX_CONFIG_FILE, leading to pretix.settings loading the local pretix.cfg

Not setting VITE_DEV_MODE outside CI only worked because most devs probably have set django.debug=on in their pretix.cfg
2026-11-04 17:44:11 +01:00
Raphael Michel fe0d0ceb2e Drop importlib_metadata dependency (#6720)
No longer needed as a polyfill and starts to break things
2026-11-04 17:44:02 +01:00
dependabot[bot] 8457603555 Update sphinx requirement from ==9.1.* to ==9.0.* (#6731)
Updates the requirements on [sphinx](https://github.com/sphinx-doc/sphinx) to permit the latest version.
- [Release notes](https://github.com/sphinx-doc/sphinx/releases)
- [Changelog](https://github.com/sphinx-doc/sphinx/blob/v9.0.4/CHANGES.rst)
- [Commits](https://github.com/sphinx-doc/sphinx/compare/v9.1.0rc1...v9.0.4)

---
updated-dependencies:
- dependency-name: sphinx
  dependency-version: 9.0.4
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-11-04 09:52:27 +01:00
dependabot[bot] ae35af596f Update tlds requirement from >=2026093003 to >=2026102900 (#6729)
Updates the requirements on [tlds](https://github.com/kichik/tlds) to permit the latest version.
- [Commits](https://github.com/kichik/tlds/commits)

---
updated-dependencies:
- dependency-name: tlds
  dependency-version: '2026102900'
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-11-04 09:52:20 +01:00
Christiaan de Die le Clercq 47c3493372 Translations: Update Dutch
Currently translated at 96.9% (6255 of 6452 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/nl/

powered by weblate
2026-11-04 09:52:05 +01:00
Isaac Raño 85d65d17b4 Translations: Update Galician
Currently translated at 18.7% (1209 of 6452 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/gl/

powered by weblate
2026-11-04 09:52:05 +01:00
vihumelo e50c845e09 Translations: Update Portuguese (Brazil)
Currently translated at 98.8% (257 of 260 strings)

Translation: pretix/pretix (JavaScript parts)
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix-js/pt_BR/

powered by weblate
2026-11-04 09:52:05 +01:00
vihumelo c84d9061da Translations: Update Portuguese (Brazil)
Currently translated at 92.9% (5995 of 6452 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/pt_BR/

powered by weblate
2026-11-04 09:52:05 +01:00
CVZ-es 25c9659655 Translations: Update Spanish
Currently translated at 100.0% (6452 of 6452 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/es/

powered by weblate
2026-11-04 09:52:05 +01:00
CVZ-es b6bce961c3 Translations: Update French
Currently translated at 100.0% (6452 of 6452 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/fr/

powered by weblate
2026-11-04 09:52:05 +01:00
Mie Frydensbjerg 1de0455ebc Translations: Update Danish
Currently translated at 62.1% (4009 of 6452 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/da/

powered by weblate
2026-11-04 09:52:05 +01:00
dependabot[bot] 9fdafa57de Update reportlab requirement from ==5.0.* to ==5.1.* (#6730)
Updates the requirements on [reportlab](https://www.reportlab.com/) to permit the latest version.

---
updated-dependencies:
- dependency-name: reportlab
  dependency-version: 5.1.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-11-04 09:51:36 +01:00
50bcfc8c74 OIDC: Expose SSO attributes to customer_signed_in signal (#6603)
* OIDC: Expose SSO attributes to customer_signed_in signal

* Change OIDC claim name

Co-authored-by: Raphael Michel <mail@raphaelmichel.de>

* Document the changed signature of the customer_signed_in signal

* Put docs on right signal

* Fix test assertions

---------

Co-authored-by: Raphael Michel <mail@raphaelmichel.de>
Co-authored-by: Raphael Michel <michel@rami.io>
2026-11-04 09:48:03 +01:00
Raphael Michel fa552fe7d1 Permissions: Add helptext for outgoingmails:read (Z#23251039) (#6707) 2026-11-04 09:20:29 +01:00
dependabot[bot] cbfc24dd64 Update css-inline requirement from ==0.22.* to ==0.23.* (#6683)
Updates the requirements on [css-inline](https://github.com/Stranger6667/css-inline) to permit the latest version.
- [Release notes](https://github.com/Stranger6667/css-inline/releases)
- [Changelog](https://github.com/Stranger6667/css-inline/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Stranger6667/css-inline/compare/c-v0.22.0...c-v0.23.0)

---
updated-dependencies:
- dependency-name: css-inline
  dependency-version: 0.23.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-11-03 17:21:28 +01:00
dependabot[bot] 6e0c2d69a5 Bump pycparser from 3.11 to 3.12 (#6701)
Bumps [pycparser](https://github.com/eliben/pycparser) from 3.11 to 3.12.
- [Release notes](https://github.com/eliben/pycparser/releases)
- [Commits](https://github.com/eliben/pycparser/compare/release_v3.11...release_v3.12)

---
updated-dependencies:
- dependency-name: pycparser
  dependency-version: '3.12'
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-11-03 17:19:46 +01:00
dependabot[bot]andRaphael Michel 34ed175abe Update dnspython requirement from ==2.8.* to ==2.9.* (#6671)
* Update dnspython requirement from ==2.8.* to ==2.9.*

Updates the requirements on [dnspython](https://github.com/rthalley/dnspython) to permit the latest version.
- [Release notes](https://github.com/rthalley/dnspython/releases)
- [Changelog](https://github.com/rthalley/dnspython/blob/main/doc/whatsnew.rst)
- [Commits](https://github.com/rthalley/dnspython/compare/v2.8.0rc1...v2.9.0)

---
updated-dependencies:
- dependency-name: dnspython
  dependency-version: 2.9.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* Update pyproject.toml

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Raphael Michel <michel@pretix.eu>
2026-11-03 17:19:17 +01:00
dependabot[bot] a9aaf8638e Update pytest-mock requirement from ==3.16.* to ==3.17.* (#6715)
Updates the requirements on [pytest-mock](https://github.com/pytest-dev/pytest-mock) to permit the latest version.
- [Release notes](https://github.com/pytest-dev/pytest-mock/releases)
- [Changelog](https://github.com/pytest-dev/pytest-mock/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-mock/compare/v3.16.0...v3.17.0)

---
updated-dependencies:
- dependency-name: pytest-mock
  dependency-version: 3.17.0
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-11-03 17:18:21 +01:00
Raphael MichelandRaphael Michel a613affa05 Sentry: Scrub secrets from event details (#6218)
* Sentry: Scrub secrets from event details

* Apply suggestions from code review

Co-authored-by: Raphael Michel <mail@raphaelmichel.de>
2026-11-03 16:45:35 +01:00
Raphael Michel cd0ed78b76 Tests: Do not rely on actual DNS for peppol validation (#6711) 2026-11-03 16:44:31 +01:00
Raphael Michel 4889abd75c PDF editor: Warn about missing scannable QR code (#6726)
* PDF editor: Warn about missing scannable QR code

* Fix
2026-11-03 16:43:59 +01:00
Raphael Michel 0a73faa8bd Bump to i18nfield 1.12.0 2026-11-03 10:38:37 +01:00
Tobias Kunze def5042661 Ignore spaces in bank transfer queries (#6724)
When copying an order code from e.g. the order list, it's easy to
include spaces when pasting, and then this does not match anything. And
as the JavaScript side of the search *does* compare the stripped string
(normalizeQuery), just deleting the whitespace does not trigger the
order to be found either, you have delete one more letter.
2026-11-03 09:12:38 +01:00
Richard Schreiber e6f8f178af Extend log_action filter and make recursive (Z#23247315) (#6598)
* Extend log_action filter and make recursive

* fix flake8

* fix type mismatch

* add "salt" to sensitive keys

* match "key" (e.g. see payone)

* add "auth" to sensitive keys

* clean lists recursively

* improve clean method name as it also cleans list recursively

* Add test
2026-10-29 10:52:00 +01:00
Raphael Michel 5f5380e8b1 Bump version to 2026.10.0.dev0 2026-10-29 09:59:11 +01:00
Raphael Michel ff102d561d Bump version to 2026.9.0 2026-10-29 09:59:06 +01:00
Raphael Michel 1c7d0233fd Fix test failure after security patch 2026-10-28 14:41:38 +01:00
Raphael Michel 936977972e Translations: Update German (informal) (de_Informal)
Currently translated at 100.0% (6452 of 6452 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de_Informal/

powered by weblate
2026-10-28 12:15:10 +01:00
Raphael Michel 46f2baa103 Translations: Update German
Currently translated at 100.0% (6452 of 6452 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de/

powered by weblate
2026-10-28 12:15:10 +01:00
Raphael Michel 1308630f6c Update po files
[CI skip]

Signed-off-by: Raphael Michel <michel@pretix.eu>
2026-10-28 11:48:31 +01:00
CVZ-es 45bd124629 Translations: Update French
Currently translated at 100.0% (260 of 260 strings)

Translation: pretix/pretix (JavaScript parts)
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix-js/fr/

powered by weblate
2026-10-28 11:47:55 +01:00
CVZ-es a1b9a557e0 Translations: Update French
Currently translated at 100.0% (6442 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/fr/

powered by weblate
2026-10-28 11:47:55 +01:00
dependabot[bot] 1860e24f8c Update python-dateutil requirement from ==2.9.* to ==3.0.* (#6710)
Updates the requirements on [python-dateutil](https://github.com/dateutil/dateutil) to permit the latest version.
- [Release notes](https://github.com/dateutil/dateutil/releases)
- [Changelog](https://github.com/dateutil/dateutil/blob/master/NEWS)
- [Commits](https://github.com/dateutil/dateutil/compare/2.9.0...3.0.0)

---
updated-dependencies:
- dependency-name: python-dateutil
  dependency-version: 3.0.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-28 11:45:53 +01:00
Raphael Michel cfbc903595 Customer SSO: Check values for "email_verified" without relying on the type (#6708) 2026-10-28 11:40:50 +01:00
Raphael Michel 9632f69edb [SECURITY] Fix more ID lookups for file downloads (CVE-2026-101272) 2026-10-28 11:22:49 +01:00
Raphael Michel 87e3b33537 [SECURITY] Customer SSO: Fix missing validation of grant type (CVE-2026-101274, Z#23251494) 2026-10-28 11:22:49 +01:00
Kara Engelhardt a4cbb58217 [SECURITY] Properly check gift card acceptance everywhere (CVE-2026-101273) 2026-10-28 11:22:49 +01:00
Raphael Michel 15527fc5de Event list: Reduce disk load of SQL query (#6505) 2026-10-28 09:26:47 +01:00
Richard Schreiber 17fc69af18 Add support for relative date to subevents batch-edit (Z#23250805) (#6693) 2026-10-28 09:08:32 +01:00
Richard Schreiber da622e6752 Fix styling for disabled buttons other than btn-default (#6685) 2026-10-27 10:40:50 +01:00
Tim b18dde855c Translations: Update Spanish
Currently translated at 100.0% (6442 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/es/

powered by weblate
2026-10-27 10:08:20 +01:00
dependabot[bot] 9dce205e12 Bump django-bootstrap3 from 26.2 to 26.3 (#6673)
Bumps [django-bootstrap3](https://github.com/zostera/django-bootstrap3) from 26.2 to 26.3.
- [Changelog](https://github.com/zostera/django-bootstrap3/blob/main/CHANGELOG.md)
- [Commits](https://github.com/zostera/django-bootstrap3/compare/v26.2...v26.3)

---
updated-dependencies:
- dependency-name: django-bootstrap3
  dependency-version: '26.3'
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-26 17:58:40 +01:00
dependabot[bot] 5d47ebd8b8 Update djangorestframework requirement from >=3.18.2 to >=3.18.3 (#6698)
Updates the requirements on [djangorestframework](https://github.com/encode/django-rest-framework) to permit the latest version.
- [Release notes](https://github.com/encode/django-rest-framework/releases)
- [Commits](https://github.com/encode/django-rest-framework/compare/3.18.2...3.18.3)

---
updated-dependencies:
- dependency-name: djangorestframework
  dependency-version: 3.18.3
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-26 17:56:33 +01:00
dependabot[bot] c550a35e62 Bump vite from 8.0.16 to 8.3.5 (#6690)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 8.0.16 to 8.3.5.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v8.3.5/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 8.3.5
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-26 17:56:22 +01:00
dependabot[bot] 76c69e785e Bump markdown from 3.11 to 3.11.2 (#6697)
Bumps [markdown](https://github.com/Python-Markdown/markdown) from 3.11 to 3.11.2.
- [Release notes](https://github.com/Python-Markdown/markdown/releases)
- [Changelog](https://github.com/Python-Markdown/markdown/blob/master/docs/changelog.md)
- [Commits](https://github.com/Python-Markdown/markdown/compare/3.11.0...3.11.2)

---
updated-dependencies:
- dependency-name: markdown
  dependency-version: 3.11.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-26 17:56:11 +01:00
Lukas Bockstaller 59b207b756 API: run clean_live() after updates to the event (Z#23250960) (#6695)
* API: run `clean_live()` after updates to the event

* raise correct validation error

* add test cases for required meta_properties and going live
2026-10-26 11:34:59 +01:00
dependabot[bot]andLukas Bockstaller c9f7bf8680 Update djangorestframework requirement from ==3.17.* to ==3.18.* (#6470)
* Update djangorestframework requirement from ==3.17.* to ==3.18.*

Updates the requirements on [djangorestframework](https://github.com/encode/django-rest-framework) to permit the latest version.
- [Release notes](https://github.com/encode/django-rest-framework/releases)
- [Commits](https://github.com/encode/django-rest-framework/compare/3.17.0...3.18.0)

---
updated-dependencies:
- dependency-name: djangorestframework
  dependency-version: 3.18.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* RestFramework: use LIST_SERIALIZER_ERRORS_AS_DICT compatibility option

* set lower bound for djangorestframework

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Lukas Bockstaller <bockstaller@pretix.eu>
2026-10-23 16:05:54 +02:00
Martin Gross 2fcb51bf2f Translations: Update Basque
Currently translated at 46.5% (121 of 260 strings)

Translation: pretix/pretix (JavaScript parts)
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix-js/eu/

powered by weblate
2026-10-23 15:03:21 +02:00
Martin Gross 6a762854e2 Translations: Update Basque
Currently translated at 48.0% (3093 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/eu/

powered by weblate
2026-10-23 15:03:21 +02:00
IÑIGO ANSA b29fb69790 Translations: Update Basque
Currently translated at 48.0% (3093 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/eu/

powered by weblate
2026-10-23 13:21:10 +02:00
IÑIGO ANSA c7a23da055 Translations: Update Basque
Currently translated at 45.7% (119 of 260 strings)

Translation: pretix/pretix (JavaScript parts)
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix-js/eu/

powered by weblate
2026-10-23 13:21:10 +02:00
IÑIGO ANSA a3704c54e9 Translations: Update Basque
Currently translated at 47.9% (3091 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/eu/

powered by weblate
2026-10-23 13:21:10 +02:00
Daniel Jaraud 764d49482a Translations: Update French
Currently translated at 100.0% (6442 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/fr/

powered by weblate
2026-10-23 13:21:10 +02:00
Raphael Michel e188796a81 Bump Pillow to 13.0.* (#6694) 2026-10-22 15:44:57 +02:00
Lukas Bockstaller 1ca41269cd test: unset EMAIL_HOST_USER and EMAIL_HOST_PASSWORD for smtp tests (#6688)
Harden tests so that they don't fail locally when the config values are set in pretix.cfg
2026-10-22 12:03:57 +02:00
Lukas Bockstaller 9581c08949 put last_seen attribute into the defaults parameter of the get_or_create (#6689) 2026-10-22 12:00:35 +02:00
luelista 5393aff5f0 Attempt to make customer account SSO configuration a bit less confusing (#6586)
* More explanation text, better titles
* Direct links to docs
* Add all information to copy/paste in one place
2026-10-22 10:57:37 +02:00
Raphael Michel 03e488ef20 Add comment on known permission issue 2026-10-21 13:55:13 +02:00
Douwe Somers 619c68e51a Fix interpolate function (#6672) 2026-10-21 10:59:46 +02:00
Richard Schreiber 10c1d5106d API: make bundle_variation optional when creating items with bundles (#6681)
* API: make bundle_variation optional when creating items with bundles

* Add test
2026-10-21 10:32:15 +02:00
Martin Gross 876566759d Stripe: Reenable Continue button for Affirm/Klarna even if CC-element is not present 2026-10-21 10:05:34 +02:00
Christiaan de Die le Clercq c6a0e06e87 Translations: Update Dutch
Currently translated at 96.9% (6247 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/nl/

powered by weblate
2026-10-20 12:09:18 +02:00
Martin Gross 39e4a6c9f7 Translations: Update Luxembourgish
Currently translated at 25.1% (1619 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/lb/

powered by weblate
2026-10-20 12:09:18 +02:00
Martin Gross 431bd038fc Translations: Update German
Currently translated at 100.0% (260 of 260 strings)

Translation: pretix/pretix (JavaScript parts)
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix-js/de/

powered by weblate
2026-10-20 12:09:18 +02:00
Martin Gross 2374a33424 Translations: Update German (informal) (de_Informal)
Currently translated at 100.0% (6442 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de_Informal/

powered by weblate
2026-10-20 12:09:18 +02:00
Martin Gross 463de6ae12 Translations: Update German
Currently translated at 100.0% (6442 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de/

powered by weblate
2026-10-20 12:09:18 +02:00
Jakob 117b300c86 Translations: Update Luxembourgish
Currently translated at 25.1% (1619 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/lb/

powered by weblate
2026-10-20 12:09:18 +02:00
Jakob 36d7f684c3 Translations: Update German
Currently translated at 100.0% (260 of 260 strings)

Translation: pretix/pretix (JavaScript parts)
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix-js/de/

powered by weblate
2026-10-20 12:09:18 +02:00
Jakob 9ceab479a4 Translations: Update German (informal) (de_Informal)
Currently translated at 100.0% (6442 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de_Informal/

powered by weblate
2026-10-20 12:09:18 +02:00
Jakob 6229b4a848 Translations: Update German
Currently translated at 100.0% (6442 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de/

powered by weblate
2026-10-20 12:09:18 +02:00
dependabot[bot] 16d0f17587 Bump pycparser from 3.0 to 3.11 (#6669)
Bumps [pycparser](https://github.com/eliben/pycparser) from 3.0 to 3.11.
- [Release notes](https://github.com/eliben/pycparser/releases)
- [Commits](https://github.com/eliben/pycparser/compare/release_v3.00...release_v3.11)

---
updated-dependencies:
- dependency-name: pycparser
  dependency-version: '3.11'
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-20 12:03:58 +02:00
dependabot[bot] a1f012805a Update pypdf requirement from ==6.19.* to ==6.20.* (#6670)
Updates the requirements on [pypdf](https://github.com/py-pdf/pypdf) to permit the latest version.
- [Release notes](https://github.com/py-pdf/pypdf/releases)
- [Changelog](https://github.com/py-pdf/pypdf/blob/main/CHANGELOG.md)
- [Commits](https://github.com/py-pdf/pypdf/compare/6.19.0...6.20.0)

---
updated-dependencies:
- dependency-name: pypdf
  dependency-version: 6.20.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-20 12:03:47 +02:00
Martin Gross b5ae2ccb25 PayPal2: CCID3 messaging (#6679) 2026-10-20 11:01:37 +02:00
Richard Schreiber f196417005 Fix customer export for no attendee_name available (#6676) 2026-10-19 15:20:41 +02:00
Lukas Bockstaller 090a73d02a migrate to new peppol lookup endpoints (#6677)
https://openpeppol.atlassian.net/wiki/spaces/PTPUB/pages/5059608580/SML+Insourcing
2026-10-19 11:08:32 +02:00
Lukas Bockstaller e4b29f56a4 updates mark_oder_expired() docstring to match reality (#6675) 2026-10-16 16:45:15 +02:00
pajowu 531758d444 Save OutgoingMail guid generated by mail() (#6674) 2026-10-16 10:34:48 +02:00
pajowu b1ec585fc8 Add attendee_name_for_salutation-Placeholder (Z#23249905) (#6666) 2026-10-16 10:34:28 +02:00
pajowu a076461eae Add missing presale_has_ended_text to EventIndex context (Z#23249717) (#6663)
Seems to have been lost in merge conflict https://github.com/pretix/pretix/commit/5ffb1f469e8f066269b407a64502353792041786
2026-10-16 10:34:06 +02:00
pajowu 8048859fb4 Match typeahead event ordering to organizer event list (Z#23249032) (#6661) 2026-10-16 10:33:39 +02:00
Martin Gross 2e4e60db34 Stripe: Enable Wero 2026-10-14 10:10:44 +02:00
Raphael Michel 6b7f2ad684 API: Fix PATCH on item addon sets without min_count or max_count (fixes #6650) (#6651) 2026-10-10 09:53:49 +02:00
dependabot[bot] 54b249acf5 Update pycryptodome requirement from ==3.23.* to ==3.24.* (#6657)
Updates the requirements on [pycryptodome](https://github.com/Legrandin/pycryptodome) to permit the latest version.
- [Release notes](https://github.com/Legrandin/pycryptodome/releases)
- [Changelog](https://github.com/Legrandin/pycryptodome/blob/master/Changelog.rst)
- [Commits](https://github.com/Legrandin/pycryptodome/compare/v3.23.0...v3.24.0)

---
updated-dependencies:
- dependency-name: pycryptodome
  dependency-version: 3.24.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-09 22:56:43 +02:00
dependabot[bot] 0cf2ba763b Update sphinxcontrib-httpdomain requirement from ~=2.0.0 to ~=2.1.0 (#6660)
Updates the requirements on [sphinxcontrib-httpdomain](https://github.com/sphinx-contrib/httpdomain) to permit the latest version.
- [Release notes](https://github.com/sphinx-contrib/httpdomain/releases)
- [Changelog](https://github.com/sphinx-contrib/httpdomain/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/sphinx-contrib/httpdomain/compare/2.0.0...2.1.0)

---
updated-dependencies:
- dependency-name: sphinxcontrib-httpdomain
  dependency-version: 2.1.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-09 22:56:27 +02:00
dependabot[bot] b44c3d707e Update fakeredis requirement from ==2.38.* to ==2.39.* (#6654)
Updates the requirements on [fakeredis](https://github.com/cunla/fakeredis-py) to permit the latest version.
- [Release notes](https://github.com/cunla/fakeredis-py/releases)
- [Commits](https://github.com/cunla/fakeredis-py/compare/v2.38.0...v2.39.0)

---
updated-dependencies:
- dependency-name: fakeredis
  dependency-version: 2.39.0
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-09 22:56:17 +02:00
dependabot[bot] 45603c6624 Update css-inline requirement from ==0.21.* to ==0.22.* (#6655)
Updates the requirements on [css-inline](https://github.com/Stranger6667/css-inline) to permit the latest version.
- [Release notes](https://github.com/Stranger6667/css-inline/releases)
- [Changelog](https://github.com/Stranger6667/css-inline/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Stranger6667/css-inline/compare/c-v0.21.0...c-v0.22.0)

---
updated-dependencies:
- dependency-name: css-inline
  dependency-version: 0.22.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-09 22:56:13 +02:00
Richard Schreiber ba36d649c6 Fix sendmail migration activating plugin on events (#6656) 2026-10-08 12:35:41 +02:00
Richard Schreiber ca90b2af09 Fix prefix for event notifications (#6653) 2026-10-08 10:09:38 +02:00
Phin Wolkwitz fe43862fa4 Sendmail: Handle scheduled mails in inactive plugin (Z#23243588) (#6587)
* Activate plugin where rules are currently active (migration)
* Check if plugin is active before sending mails
* Disable rules when the plugin gets (manually) uninstalled
2026-10-07 10:33:16 +02:00
Raphael MichelandRichard Schreiber 411cd764a6 Order changes: Log more information about taxes (#6637)
* Order changes: Log more information about taxes

* Apply batched suggestions from code review

Co-authored-by: Richard Schreiber <wiffbi@gmail.com>

* Add to tax_rule change as well

---------

Co-authored-by: Richard Schreiber <wiffbi@gmail.com>
2026-10-07 09:28:35 +02:00
6618e3a039 Organizer-level notifications (#6462)
* Organizer-level notifications

* Update signals

* Update signal docs

* Add tests

* Apply batched suggestions from code review

Co-authored-by: Richard Schreiber <wiffbi@gmail.com>

* Update src/pretix/base/models/organizer.py

Co-authored-by: Richard Schreiber <schreiber@pretix.eu>

---------

Co-authored-by: Richard Schreiber <wiffbi@gmail.com>
Co-authored-by: Richard Schreiber <schreiber@pretix.eu>
2026-10-07 09:28:15 +02:00
Richard Schreiber b7cd97c33e API: fix payment confirm if request.data is empty string (#6634)
* API: fix payment confirm if request.data is empty string

* fix fallback value
2026-10-07 09:21:30 +02:00
dependabot[bot] eae3229e68 Update pytest-mock requirement from ==3.15.* to ==3.16.* (#6628)
Updates the requirements on [pytest-mock](https://github.com/pytest-dev/pytest-mock) to permit the latest version.
- [Release notes](https://github.com/pytest-dev/pytest-mock/releases)
- [Changelog](https://github.com/pytest-dev/pytest-mock/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-mock/compare/v3.15.0...v3.16.0)

---
updated-dependencies:
- dependency-name: pytest-mock
  dependency-version: 3.16.0
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-07 09:13:05 +02:00
Raphael Michel d291cd02e7 Docs: Fix invalid example of i18n string 2026-10-07 08:55:26 +02:00
dependabot[bot] e5dcb50229 Bump @vue/server-renderer and vue (#6646)
Bumps [@vue/server-renderer](https://github.com/vuejs/core/tree/HEAD/packages/server-renderer) to 3.5.43 and updates ancestor dependency [vue](https://github.com/vuejs/core). These dependencies need to be updated together.


Updates `@vue/server-renderer` from 3.5.30 to 3.5.43
- [Release notes](https://github.com/vuejs/core/releases)
- [Changelog](https://github.com/vuejs/core/blob/main/CHANGELOG.md)
- [Commits](https://github.com/vuejs/core/commits/v3.5.43/packages/server-renderer)

Updates `vue` from 3.5.30 to 3.5.43
- [Release notes](https://github.com/vuejs/core/releases)
- [Changelog](https://github.com/vuejs/core/blob/main/CHANGELOG.md)
- [Commits](https://github.com/vuejs/core/compare/v3.5.30...v3.5.43)

---
updated-dependencies:
- dependency-name: "@vue/server-renderer"
  dependency-version: 3.5.43
  dependency-type: indirect
- dependency-name: vue
  dependency-version: 3.5.43
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-07 08:54:01 +02:00
dependabot[bot] 9d333bc2cf Update cryptography requirement from >=50.0.1 to >=50.0.2 (#6648)
Updates the requirements on [cryptography](https://github.com/pyca/cryptography) to permit the latest version.
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/50.0.1...50.0.2)

---
updated-dependencies:
- dependency-name: cryptography
  dependency-version: 50.0.2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-06 22:33:33 +02:00
dependabot[bot] 45038d07f3 Bump django-filter from 26.1 to 26.2 (#6647)
Bumps [django-filter](https://github.com/carltongibson/django-filter) from 26.1 to 26.2.
- [Release notes](https://github.com/carltongibson/django-filter/releases)
- [Changelog](https://github.com/carltongibson/django-filter/blob/main/CHANGES.rst)
- [Commits](https://github.com/carltongibson/django-filter/compare/26.1...26.2)

---
updated-dependencies:
- dependency-name: django-filter
  dependency-version: '26.2'
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-06 22:33:30 +02:00
dependabot[bot] 00f0dfec88 Bump postcss-selector-parser from 7.1.5 to 7.1.6 (#6644)
Bumps [postcss-selector-parser](https://github.com/postcss/postcss-selector-parser) from 7.1.5 to 7.1.6.
- [Release notes](https://github.com/postcss/postcss-selector-parser/releases)
- [Changelog](https://github.com/postcss/postcss-selector-parser/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss-selector-parser/compare/7.1.5...7.1.6)

---
updated-dependencies:
- dependency-name: postcss-selector-parser
  dependency-version: 7.1.6
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-06 22:30:52 +02:00
dependabot[bot] 1975a9d891 Bump source-map-js from 1.2.1 to 1.2.2 (#6645)
Bumps [source-map-js](https://github.com/7rulnik/source-map-js) from 1.2.1 to 1.2.2.
- [Release notes](https://github.com/7rulnik/source-map-js/releases)
- [Changelog](https://github.com/7rulnik/source-map-js/blob/main/CHANGELOG.md)
- [Commits](https://github.com/7rulnik/source-map-js/compare/v1.2.1...v1.2.2)

---
updated-dependencies:
- dependency-name: source-map-js
  dependency-version: 1.2.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-06 22:30:42 +02:00
dependabot[bot] 02b9b6941d Bump smol-toml from 1.7.1 to 1.9.0 (#6643)
Bumps [smol-toml](https://github.com/squirrelchat/smol-toml) from 1.7.1 to 1.9.0.
- [Release notes](https://github.com/squirrelchat/smol-toml/releases)
- [Commits](https://github.com/squirrelchat/smol-toml/compare/v1.7.1...v1.9.0)

---
updated-dependencies:
- dependency-name: smol-toml
  dependency-version: 1.9.0
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-06 22:30:34 +02:00
dependabot[bot] da2ac6c386 Update tlds requirement from >=2026072401 to >=2026093003 (#6642)
Updates the requirements on [tlds](https://github.com/kichik/tlds) to permit the latest version.
- [Commits](https://github.com/kichik/tlds/commits)

---
updated-dependencies:
- dependency-name: tlds
  dependency-version: '2026093003'
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-06 11:39:19 +02:00
Hijiri Umemoto b9fbe699ab Translations: Update Japanese
Currently translated at 100.0% (6442 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/ja/

powered by weblate
2026-10-06 11:04:53 +02:00
Oksigenia 8e3f3cc8c8 Translations: Update Spanish
Currently translated at 100.0% (260 of 260 strings)

Translation: pretix/pretix (JavaScript parts)
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix-js/es/

powered by weblate
2026-10-06 11:04:53 +02:00
Oksigenia 945f80b288 Translations: Update Spanish
Currently translated at 100.0% (6442 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/es/

powered by weblate
2026-10-06 11:04:53 +02:00
Translate pretix user 594 25799da70d Translations: Update Russian
Currently translated at 25.9% (1672 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/ru/

powered by weblate
2026-10-06 11:04:53 +02:00
Nate Horst 6b01023d16 Translations: Update Thai
Currently translated at 100.0% (260 of 260 strings)

Translation: pretix/pretix (JavaScript parts)
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix-js/th/

powered by weblate
2026-10-06 11:04:53 +02:00
Nate Horst 98644db976 Translations: Update Thai
Currently translated at 100.0% (6442 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/th/

powered by weblate
2026-10-06 11:04:53 +02:00
Translate pretix user 594 814ae7f4d9 Translations: Update Russian
Currently translated at 44.6% (116 of 260 strings)

Translation: pretix/pretix (JavaScript parts)
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix-js/ru/

powered by weblate
2026-10-06 11:04:53 +02:00
Translate pretix user 594 ae39a1e112 Translations: Update Russian
Currently translated at 25.9% (1670 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/ru/

powered by weblate
2026-10-06 11:04:53 +02:00
Translate pretix user 594 61b94f1128 Translations: Update Russian
Currently translated at 41.9% (109 of 260 strings)

Translation: pretix/pretix (JavaScript parts)
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix-js/ru/

powered by weblate
2026-10-06 11:04:53 +02:00
Translate pretix user 594 dbb586ad5a Translations: Update Russian
Currently translated at 24.3% (1569 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/ru/

powered by weblate
2026-10-06 11:04:53 +02:00
Nate Horst 295b0443fb Translations: Update Thai
Currently translated at 99.9% (6441 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/th/

powered by weblate
2026-10-06 11:04:53 +02:00
Nate Horst 31031225d3 Translations: Update Thai
Currently translated at 97.7% (6299 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/th/

powered by weblate
2026-10-06 11:04:53 +02:00
Nate Horst d600115ea5 Translations: Update Thai
Currently translated at 95.2% (6134 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/th/

powered by weblate
2026-10-06 11:04:53 +02:00
CVZ-es 3d9ebb3072 Translations: Update Spanish
Currently translated at 100.0% (6442 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/es/

powered by weblate
2026-10-06 11:04:53 +02:00
CVZ-es c9667e77c3 Translations: Update French
Currently translated at 100.0% (6442 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/fr/

powered by weblate
2026-10-06 11:04:53 +02:00
Nate Horst b2b797f4d3 Translations: Update Thai
Currently translated at 83.2% (5366 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/th/

powered by weblate
2026-10-06 11:04:53 +02:00
Nate Horst 693adbc727 Translations: Update Thai
Currently translated at 81.3% (5242 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/th/

powered by weblate
2026-10-06 11:04:53 +02:00
szurofkamarciidfbe08444ef04788 8d9840be8d Translations: Update Hungarian
Currently translated at 98.7% (6364 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/hu/

powered by weblate
2026-10-06 11:04:53 +02:00
Raphael Michel 73c0c61b6d Translations: Update Swedish
Currently translated at 98.4% (256 of 260 strings)

Translation: pretix/pretix (JavaScript parts)
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix-js/sv/

powered by weblate
2026-10-06 11:04:53 +02:00
Raphael Michel a813269d1f Translations: Update Swedish
Currently translated at 85.4% (5503 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/sv/

powered by weblate
2026-10-06 11:04:53 +02:00
Translate pretix user 594 d6bc1fa977 Translations: Update Russian
Currently translated at 38.8% (101 of 260 strings)

Translation: pretix/pretix (JavaScript parts)
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix-js/ru/

powered by weblate
2026-10-06 11:04:53 +02:00
Translate pretix user 594 249edfa2c4 Translations: Update Russian
Currently translated at 20.5% (1322 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/ru/

powered by weblate
2026-10-06 11:04:53 +02:00
dependabot[bot] 0c28151d30 Update sentry-sdk requirement from ==2.70.* to ==2.71.* (#6632)
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.70.0...2.71.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-06 10:59:40 +02:00
pajowu 5bb3b7e35e Fix help_text showing as 'None' in orderimport&permissions (#6631) 2026-10-06 10:12:27 +02:00
Richard Schreiber 4119d04fba Add border to and increase text-contrast on disabled button (#6622)
* Add border to and increase text-contrast on disabled button

* Do not add border to disabled btn-link

* Add background to disabled button to further distinguish
2026-10-02 09:15:05 +02:00
84858bc048 Allow mails to be sent to addon-attendees (Z#23213551) (#6235)
Remove restrictions that prevent mails to be sent to addon-product-attendees while reducing amount of mails sent to the same email-addresses

Co-authored-by: Richard Schreiber <schreiber@rami.io>
Co-authored-by: Kara Engelhardt <engelhardt@pretix.eu>
2026-10-01 13:13:55 +02:00
Raphael Michel e8c091741b Invoice export: Fix crash PRETIXEU-FGE 2026-10-01 11:43:36 +02:00
Richard Schreiber ebdfd21b0f Fix JavaScript error description passing HTML (#6630) 2026-10-01 11:28:36 +02:00
pajowuandRichard Schreiber ed0b3cab7f Fix addon legend overlapping with profile checkbox (Z#23247075) (#6568)
* Fix addon legend overlapping with profile checkbox (Z#23247075)

* Update src/pretix/static/pretixpresale/scss/_checkout.scss

Co-authored-by: Richard Schreiber <schreiber@pretix.eu>

---------

Co-authored-by: Richard Schreiber <schreiber@pretix.eu>
2026-10-01 09:49:23 +02:00
Richard Schreiber 3dd8cc5862 PDF Editor: select newly created element after insert (#6596)
* PDF Editor: select newly created element after insert

* Do not create so many savepoints
2026-09-30 12:19:03 +02:00
dependabot[bot] 23e9ca8f34 Bump brace-expansion (#6625)
Bumps  and [brace-expansion](https://github.com/juliangruber/brace-expansion). These dependencies needed to be updated together.

Updates `brace-expansion` from 5.0.4 to 5.0.12
- [Release notes](https://github.com/juliangruber/brace-expansion/releases)
- [Commits](https://github.com/juliangruber/brace-expansion/compare/v5.0.4...v5.0.12)

Updates `brace-expansion` from 2.0.2 to 2.1.7
- [Release notes](https://github.com/juliangruber/brace-expansion/releases)
- [Commits](https://github.com/juliangruber/brace-expansion/compare/v5.0.4...v5.0.12)

---
updated-dependencies:
- dependency-name: brace-expansion
  dependency-version: 5.0.12
  dependency-type: indirect
- dependency-name: brace-expansion
  dependency-version: 2.1.7
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-30 10:53:41 +02:00
Raphael Michel e19afd39fb Bump version to 2026.9.0.dev0 2026-09-30 10:50:09 +02:00
Raphael Michel f7863c9fee Bump version to 2026.8.0 2026-09-30 10:50:03 +02:00
Raphael Michel fc3150fecc Revert "DE: Update Wordlist"
This reverts commit 89318bcc24.
2026-09-30 10:49:57 +02:00
Martin Gross 89318bcc24 DE: Update Wordlist 2026-09-30 10:24:13 +02:00
dependabot[bot] a388391f06 Update pyjwt requirement from ==2.14.* to ==2.15.* (#6620) 2026-09-30 10:12:38 +02:00
Raphael Michel b4d000379c Translations: Update German (informal) (de_Informal)
Currently translated at 100.0% (6442 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de_Informal/

powered by weblate
2026-09-30 10:10:52 +02:00
Phin Wolkwitz ba9bba49c6 Translations: Update German (informal) (de_Informal)
Currently translated at 100.0% (6442 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de_Informal/

powered by weblate
2026-09-30 10:10:52 +02:00
Daniel Musketa 824624cce6 Translations: Update German (informal) (de_Informal)
Currently translated at 100.0% (6442 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de_Informal/

powered by weblate
2026-09-30 10:10:52 +02:00
Phin Wolkwitz 8601f62581 Translations: Update German
Currently translated at 100.0% (6442 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de/

powered by weblate
2026-09-30 10:10:52 +02:00
Daniel Musketa 7547d64dea Translations: Update German
Currently translated at 100.0% (6442 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de/

powered by weblate
2026-09-30 10:10:52 +02:00
Matthias Schrumpf d1186c83ef Translations: Update German
Currently translated at 100.0% (6442 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de/

powered by weblate
2026-09-30 10:10:52 +02:00
Raphael Michel e4782ff217 Translations: Update German
Currently translated at 100.0% (6442 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de/

powered by weblate
2026-09-30 10:10:52 +02:00
Matthias Schrumpf 3328dc28c7 Translations: Update German
Currently translated at 100.0% (6442 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de/

powered by weblate
2026-09-30 10:10:52 +02:00
Raphael Michel 6c83b4288a Translations: Update German (informal) (de_Informal)
Currently translated at 100.0% (6442 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de_Informal/

powered by weblate
2026-09-30 10:10:52 +02:00
Raphael Michel 6ff37796c3 Translations: Update German
Currently translated at 100.0% (6442 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de/

powered by weblate
2026-09-30 10:10:52 +02:00
Raphael Michel fa60c320b9 Translations: Update German (informal) (de_Informal)
Currently translated at 100.0% (6442 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de_Informal/

powered by weblate
2026-09-30 10:10:52 +02:00
Raphael Michel ca9d9faef4 Translations: Update German
Currently translated at 100.0% (6442 of 6442 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de/

powered by weblate
2026-09-30 10:10:52 +02:00
Raphael Michel 9718d1ee83 Translations: Update wordlist 2026-09-30 10:09:23 +02:00
pajowu 7bdb2c1555 Email: always use quoted-printable (#6617) 2026-09-30 09:54:21 +02:00
Raphael Michel da6753b53f Update po files
[CI skip]

Signed-off-by: Raphael Michel <michel@pretix.eu>
2026-09-30 09:26:26 +02:00
CVZ-es 33df9d13be Translations: Update French
Currently translated at 100.0% (6419 of 6419 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/fr/

powered by weblate
2026-09-30 09:25:43 +02:00
Nate Horst 582f9ac642 Translations: Update Thai
Currently translated at 81.1% (5206 of 6419 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/th/

powered by weblate
2026-09-30 09:25:00 +02:00
Translate pretix user 594 5ce2957965 Translations: Update Russian
Currently translated at 20.0% (1285 of 6419 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/ru/

powered by weblate
2026-09-30 09:25:00 +02:00
Ыукпун eb9d6ad9a3 Translations: Update Russian
Currently translated at 20.0% (1285 of 6419 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/ru/

powered by weblate
2026-09-30 09:25:00 +02:00
Raphael Michel d339e1d594 Hotfix: Perform validation on the selected step, not on all steps before 2026-09-29 20:11:51 +02:00
Raphael Michel cb15559ac6 Scheduled export: Fix copying of email subject and text (Z#23221224) (#6616) 2026-09-29 16:44:42 +02:00
pajowu 3c95f1fee7 Add HERMA 9012 90 x 90mm Badge format (Z#23248189) (#6619) 2026-09-29 16:44:02 +02:00
Richard Schreiber 6a380c9356 Presale: add js-helper to disable submit for x seconds (#6592)
* Presale: add js-helper to disable submit for x seconds

* Remove disabled-class from button, if any

* Use Intl.RelativeTimeFormat for time formatting
2026-09-29 16:36:09 +02:00
Kara Engelhardt eeea01b31a Fix linter errors 2026-09-29 15:34:26 +02:00
Kara Engelhardt 470621b5cb Add missing licenseheader 2026-09-29 15:34:23 +02:00
dependabot[bot] 5802153101 Update sentry-sdk requirement from ==2.69.* to ==2.70.* (#6600)
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.69.0...2.70.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-29 15:33:24 +02:00
Nate Horst e9f89d5d92 Translations: Update Thai
Currently translated at 70.0% (4494 of 6419 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/th/

powered by weblate
2026-09-29 15:33:15 +02:00
Nate Horst 695689ed06 Translations: Update Thai
Currently translated at 98.8% (257 of 260 strings)

Translation: pretix/pretix (JavaScript parts)
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix-js/th/

powered by weblate
2026-09-29 15:33:15 +02:00
Nate Horst 12d405d861 Translations: Update Thai
Currently translated at 69.5% (4463 of 6419 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/th/

powered by weblate
2026-09-29 15:33:15 +02:00
Nate Horst 649eee3025 Translations: Update Thai
Currently translated at 65.8% (4230 of 6419 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/th/

powered by weblate
2026-09-29 15:33:15 +02:00
Tim 149b4f23aa Translations: Update Spanish
Currently translated at 100.0% (6419 of 6419 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/es/

powered by weblate
2026-09-29 15:33:15 +02:00
Nate Horst fa40ccc623 Translations: Update Thai
Currently translated at 55.9% (3593 of 6419 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/th/

powered by weblate
2026-09-29 15:33:15 +02:00
Mira Weller 2ba74b1697 Fix various redirects for events on MODE_ORG_ALT_DOMAIN 2026-09-29 14:34:49 +02:00
Mira Weller e54cd6af44 Fix redirect to customer login page when:
- event on custom domain (MODE_EVENT_DOMAIN or MODE_ORG_ALT_DOMAIN)
- organizer on system domain
2026-09-29 14:34:49 +02:00
Mira Weller d2b58d428e Fix customer logout when:
- event on custom domain (MODE_EVENT_DOMAIN or MODE_ORG_ALT_DOMAIN)
- organizer on system domain
2026-09-29 14:34:49 +02:00
Raphael Michel 74332faa7b [SECURITY] API: Fix session validation for uploaded files (CVE-2026-101269, Z#23247174) 2026-09-29 14:30:54 +02:00
Mira Weller bbf391f7d5 Block out of bounds image crop dimensions (Z#23245937 / PRT-009) 2026-09-29 14:30:54 +02:00
Mira Weller d78d5b52fa Prevent parsing non-standard-compliant JSON float values (Z#23245937 / PRT-021) 2026-09-29 14:30:54 +02:00
Mira Weller 9c0fef3d72 Fix potential infinite loop in pdf render (Z#23245937 / PRT-021) 2026-09-29 14:30:54 +02:00
Mira Weller c7d6630979 Fix inefficient loop in compute_validity (Z#23245937 / PRT-013) 2026-09-29 14:30:53 +02:00
Raphael Michel 4edd3c4654 [SECURITY] OAuth: Disable existing tokens when deactivating Application (CVE-2026-101271, Z#23247296) 2026-09-29 14:30:53 +02:00
Mira Weller b1ae638394 [SECURITY] Escape help texts (CVE-2026-101270) 2026-09-29 14:30:53 +02:00
Raphael Michel ae9bb68645 [SECURITY] Fix customer session fixation on cross-domain login (CVE-2026-101268, Z#23247268) 2026-09-29 14:30:53 +02:00
Raphael Michel 48f5a7c8cc [SECURITY] Fix information leak in widgets.json on dashboard (CVE-2026-101267, Z#23247172)
Thanks to Wenhao Wu, Southeast University
2026-09-29 14:30:53 +02:00
Raphael Michel d43032274b [SECURITY] Fix checkout validation bypass (CVE-2026-101266, Z#23245008) 2026-09-29 14:30:53 +02:00
Raphael Michel ae9a744fd9 Revert "Always base64-encode email attachments (Z#23242540) (#6476)"
This reverts commit ff4d3cd403.
2026-09-29 14:07:57 +02:00
pajowu ff4d3cd403 Always base64-encode email attachments (Z#23242540) (#6476)
It might sound unneccesary to base64-encode plaintext attachments, but some smtp providers modify them otherwise
2026-09-29 12:27:43 +02:00
pajowu 3440ee16f2 Plugin List: Apply search filter if prefilled by browser (#6543)
* Plugin List: Apply searchfilter if prefilled by browser

Browsers often prefill the form fields, e.g. with their old content when reloading or going back from the previous page. However these filters were not applied until you changed one of the form fields

* Fix linting errors in plugins.js

* Apply review suggestions
2026-09-29 11:51:29 +02:00
pajowu 43e5b62db3 Banktransfer: Make actionvie atomic (Z#23246414) (#6604) 2026-09-29 11:51:12 +02:00
dependabot[bot] b249c7b417 Bump markdown from 3.10.3 to 3.11 (#6608)
Bumps [markdown](https://github.com/Python-Markdown/markdown) from 3.10.3 to 3.11.
- [Release notes](https://github.com/Python-Markdown/markdown/releases)
- [Changelog](https://github.com/Python-Markdown/markdown/blob/master/docs/changelog.md)
- [Commits](https://github.com/Python-Markdown/markdown/compare/3.10.3...3.11.0)

---
updated-dependencies:
- dependency-name: markdown
  dependency-version: '3.11'
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-29 10:17:48 +02:00
dependabot[bot] b68c324389 Update flake8 requirement from ==7.3.* to ==7.4.* (#6609)
Updates the requirements on [flake8](https://github.com/pycqa/flake8) to permit the latest version.
- [Commits](https://github.com/pycqa/flake8/compare/7.3.0...7.4.1)

---
updated-dependencies:
- dependency-name: flake8
  dependency-version: 7.4.1
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-29 10:17:29 +02:00
Aodhán Burke 4b320b6dab Fix typo: then -> than (#6615) 2026-09-29 10:16:54 +02:00
Richard Schreiber df74cbf5fc Remove Vue2-based widget (#6610)
* Remove Vue2-based widget

* move floatformat.js

* Delete docready.js

* Update widget.py
2026-09-29 10:14:21 +02:00
pajowu c875d758f9 Fix crash on too old time machine date (Z#23245824) (#6599)
* Fix crash on too old time machine date (Z#23245824)

dateutil.parser seems to reject dates with second-precision timezone-offsets, which datetime produces for some dates aroung the year 200. datetime.fromisoformat has no problem parsing them

* Review comments

* Add min date
2026-09-28 17:28:26 +02:00
Martin Gross 2ebdd048c2 PayPal2: Drop maximum length of client ID (Rel: #6424) 2026-09-28 16:12:55 +02:00
Raphael Michel ca40b09080 Fix API documentation bug 2026-09-28 15:46:41 +02:00
pajowuandRaphael Michel 558bf910fd Use fragment_product_list in voucher redemption view (Z#23246929) (#6567)
* Use fragment_product_list in voucher redemption view (Z#23246929)

* Formatting

* Fix usage in templates

* Review comments

* handle form prefix in fragment_product_list.html

---------

Co-authored-by: Raphael Michel <michel@pretix.eu>
2026-09-28 13:01:15 +02:00
pajowu 7e1e472691 Monkeypatch stock csrfmiddleware (#6401)
* Monkeypatch stock csrfmiddleware

* Add test for ensure_csrf_cookie
2026-09-28 11:46:23 +02:00
Richard Schreiber b06c9ef463 Control: do not fail on missing reason when user confirm (#6602) 2026-09-28 11:43:52 +02:00
pajowu 2af8d29ca9 Add pdf render tests (#6566)
* Add pdf tests

* pdf tests: Save temporary pdfs for failed test debugging

* Review comments
2026-09-25 16:54:58 +02:00
Raphael Michel 2791d5e49e Celery: Fix missing log if workers are recycled due to RAM usage (#6588) 2026-09-25 08:56:49 +02:00
288 changed files with 38067 additions and 30666 deletions

No files matched your search

+1
View File
@@ -42,6 +42,7 @@ recursive-include src *.py
recursive-include src *.svg
recursive-include src *.txt
recursive-include src Makefile
recursive-include src *.pdf
recursive-exclude doc *
recursive-exclude deployment *
+1 -1
View File
@@ -173,7 +173,7 @@ Datetime String in ISO 8601 format ``"2017-12-27T10:00:00Z"``
with timezone (normally UTC) ``"2017-12-27T10:00:00.596934Z"``,
``"2017-12-27T10:00:00+02:00"``
Date String in ISO 8601 format ``2017-12-27``
Multi-lingual string Object of strings ``{"en": "red", "de": "rot", "de_Informal": "rot"}``
Multi-lingual string Object of strings ``{"en": "red", "de": "rot", "de-informal": "rot"}``
Money String with decimal number ``"23.42"``
Currency String with ISO 4217 code ``"EUR"``, ``"USD"``
Relative datetime *either* String in ISO 8601 ``"2017-12-27T10:00:00.596934Z"``,
+1 -1
View File
@@ -56,7 +56,7 @@ calculated automatically.
},
"answers": [
{
"question": 1,
"datafield": "A1B2C3D4",
"answer": "23",
"options": []
}
+18 -8
View File
@@ -3,6 +3,14 @@
Cart positions
==============
.. note::
This API is affected by an upcoming larger change to our API. The API documentation already reflects the future
version. Features or fields not yet available are marked with **NEW**.
The new version is expected to be released for hosted pretix early December and for self-hosted pretix with
version 2027.1.
You can find more information `on our blog <https://pretix.eu/about/en/blog/20261110-questionnaires/>`_.
The API provides limited access to the cart position data model. This API currently only allows creating and deleting
cart positions to reserve quota.
@@ -31,12 +39,13 @@ voucher integer Internal ID of
addon_to integer Internal ID of the position this position is an add-on for (or ``null``)
is_bundled boolean If ``addon_to`` is set, this shows whether this is a bundled product or an addon product
subevent integer ID of the date inside an event series this position belongs to (or ``null``)
answers list of objects Answers to user-defined questions
├ question integer Internal ID of the answered question
answers list of objects Values of data fields (answers to user-defined questions)
├ datafield string **NEW** The data field's ``identifier`` (internal reference)
├ answer string Text representation of the answer
├ question_identifier string The question's ``identifier`` field
├ options list of integers Internal IDs of selected option(s)s (only for choice types)
└ option_identifiers list of strings The ``identifier`` fields of the selected option(s)s
├ option_identifiers list of strings The ``identifier`` fields of the selected option(s)s
├ question integer **Deprecated.** Internal ID of the data field
└ question_identifier string **Read-only, deprecated.** The data field's ``identifier`` (internal reference)
seat objects The assigned seat (or ``null``)
├ id integer Internal ID of the seat instance
├ name string Human-readable seat name
@@ -199,7 +208,8 @@ Cart position endpoints
* ``bundled`` (optional, expect a list of nested objects of cart positions)
* ``answers``
* ``question``
* ``datafield`` **NEW**
* ``question`` **DEPRECATED**
* ``answer``
* ``options``
@@ -223,7 +233,7 @@ Cart position endpoints
"attendee_email": null,
"answers": [
{
"question": 1,
"datafield": "A1B2C3D4",
"answer": "23",
"options": []
}
@@ -285,7 +295,7 @@ Cart position endpoints
"attendee_email": null,
"answers": [
{
"question": 1,
"datafield": "A1B2C3D4",
"answer": "23",
"options": []
}
@@ -303,7 +313,7 @@ Cart position endpoints
"attendee_email": null,
"answers": [
{
"question": 1,
"datafield": "A1B2C3D4",
"answer": "23",
"options": []
}
+38 -27
View File
@@ -5,6 +5,14 @@
Check-in
========
.. note::
This API is affected by an upcoming larger change to our API. The API documentation already reflects the future
version. Features or fields not yet available are marked with **NEW**.
The new version is expected to be released for hosted pretix early December and for self-hosted pretix with
version 2027.1.
You can find more information `on our blog <https://pretix.eu/about/en/blog/20261110-questionnaires/>`_.
This page describes special APIs built for ticket scanning apps. For managing check-in configuration or other operations,
please also see :ref:`rest-checkinlists`. The check-in list API also contains endpoints to obtain statistics or log
failed scans.
@@ -24,39 +32,43 @@ Checking a ticket in
passed needs to be from a distinct event.
:query string expand: Expand a field inside the ``position`` object into a full object. Currently ``subevent``, ``item``, ``variation``, and ``answers.question`` are supported. Can be passed multiple times.
:<json string secret: Scanned QR code corresponding to the ``secret`` attribute of a ticket.
:<json string source_type: Type of source the ``secret`` was obtained form. Defaults to ``"barcode"``.
:<json array lists: List of check-in list IDs to search on. No two check-in lists may be from the same event.
:<json string type: Send ``"exit"`` for an exit and ``"entry"`` (default) for an entry.
:<json datetime datetime: Specifies the datetime of the check-in. If not supplied, the current time will be used.
:<json boolean force: Specifies that the check-in should succeed regardless of revoked barcode, previous check-ins or required
:>json string secret: Scanned QR code corresponding to the ``secret`` attribute of a ticket.
:>json string source_type: Type of source the ``secret`` was obtained form. Defaults to ``"barcode"``.
:>json array lists: List of check-in list IDs to search on. No two check-in lists may be from the same event.
:>json string type: Send ``"exit"`` for an exit and ``"entry"`` (default) for an entry.
:>json datetime datetime: Specifies the datetime of the check-in. If not supplied, the current time will be used.
:>json boolean force: Specifies that the check-in should succeed regardless of revoked barcode, previous check-ins or required
questions that have not been filled. This is usually used to upload offline scans that already happened,
because there's no point in validating them since they happened whether they are valid or not. Defaults to ``false``.
:<json boolean questions_supported: When this parameter is set to ``true``, handling of questions is supported. If
:>json boolean questions_supported: When this parameter is set to ``true``, handling of questions is supported. If
you do not implement question handling in your user interface, you **must**
set this to ``false``. In that case, questions will just be ignored. Defaults
to ``true``.
:<json boolean ignore_unpaid: Specifies that the check-in should succeed even if the order is in pending state.
:>json boolean ignore_unpaid: Specifies that the check-in should succeed even if the order is in pending state.
Defaults to ``false`` and only works when ``include_pending`` is set on the check-in
list.
:<json object answers: If questions are supported/required, you may/must supply a mapping of question IDs to their
respective answers. The answers should always be strings. In case of (multiple-)choice-type
:>json object answers: If questions are supported/required, you may/must supply a mapping of ``identifier`` (`internal
reference`) of data fields to their respective answers (**NEW**).
For backwards compatibility, a mapping of data field ``id`` to answer is supported, as well.
The answers should always be strings. In case of (multiple-)choice-type
answers, the string should contain the (comma-separated) IDs of the selected options.
:<json string nonce: You can set this parameter to a unique random value to identify this check-in. If you're sending
:>json string nonce: You can set this parameter to a unique random value to identify this check-in. If you're sending
this request twice with the same nonce, the second request will also succeed but will always
create only one check-in object even when the previous request was successful as well. This
allows for a certain level of idempotency and enables you to re-try after a connection failure.
:<json string exchange_medium_type: To perform an exchange to a reusable medium, pass the type of the new reusable medium
:<json string exchange_medium_identifier: To perform an exchange to a reusable media, pass the identifier of the new medium
:<json boolean use_order_locale: Specifies that pretix should use the customer's language (``locale`` field from the
:>json string exchange_medium_type: To perform an exchange to a reusable medium, pass the type of the new reusable medium
:>json string exchange_medium_identifier: To perform an exchange to a reusable media, pass the identifier of the new medium
:>json boolean use_order_locale: Specifies that pretix should use the customer's language (``locale`` field from the
order) when building texts (currently only the ``reason_explanation`` response field).
Defaults to ``false`` in which case the server will determine the language (currently
the event default language, might change in the future with support for the
``Accept-Language`` header).
:>json string status: ``"ok"``, ``"incomplete"``, ``"exchange"``, or ``"error"``
:>json string reason: Reason code, only set on status ``"error"``, see below for possible values.
:>json string reason_explanation: Human-readable explanation, only set on status ``"error"`` and reason ``"rules"``, can be null.
:>json object position: Copy of the matching order position (if any was found). The contents are the same as the
:>json boolean simulate: Do not actually perform the check-in, only simulate the response. The ``position`` response
object will not reflect the simulated changes.
:<json string status: ``"ok"``, ``"incomplete"``, ``"exchange"``, or ``"error"``
:<json string reason: Reason code, only set on status ``"error"``, see below for possible values.
:<json string reason_explanation: Human-readable explanation, only set on status ``"error"`` and reason ``"rules"``, can be null.
:<json object position: Copy of the matching order position (if any was found). The contents are the same as the
:ref:`order-position-resource`, with the following differences: (1) The ``checkins`` value
will only include check-ins for the selected list. (2) An additional boolean property
``require_attention`` will inform you whether either the order or the item have the
@@ -64,15 +76,13 @@ Checking a ticket in
back to values from a parent product or from invoice addresses. (4) Additional properties
``order__status``, ``order__valid_if_pending``, ``order__require_approval``, and
``order__locale`` are included with details form the order for convenience.
:>json boolean require_attention: Whether or not the ``require_attention`` flag is set on the item or order.
:>json list checkin_texts: List of additional texts to show to the user.
:>json object list: Excerpt of information about the matching :ref:`check-in list <rest-checkinlists>` (if any was found),
:<json boolean require_attention: Whether or not the ``require_attention`` flag is set on the item or order.
:<json list checkin_texts: List of additional texts to show to the user.
:<json object list: Excerpt of information about the matching :ref:`check-in list <rest-checkinlists>` (if any was found),
including the attributes ``id``, ``name``, ``event``, ``subevent``, and ``include_pending``.
:>json object questions: List of questions to be answered for check-in, only set on status ``"incomplete"``.
:>json object media_policy: Reusable media policy (see documentation on items), only set on status ``"exchange"``.
:>json object media_type: Reusable media type (see documentation on items), only set on status ``"exchange"``.
:>json boolean simulate: Do not actually perform the check-in, only simulate the response. The ``position`` response
object will not reflect the simulated changes.
:<json object questions: List of questions to be answered for check-in, only set on status ``"incomplete"``.
:<json object media_policy: Reusable media policy (see documentation on items), only set on status ``"exchange"``.
:<json object media_type: Reusable media type (see documentation on items), only set on status ``"exchange"``.
**Example request**:
@@ -92,7 +102,7 @@ Checking a ticket in
"datetime": null,
"questions_supported": true,
"answers": {
"4": "XS"
"A1B2C3D4": "XS"
}
}
@@ -318,6 +328,7 @@ Performing a ticket search
],
"answers": [
{
"datafield": "A1B2C3D4",
"question": 12,
"answer": "Foo",
"options": []
+21 -10
View File
@@ -5,6 +5,14 @@
Check-in lists
==============
.. note::
This API is affected by an upcoming larger change to our API. The API documentation already reflects the future
version. Features or fields not yet available are marked with **NEW**.
The new version is expected to be released for hosted pretix early December and for self-hosted pretix with
version 2027.1.
You can find more information `on our blog <https://pretix.eu/about/en/blog/20261110-questionnaires/>`_.
Resource description
--------------------
@@ -569,6 +577,7 @@ Order position endpoints
],
"answers": [
{
"datafield": "A1B2C3D4",
"question": 12,
"answer": "Foo",
"options": []
@@ -609,27 +618,29 @@ Order position endpoints
:query boolean untrusted_input: If set to true, the lookup parameter is **always** interpreted as a ``secret``, never
as an ``id``. This should be always set if you are passing through untrusted, scanned
data to avoid guessing of ticket IDs.
:<json boolean questions_supported: When this parameter is set to ``true``, handling of questions is supported. If
:>json boolean questions_supported: When this parameter is set to ``true``, handling of questions is supported. If
you do not implement question handling in your user interface, you **must**
set this to ``false``. In that case, questions will just be ignored. Defaults
to ``true``.
:<json boolean canceled_supported: When this parameter is set to ``true``, the response code ``canceled`` may be
:>json boolean canceled_supported: When this parameter is set to ``true``, the response code ``canceled`` may be
returned. Otherwise, canceled orders will return ``unpaid``. (**Deprecated**, in
the future, this will be ignored and ``canceled`` may always be returned.)
:<json datetime datetime: Specifies the datetime of the check-in. If not supplied, the current time will be used.
:<json boolean force: Specifies that the check-in should succeed regardless of revoked barcode, previous check-ins or required
:>json datetime datetime: Specifies the datetime of the check-in. If not supplied, the current time will be used.
:>json boolean force: Specifies that the check-in should succeed regardless of revoked barcode, previous check-ins or required
questions that have not been filled. This is usually used to upload offline scans that already happened,
because there's no point in validating them since they happened whether they are valid or not. Defaults to ``false``.
:<json string type: Send ``"exit"`` for an exit and ``"entry"`` (default) for an entry.
:<json boolean ignore_unpaid: Specifies that the check-in should succeed even if the order is in pending state.
:>json string type: Send ``"exit"`` for an exit and ``"entry"`` (default) for an entry.
:>json boolean ignore_unpaid: Specifies that the check-in should succeed even if the order is in pending state.
Defaults to ``false`` and only works when ``include_pending`` is set on the check-in
list.
:<json string nonce: You can set this parameter to a unique random value to identify this check-in. If you're sending
:>json string nonce: You can set this parameter to a unique random value to identify this check-in. If you're sending
this request twice with the same nonce, the second request will also succeed but will always
create only one check-in object even when the previous request was successful as well. This
allows for a certain level of idempotency and enables you to re-try after a connection failure.
:<json object answers: If questions are supported/required, you may/must supply a mapping of question IDs to their
respective answers. The answers should always be strings. In case of (multiple-)choice-type
:>json object answers: If questions are supported/required, you may/must supply a mapping of ``identifier`` (`internal
reference`) of data fields to their respective answers (**NEW**).
For backwards compatibility, a mapping of data field ``id`` to answer is supported, as well.
The answers should always be strings. In case of (multiple-)choice-type
answers, the string should contain the (comma-separated) IDs of the selected options.
**Example request**:
@@ -648,7 +659,7 @@ Order position endpoints
"questions_supported": true,
"canceled_supported": true,
"answers": {
"4": "XS"
"A1B2C3D4": "XS"
}
}
+250
View File
@@ -0,0 +1,250 @@
.. _rest-datafieldoptions:
Data field options
================
.. note::
This API is part of an upcoming larger change to our API. The API documentation already reflects the future
version. Until the change, this resource is still available at ``/questions/(id)/options/``.
The new version is expected to be released for hosted pretix early December and for self-hosted pretix with
version 2027.1.
You can find more information `on our blog <https://pretix.eu/about/en/blog/20261110-questionnaires/>`_.
Resource description
--------------------
:ref:`Data fields <rest-datafields>` of type "choice" or "multiple choice" can have different options attached.
As with data fields, data field options exist on two resource paths, depending on whether
the data field is attached to orders or order positions. Therefore, each endpoint below has two
different URLs.
The options resource contains the following public fields:
.. rst-class:: rest-resource-table
===================================== ========================== =======================================================
Field Type Description
===================================== ========================== =======================================================
id integer Internal ID of the option
position integer An integer, used for sorting
identifier string An arbitrary string that can be used for matching with
other sources.
answer multi-lingual string The displayed value of this option
===================================== ========================== =======================================================
Endpoints
---------
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/datafields/position/(datafield)/options/
/api/v1/organizers/(organizer)/events/(event)/datafields/order/(datafield)/options/
Returns a list of all options for a given data field.
**Example request**:
.. sourcecode:: http
GET /api/v1/organizers/bigevents/events/sampleconf/datafields/position/11/options/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Vary: Accept
Content-Type: application/json
{
"count": 2,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"identifier": "LVETRWVU",
"position": 1,
"answer": {"en": "S"}
},
{
"id": 2,
"identifier": "DFEMJWMJ",
"position": 2,
"answer": {"en": "M"}
},
{
"id": 3,
"identifier": "W9AH7RDE",
"position": 3,
"answer": {"en": "L"}
}
]
}
:query integer page: The page number in case of a multi-page result set, default is 1
:query boolean active: If set to ``true`` or ``false``, only data fields with this value for the field ``active`` will be
returned.
:param organizer: The ``slug`` field of the organizer to fetch
:param event: The ``slug`` field of the event to fetch
:param datafield: The ``id`` field of the data field to fetch
:statuscode 200: no error
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer/event/data field does not exist **or** you have no permission to view this resource.
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/datafields/position/(datafield)/options/(id)/
/api/v1/organizers/(organizer)/events/(event)/datafields/order/(datafield)/options/(id)/
Returns information on one option, identified by its ID.
**Example request**:
.. sourcecode:: http
GET /api/v1/organizers/bigevents/events/sampleconf/datafields/position/1/options/1/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Vary: Accept
Content-Type: application/json
{
"id": 1,
"identifier": "LVETRWVU",
"position": 1,
"answer": {"en": "S"}
}
:param organizer: The ``slug`` field of the organizer to fetch
:param event: The ``slug`` field of the event to fetch
:param datafield: The ``id`` field of the data field to fetch
:param id: The ``id`` field of the option to fetch
:statuscode 200: no error
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/datafields/position/(datafield)/options/
/api/v1/organizers/(organizer)/events/(event)/datafields/order/(datafield)/options/
Create a new option
**Example request**:
.. sourcecode:: http
POST /api/v1/organizers/bigevents/events/sampleconf/datafields/position/1/options/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
Content-Type: application/json
{
"identifier": "LVETRWVU",
"position": 1,
"answer": {"en": "S"}
}
**Example response**:
.. sourcecode:: http
HTTP/1.1 201 Created
Vary: Accept
Content-Type: application/json
{
"id": 1,
"identifier": "LVETRWVU",
"position": 1,
"answer": {"en": "S"}
}
:param organizer: The ``slug`` field of the organizer of the event/data field to create a option for
:param event: The ``slug`` field of the event to create a option for
:param datafield: The ``id`` field of the data field to create a option for
:statuscode 201: no error
:statuscode 400: The option could not be created due to invalid submitted data.
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to create this resource.
.. http:patch:: /api/v1/organizers/(organizer)/events/(event)/datafields/position/(datafield)/options/(id)/
/api/v1/organizers/(organizer)/events/(event)/datafields/order/(datafield)/options/(id)/
Update an option. You can also use ``PUT`` instead of ``PATCH``. With ``PUT``, you have to provide all fields of
the resource, other fields will be reset to default. With ``PATCH``, you only need to provide the fields that you
want to change.
You can change all fields of the resource except the ``id`` field.
**Example request**:
.. sourcecode:: http
PATCH /api/v1/organizers/bigevents/events/sampleconf/datafields/position/1/options/1/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
Content-Type: application/json
Content-Length: 94
{
"position": 3
}
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Vary: Accept
Content-Type: application/json
{
"id": 1,
"identifier": "LVETRWVU",
"position": 1,
"answer": {"en": "S"}
}
:param organizer: The ``slug`` field of the organizer to modify
:param event: The ``slug`` field of the event to modify
:param id: The ``id`` field of the data field to modify
:param id: The ``id`` field of the option to modify
:statuscode 200: no error
:statuscode 400: The option could not be modified due to invalid submitted data
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to change this resource.
.. http:delete:: /api/v1/organizers/(organizer)/events/(event)/datafields/position/(datafield)/options/(id)/
/api/v1/organizers/(organizer)/events/(event)/datafields/order/(datafield)/options/(id)/
Delete an option.
**Example request**:
.. sourcecode:: http
DELETE /api/v1/organizers/bigevents/events/sampleconf/datafields/position/1/options/1/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
**Example response**:
.. sourcecode:: http
HTTP/1.1 204 No Content
Vary: Accept
:param organizer: The ``slug`` field of the organizer to modify
:param event: The ``slug`` field of the event to modify
:param datafield: The ``id`` field of the data field to modify
:param id: The ``id`` field of the option to delete
:statuscode 204: no error
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to delete this resource.
+428
View File
@@ -0,0 +1,428 @@
.. _rest-datafields:
Data fields
=========
.. note::
This API is part of an upcoming larger change to our API. The API documentation already reflects the future
version. Until the change, please keep using the endpoints at ``/questions/``.
The new version is expected to be released for hosted pretix early December and for self-hosted pretix with
version 2027.1.
You can find more information `on our blog <https://pretix.eu/about/en/blog/20261110-questionnaires/>`_.
Resource description
--------------------
Data fields define additional fields related to an order or an order position.
By referencing data fields in a questionnaire, you can have customers or staff fill them out -- during or
after checkout (web or POS), during check-in in the ticket scanner app, or in the backend.
There are two different resource paths for data fields, depending on whether the data field is attached
to orders or order positions. Therefore, each endpoint below has two different URLs.
The data field resource contains the following public fields:
.. rst-class:: rest-resource-table
===================================== ========================== =======================================================
Field Type Description
===================================== ========================== =======================================================
id integer Internal ID of the data field
internal_name string **Required.** An internal field label
identifier string An arbitrary string that can be used for matching with
other sources.
Must be unique per event, across all types of data fields.
type string **Required.** The expected type of data. Valid options:
* ``N`` – number
* ``S`` – one-line string
* ``T`` – multi-line string
* ``B`` – boolean
* ``C`` – choice from a list
* ``M`` – multiple choice from a list
* ``F`` – file upload
* ``D`` – date
* ``H`` – time
* ``W`` – date and time
* ``CC`` – country code (ISO 3666-1 alpha-2)
* ``TEL`` – telephone number
show_during_checkin boolean If ``true``, the value of the data field will be shown
during check-in (if the check-in client supports it).
*Only supported on per-position data fields.*
print_on_invoice boolean If ``true``, the data field will be shown on
invoices.
*Only supported on per-position data fields.*
print_on_invoice_label multi-lingual string **Required if ``print_on_invoice`` is ``true``.** Label
to print on the invoice before the value of this field.
Otherwise `null`.
options list of objects In case of data field type ``C`` or ``M``, this lists the
available objects. Only writable during creation,
use :ref:`separate endpoint <rest-datafieldoptions>` to modify this later.
├ id integer Internal ID of the option
├ position integer An integer, used for sorting
├ identifier string An arbitrary string that can be used for matching with
other sources.
└ answer multi-lingual string The displayed value of this option
valid_number_min string Minimum value for number fields (optional)
valid_number_max string Maximum value for number fields (optional)
valid_date_min date Minimum value for date fields (optional)
valid_date_max date Maximum value for date fields (optional)
valid_datetime_min datetime Minimum value for date and time fields (optional)
valid_datetime_max datetime Maximum value for date and time fields (optional)
valid_file_portrait boolean Turn on file validation for portrait photos
valid_string_length_min integer Minimum length for string fields (optional)
valid_string_length_max integer Maximum length for string fields (optional)
referenced_by_questionnaires list of integers **Read-only.** List of questionnaire IDs that reference
this data field
===================================== ========================== =======================================================
Endpoints
---------
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/datafields/position/
/api/v1/organizers/(organizer)/events/(event)/datafields/order/
Returns a list of all data fields within a given event.
**Example request**:
.. sourcecode:: http
GET /api/v1/organizers/bigevents/events/sampleconf/datafields/position/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Vary: Accept
Content-Type: application/json
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"internal_name": "T-Shirt size",
"type": "C",
"identifier": "WY3TP9SL",
"show_during_checkin": false,
"print_on_invoice": false,
"print_on_invoice_label": null,
"valid_number_min": null,
"valid_number_max": null,
"valid_date_min": null,
"valid_date_max": null,
"valid_datetime_min": null,
"valid_datetime_max": null,
"valid_string_length_min": null,
"valid_string_length_max": null,
"valid_file_portrait": false,
"options": [
{
"id": 1,
"identifier": "LVETRWVU",
"position": 0,
"answer": {"en": "S"}
},
{
"id": 2,
"identifier": "DFEMJWMJ",
"position": 1,
"answer": {"en": "M"}
},
{
"id": 3,
"identifier": "W9AH7RDE",
"position": 2,
"answer": {"en": "L"}
}
],
"referenced_by_questionnaires": [1]
}
]
}
:query integer page: The page number in case of a multi-page result set, default is 1
:query string ordering: Manually set the ordering of results. Valid fields to be used are ``id`` and ``position``.
Default: ``position``
:query string identifier: Only return questions with the given identifier string
:query boolean ask_during_checkin: Only return questions that are or are not to be asked during check-in
:query boolean required: Only return questions that are or are not required to fill in
:param organizer: The ``slug`` field of the organizer to fetch
:param event: The ``slug`` field of the event to fetch
:statuscode 200: no error
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/datafields/position/(id)/
/api/v1/organizers/(organizer)/events/(event)/datafields/order/(id)/
Returns information on one data field, identified by its ID.
**Example request**:
.. sourcecode:: http
GET /api/v1/organizers/bigevents/events/sampleconf/datafields/position/1/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Vary: Accept
Content-Type: application/json
{
"id": 1,
"internal_name": "T-Shirt size",
"type": "C",
"identifier": "WY3TP9SL",
"show_during_checkin": false,
"print_on_invoice": false,
"print_on_invoice_label": null,
"valid_number_min": null,
"valid_number_max": null,
"valid_date_min": null,
"valid_date_max": null,
"valid_datetime_min": null,
"valid_datetime_max": null,
"valid_string_length_min": null,
"valid_string_length_max": null,
"valid_file_portrait": false,
"options": [
{
"id": 1,
"identifier": "LVETRWVU",
"position": 0,
"answer": {"en": "S"}
},
{
"id": 2,
"identifier": "DFEMJWMJ",
"position": 1,
"answer": {"en": "M"}
},
{
"id": 3,
"identifier": "W9AH7RDE",
"position": 2,
"answer": {"en": "L"}
}
],
"referenced_by_questionnaires": [1]
}
:param organizer: The ``slug`` field of the organizer to fetch
:param event: The ``slug`` field of the event to fetch
:param id: The ``id`` field of the question to fetch
:statuscode 200: no error
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/datafields/position/
/api/v1/organizers/(organizer)/events/(event)/datafields/order/
Create a new question
**Example request**:
.. sourcecode:: http
POST /api/v1/organizers/bigevents/events/sampleconf/datafields/position/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
Content-Type: application/json
{
"internal_name": "T-Shirt size",
"type": "C",
"show_during_checkin": false,
"print_on_invoice": false,
"print_on_invoice_label": null,
"options": [
{
"answer": {"en": "S"}
},
{
"answer": {"en": "M"}
},
{
"answer": {"en": "L"}
}
]
}
**Example response**:
.. sourcecode:: http
HTTP/1.1 201 Created
Vary: Accept
Content-Type: application/json
{
"id": 1,
"internal_name": "T-Shirt size",
"type": "C",
"identifier": "WY3TP9SL",
"show_during_checkin": false,
"print_on_invoice": false,
"print_on_invoice_label": null,
"valid_number_min": null,
"valid_number_max": null,
"valid_date_min": null,
"valid_date_max": null,
"valid_datetime_min": null,
"valid_datetime_max": null,
"valid_string_length_min": null,
"valid_string_length_max": null,
"valid_file_portrait": false,
"options": [
{
"id": 1,
"identifier": "LVETRWVU",
"position": 0,
"answer": {"en": "S"}
},
{
"id": 2,
"identifier": "DFEMJWMJ",
"position": 1,
"answer": {"en": "M"}
},
{
"id": 3,
"identifier": "W9AH7RDE",
"position": 2,
"answer": {"en": "L"}
}
],
"referenced_by_questionnaires": [1]
}
:param organizer: The ``slug`` field of the organizer of the event to create an item for
:param event: The ``slug`` field of the event to create an item for
:statuscode 201: no error
:statuscode 400: The item could not be created due to invalid submitted data.
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to create this resource.
.. http:patch:: /api/v1/organizers/(organizer)/events/(event)/datafields/position/(id)/
/api/v1/organizers/(organizer)/events/(event)/datafields/order/(id)/
Update a data field. You can also use ``PUT`` instead of ``PATCH``. With ``PUT``, you have to provide all fields of
the resource, other fields will be reset to default. With ``PATCH``, you only need to provide the fields that you
want to change.
You can change all fields of the resource except the ``options`` field. If
you need to update/delete options please use the nested dedicated endpoints.
**Example request**:
.. sourcecode:: http
PATCH /api/v1/organizers/bigevents/events/sampleconf/datafields/position/1/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
Content-Type: application/json
Content-Length: 94
{
"internal_name": "Clothing size"
}
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Vary: Accept
Content-Type: application/json
{
"id": 1,
"internal_name": "Clothing size",
"type": "C",
"identifier": "WY3TP9SL",
"show_during_checkin": false,
"print_on_invoice": false,
"print_on_invoice_label": null,
"valid_number_min": null,
"valid_number_max": null,
"valid_date_min": null,
"valid_date_max": null,
"valid_datetime_min": null,
"valid_datetime_max": null,
"valid_string_length_min": null,
"valid_string_length_max": null,
"valid_file_portrait": false,
"options": [
{
"id": 1,
"identifier": "LVETRWVU",
"position": 0,
"answer": {"en": "S"}
},
{
"id": 2,
"identifier": "DFEMJWMJ",
"position": 1,
"answer": {"en": "M"}
},
{
"id": 3,
"identifier": "W9AH7RDE",
"position": 2,
"answer": {"en": "L"}
}
],
"referenced_by_questionnaires": [1]
}
:param organizer: The ``slug`` field of the organizer to modify
:param event: The ``slug`` field of the event to modify
:param id: The ``id`` field of the question to modify
:statuscode 200: no error
:statuscode 400: The question could not be modified due to invalid submitted data
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to change this resource.
.. http:delete:: /api/v1/organizers/(organizer)/events/(event)/datafields/position/(id)/
/api/v1/organizers/(organizer)/events/(event)/datafields/order/(id)/
Delete a data field.
**Example request**:
.. sourcecode:: http
DELETE /api/v1/organizers/bigevents/events/sampleconf/datafields/position/1/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
**Example response**:
.. sourcecode:: http
HTTP/1.1 204 No Content
Vary: Accept
:param organizer: The ``slug`` field of the organizer to modify
:param event: The ``slug`` field of the event to modify
:param id: The ``id`` field of the question to delete
:statuscode 204: no error
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to delete this resource.
+3
View File
@@ -21,6 +21,9 @@ at :ref:`plugin-docs`.
item_add-ons
item_meta_properties
item_program_times
datafields
datafield_options
questionnaires
questions
question_options
quotas
+13 -5
View File
@@ -37,12 +37,9 @@ tax_rule integer The internal
admission boolean ``true`` for items that grant admission to the event
(such as primary tickets) and ``false`` for others
(such as add-ons or merchandise).
personalized boolean ``true`` for items that require personalization according
personalized boolean **DEPRECATED.** ``true`` for items that require personalization according
to event settings. Only affects system-level fields, not
custom questions. Currently only allowed for products with
``admission`` set to ``true``. For backwards compatibility,
when creating new items and this field is not given, it defaults
to the same value as ``admission``.
custom questions. Defaults to ``false``.
position integer An integer, used for sorting
picture file A product picture to be displayed in the shop
(can be ``null``).
@@ -233,6 +230,17 @@ meta_data object Values set fo
The ``program_times`` attribute has been added.
.. versionchanged:: 2027.1
The ``personalized`` attribute has been deprecated.
For compatibility with existing applications:
* When retrieving products, `personalized` is `True` if any attached questionnaire asks for `attendee_name` and/or `attendee_email`.
* When creating a new product, setting the `personalized` field to `True` will attach the "Attendee data" questionnaire to the new product. If no such questionnaire exists, it will be created.
Before, the `personalized` field defaulted to the same value as `admission`. Now, it defaults to `false`.
* When updating a product, the `personalized` field cannot be changed, returning an HTTP 400 error if attempted.
Notes
-----
+63 -12
View File
@@ -9,6 +9,14 @@
Orders
======
.. note::
This API is affected by an upcoming larger change to our API. The API documentation already reflects the future
version. Features or fields not yet available are marked with **NEW**.
The new version is expected to be released for hosted pretix early December and for self-hosted pretix with
version 2027.1.
You can find more information `on our blog <https://pretix.eu/about/en/blog/20261110-questionnaires/>`_.
Order resource
--------------
@@ -119,6 +127,11 @@ cancellation_date datetime Time of order c
plugin_data object Additional data added by plugins.
use_gift_cards list of strings List of unique gift card secrets that are used to pay
for this order.
answers list of objects **NEW** Values of data fields (answers to user-defined questions)
├ datafield string The data field's ``identifier`` (internal reference)
├ answer string Text representation of the answer
├ options list of integers Internal IDs of selected option(s)s (only for choice types)
└ option_identifiers list of strings The ``identifier`` fields of the selected option(s)s
===================================== ========================== =======================================================
@@ -162,6 +175,10 @@ use_gift_cards list of strings List of unique
The ``use_gift_cards`` attribute has been added.
.. versionchanged:: 2027.1
The ``answers`` attribute has been added.
.. _order-position-resource:
Order position resource
@@ -231,12 +248,13 @@ print_logs list of objects List of print j
downloads list of objects List of ticket download options
├ output string Ticket output provider (e.g. ``pdf``, ``passbook``)
└ url string Download URL
answers list of objects Answers to user-defined questions
├ question integer Internal ID of the answered question
├ answer string Text representation of the answer (URL if answer is a file)
├ question_identifier string The question's ``identifier`` field
answers list of objects Values of data fields (answers to user-defined questions)
├ datafield string **NEW** The data field's ``identifier`` (internal reference)
├ answer string Text representation of the answer
├ options list of integers Internal IDs of selected option(s)s (only for choice types)
└ option_identifiers list of strings The ``identifier`` fields of the selected option(s)s
├ option_identifiers list of strings The ``identifier`` fields of the selected option(s)s
├ question integer **Deprecated.** Internal ID of the data field
└ question_identifier string **Read-only, deprecated.** The data field's ``identifier`` (internal reference)
seat objects The assigned seat. Can be ``null``.
├ id integer Internal ID of the seat instance
├ name string Human-readable seat name
@@ -452,10 +470,11 @@ List of all orders
],
"answers": [
{
"datafield": "WY3TP9SL",
"question": 12,
"question_identifier": "WY3TP9SL",
"answer": "Foo",
"option_idenfiters": [],
"option_identifiers": [],
"options": []
}
],
@@ -488,7 +507,15 @@ List of all orders
],
"refunds": [],
"cancellation_date": null,
"plugin_data": {}
"plugin_data": {},
"answers": [
{
"datafield": "XYZ12345",
"answer": "42",
"option_identifiers": [],
"options": []
}
]
}
]
}
@@ -699,6 +726,7 @@ Fetching individual orders
],
"answers": [
{
"datafield": "WY3TP9SL",
"question": 12,
"question_identifier": "WY3TP9SL",
"answer": "Foo",
@@ -735,7 +763,15 @@ Fetching individual orders
],
"refunds": [],
"cancellation_date": null,
"plugin_data": {}
"plugin_data": {},
"answers": [
{
"datafield": "XYZ12345",
"answer": "42",
"option_identifiers": [],
"options": []
}
]
}
:param organizer: The ``slug`` field of the organizer to fetch
@@ -1079,7 +1115,8 @@ Creating orders
* ``discount`` (optional, only possible if ``price`` is set; attention: if this is set to not-``null`` on any position, automatic calculation of discounts will not run)
* ``answers``
* ``question``
* ``datafield`` (**NEW**)
* ``question`` (**DEPRECATED**)
* ``answer``
* ``options``
@@ -1114,6 +1151,12 @@ Creating orders
order isn't completely paid after its creation with ``use_gift_cards``, then a subsequent request to the payment
endpoint is needed.
* **NEW** ``answers`` (optional). Values for order-level data fields.
* ``datafield``
* ``answer``
* ``options``
If you want to use add-on products, you need to set the ``positionid`` fields of all positions manually
to incrementing integers starting with ``1``. Then, you can reference one of these
IDs in the ``addon_to`` field of another position. Note that all add_ons for a specific position need to come
@@ -1161,6 +1204,12 @@ Creating orders
"internal_reference": "",
"vat_id": ""
},
"answers": [
{
"datafield": "XYZ12345",
"answer": "42"
}
],
"positions": [
{
"positionid": 1,
@@ -1174,7 +1223,7 @@ Creating orders
"addon_to": null,
"answers": [
{
"question": 1,
"datafield": "WY3TP9SL",
"answer": "23",
"options": []
}
@@ -1684,6 +1733,7 @@ List of all order positions
],
"answers": [
{
"datafield": "WY3TP9SL",
"question": 12,
"question_identifier": "WY3TP9SL",
"answer": "Foo",
@@ -1863,6 +1913,7 @@ Fetching individual positions
],
"answers": [
{
"datafield": "WY3TP9SL",
"question": 12,
"question_identifier": "WY3TP9SL",
"answer": "Foo",
@@ -1971,7 +2022,7 @@ Manipulating individual positions
* ``answers``: If specified, you will need to provide **all** answers for this order position.
Validation is handled the same way as when creating orders through the API. You are therefore
expected to provide ``question``, ``answer``, and possibly ``options``. ``question_identifier``
expected to provide ``datafield``, ``answer``, and possibly ``options``. ``question`` is deprecated. ``question_identifier``
and ``option_identifiers`` will be ignored. As a special case, you can submit the magic value
``"file:keep"`` as the answer to a file question to keep the current value without re-uploading it.
@@ -2067,7 +2118,7 @@ Manipulating individual positions
* ``state``
* ``answers``: Validation is handled the same way as when creating orders through the API. You are therefore
expected to provide ``question``, ``answer``, and possibly ``options``. ``question_identifier``
expected to provide ``datafield``, ``answer``, and possibly ``options``. ``question`` is deprecated. ``question_identifier``
and ``option_identifiers`` will be ignored. As a special case, you can submit the magic value
``"file:keep"`` as the answer to a file question to keep the current value without re-uploading it.
+2 -224
View File
@@ -1,229 +1,7 @@
Question options
================
Resource description
--------------------
.. warning:: This resource is **deprecated**.
Questions of type "choice" or "multiple choice" can have different options attached.
The options resource contains the following public fields:
New applications must use the :ref:`rest-datafieldoptions` resource.
.. rst-class:: rest-resource-table
===================================== ========================== =======================================================
Field Type Description
===================================== ========================== =======================================================
id integer Internal ID of the option
position integer An integer, used for sorting
identifier string An arbitrary string that can be used for matching with
other sources.
answer multi-lingual string The displayed value of this option
===================================== ========================== =======================================================
Endpoints
---------
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/questions/(question)/options/
Returns a list of all options for a given question.
**Example request**:
.. sourcecode:: http
GET /api/v1/organizers/bigevents/events/sampleconf/questions/11/options/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Vary: Accept
Content-Type: application/json
{
"count": 2,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"identifier": "LVETRWVU",
"position": 1,
"answer": {"en": "S"}
},
{
"id": 2,
"identifier": "DFEMJWMJ",
"position": 2,
"answer": {"en": "M"}
},
{
"id": 3,
"identifier": "W9AH7RDE",
"position": 3,
"answer": {"en": "L"}
}
]
}
:query integer page: The page number in case of a multi-page result set, default is 1
:query boolean active: If set to ``true`` or ``false``, only questions with this value for the field ``active`` will be
returned.
:param organizer: The ``slug`` field of the organizer to fetch
:param event: The ``slug`` field of the event to fetch
:param question: The ``id`` field of the question to fetch
:statuscode 200: no error
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer/event/question does not exist **or** you have no permission to view this resource.
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/questions/(question)/options/(id)/
Returns information on one option, identified by its ID.
**Example request**:
.. sourcecode:: http
GET /api/v1/organizers/bigevents/events/sampleconf/questions/1/options/1/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Vary: Accept
Content-Type: application/json
{
"id": 1,
"identifier": "LVETRWVU",
"position": 1,
"answer": {"en": "S"}
}
:param organizer: The ``slug`` field of the organizer to fetch
:param event: The ``slug`` field of the event to fetch
:param question: The ``id`` field of the question to fetch
:param id: The ``id`` field of the option to fetch
:statuscode 200: no error
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/questions/(question)/options/
Creates a new option
**Example request**:
.. sourcecode:: http
POST /api/v1/organizers/bigevents/events/sampleconf/questions/1/options/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
Content-Type: application/json
{
"identifier": "LVETRWVU",
"position": 1,
"answer": {"en": "S"}
}
**Example response**:
.. sourcecode:: http
HTTP/1.1 201 Created
Vary: Accept
Content-Type: application/json
{
"id": 1,
"identifier": "LVETRWVU",
"position": 1,
"answer": {"en": "S"}
}
:param organizer: The ``slug`` field of the organizer of the event/question to create a option for
:param event: The ``slug`` field of the event to create a option for
:param question: The ``id`` field of the question to create a option for
:statuscode 201: no error
:statuscode 400: The option could not be created due to invalid submitted data.
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to create this resource.
.. http:patch:: /api/v1/organizers/(organizer)/events/(event)/questions/(question)/options/(id)/
Update an option. You can also use ``PUT`` instead of ``PATCH``. With ``PUT``, you have to provide all fields of
the resource, other fields will be reset to default. With ``PATCH``, you only need to provide the fields that you
want to change.
You can change all fields of the resource except the ``id`` field.
**Example request**:
.. sourcecode:: http
PATCH /api/v1/organizers/bigevents/events/sampleconf/questions/1/options/1/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
Content-Type: application/json
Content-Length: 94
{
"position": 3
}
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Vary: Accept
Content-Type: application/json
{
"id": 1,
"identifier": "LVETRWVU",
"position": 1,
"answer": {"en": "S"}
}
:param organizer: The ``slug`` field of the organizer to modify
:param event: The ``slug`` field of the event to modify
:param id: The ``id`` field of the question to modify
:param id: The ``id`` field of the option to modify
:statuscode 200: no error
:statuscode 400: The option could not be modified due to invalid submitted data
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to change this resource.
.. http:delete:: /api/v1/organizers/(organizer)/events/(event)/questions/(id)/options/(id)/
Delete an option.
**Example request**:
.. sourcecode:: http
DELETE /api/v1/organizers/bigevents/events/sampleconf/questions/1/options/1/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
**Example response**:
.. sourcecode:: http
HTTP/1.1 204 No Content
Vary: Accept
:param organizer: The ``slug`` field of the organizer to modify
:param event: The ``slug`` field of the event to modify
:param id: The ``id`` field of the question to modify
:param id: The ``id`` field of the option to delete
:statuscode 204: no error
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to delete this resource.
+379
View File
@@ -0,0 +1,379 @@
.. _rest-questionnaires:
Questionnaires
=========
.. note::
This API is part of an upcoming larger change to our API. The API documentation already reflects the future
version. Until the change, please keep using the endpoints at ``/questions/``.
The new version is expected to be released for hosted pretix early December and for self-hosted pretix with
version 2027.1.
You can find more information `on our blog <https://pretix.eu/about/en/blog/20261110-questionnaires/>`_.
Questionnaires are attached to one or more products, and a product can have multiple questionnaires.
They consist of questionnaire rows, each of which can be one of the following:
Reference to system field
To reference a system field, use one of the identifier strings from the table below in the row's `datafield` attribute.
Currently, system fields are only defined on order positions, not on orders.
=============== =========================== ============================
Container Identifier Label
=============== =========================== ============================
Order position `"@attendee_name_parts"` Attendee name
Order position `"@attendee_email"` Attendee email
Order position `"@company"` Company
Order position `"@street"` Street
Order position `"@zipcode"` ZIP code
Order position `"@city"` City
Order position `"@state"` State
Order position `"@country"` Country
=============== =========================== ============================
Reference to user-defined data field
To reference a :ref:`user-defined data field <rest-datafields>`, use its internal reference (`identifier`)
in the row's `datafield` attribute.
Static explanation text / subheading
To add a static text block, set the row's `datafield` attribute to `null`. In this case, the text
from the `label` attribute is displayed as a subheading, and the `help_text` attribute as a normal paragraph.
Resource description
--------------------
.. rst-class:: rest-resource-table
===================================== ========================== =======================================================
Field Type Description
===================================== ========================== =======================================================
id integer Internal ID of the questionnaire
type string The type of questionnaire. Valid options:
* ``order_purchase`` — Order-wide, before purchase
* ``position_purchase`` — Per product, before purchase
* ``position_attendee`` — Per product, via attendee link
* ``position_checkin`` — Per product, at check-in
* ``position_hidden`` — Per product, hidden
internal_name string Internal label for the questionnaire.
items list of integers List of item IDs this questionnaire is assigned to.
*Only supported on per-product questionnaires.*
position integer An integer, used for sorting
all_sales_channels boolean If ``true`` (default), the questions from this questionnaire
are asked on all sales channels.
limit_sales_channels list of strings List of sales channel identifiers the questions are asked on
if ``all_sales_channels`` is ``false``.
rows list of objects List of all questionnaire rows.
├ datafield string Reference to a data field (see above)
├ required boolean If ``true``, the question needs to be filled out.
├ label multi-lingual string The field label shown to the customer. In case of a static
text block, the subheading.
├ help_text multi-lingual string The help text shown to the customer.
├ dependency_datafield string ``datafield`` reference of a different row in the same
questionnaire.
The current question will only be shown if the question
given in this attribute is set to one of the values given
in ``dependency_values``.
├ dependency_values list of strings If ``dependency_datafield`` is set to reference a boolean
data field, this should be ``["True"]`` or ``["False"]``.
Otherwise, it should be a list of ``identifier`` values
of question options.
├ rendered_help_text string **Read-only.** Markdown contents from help_text rendered
to HTML
===================================== ========================== =======================================================
Endpoints
---------
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/questionnaires/
Returns a list of all questionnaires within a given event.
**Example request**:
.. sourcecode:: http
GET /api/v1/organizers/bigevents/events/sampleconf/questionnaires/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Vary: Accept
Content-Type: application/json
{
"count": 2,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"type": "position_purchase",
"internal_name": "Attendee data",
"items": [1, 2],
"position": 0,
"all_sales_channels": true,
"limit_sales_channels": [],
"rows": [
{
"datafield": "@attendee_name_parts",
"required": false,
"label": {"en": "Attendee name"},
"help_text": {},
"dependency_datafield": null,
"dependency_values": [],
"rendered_help_text": ""
},
{
"datafield": "@attendee_email",
"required": false,
"label": {"en": "Attendee email"},
"help_text": {"en": "*We'll send you our program guide a few days before the event.*"},
"dependency_datafield": null,
"dependency_values": [],
"rendered_help_text": "<em>We'll send you our program guide a few days before the event.</em>"
}
]
},
{
"id": 2,
"type": "order_purchase",
"internal_name": "Per-order questions",
"items": [],
"position": 0,
"all_sales_channels": true,
"limit_sales_channels": [],
"rows": [
{
"datafield": "87Y8DCS9",
"required": false,
"label": {"en": "How did you find us?"},
"help_text": {},
"dependency_datafield": null,
"dependency_values": [],
"rendered_help_text": ""
}
]
}
]
}
:query integer page: The page number in case of a multi-page result set, default is 1
:query string ordering: Manually set the ordering of results. Valid fields to be used are ``id`` and ``position``.
Default: ``position``
:query string type: Only return questionnaires with the given type
:query string items: Only return questionnaires associated with the given item (internal item ID)
:query boolean sales_channel: Only return questionnaires visible on the given sales channel (sales channel identifier string)
:param organizer: The ``slug`` field of the organizer to fetch
:param event: The ``slug`` field of the event to fetch
:statuscode 200: no error
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/questionnaires/(id)/
Returns information on one questionnaire, identified by its ID.
**Example request**:
.. sourcecode:: http
GET /api/v1/organizers/bigevents/events/sampleconf/questionnaires/2/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Vary: Accept
Content-Type: application/json
{
"id": 2,
"type": "order_purchase",
"internal_name": "Per-order questions",
"items": [],
"position": 0,
"all_sales_channels": true,
"limit_sales_channels": [],
"rows": [
{
"datafield": "87Y8DCS9",
"required": false,
"label": {"en": "How did you find us?"},
"help_text": {},
"dependency_datafield": null,
"dependency_values": [],
"rendered_help_text": ""
}
]
}
:param organizer: The ``slug`` field of the organizer to fetch
:param event: The ``slug`` field of the event to fetch
:param id: The ``id`` field of the questionnaire to fetch
:statuscode 200: no error
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/questionnaires/
Create a new questionnaire
**Example request**:
.. sourcecode:: http
POST /api/v1/organizers/bigevents/events/sampleconf/questionnaires/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
Content-Type: application/json
{
"type": "order_purchase",
"internal_name": "Per-order questions",
"position": 0,
"all_sales_channels": true,
"rows": [
{
"datafield": "87Y8DCS9",
"required": false,
"label": {"en": "How did you find us?"}
}
]
}
**Example response**:
.. sourcecode:: http
HTTP/1.1 201 Created
Vary: Accept
Content-Type: application/json
{
"id": 2,
"type": "order_purchase",
"internal_name": "Per-order questions",
"items": [],
"position": 0,
"all_sales_channels": true,
"limit_sales_channels": [],
"rows": [
{
"datafield": "87Y8DCS9",
"required": false,
"label": {"en": "How did you find us?"},
"help_text": {},
"dependency_datafield": null,
"dependency_values": [],
"rendered_help_text": ""
}
]
}
:param organizer: The ``slug`` field of the organizer of the event to create a questionnaire for
:param event: The ``slug`` field of the event to create a questionnaire for
:statuscode 201: no error
:statuscode 400: The questionnaire could not be created due to invalid submitted data.
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to create this resource.
.. http:patch:: /api/v1/organizers/(organizer)/events/(event)/questionnaires/(id)/
Update a questionnaire. You can also use ``PUT`` instead of ``PATCH``. With ``PUT``, you have to provide all fields of
the resource, other fields will be reset to default. With ``PATCH``, you only need to provide the fields that you
want to change.
You can only change all ``rows`` en bloc, or keep all of them unchanged in case of a ``PATCH``. If you
change ``rows``, you need to specify all fields of the resource.
**Example request**:
.. sourcecode:: http
PATCH /api/v1/organizers/bigevents/events/sampleconf/questionnaires/2/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
Content-Type: application/json
{
"internal_name": "Questions asked per order"
}
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Vary: Accept
Content-Type: application/json
{
"id": 2,
"type": "order_purchase",
"internal_name": "Questions asked per order",
"items": [],
"position": 0,
"all_sales_channels": true,
"limit_sales_channels": [],
"rows": [
{
"datafield": "87Y8DCS9",
"required": false,
"label": {"en": "How did you find us?"},
"help_text": {},
"dependency_datafield": null,
"dependency_values": [],
"rendered_help_text": ""
}
]
}
:param organizer: The ``slug`` field of the organizer of the questionnaire to modify
:param event: The ``slug`` field of the event of the questionnaire to modify
:param id: The ``id`` field of the questionnaire to modify
:statuscode 200: no error
:statuscode 400: The questionnaire could not be modified due to invalid submitted data
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to change this resource.
.. http:delete:: /api/v1/organizers/(organizer)/events/(event)/questionnaires/(id)/
Delete a questionnaire.
**Example request**:
.. sourcecode:: http
DELETE /api/v1/organizers/bigevents/events/sampleconf/questionnaires/1/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
**Example response**:
.. sourcecode:: http
HTTP/1.1 204 No Content
Vary: Accept
:param organizer: The ``slug`` field of the organizer of the questionnaire to modify
:param event: The ``slug`` field of the event of the questionnaire to modify
:param id: The ``id`` field of the questionnaire to delete
:statuscode 204: no error
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to delete this resource.
+40 -1
View File
@@ -8,10 +8,23 @@
Questions
=========
.. warning:: This resource is **deprecated**. It is only provided for compatibility with existing applications
and should not be used in new development.
New applications must use the :ref:`rest-datafields` and :ref:`rest-questionnaires` resources.
The new version is expected to be released for hosted pretix early December and for self-hosted pretix with
version 2027.1.
You can find more information `on our blog <https://pretix.eu/about/en/blog/20261110-questionnaires/>`_.
This resource will continue to work in read-only mode on events where the
:ref:`questionnaire configuration <rest-questionnaires>` is compatible with the old data model.
If incompatible configuration is detected, all endpoints return HTTP 410.
Resource description
--------------------
Questions define additional fields that need to be filled out by customers during checkout.
Questions define additional fields related to an order position that need to be filled out by customers during checkout.
The question resource contains the following public fields:
.. rst-class:: rest-resource-table
@@ -84,6 +97,10 @@ dependency_value string An old version
The ``show_during_checkin`` attribute has been added.
.. versionchanged:: 2026.[TODO]
The questions resource was deprecated and replaced by the :ref:`rest-datafields` and :ref:`rest-questionnaires` resources.
Endpoints
---------
@@ -249,6 +266,13 @@ Endpoints
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/questions/
.. warning:: This endpoint is **deprecated** and will be removed as part of an upcoming API change.
The new version is expected to be released for hosted pretix early December and for self-hosted
pretix with version 2027.1.
You can find more information `on our blog <https://pretix.eu/about/en/blog/20261110-questionnaires/>`_.
After the change, instead create a :ref:`data field <rest-datafields>` first, then add
it to a :ref:`questionnaire <rest-questionnaires>`.
Creates a new question
**Example request**:
@@ -351,6 +375,13 @@ Endpoints
.. http:patch:: /api/v1/organizers/(organizer)/events/(event)/questions/(id)/
.. warning:: This endpoint is **deprecated** and will be removed as part of an upcoming API change.
The new version is expected to be released for hosted pretix early December and for self-hosted
pretix with version 2027.1.
You can find more information `on our blog <https://pretix.eu/about/en/blog/20261110-questionnaires/>`_.
After the change, instead update the relevant :ref:`data field <rest-datafields>`, or
the reference to it inside a :ref:`questionnaire <rest-questionnaires>`.
Update a question. You can also use ``PUT`` instead of ``PATCH``. With ``PUT``, you have to provide all fields of
the resource, other fields will be reset to default. With ``PATCH``, you only need to provide the fields that you
want to change.
@@ -437,6 +468,14 @@ Endpoints
.. http:delete:: /api/v1/organizers/(organizer)/events/(event)/questions/(id)/
.. warning:: This endpoint is **deprecated** and will be removed as part of an upcoming API change.
The new version is expected to be released for hosted pretix early December and for self-hosted
pretix with version 2027.1.
You can find more information `on our blog <https://pretix.eu/about/en/blog/20261110-questionnaires/>`_.
After the change, insteadremove the questionnaire child from its :ref:`questionnaire <rest-questionnaires>`,
or delete the relevant :ref:`data field <rest-datafields>`.
Delete a question.
**Example request**:
+2 -1
View File
@@ -11,7 +11,8 @@ Core
----
.. automodule:: pretix.base.signals
:members: periodic_task, event_live_issues, event_copy_data, email_filter, register_notification_types, notification,
:members: periodic_task, event_live_issues, event_copy_data, email_filter,
register_notification_types, event_notification_sent, organizer_notification_sent,
item_copy_data, register_sales_channel_types, register_global_settings, quota_availability, global_email_filter,
register_ticket_secret_generators, gift_card_transaction_display,
register_text_placeholders, register_mail_placeholders, device_info_updated,
+2 -2
View File
@@ -1,6 +1,6 @@
sphinx==9.1.*
sphinx==9.0.*
sphinx-rtd-theme~=3.1.0
sphinxcontrib-httpdomain~=2.0.0
sphinxcontrib-httpdomain~=2.1.0
sphinxcontrib-images~=1.0.1
sphinxcontrib-jquery~=4.1
sphinxcontrib-spelling~=8.0.2
+2 -2
View File
@@ -1,7 +1,7 @@
-e ../
sphinx==9.1.*
sphinx==9.0.*
sphinx-rtd-theme~=3.1.0
sphinxcontrib-httpdomain~=2.0.0
sphinxcontrib-httpdomain~=2.1.0
sphinxcontrib-images~=1.0.1
sphinxcontrib-jquery~=4.1
sphinxcontrib-spelling~=8.0.2
-1
View File
@@ -49,7 +49,6 @@ const ignores = globalIgnores([
'src/pretix/static/pretixcontrol/js/ui/editor.js',
'src/pretix/static/pretixcontrol/js/ui/geo.js',
'src/pretix/static/pretixcontrol/js/ui/main.js',
'src/pretix/static/pretixcontrol/js/ui/plugins.js',
'src/pretix/static/pretixcontrol/js/ui/subevent.js',
'src/pretix/static/pretixcontrol/js/ui/variations.js',
'src/pretix/static/pretixcontrol/js/ui/webauthn.js',
+258 -314
View File
@@ -40,30 +40,30 @@
"license": "MIT"
},
"node_modules/@babel/helper-string-parser": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
"integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz",
"integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==",
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-identifier": {
"version": "7.28.5",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
"integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz",
"integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==",
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/parser": {
"version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz",
"integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==",
"version": "7.29.9",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.9.tgz",
"integrity": "sha512-CjXrNHTnvqBVqHgdBysY3vk2T8tpJHb5/RMeHJBTyVa9xgugCB0CJTx/3oO8RV2QRQP391RWpB7D6hLjm8V9uA==",
"license": "MIT",
"dependencies": {
"@babel/types": "^7.29.0"
"@babel/types": "^7.29.8"
},
"bin": {
"parser": "bin/babel-parser.js"
@@ -73,13 +73,13 @@
}
},
"node_modules/@babel/types": {
"version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz",
"integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==",
"version": "7.29.8",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz",
"integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==",
"license": "MIT",
"dependencies": {
"@babel/helper-string-parser": "^7.27.1",
"@babel/helper-validator-identifier": "^7.28.5"
"@babel/helper-string-parser": "^7.29.7",
"@babel/helper-validator-identifier": "^7.29.7"
},
"engines": {
"node": ">=6.9.0"
@@ -92,40 +92,6 @@
"dev": true,
"license": "(Apache-2.0 AND BSD-3-Clause)"
},
"node_modules/@emnapi/core": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
"integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"@emnapi/wasi-threads": "1.2.1",
"tslib": "^2.4.0"
}
},
"node_modules/@emnapi/runtime": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
"integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@emnapi/wasi-threads": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
"integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@eslint-community/eslint-utils": {
"version": "4.9.1",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
@@ -194,16 +160,16 @@
}
},
"node_modules/@eslint/config-array/node_modules/brace-expansion": {
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz",
"integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==",
"version": "5.0.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz",
"integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^4.0.2"
},
"engines": {
"node": "18 || 20 || >=22"
"node": "20 || >=22"
}
},
"node_modules/@eslint/config-array/node_modules/minimatch": {
@@ -378,30 +344,11 @@
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz",
"integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==",
"license": "MIT"
},
"node_modules/@napi-rs/wasm-runtime": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.5.tgz",
"integrity": "sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"@tybys/wasm-util": "^0.10.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Brooooooklyn"
},
"peerDependencies": {
"@emnapi/core": "^1.7.1",
"@emnapi/runtime": "^1.7.1"
}
},
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -441,13 +388,13 @@
}
},
"node_modules/@oxc-project/types": {
"version": "0.133.0",
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.133.0.tgz",
"integrity": "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==",
"version": "0.155.0",
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.155.0.tgz",
"integrity": "sha512-SeE8JPwW1xs1tHeNycjUtUBdhorRa8o4jlvjwk49R7/Z291i+4DQa7JJIgOm/TaYQZx+QrPQbVJ/9c8dMIZN8Q==",
"dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/Boshen"
"url": "https://github.com/sponsors/oxc-project"
}
},
"node_modules/@parcel/watcher": {
@@ -771,10 +718,27 @@
"node": ">=14"
}
},
"node_modules/@rolldown/binding-android-arm-eabi": {
"version": "1.2.15",
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.15.tgz",
"integrity": "sha512-aLcgK9gIJ3YRvrrtfSBbRa27F5WrpiTaPulnFpsHPxpUHgFlSgnU4854MHwoRGEBhfRJDWCS2WQ7lIjskE9Olw==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@rolldown/binding-android-arm64": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.3.tgz",
"integrity": "sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==",
"version": "1.2.15",
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.15.tgz",
"integrity": "sha512-xD7DdZCrbThKuxNg7ooQmvp07ys4J/pnSEMTG3/OdOWl6daC67m/Q4fL78sRHMxTH/N4fGUbYhcPM0MF5WFHkg==",
"cpu": [
"arm64"
],
@@ -789,9 +753,9 @@
}
},
"node_modules/@rolldown/binding-darwin-arm64": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.3.tgz",
"integrity": "sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==",
"version": "1.2.15",
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.15.tgz",
"integrity": "sha512-m2WuQ6r0B4OTYxyPpNLtXaMRbRDUbG8YQV2Q3KTdSSK8Th6KHCnC8jVCJt8bvYeSB5WivkkNbc85mKadaSdOxA==",
"cpu": [
"arm64"
],
@@ -806,9 +770,9 @@
}
},
"node_modules/@rolldown/binding-darwin-x64": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.3.tgz",
"integrity": "sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==",
"version": "1.2.15",
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.15.tgz",
"integrity": "sha512-5RtnsHM36nodM9WbMy+zip0LGS/G+y5wro5RHrpOlr4ac24+1zSi9kiV2MP1myZeZ/ifEHfulQcWjnAXzc2C2A==",
"cpu": [
"x64"
],
@@ -823,9 +787,9 @@
}
},
"node_modules/@rolldown/binding-freebsd-x64": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.3.tgz",
"integrity": "sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==",
"version": "1.2.15",
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.15.tgz",
"integrity": "sha512-g3l09pyFqhu+135JKkbkwiKGQmwU5hUMUPJ4VdBADvuqR8d33L6H578rh8m7rtxbdp+VmX/+nzI7nvhSZlzpUQ==",
"cpu": [
"x64"
],
@@ -840,9 +804,9 @@
}
},
"node_modules/@rolldown/binding-linux-arm-gnueabihf": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.3.tgz",
"integrity": "sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==",
"version": "1.2.15",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.15.tgz",
"integrity": "sha512-nIe3VugI97nGQtspPxDqA4sXMUpeiocKIP/CqpY/u/vgbT+alX+cVxu1C/oVBPKg4feNTmYovE91v4DgXvXNwQ==",
"cpu": [
"arm"
],
@@ -857,9 +821,9 @@
}
},
"node_modules/@rolldown/binding-linux-arm64-gnu": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.3.tgz",
"integrity": "sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==",
"version": "1.2.15",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.15.tgz",
"integrity": "sha512-iTBjXx+B5QSvgI89lJfmqh4wTh8NabR1YZIIN3hNx4zSG0EVfVqkOvLulNpG4251pbd6/IAmZ/LefVk1Y4rPhw==",
"cpu": [
"arm64"
],
@@ -877,9 +841,9 @@
}
},
"node_modules/@rolldown/binding-linux-arm64-musl": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.3.tgz",
"integrity": "sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==",
"version": "1.2.15",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.15.tgz",
"integrity": "sha512-uN26XOnVR7rqQupG3V9oAG2EGGatWjcJHOeDOHUFCh4TBWmP2tHTFoVN13aYbwfm0aHqJAEmcwhAu6sooIjfqQ==",
"cpu": [
"arm64"
],
@@ -897,9 +861,9 @@
}
},
"node_modules/@rolldown/binding-linux-ppc64-gnu": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.3.tgz",
"integrity": "sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==",
"version": "1.2.15",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.15.tgz",
"integrity": "sha512-9nWkcdd+H+XhaA3fQIwpHnKIrfx/PQ6rO0pivr78Og07tXlUlctBBJoEYLPfhTmCR/QxEVdn6uPjHV5SymPhdw==",
"cpu": [
"ppc64"
],
@@ -917,9 +881,9 @@
}
},
"node_modules/@rolldown/binding-linux-s390x-gnu": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.3.tgz",
"integrity": "sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==",
"version": "1.2.15",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.15.tgz",
"integrity": "sha512-Ggh0ciFjLwIusLSLz7LZYEaGdxOAUJXI+Qu5JCbhPJJHEt8vP+IjRATTJheiJsdzzTYgUiHUiw3X1Ea3ZpMBdA==",
"cpu": [
"s390x"
],
@@ -937,9 +901,9 @@
}
},
"node_modules/@rolldown/binding-linux-x64-gnu": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.3.tgz",
"integrity": "sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==",
"version": "1.2.15",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.15.tgz",
"integrity": "sha512-FHg60rS6DBePAYZ9X9F67x+JObFdmgn6tupA1C/a3B+CufFmTD4mX+e8M75tCiAO3foR/6xwVBI0KQiI7sn/rw==",
"cpu": [
"x64"
],
@@ -957,9 +921,9 @@
}
},
"node_modules/@rolldown/binding-linux-x64-musl": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.3.tgz",
"integrity": "sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==",
"version": "1.2.15",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.15.tgz",
"integrity": "sha512-/cvV/7v5VGz/moiz0XKRj2dE8DzsKyhIu1KpOvJGPjRywg3yscON889UGvAe8zfiJLHup7VLjBduoGWi3HusWQ==",
"cpu": [
"x64"
],
@@ -977,9 +941,9 @@
}
},
"node_modules/@rolldown/binding-openharmony-arm64": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.3.tgz",
"integrity": "sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==",
"version": "1.2.15",
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.15.tgz",
"integrity": "sha512-MyzC5Hrv/sm+Z7TSGKP/j8001RO2xQm1zOpCNVL4j0cY/VhBZviludA2YFQ7i4lH6ZAXxQm0lcMdBzM+99mE7w==",
"cpu": [
"arm64"
],
@@ -993,29 +957,10 @@
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@rolldown/binding-wasm32-wasi": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.3.tgz",
"integrity": "sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==",
"cpu": [
"wasm32"
],
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"@emnapi/core": "1.10.0",
"@emnapi/runtime": "1.10.0",
"@napi-rs/wasm-runtime": "^1.1.4"
},
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@rolldown/binding-win32-arm64-msvc": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.3.tgz",
"integrity": "sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==",
"version": "1.2.15",
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.15.tgz",
"integrity": "sha512-+PgYiS+AH5omy6L45ZLxybasauJaj3M8buoT83D+nzPmCayXlxUV9hydhciCKVyIg0B/v0BtXPDE1uGqNwCPpg==",
"cpu": [
"arm64"
],
@@ -1030,9 +975,9 @@
}
},
"node_modules/@rolldown/binding-win32-x64-msvc": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.3.tgz",
"integrity": "sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==",
"version": "1.2.15",
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.15.tgz",
"integrity": "sha512-HFZd2QNQYn1JbIi+Hpd7H+r/lkWxcfIu28nirZ6eCn2LafuvmExMlb/P96Sfx5tf7pPArw39IdhmCF8vmV+NhQ==",
"cpu": [
"x64"
],
@@ -1074,17 +1019,6 @@
"eslint": "^9.0.0 || ^10.0.0"
}
},
"node_modules/@tybys/wasm-util": {
"version": "0.10.2",
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz",
"integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@types/esrecurse": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz",
@@ -1339,16 +1273,16 @@
}
},
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz",
"integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==",
"version": "5.0.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz",
"integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^4.0.2"
},
"engines": {
"node": "18 || 20 || >=22"
"node": "20 || >=22"
}
},
"node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
@@ -1447,53 +1381,53 @@
"license": "MIT"
},
"node_modules/@vue/compiler-core": {
"version": "3.5.30",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.30.tgz",
"integrity": "sha512-s3DfdZkcu/qExZ+td75015ljzHc6vE+30cFMGRPROYjqkroYI5NV2X1yAMX9UeyBNWB9MxCfPcsjpLS11nzkkw==",
"version": "3.5.43",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.43.tgz",
"integrity": "sha512-zdiLhnbe1QQqgDT8xZMpNmyqZ3qlI+/Q/FHQco57Kwl/b05HhCzN6eVGN9QU9rbga4CrS0H5SYY8VGHZCt/1Hg==",
"license": "MIT",
"dependencies": {
"@babel/parser": "^7.29.0",
"@vue/shared": "3.5.30",
"@babel/parser": "^7.29.8",
"@vue/shared": "3.5.43",
"entities": "^7.0.1",
"estree-walker": "^2.0.2",
"source-map-js": "^1.2.1"
}
},
"node_modules/@vue/compiler-dom": {
"version": "3.5.30",
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.30.tgz",
"integrity": "sha512-eCFYESUEVYHhiMuK4SQTldO3RYxyMR/UQL4KdGD1Yrkfdx4m/HYuZ9jSfPdA+nWJY34VWndiYdW/wZXyiPEB9g==",
"version": "3.5.43",
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.43.tgz",
"integrity": "sha512-PEZoAk3NQmsn/ejMzSOCyTYqwGqczrWm70PuhBKjjv1+TCoQAaO/zOqNwjV+honlNstT5ILxtc+8r8UUfj+iEQ==",
"license": "MIT",
"dependencies": {
"@vue/compiler-core": "3.5.30",
"@vue/shared": "3.5.30"
"@vue/compiler-core": "3.5.43",
"@vue/shared": "3.5.43"
}
},
"node_modules/@vue/compiler-sfc": {
"version": "3.5.30",
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.30.tgz",
"integrity": "sha512-LqmFPDn89dtU9vI3wHJnwaV6GfTRD87AjWpTWpyrdVOObVtjIuSeZr181z5C4PmVx/V3j2p+0f7edFKGRMpQ5A==",
"version": "3.5.43",
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.43.tgz",
"integrity": "sha512-FCbrG3XNCRl+js3huuKx4IVHBLTvMkJhVepjbxSPu1gn4yWLaYtGNQdjJGZaMytXB6qb76qQDDmDSLy/vkmleQ==",
"license": "MIT",
"dependencies": {
"@babel/parser": "^7.29.0",
"@vue/compiler-core": "3.5.30",
"@vue/compiler-dom": "3.5.30",
"@vue/compiler-ssr": "3.5.30",
"@vue/shared": "3.5.30",
"@babel/parser": "^7.29.8",
"@vue/compiler-core": "3.5.43",
"@vue/compiler-dom": "3.5.43",
"@vue/compiler-ssr": "3.5.43",
"@vue/shared": "3.5.43",
"estree-walker": "^2.0.2",
"magic-string": "^0.30.21",
"postcss": "^8.5.8",
"postcss": "^8.5.28",
"source-map-js": "^1.2.1"
}
},
"node_modules/@vue/compiler-ssr": {
"version": "3.5.30",
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.30.tgz",
"integrity": "sha512-NsYK6OMTnx109PSL2IAyf62JP6EUdk4Dmj6AkWcJGBvN0dQoMYtVekAmdqgTtWQgEJo+Okstbf/1p7qZr5H+bA==",
"version": "3.5.43",
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.43.tgz",
"integrity": "sha512-GF62orf7KiJX9RqrHNGrYBudsQGD0OhJ5nDs90O8UiDuS40+YMYomiXu6w6EuvtXuRDc3MSNis3EaaSKAVSWpg==",
"license": "MIT",
"dependencies": {
"@vue/compiler-dom": "3.5.30",
"@vue/shared": "3.5.30"
"@vue/compiler-dom": "3.5.43",
"@vue/shared": "3.5.43"
}
},
"node_modules/@vue/eslint-config-typescript": {
@@ -1537,53 +1471,51 @@
}
},
"node_modules/@vue/reactivity": {
"version": "3.5.30",
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.30.tgz",
"integrity": "sha512-179YNgKATuwj9gB+66snskRDOitDiuOZqkYia7mHKJaidOMo/WJxHKF8DuGc4V4XbYTJANlfEKb0yxTQotnx4Q==",
"version": "3.5.43",
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.43.tgz",
"integrity": "sha512-G/c9GyOZNI2jVaaS6OX1EF1SSFSv7H0ERqNTl4+DTFMlZmB5eVAB53aLQNam/7NL2NPtaDD7RdVrzf8uJzMuOA==",
"license": "MIT",
"dependencies": {
"@vue/shared": "3.5.30"
"@vue/shared": "3.5.43"
}
},
"node_modules/@vue/runtime-core": {
"version": "3.5.30",
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.30.tgz",
"integrity": "sha512-e0Z+8PQsUTdwV8TtEsLzUM7SzC7lQwYKePydb7K2ZnmS6jjND+WJXkmmfh/swYzRyfP1EY3fpdesyYoymCzYfg==",
"version": "3.5.43",
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.43.tgz",
"integrity": "sha512-hU6U6VnVhBGQDpvlnnDlIB8ZGJBiOcgk2lh/0InltHiz3D8oSkluvuvY+do1G2H3+udeKFsmaBlgVYP7gXQzEw==",
"license": "MIT",
"dependencies": {
"@vue/reactivity": "3.5.30",
"@vue/shared": "3.5.30"
"@vue/reactivity": "3.5.43",
"@vue/shared": "3.5.43"
}
},
"node_modules/@vue/runtime-dom": {
"version": "3.5.30",
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.30.tgz",
"integrity": "sha512-2UIGakjU4WSQ0T4iwDEW0W7vQj6n7AFn7taqZ9Cvm0Q/RA2FFOziLESrDL4GmtI1wV3jXg5nMoJSYO66egDUBw==",
"version": "3.5.43",
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.43.tgz",
"integrity": "sha512-Bb2Jc0YjjJdMt1SJmb9b2L/IWd3I8lIT9x9eS/xvvP9CiVgna0ffua74xKRmt4/uSJ+0r4iN8ex1jrqkhQGWQw==",
"license": "MIT",
"dependencies": {
"@vue/reactivity": "3.5.30",
"@vue/runtime-core": "3.5.30",
"@vue/shared": "3.5.30",
"@vue/reactivity": "3.5.43",
"@vue/runtime-core": "3.5.43",
"@vue/shared": "3.5.43",
"csstype": "^3.2.3"
}
},
"node_modules/@vue/server-renderer": {
"version": "3.5.30",
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.30.tgz",
"integrity": "sha512-v+R34icapydRwbZRD0sXwtHqrQJv38JuMB4JxbOxd8NEpGLny7cncMp53W9UH/zo4j8eDHjQ1dEJXwzFQknjtQ==",
"version": "3.5.43",
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.43.tgz",
"integrity": "sha512-l2Ygjv9NehV94PSBxNWsAHC0j/eIIKbn92mBuWXAPGLnn6HfJ6MH5ubsd+Nk0YoZ5FRuxWI1P2VSoh+dbPQhCQ==",
"license": "MIT",
"dependencies": {
"@vue/compiler-ssr": "3.5.30",
"@vue/shared": "3.5.30"
},
"peerDependencies": {
"vue": "3.5.30"
"@vue/compiler-ssr": "3.5.43",
"@vue/runtime-dom": "3.5.43",
"@vue/shared": "3.5.43"
}
},
"node_modules/@vue/shared": {
"version": "3.5.30",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.30.tgz",
"integrity": "sha512-YXgQ7JjaO18NeK2K9VTbDHaFy62WrObMa6XERNfNOkAhD1F1oDSf3ZJ7K6GqabZ0BvSDHajp8qfS5Sa2I9n8uQ==",
"version": "3.5.43",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.43.tgz",
"integrity": "sha512-uksS7YGMR5NZyr4JNq0Rp+QyLns0ueaz20KwzIPW9R0LH1Vnt4E+XUM29PNseEbf1www2gOuhuDi5AKOIXag9Q==",
"license": "MIT"
},
"node_modules/acorn": {
@@ -1697,9 +1629,9 @@
"license": "ISC"
},
"node_modules/brace-expansion": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
"version": "2.1.7",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.7.tgz",
"integrity": "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -2122,16 +2054,16 @@
}
},
"node_modules/eslint/node_modules/brace-expansion": {
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz",
"integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==",
"version": "5.0.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz",
"integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^4.0.2"
},
"engines": {
"node": "18 || 20 || >=22"
"node": "20 || >=22"
}
},
"node_modules/eslint/node_modules/eslint-visitor-keys": {
@@ -2810,9 +2742,9 @@
}
},
"node_modules/lightningcss": {
"version": "1.32.0",
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
"integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==",
"version": "1.33.0",
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz",
"integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==",
"dev": true,
"license": "MPL-2.0",
"dependencies": {
@@ -2826,23 +2758,23 @@
"url": "https://opencollective.com/parcel"
},
"optionalDependencies": {
"lightningcss-android-arm64": "1.32.0",
"lightningcss-darwin-arm64": "1.32.0",
"lightningcss-darwin-x64": "1.32.0",
"lightningcss-freebsd-x64": "1.32.0",
"lightningcss-linux-arm-gnueabihf": "1.32.0",
"lightningcss-linux-arm64-gnu": "1.32.0",
"lightningcss-linux-arm64-musl": "1.32.0",
"lightningcss-linux-x64-gnu": "1.32.0",
"lightningcss-linux-x64-musl": "1.32.0",
"lightningcss-win32-arm64-msvc": "1.32.0",
"lightningcss-win32-x64-msvc": "1.32.0"
"lightningcss-android-arm64": "1.33.0",
"lightningcss-darwin-arm64": "1.33.0",
"lightningcss-darwin-x64": "1.33.0",
"lightningcss-freebsd-x64": "1.33.0",
"lightningcss-linux-arm-gnueabihf": "1.33.0",
"lightningcss-linux-arm64-gnu": "1.33.0",
"lightningcss-linux-arm64-musl": "1.33.0",
"lightningcss-linux-x64-gnu": "1.33.0",
"lightningcss-linux-x64-musl": "1.33.0",
"lightningcss-win32-arm64-msvc": "1.33.0",
"lightningcss-win32-x64-msvc": "1.33.0"
}
},
"node_modules/lightningcss-android-arm64": {
"version": "1.32.0",
"resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz",
"integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==",
"version": "1.33.0",
"resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz",
"integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==",
"cpu": [
"arm64"
],
@@ -2861,9 +2793,9 @@
}
},
"node_modules/lightningcss-darwin-arm64": {
"version": "1.32.0",
"resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz",
"integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==",
"version": "1.33.0",
"resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz",
"integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==",
"cpu": [
"arm64"
],
@@ -2882,9 +2814,9 @@
}
},
"node_modules/lightningcss-darwin-x64": {
"version": "1.32.0",
"resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz",
"integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==",
"version": "1.33.0",
"resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz",
"integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==",
"cpu": [
"x64"
],
@@ -2903,9 +2835,9 @@
}
},
"node_modules/lightningcss-freebsd-x64": {
"version": "1.32.0",
"resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz",
"integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==",
"version": "1.33.0",
"resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz",
"integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==",
"cpu": [
"x64"
],
@@ -2924,9 +2856,9 @@
}
},
"node_modules/lightningcss-linux-arm-gnueabihf": {
"version": "1.32.0",
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz",
"integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==",
"version": "1.33.0",
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz",
"integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==",
"cpu": [
"arm"
],
@@ -2945,13 +2877,16 @@
}
},
"node_modules/lightningcss-linux-arm64-gnu": {
"version": "1.32.0",
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz",
"integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==",
"version": "1.33.0",
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz",
"integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==",
"cpu": [
"arm64"
],
"dev": true,
"libc": [
"glibc"
],
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -2966,13 +2901,16 @@
}
},
"node_modules/lightningcss-linux-arm64-musl": {
"version": "1.32.0",
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz",
"integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==",
"version": "1.33.0",
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz",
"integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==",
"cpu": [
"arm64"
],
"dev": true,
"libc": [
"musl"
],
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -2987,13 +2925,16 @@
}
},
"node_modules/lightningcss-linux-x64-gnu": {
"version": "1.32.0",
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz",
"integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==",
"version": "1.33.0",
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz",
"integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==",
"cpu": [
"x64"
],
"dev": true,
"libc": [
"glibc"
],
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -3008,13 +2949,16 @@
}
},
"node_modules/lightningcss-linux-x64-musl": {
"version": "1.32.0",
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz",
"integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==",
"version": "1.33.0",
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz",
"integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==",
"cpu": [
"x64"
],
"dev": true,
"libc": [
"musl"
],
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -3029,9 +2973,9 @@
}
},
"node_modules/lightningcss-win32-arm64-msvc": {
"version": "1.32.0",
"resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz",
"integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==",
"version": "1.33.0",
"resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz",
"integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==",
"cpu": [
"arm64"
],
@@ -3050,9 +2994,9 @@
}
},
"node_modules/lightningcss-win32-x64-msvc": {
"version": "1.32.0",
"resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz",
"integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==",
"version": "1.33.0",
"resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz",
"integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==",
"cpu": [
"x64"
],
@@ -3190,9 +3134,9 @@
"license": "MIT"
},
"node_modules/nanoid": {
"version": "3.3.16",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz",
"integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==",
"version": "3.3.20",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.20.tgz",
"integrity": "sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==",
"funding": [
{
"type": "github",
@@ -3353,9 +3297,9 @@
"license": "ISC"
},
"node_modules/picomatch": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz",
"integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==",
"dev": true,
"license": "MIT",
"engines": {
@@ -3366,9 +3310,9 @@
}
},
"node_modules/postcss": {
"version": "8.5.23",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.23.tgz",
"integrity": "sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==",
"version": "8.5.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.31.tgz",
"integrity": "sha512-YUbWYCgErwnMAVkjUnYa+KlMBzGpHwiIt/DE7f0G33AuX2LH9UcTk6KgWxd3zRU+pN3u/C+Xl3EnMLM4Hea7Sg==",
"funding": [
{
"type": "opencollective",
@@ -3385,18 +3329,18 @@
],
"license": "MIT",
"dependencies": {
"nanoid": "^3.3.16",
"nanoid": "^3.3.20",
"picocolors": "^1.1.1",
"source-map-js": "^1.2.1"
"source-map-js": "^1.2.2"
},
"engines": {
"node": "^10 || ^12 || >=14"
}
},
"node_modules/postcss-selector-parser": {
"version": "7.1.5",
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.5.tgz",
"integrity": "sha512-KvvtD7SrlBP7dlgkBghEE3r84CABm5SmV2aNcG4oCA+qDnJ/tvKonFVvwWAyyWUEwxuNawdfEAZKP9zM3oZ2Uw==",
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.6.tgz",
"integrity": "sha512-7qASPzhKF2l2KLboRZux8CCTRMdGiV08vWmyKzPz22qZ7ZjQBOeY7rNzNoCLSUiftJ7HUq0GERHmxw/t0dCdMw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -3642,13 +3586,13 @@
}
},
"node_modules/rolldown": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz",
"integrity": "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==",
"version": "1.2.15",
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.15.tgz",
"integrity": "sha512-6odND+fel5zVw3I4Yc2e69gvguDnX0CAAGiNDZSq4ik5WUcaLrkD2GLuog0XcODbor31hZ5ayEMgVDno+KPV5g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@oxc-project/types": "=0.133.0",
"@oxc-project/types": "=0.155.0",
"@rolldown/pluginutils": "^1.0.0"
},
"bin": {
@@ -3658,21 +3602,21 @@
"node": "^20.19.0 || >=22.12.0"
},
"optionalDependencies": {
"@rolldown/binding-android-arm64": "1.0.3",
"@rolldown/binding-darwin-arm64": "1.0.3",
"@rolldown/binding-darwin-x64": "1.0.3",
"@rolldown/binding-freebsd-x64": "1.0.3",
"@rolldown/binding-linux-arm-gnueabihf": "1.0.3",
"@rolldown/binding-linux-arm64-gnu": "1.0.3",
"@rolldown/binding-linux-arm64-musl": "1.0.3",
"@rolldown/binding-linux-ppc64-gnu": "1.0.3",
"@rolldown/binding-linux-s390x-gnu": "1.0.3",
"@rolldown/binding-linux-x64-gnu": "1.0.3",
"@rolldown/binding-linux-x64-musl": "1.0.3",
"@rolldown/binding-openharmony-arm64": "1.0.3",
"@rolldown/binding-wasm32-wasi": "1.0.3",
"@rolldown/binding-win32-arm64-msvc": "1.0.3",
"@rolldown/binding-win32-x64-msvc": "1.0.3"
"@rolldown/binding-android-arm-eabi": "1.2.15",
"@rolldown/binding-android-arm64": "1.2.15",
"@rolldown/binding-darwin-arm64": "1.2.15",
"@rolldown/binding-darwin-x64": "1.2.15",
"@rolldown/binding-freebsd-x64": "1.2.15",
"@rolldown/binding-linux-arm-gnueabihf": "1.2.15",
"@rolldown/binding-linux-arm64-gnu": "1.2.15",
"@rolldown/binding-linux-arm64-musl": "1.2.15",
"@rolldown/binding-linux-ppc64-gnu": "1.2.15",
"@rolldown/binding-linux-s390x-gnu": "1.2.15",
"@rolldown/binding-linux-x64-gnu": "1.2.15",
"@rolldown/binding-linux-x64-musl": "1.2.15",
"@rolldown/binding-openharmony-arm64": "1.2.15",
"@rolldown/binding-win32-arm64-msvc": "1.2.15",
"@rolldown/binding-win32-x64-msvc": "1.2.15"
}
},
"node_modules/rolldown/node_modules/@rolldown/pluginutils": {
@@ -4162,9 +4106,9 @@
}
},
"node_modules/smol-toml": {
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.7.1.tgz",
"integrity": "sha512-PPlsspAZ4jbMBu5DMFhfUGDQLu/vrL4SyBROVS37x8ynnVmFIs1VPBz1Co8Xks3TvpIaZXmU85y4DrQ+UyVFoQ==",
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.9.0.tgz",
"integrity": "sha512-hpd+HLON7HdZXqYchMM/+LaTTbdK0AU3NngIJ4KVyWbY9bfQqdL9cD+4yf6dUoU2Ap4VsU0JkQi6FxAI1B2mXQ==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
@@ -4185,9 +4129,9 @@
}
},
"node_modules/source-map-js": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz",
"integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==",
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
@@ -4497,16 +4441,16 @@
"license": "MIT"
},
"node_modules/vite": {
"version": "8.0.16",
"resolved": "https://registry.npmjs.org/vite/-/vite-8.0.16.tgz",
"integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==",
"version": "8.3.5",
"resolved": "https://registry.npmjs.org/vite/-/vite-8.3.5.tgz",
"integrity": "sha512-z1YpjieJ9g0ebTmQpLBv/oq9E3F9EIlOe+7LahW8SrE3LTiG3udBRUXQOlYXP9b+IC2q2phHeVxj9xGlw34OEQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"lightningcss": "^1.32.0",
"picomatch": "^4.0.4",
"postcss": "^8.5.15",
"rolldown": "1.0.3",
"lightningcss": "^1.33.0",
"picomatch": "^4.0.7",
"postcss": "^8.5.30",
"rolldown": "~1.2.14",
"tinyglobby": "^0.2.17"
},
"bin": {
@@ -4523,7 +4467,7 @@
},
"peerDependencies": {
"@types/node": "^20.19.0 || >=22.12.0",
"@vitejs/devtools": "^0.1.18",
"@vitejs/devtools": "^0.7.1 || ^0.8.0",
"esbuild": "^0.27.0 || ^0.28.0",
"jiti": ">=1.21.0",
"less": "^4.0.0",
@@ -4592,16 +4536,16 @@
"license": "MIT"
},
"node_modules/vue": {
"version": "3.5.30",
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.30.tgz",
"integrity": "sha512-hTHLc6VNZyzzEH/l7PFGjpcTvUgiaPK5mdLkbjrTeWSRcEfxFrv56g/XckIYlE9ckuobsdwqd5mk2g1sBkMewg==",
"version": "3.5.43",
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.43.tgz",
"integrity": "sha512-o5qZoksdnjIKvW1srZ3ab7pcDNYAerBjRe54D0LBLfRdCYFrSgBHVXokMas35czQc0//lmx4/tuY4ZNQ+Rf2Ng==",
"license": "MIT",
"dependencies": {
"@vue/compiler-dom": "3.5.30",
"@vue/compiler-sfc": "3.5.30",
"@vue/runtime-dom": "3.5.30",
"@vue/server-renderer": "3.5.30",
"@vue/shared": "3.5.30"
"@vue/compiler-dom": "3.5.43",
"@vue/compiler-sfc": "3.5.43",
"@vue/runtime-dom": "3.5.43",
"@vue/server-renderer": "3.5.43",
"@vue/shared": "3.5.43"
},
"peerDependencies": {
"typescript": "*"
+23 -25
View File
@@ -27,26 +27,26 @@ classifiers = [
]
dependencies = [
"arabic-reshaper==3.0.1", # Support for Arabic in reportlab
"arabic-reshaper==3.1.0", # Support for Arabic in reportlab
"babel",
"BeautifulSoup4==4.15.*",
"bleach==6.4.*",
"celery==5.6.*",
"chardet==5.2.*",
"cryptography>=50.0.1",
"css-inline==0.21.*",
"cryptography>=50.0.2",
"css-inline==0.23.*",
"defusedcsv>=3.0.0",
"dnspython==2.*",
"dnspython==2.9.*",
"Django[argon2]==5.2.*,>=5.2.17",
"django-bootstrap3==26.2",
"django-bootstrap3==26.3",
"django-compressor==4.6.0",
"django-countries==9.1.*",
"django-filter==26.1",
"django-filter==26.2",
"django-formset-js-improved==0.5.0.5",
"django-formtools==2.7",
"django-hierarkey==2.0.*,>=2.0.2",
"django-hijack==3.7.*",
"django-i18nfield==1.11.*",
"django-i18nfield==1.12.*",
"django-libsass==0.9",
"django-localflavor==5.1",
"django-markup",
@@ -57,48 +57,45 @@ dependencies = [
"django-redis==7.0.*",
"django-scopes==2.1.*",
"django-statici18n==2.8.*",
"djangorestframework==3.17.*",
"dnspython==2.8.*",
"djangorestframework>=3.18.3",
"drf_ujson2==1.7.*",
"geoip2==5.*",
"importlib_metadata==9.*", # Polyfill, we can probably drop this once we require Python 3.10+
"isoweek",
"jsonschema",
"kombu==5.6.*",
"libsass==0.23.*",
"lxml",
"markdown==3.10.3", # 3.3.5 requires importlib-metadata>=4.4, but django-bootstrap3 requires importlib-metadata<3.
# We can upgrade markdown again once django-bootstrap3 upgrades or once we drop Python 3.6 and 3.7
"markdown==3.11.2",
"mt-940==4.30.*",
"oauthlib==3.3.*",
"openpyxl==3.1.*",
"packaging",
"paypalrestsdk==1.13.*",
"paypal-checkout-serversdk==1.0.*",
"PyJWT==2.14.*",
"PyJWT==2.15.*",
"phonenumberslite==9.0.*",
"Pillow==12.3.*",
"Pillow==13.0.*",
"pretix-plugin-build",
"protobuf==7.36.*",
"psycopg2-binary",
"pycountry",
"pycparser==3.0",
"pycryptodome==3.23.*",
"pypdf==6.19.*",
"pycparser==3.12",
"pycryptodome==3.24.*",
"pypdf==6.20.*",
"python-bidi==0.6.*", # Support for Arabic in reportlab
"python-dateutil==2.9.*",
"python-dateutil==4.0.*",
"pytz",
"pytz-deprecation-shim==0.1.*",
"pyuca",
"qrcode==8.2",
"redis==7.4.*",
"reportlab==5.0.*",
"reportlab==5.1.*",
"requests==2.34.*",
"sentry-sdk==2.69.*",
"sentry-sdk==2.71.*",
"sepaxml==2.7.*",
"stripe==7.9.*",
"text-unidecode==1.*",
"tlds>=2026072401",
"tlds>=2026102900",
"tqdm==4.*",
"ua-parser==1.0.*",
"vobject==0.9.*",
@@ -112,23 +109,24 @@ dev = [
"aiohttp==3.14.*",
"coverage",
"coveralls",
"fakeredis==2.38.*",
"flake8==7.3.*",
"fakeredis==2.40.*",
"flake8==7.5.*",
"freezegun",
"isort==9.0.*",
"pep8-naming==0.15.*",
"potypo",
"pytest-asyncio>=1.4.0",
"pytest-asyncio>=1.4.1.post1",
"pytest-cache",
"pytest-cov",
"pytest-django==4.*",
"pytest-mock==3.15.*",
"pytest-mock==3.17.*",
"pytest-sugar",
"pytest-xdist==3.8.*",
"pytest-playwright",
"pytest==9.1.*",
"playwright",
"responses",
"pypdfium2"
]
[project.entry-points."distutils.commands"]
+2
View File
@@ -30,3 +30,5 @@ npminstall:
npmbuild:
npm run build
licenseheaders:
licenseheaders -t ../.licenseheader -E .py -x "*/migrations/*.py"
+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.8.0.dev0"
__version__ = "2026.10.0.dev0"
+1 -1
View File
@@ -76,7 +76,7 @@ class DeviceTokenAuthentication(TokenAuthentication):
except DeviceLastSeen.DoesNotExist:
# First request from device, create model, ignore result. Use get_or_create to be safe
# against concurrent create requests
DeviceLastSeen.objects.get_or_create(device=device, last_seen=now())
DeviceLastSeen.objects.get_or_create(device=device, defaults={"last_seen": now()})
else:
if now() - last_seen_obj.last_seen < timedelta(seconds=10):
# We don't need to know the last seen info of a device to more precision than this,
+30
View File
@@ -0,0 +1,30 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# 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/>.
#
def get_session_key_for_api_auth(user, auth, prefix='api-upload'):
if user.is_authenticated:
return f'{prefix}-User-{user.pk}'
else:
return f'{prefix}-{str(type(auth))}-{auth.pk}'
def get_session_key_for_api_request(request, prefix='api-upload'):
return get_session_key_for_api_auth(request.user, request.auth, prefix)
+4
View File
@@ -101,6 +101,10 @@ class OAuthAccessToken(AbstractAccessToken):
self.expires = now() - timedelta(hours=1)
self.save(update_fields=['expires'])
def is_valid(self, scopes=None):
# Can maybe be removed after upgrading django-oauth-toolkit to 3.4.1
return super().is_valid(scopes) and self.application.is_usable(None)
class OAuthRefreshToken(AbstractRefreshToken):
application = models.ForeignKey(
+12 -3
View File
@@ -35,10 +35,13 @@
import logging
from django.conf import settings
from django.core.exceptions import PermissionDenied
from django.core.exceptions import (
PermissionDenied, ValidationError as DjangoValidationError,
)
from django.db import transaction
from django.utils.crypto import get_random_string
from django.utils.functional import cached_property
from django.utils.html import strip_tags
from django.utils.translation import gettext as _
from django_countries.serializers import CountryFieldMixin
from pytz import common_timezones
@@ -218,8 +221,6 @@ class EventSerializer(SalesChannelMigrationMixin, I18nAwareModelSerializer):
if self.instance is None:
raise ValidationError(_('Events cannot be created as \'live\'. Quotas and payment must be added to the '
'event before sales can go live.'))
else:
self.instance.clean_live()
return value
@cached_property
@@ -429,6 +430,14 @@ class EventSerializer(SalesChannelMigrationMixin, I18nAwareModelSerializer):
event.set_active_plugins(plugins)
event.save()
live = validated_data.get('live') or event.live
if live:
event.refresh_from_db()
try:
event.clean_live()
except DjangoValidationError as e:
raise ValidationError({'live': [strip_tags(m) for m in e.messages]})
return event
+9 -1
View File
@@ -37,6 +37,8 @@ from collections import OrderedDict
from django.core.exceptions import ValidationError
from rest_framework import serializers
from pretix.api.auth.utils import get_session_key_for_api_request
def remove_duplicates_from_list(data):
return list(OrderedDict.fromkeys(data))
@@ -83,10 +85,16 @@ class UploadedFileField(serializers.Field):
request = self.context.get('request', None)
try:
cf = CachedFile.objects.get(
session_key=f'api-upload-{str(type(request.user or request.auth))}-{(request.user or request.auth).pk}',
file__isnull=False,
pk=data[len("file:"):],
)
if cf.session_key == "api-upload-<class 'django.contrib.auth.models.AnonymousUser'>-None":
# OK, backwards-compatibility of a security bug fixed 2026-09, delete this at some point, but should
# also be harmless because all files with this key are expired one day after deployment of this fix
# and no new files with this key are created
pass
elif cf.session_key != get_session_key_for_api_request(request):
self.fail('not_found')
except (ValidationError, IndexError): # invalid uuid
self.fail('not_found')
except CachedFile.DoesNotExist:
+4 -2
View File
@@ -261,7 +261,9 @@ class ItemAddOnSerializer(serializers.ModelSerializer):
def validate(self, data):
data = super().validate(data)
ItemAddOn.clean_max_min_count(data.get('max_count'), data.get('min_count'))
full_data = self.to_internal_value(self.to_representation(self.instance)) if self.instance else {}
full_data.update(data)
ItemAddOn.clean_max_min_count(full_data.get('max_count'), full_data.get('min_count'))
return data
@@ -376,7 +378,7 @@ class ItemSerializer(SalesChannelMigrationMixin, I18nAwareModelSerializer):
def validate_bundles(self, value):
if not self.instance:
for b_data in value:
ItemBundle.clean_itemvar(self.context['event'], b_data['bundled_item'], b_data['bundled_variation'])
ItemBundle.clean_itemvar(self.context['event'], b_data.get('bundled_item'), b_data.get('bundled_variation'))
return value
def validate_addons(self, value):
+36 -16
View File
@@ -41,6 +41,7 @@ from rest_framework.exceptions import ValidationError
from rest_framework.relations import SlugRelatedField
from rest_framework.reverse import reverse
from pretix.api.auth.utils import get_session_key_for_api_request
from pretix.api.serializers import CompatDecimalField, CompatibleJSONField
from pretix.api.serializers.event import SubEventSerializer
from pretix.api.serializers.forms import form_field_to_serializer_field
@@ -258,16 +259,21 @@ class AnswerSerializer(I18nAwareModelSerializer):
if data['answer'] == 'file:keep':
return data
try:
ao = self.context["request"].user or self.context["request"].auth
cf = CachedFile.objects.get(
session_key=f'api-upload-{str(type(ao))}-{ao.pk}',
file__isnull=False,
pk=data['answer'][len("file:"):],
)
if cf.session_key == "api-upload-<class 'django.contrib.auth.models.AnonymousUser'>-None":
# OK, backwards-compatibility of a security bug fixed 2026-09, delete this at some point, but should
# also be harmless because all files with this key are expired one day after deployment of this fix
# and no new files with this key are created
pass
elif cf.session_key != get_session_key_for_api_request(self.context["request"]):
raise ValidationError('The submitted file ID "{fid}" was not found.'.format(fid=data['answer']))
except (ValidationError, IndexError): # invalid uuid
raise ValidationError('The submitted file ID "{fid}" was not found.'.format(fid=data))
raise ValidationError('The submitted file ID "{fid}" was not found.'.format(fid=data['answer']))
except CachedFile.DoesNotExist:
raise ValidationError('The submitted file ID "{fid}" was not found.'.format(fid=data))
raise ValidationError('The submitted file ID "{fid}" was not found.'.format(fid=data['answer']))
allowed_types = (
'image/png', 'image/jpeg', 'image/gif', 'application/pdf'
@@ -1234,6 +1240,9 @@ class OrderCreateSerializer(I18nAwareModelSerializer):
return None
if pp not in self.context['event'].get_payment_providers():
raise ValidationError('The given payment provider is not known.')
if pp == "giftcard":
raise serializers.ValidationError("Cannot create giftcard payment. Use `use_gift_cards` instead")
return pp
def validate_payment_info(self, info):
@@ -1273,7 +1282,7 @@ class OrderCreateSerializer(I18nAwareModelSerializer):
raise ValidationError(
'Orders cannot have more than %(max)s positions.' % {'max': settings.PRETIX_MAX_ORDER_SIZE}
)
errs = [{} for p in data]
errs = defaultdict(dict)
if any([p.get('positionid') for p in data]):
if not all([p.get('positionid') for p in data]):
for i, p in enumerate(data):
@@ -1302,16 +1311,16 @@ class OrderCreateSerializer(I18nAwareModelSerializer):
last_posid = p['positionid']
elif any([p.get('addon_to') for p in data]):
errs = [
{'positionid': ["If you set addon_to on any position, you need to specify position IDs manually."]}
for p in data
]
errs = {
i: {'positionid': ["If you set addon_to on any position, you need to specify position IDs manually."]}
for i, p in enumerate(data)
}
else:
for i, p in enumerate(data):
p['positionid'] = i + 1
if any(errs):
raise ValidationError(errs)
if errs:
raise ValidationError(dict(errs))
return data
def create(self, validated_data):
@@ -1428,7 +1437,7 @@ class OrderCreateSerializer(I18nAwareModelSerializer):
# use further down
del quota_diff_for_locking, voucher_diff_for_locking, seat_diff_for_locking
errs = [{} for p in positions_data]
errs = defaultdict(dict)
for i, pos_data in enumerate(positions_data):
if pos_data.get('voucher'):
@@ -1557,7 +1566,7 @@ class OrderCreateSerializer(I18nAwareModelSerializer):
)
]
if any(errs):
if errs:
raise ValidationError({'positions': errs})
if validated_data.get('locale', None) is None:
@@ -1954,10 +1963,15 @@ class OrderPaymentCreateSerializer(I18nAwareModelSerializer):
model = OrderPayment
fields = ('state', 'amount', 'payment_date', 'provider', 'info')
def validate_provider(self, value):
if value == "giftcard":
raise serializers.ValidationError("Cannot create giftcard payment")
return value
def create(self, validated_data):
order = OrderPayment(order=self.context['order'], **validated_data)
order.save()
return order
payment = OrderPayment(order=self.context['order'], **validated_data)
payment.save()
return payment
class OrderRefundCreateSerializer(I18nAwareModelSerializer):
@@ -1969,6 +1983,12 @@ class OrderRefundCreateSerializer(I18nAwareModelSerializer):
model = OrderRefund
fields = ('state', 'source', 'amount', 'payment', 'execution_date', 'provider', 'info', 'comment')
def validate_provider(self, value):
if value == "giftcard":
raise serializers.ValidationError("Cannot create giftcard payment")
return value
def create(self, validated_data):
pid = validated_data.pop('payment', None)
if pid:
+4 -13
View File
@@ -41,10 +41,9 @@ from pretix.api.serializers.settings import SettingsSerializer
from pretix.base.auth import get_auth_backends
from pretix.base.i18n import get_language_without_region
from pretix.base.models import (
Customer, Device, EventMetaProperty, GiftCard, GiftCardAcceptance,
GiftCardTransaction, Membership, MembershipType, OrderPosition, Organizer,
ReusableMedium, SalesChannel, SeatingPlan, Team, TeamAPIToken, TeamInvite,
User,
Customer, Device, EventMetaProperty, GiftCard, GiftCardTransaction,
Membership, MembershipType, OrderPosition, Organizer, ReusableMedium,
SalesChannel, SeatingPlan, Team, TeamAPIToken, TeamInvite, User,
)
from pretix.base.models.seating import SeatingPlanLayoutValidator
from pretix.base.permissions import (
@@ -270,15 +269,7 @@ class GiftCardSerializer(I18nAwareModelSerializer):
data = super().validate(data)
if 'secret' in data:
s = data['secret']
qs = GiftCard.objects.filter(
secret=s
).filter(
Q(issuer=self.context["organizer"]) |
Q(issuer__in=GiftCardAcceptance.objects.filter(
acceptor=self.context["organizer"],
active=True,
).values_list('issuer', flat=True))
)
qs = self.context["organizer"].accepted_gift_cards.filter(secret=s)
if self.instance:
qs = qs.exclude(pk=self.instance.pk)
if qs.exists():
+7 -9
View File
@@ -19,6 +19,7 @@
# 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/>.
#
from collections import defaultdict
from decimal import Decimal
from rest_framework import serializers
@@ -38,23 +39,20 @@ class VoucherListSerializer(serializers.ListSerializer):
codes = set()
seats = set()
errs = []
err = False
for voucher_data in validated_data:
errs = defaultdict(dict)
for i, voucher_data in enumerate(validated_data):
if voucher_data.get('seat') and (voucher_data.get('seat'), voucher_data.get('subevent')) in seats:
err = True
errs.append({'code': ['Duplicate seat ID in request.']})
errs[i] = {'code': ['Duplicate seat ID in request.']}
continue
else:
seats.add((voucher_data.get('seat'), voucher_data.get('subevent')))
if voucher_data['code'] in codes:
err = True
errs.append({'code': ['Duplicate voucher code in request.']})
errs[i] = {'code': ['Duplicate voucher code in request.']}
else:
codes.add(voucher_data['code'])
errs.append({})
if err:
if errs:
raise ValidationError(errs)
return super().create(validated_data)
+8 -1
View File
@@ -50,6 +50,7 @@ from rest_framework.generics import ListAPIView
from rest_framework.permissions import SAFE_METHODS
from rest_framework.response import Response
from pretix.api.auth.utils import get_session_key_for_api_auth
from pretix.api.serializers.checkin import (
CheckinListSerializer, CheckinRPCAnnulInputSerializer,
CheckinRPCRedeemInputSerializer, MiniCheckinListSerializer,
@@ -331,10 +332,16 @@ with scopes_disabled():
def _handle_file_upload(data, user, auth):
try:
cf = CachedFile.objects.get(
session_key=f'api-upload-{str(type(user or auth))}-{(user or auth).pk}',
file__isnull=False,
pk=data[len("file:"):],
)
if cf.session_key == "api-upload-<class 'django.contrib.auth.models.AnonymousUser'>-None":
# OK, backwards-compatibility of a security bug fixed 2026-09, delete this at some point, but should
# also be harmless because all files with this key are expired one day after deployment of this fix
# and no new files with this key are created
pass
elif cf.session_key != get_session_key_for_api_auth(user, auth):
raise ValidationError('The submitted file ID "{fid}" was not found.'.format(fid=data))
except (ValidationError, BaseValidationError, IndexError): # invalid uuid
raise ValidationError('The submitted file ID "{fid}" was not found.'.format(fid=data))
except CachedFile.DoesNotExist:
+1 -1
View File
@@ -75,7 +75,7 @@ class ExportersMixin:
@action(detail=True, methods=['GET'], url_name='download', url_path='download/(?P<asyncid>[^/]+)/(?P<cfid>[^/]+)')
def download(self, *args, **kwargs):
cf = get_object_or_404(CachedFile, id=kwargs['cfid'])
cf = get_object_or_404(CachedFile, id=kwargs['cfid'], web_download=True)
if not cf.allowed_for_session(self.request, "exporters-api"):
return Response(
{'status': 'failed', 'message': 'Unknown file ID or export failed'},
+2 -2
View File
@@ -39,7 +39,7 @@ from pretix.api.serializers.media import (
)
from pretix.base.media import MEDIA_TYPES
from pretix.base.models import (
Checkin, GiftCard, GiftCardAcceptance, GiftCardTransaction, OrderPosition,
Checkin, GiftCardAcceptance, GiftCardTransaction, OrderPosition,
ReusableMedium,
)
from pretix.base.models.orders import PrintLog
@@ -88,7 +88,7 @@ class ReusableMediaViewSet(viewsets.ModelViewSet):
),
Prefetch(
'linked_giftcard',
queryset=GiftCard.objects.annotate(
queryset=self.request.organizer.accepted_gift_cards.annotate(
cached_value=Coalesce(Subquery(s), Decimal('0.00'))
)
)
+1 -1
View File
@@ -1683,7 +1683,7 @@ class PaymentViewSet(CreateModelMixin, viewsets.ReadOnlyModelViewSet):
@action(detail=True, methods=['POST'])
def confirm(self, request, **kwargs):
payment = self.get_object()
force = request.data.get('force', False)
force = request.data.get('force', False) if request.data else False
send_mail = request.data.get('send_email', True) if request.data else True
if payment.state not in (OrderPayment.PAYMENT_STATE_PENDING, OrderPayment.PAYMENT_STATE_CREATED):
+25 -6
View File
@@ -33,6 +33,7 @@ from rest_framework.exceptions import ValidationError
from rest_framework.response import Response
from rest_framework.reverse import reverse
from pretix.api.auth.utils import get_session_key_for_api_request
from pretix.api.serializers.shredders import (
JobRunSerializer, ShredderSerializer,
)
@@ -68,8 +69,14 @@ class ShreddersMixin:
cf = get_object_or_404(
CachedFile,
id=kwargs['cfid'],
session_key=f'api-shredder-{str(type(self.request.user or self.request.auth))}-{(self.request.user or self.request.auth).pk}'
)
if cf.session_key == "api-shredder-<class 'django.contrib.auth.models.AnonymousUser'>-None":
# OK, backwards-compatibility of a security bug fixed 2026-10, delete this at some point, but should
# also be harmless because all files with this key are expired one day after deployment of this fix
# and no new files with this key are created
pass
elif cf.session_key != get_session_key_for_api_request(self.request, prefix='api-shredder'):
raise Http404()
if cf.file:
resp = ChunkBasedFileResponse(cf.file.file, content_type=cf.type)
resp['Content-Disposition'] = 'attachment; filename="{}"'.format(cf.filename).encode("ascii", "ignore")
@@ -118,10 +125,16 @@ class ShreddersMixin:
)
try:
CachedFile.objects.get(
cf = CachedFile.objects.get(
id=kwargs['cfid'],
session_key=f'api-shredder-{str(type(self.request.user or self.request.auth))}-{(self.request.user or self.request.auth).pk}'
)
if cf.session_key == "api-shredder-<class 'django.contrib.auth.models.AnonymousUser'>-None":
# OK, backwards-compatibility of a security bug fixed 2026-10, delete this at some point, but should
# also be harmless because all files with this key are expired one day after deployment of this fix
# and no new files with this key are created
pass
elif cf.session_key != get_session_key_for_api_request(self.request, prefix='api-shredder'):
raise CachedFile.DoesNotExist()
except CachedFile.DoesNotExist:
return Response(
{'status': 'gone', 'message': 'May have succeeded or timed out'},
@@ -140,8 +153,14 @@ class ShreddersMixin:
cf = get_object_or_404(
CachedFile,
id=kwargs['cfid'],
session_key=f'api-shredder-{str(type(self.request.user or self.request.auth))}-{(self.request.user or self.request.auth).pk}'
)
if cf.session_key == "api-shredder-<class 'django.contrib.auth.models.AnonymousUser'>-None":
# OK, backwards-compatibility of a security bug fixed 2026-10, delete this at some point, but should
# also be harmless because all files with this key are expired one day after deployment of this fix
# and no new files with this key are created
pass
elif cf.session_key != get_session_key_for_api_request(self.request, prefix='api-shredder'):
raise Http404()
if cf.file:
async_result = self.do_shred(cf)
url_kwargs = {
@@ -184,7 +203,7 @@ class ShreddersMixin:
cf = CachedFile(web_download=False)
cf.date = now()
cf.expires = now() + timedelta(hours=2)
cf.session_key = f'api-shredder-{str(type(self.request.user or self.request.auth))}-{(self.request.user or self.request.auth).pk}'
cf.session_key = get_session_key_for_api_request(self.request, prefix='api-shredder')
cf.save()
d = serializer.data
for k, v in d.items():
@@ -224,7 +243,7 @@ class EventShreddersViewSet(ShreddersMixin, viewsets.ViewSet):
return export.apply_async(args=(
self.request.event.id,
list(shredders),
f'api-shredder-{str(type(self.request.user or self.request.auth))}-{(self.request.user or self.request.auth).pk}',
get_session_key_for_api_request(self.request, prefix='api-shredder'),
str(cf.pk)
))
+2 -1
View File
@@ -33,6 +33,7 @@ from rest_framework.views import APIView
from pretix.api.auth.device import DeviceTokenAuthentication
from pretix.api.auth.permission import AnyAuthenticatedClientPermission
from pretix.api.auth.token import TeamTokenAuthentication
from pretix.api.auth.utils import get_session_key_for_api_request
from pretix.base.models import CachedFile
from pretix.helpers.images import (
IMAGE_TYPES, validate_uploaded_file_for_valid_image,
@@ -78,7 +79,7 @@ class UploadView(APIView):
web_download=False,
filename=file_obj.name,
type=content_type,
session_key=f'api-upload-{str(type(request.user or request.auth))}-{(request.user or request.auth).pk}'
session_key=get_session_key_for_api_request(request)
)
cf.file.save(file_obj.name, file_obj)
cf.save()
+5 -2
View File
@@ -239,8 +239,9 @@ def oidc_validate_authorization(provider, code, redirect_uri, pkce_code_verifier
)
)
if 'email_verified' in userinfo and not userinfo['email_verified']:
# todo: how universal is this, do we need to make this configurable?
if 'email_verified' in userinfo and userinfo['email_verified'] not in (True, 1, "1", "True", "true", "TRUE"):
# Documented criteria for using a provider with pretix:
# "The SSO provider only allows verified accounts to log in or the SSO provider sends the claim email_verified. "
raise ValidationError(_('The email address on this account is not yet verified. Please first confirm the '
'email address in your customer account.'))
@@ -263,6 +264,8 @@ def oidc_validate_authorization(provider, code, redirect_uri, pkce_code_verifier
)
)
profile['oidc_claims'] = userinfo
return profile
+3 -3
View File
@@ -29,6 +29,7 @@ from typing import List, Optional, Protocol
from django.conf import settings
from django.db import DatabaseError, transaction
from django.utils.functional import classproperty
from django.utils.timezone import now
from django.utils.translation import gettext_lazy as _
@@ -101,9 +102,8 @@ class OutboundSyncProvider:
def __exit__(self, exc_type, exc_val, exc_tb):
self.close()
@classmethod
@property
def display_name(cls):
@classproperty
def display_name(cls): # noqa: N805
return str(cls.identifier)
@classmethod
+5 -1
View File
@@ -160,7 +160,11 @@ class CustomerListExporter(OrganizerLevelExportMixin, MultiSheetListExporter):
]
if name_scheme and len(name_scheme['fields']) > 1:
for k, label, w in name_scheme['fields']:
row.append(obj.attendee_name_parts.get(k, ''))
row.append(
obj.attendee_name_parts.get(k, '')
if obj.attendee_name_parts
else ''
)
yield row
def get_filename(self):
+6 -5
View File
@@ -55,9 +55,10 @@ from openpyxl.comments import Comment
from openpyxl.styles import Font, PatternFill
from pretix.base.models import (
Checkin, GiftCard, GiftCardTransaction, Invoice, InvoiceAddress, Order,
Checkin, GiftCardTransaction, Invoice, InvoiceAddress, Order,
OrderPosition, Question,
)
from pretix.base.models.giftcards import GiftCard
from pretix.base.models.orders import (
OrderFee, OrderPayment, OrderRefund, Transaction,
)
@@ -1326,12 +1327,12 @@ class GiftcardRedemptionListExporter(ListExporter):
order__event__in=self.events,
provider='giftcard',
state__in=(OrderPayment.PAYMENT_STATE_CONFIRMED, OrderPayment.PAYMENT_STATE_REFUNDED),
).order_by('created')
).order_by('created').select_related("order__event__organizer")
refunds = OrderRefund.objects.filter(
order__event__in=self.events,
provider='giftcard',
state=OrderRefund.REFUND_STATE_DONE
).order_by('created')
).order_by('created').select_related("order__event__organizer")
objs = sorted(list(payments) + list(refunds), key=lambda o: (o.order.code, o.created))
@@ -1348,9 +1349,9 @@ class GiftcardRedemptionListExporter(ListExporter):
obj.order.code,
obj.full_id,
obj.created.astimezone(tz).date().strftime('%Y-%m-%d'),
gc.secret,
gc.secret if gc.accepted_by(obj.order.event.organizer) else '?',
obj.amount * (-1 if isinstance(obj, OrderRefund) else 1),
gc.issuer
gc.issuer.slug
]
yield row
+10 -6
View File
@@ -600,12 +600,16 @@ class PortraitImageField(SizeValidationMixin, ExtValidationMixin, forms.FileFiel
image = ImageOps.exif_transpose(image)
if f._cropdata:
image = image.crop((
f._cropdata.get('x', 0),
f._cropdata.get('y', 0),
f._cropdata.get('x', 0) + f._cropdata.get('width', image.width),
f._cropdata.get('y', 0) + f._cropdata.get('height', image.height),
))
left = int(f._cropdata.get('x', 0))
top = int(f._cropdata.get('y', 0))
right = left + int(f._cropdata.get('width', image.width))
bottom = top + int(f._cropdata.get('height', image.height))
if left >= image.width or top >= image.height or right > image.width or bottom > image.height:
raise ValidationError(
self.error_messages['max_dimension'],
code='max_dimension',
)
image = image.crop((left, top, right, bottom))
with BytesIO() as output:
# This might use a lot of memory, but temporary files are not a good option since
# we don't control the cleanup
+2 -2
View File
@@ -71,8 +71,8 @@ class EmailTransmissionType(TransmissionType):
def transmission_info_to_form_data(self, transmission_info: dict) -> dict:
return {
"transmission_email_other": bool(transmission_info.get("transmission_email_address")),
"transmission_email_address": transmission_info.get("transmission_email_address"),
"transmission_email_other": bool((transmission_info or {}).get("transmission_email_address")),
"transmission_email_address": (transmission_info or {}).get("transmission_email_address"),
}
def form_data_to_transmission_info(self, form_data: dict) -> dict:
+22 -19
View File
@@ -131,6 +131,27 @@ class PeppolIdValidator:
def __init__(self, validate_online=False):
self.validate_online = validate_online
def _validate_peppol_id_online(self, value):
base_hostnames = ['participant.sml.prod.tech.peppol.org', 'participant.sml.test.tech.peppol.org']
smp_id = base64.b32encode(hashlib.sha256(value.lower().encode()).digest()).decode().rstrip("=")
for base_hostname in base_hostnames:
smp_domain = f'{smp_id}.iso6523-actorid-upis.{base_hostname}'
resolver = dns.resolver.Resolver()
try:
answers = resolver.resolve(smp_domain, 'NAPTR', lifetime=1.0)
if answers:
return value
except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
# ID not registered, do not set found=True
pass
except Exception: # noqa
# Error likely on our end or infrastructure is down, allow user to proceed
return value
raise ValidationError(
_("The Peppol participant ID is not registered on the Peppol network."),
)
def __call__(self, value):
if ":" not in value:
raise ValidationError(_("A Peppol participant ID always starts with a prefix, followed by a colon (:)."))
@@ -146,25 +167,7 @@ class PeppolIdValidator:
params={"number": prefix})
if self.validate_online:
base_hostnames = ['edelivery.tech.ec.europa.eu', 'acc.edelivery.tech.ec.europa.eu']
smp_id = base64.b32encode(hashlib.sha256(value.lower().encode()).digest()).decode().rstrip("=")
for base_hostname in base_hostnames:
smp_domain = f'{smp_id}.iso6523-actorid-upis.{base_hostname}'
resolver = dns.resolver.Resolver()
try:
answers = resolver.resolve(smp_domain, 'NAPTR', lifetime=1.0)
if answers:
return value
except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
# ID not registered, do not set found=True
pass
except Exception: # noqa
# Error likely on our end or infrastructure is down, allow user to proceed
return value
raise ValidationError(
_("The Peppol participant ID is not registered on the Peppol network."),
)
value = self._validate_peppol_id_online(value)
return value
+21 -4
View File
@@ -151,12 +151,29 @@ class LoggingMixin:
logentry = LogEntry(content_object=self, user=user, action_type=action, event=event,
organizer_id=organizer_id, **kwargs)
if isinstance(data, dict):
sensitivekeys = ['password', 'secret', 'api_key']
# sensitivekeys are matched whether contained, not exactly
sensitivekeys = [
'auth',
'key',
'token',
'password',
'Password',
'_pass',
'salt',
'secret',
]
for sensitivekey in sensitivekeys:
for k, v in data.items():
if (sensitivekey in k) and v:
def clean_recursive(d):
data = d
data_iterator = d.items() if isinstance(d, dict) else enumerate(d)
for k, v in data_iterator:
if v and any([sensitivekey in str(k) for sensitivekey in sensitivekeys]):
data[k] = "********"
elif isinstance(v, (list, dict)):
data[k] = clean_recursive(v)
return data
data = clean_recursive(data)
logentry.data = json.dumps(data, cls=CustomJSONEncoder, sort_keys=True)
elif data:
+20 -6
View File
@@ -83,6 +83,8 @@ from .organizer import Organizer, Team
if TYPE_CHECKING:
from hierarkey.proxy import HierarkeyProxy
from .organizer import SalesChannel
logger = logging.getLogger(__name__)
@@ -336,12 +338,18 @@ class EventMixin:
return safe_string(json.dumps(eventdict))
@classmethod
def annotated(cls, qs, channel, voucher=None):
def annotated(cls, qs, channel: "str | SalesChannel | list[SalesChannel]", voucher=None):
# Channel can currently be a SalesChannel or a str, since we need that compatibility, but a SalesChannel
# makes the query SIGNIFICANTLY faster
from pretix.base.models import Item, ItemVariation, Quota, SalesChannel
assert isinstance(channel, (SalesChannel, str))
assert isinstance(channel, (SalesChannel, str, list))
if isinstance(channel, SalesChannel):
channel = [channel]
if isinstance(channel, list):
assert all(isinstance(c, SalesChannel) for c in channel)
sq_active_item = Item.objects.using(settings.DATABASE_REPLICA).filter_available(channel=channel, voucher=voucher).filter(
Q(variations__isnull=True)
@@ -364,8 +372,8 @@ class EventMixin:
q_variation &= Q(Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=channel))
q_variation &= Q(Q(item__all_sales_channels=True) | Q(item__limit_sales_channels__identifier=channel))
else:
q_variation &= Q(Q(all_sales_channels=True) | Q(limit_sales_channels=channel))
q_variation &= Q(Q(item__all_sales_channels=True) | Q(item__limit_sales_channels=channel))
q_variation &= Q(Q(all_sales_channels=True) | Q(limit_sales_channels__in=channel))
q_variation &= Q(Q(item__all_sales_channels=True) | Q(item__limit_sales_channels__in=channel))
if voucher:
if voucher.variation_id:
@@ -1661,11 +1669,17 @@ class SubEvent(EventMixin, LoggedModel):
return qs_annotated
@classmethod
def annotated(cls, qs, channel, voucher=None):
def annotated(cls, qs, channel: "str | SalesChannel | list[SalesChannel]", voucher=None):
from .items import SubEventItem, SubEventItemVariation
from .organizer import SalesChannel
assert isinstance(channel, (str, SalesChannel))
assert isinstance(channel, (SalesChannel, str, list))
if isinstance(channel, SalesChannel):
channel = [channel]
if isinstance(channel, list):
assert all(isinstance(c, SalesChannel) for c in channel)
qs = super().annotated(qs, channel, voucher=voucher)
qs = qs.annotate(
+11 -6
View File
@@ -313,7 +313,14 @@ def filter_available(qs, channel='web', voucher=None, allow_addons=False, allow_
# makes the query SIGNIFICANTLY faster
from .organizer import SalesChannel
assert isinstance(channel, (SalesChannel, str))
assert isinstance(channel, (SalesChannel, str, list))
if isinstance(channel, SalesChannel):
channel = [channel]
if isinstance(channel, list):
assert all(isinstance(c, SalesChannel) for c in channel)
q = (
# IMPORTANT: If this is updated, also update the ItemVariation query
# in models/event.py: EventMixin.annotated()
@@ -325,7 +332,7 @@ def filter_available(qs, channel='web', voucher=None, allow_addons=False, allow_
if isinstance(channel, str):
q &= Q(Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=channel))
else:
q &= Q(Q(all_sales_channels=True) | Q(limit_sales_channels=channel))
q &= Q(Q(all_sales_channels=True) | Q(limit_sales_channels__in=channel))
if not allow_addons:
q &= Q(Q(category__isnull=True) | Q(category__is_addon=False))
@@ -1050,10 +1057,8 @@ class Item(LoggedModel):
replace_year = valid_until.year
replace_month = valid_until.month + self.validity_dynamic_duration_months
while replace_month > 12:
replace_month -= 12
replace_year += 1
replace_year += (replace_month - 1) // 12
replace_month = ((replace_month - 1) % 12) + 1
max_day = calendar.monthrange(replace_year, replace_month)[1]
replace_date = date(
year=replace_year,
+20 -1
View File
@@ -42,7 +42,7 @@ from django.conf import settings
from django.core.mail import get_connection
from django.core.validators import MinLengthValidator, RegexValidator
from django.db import models
from django.db.models import Q
from django.db.models import Exists, OuterRef, Q
from django.urls import reverse
from django.utils.crypto import get_random_string
from django.utils.functional import cached_property
@@ -312,6 +312,25 @@ class Organizer(LoggedModel):
)
i += 1
def get_users_with_permission(self, permission):
"""
Returns a queryset of users who have a specific permission to this organizer.
:return: Iterable of User
"""
from .auth import User
if permission:
qs = Team.objects.with_organizer_permission(permission)
else:
qs = Team.objects.all()
team_with_perm = qs.filter(
members__pk=OuterRef('pk'),
organizer=self,
)
return User.objects.filter(Exists(team_with_perm))
def generate_invite_token():
return get_random_string(length=32, allowed_chars=string.ascii_lowercase + string.digits)
+34 -11
View File
@@ -35,12 +35,13 @@
import logging
from collections import OrderedDict, namedtuple
from itertools import groupby
from typing import Optional, Union
from django.dispatch import receiver
from django.utils.formats import date_format
from django.utils.translation import gettext_lazy as _, pgettext_lazy
from pretix.base.models import Event, LogEntry
from pretix.base.models import Event, LogEntry, Organizer
from pretix.base.signals import register_notification_types
from pretix.base.templatetags.money import money_filter
from pretix.helpers.urls import mainreverse_absolute
@@ -57,7 +58,8 @@ class Notification:
"""
Represents a notification that is sent/shown to a user. A notification consists of:
* one ``event`` reference
* one ``event`` reference (can be ``Ǹone``)
* one ``organizer`` reference
* one ``title`` text that is shown e.g. in the email subject or in a headline
* optionally one ``detail`` text that may or may not be shown depending on the notification method
* optionally one ``url`` that should be absolute and point to the context of an notification (e.g. an order)
@@ -67,8 +69,12 @@ class Notification:
each consisting of a button label and an absolute URL to point to.
"""
def __init__(self, event: Event, title: str, detail: str=None, url: str=None):
def __init__(self, event: Optional[Event], title: str, detail: Optional[str]=None, url: Optional[str]=None, organizer: Optional[Organizer]=None):
assert event or organizer, "You need to pass either event or organizer"
if event and organizer:
assert event.organizer_id == organizer.id, "Organizer and event mismatch"
self.title = title
self.organizer = organizer or event.organizer
self.event = event
self.detail = detail
self.url = url
@@ -91,8 +97,16 @@ class Notification:
class NotificationType:
def __init__(self, event: Event = None):
self.event = event
def __init__(self, event_or_organizer: Union[Event, Organizer] = None):
if isinstance(event_or_organizer, Event):
self.event = event_or_organizer
self.organizer = event_or_organizer.organizer
elif isinstance(event_or_organizer, Organizer):
self.event = None
self.organizer = event_or_organizer
else:
self.event = None
self.organizer = None
def __repr__(self):
return '<NotificationType: {}>'.format(self.action_type)
@@ -121,31 +135,39 @@ class NotificationType:
"""
raise NotImplementedError() # NOQA
@property
def is_event_level(self) -> bool:
"""
Return `True` if this notification type can be configured per event (the default).
"""
return True
def build_notification(self, logentry: LogEntry) -> Notification:
"""
This is the main function that you should override. It is supposed to turn a log entry
object into a notification object that can then be rendered e.g. into an email.
"""
return Notification(
logentry.event,
logentry.display()
event=logentry.event,
title=logentry.display(),
organizer=logentry.organizer,
)
def get_all_notification_types(event=None):
def get_all_notification_types(event_or_organizer=None):
global _ALL_TYPES
if event is None and _ALL_TYPES:
if event_or_organizer is None and _ALL_TYPES:
return _ALL_TYPES
types = OrderedDict()
for recv, ret in register_notification_types.send(event):
for recv, ret in register_notification_types.send(event_or_organizer):
if isinstance(ret, (list, tuple)):
for r in ret:
types[r.action_type] = r
else:
types[ret.action_type] = ret
if event is None:
if event_or_organizer is None:
_ALL_TYPES = types
return types
@@ -181,6 +203,7 @@ class ParametrizedOrderNotificationType(NotificationType):
n = Notification(
event=logentry.event,
organizer=logentry.organizer,
title=self._title.format(order=order, event=logentry.event),
url=order_url
)
+35 -29
View File
@@ -1527,42 +1527,37 @@ class GiftCardPayment(BasePaymentProvider):
})
def refund_control_render(self, request, refund) -> str:
from .models import GiftCard
if 'gift_card' in refund.info_data:
gc = GiftCard.objects.get(pk=refund.info_data.get('gift_card'))
template = get_template('pretixcontrol/giftcards/payment.html')
ctx = {
'request': request,
'event': self.event,
'gc': gc,
}
try:
gc = self.event.organizer.accepted_gift_cards.get(pk=refund.info_data.get('gift_card'))
ctx['gc'] = gc
except GiftCard.DoesNotExist:
pass
return template.render(ctx)
def payment_control_render(self, request, payment) -> str:
from .models import GiftCard
template = get_template('pretixcontrol/giftcards/payment.html')
ctx = {
'request': request,
'event': self.event,
**({'error': payment.info_data[
'error']} if 'error' in payment.info_data else {}),
**({'gift_card_secret': payment.info_data[
'gift_card_secret']} if 'gift_card_secret' in payment.info_data else {})
}
if any(key in payment.info_data for key in ('gift_card', 'error')):
template = get_template('pretixcontrol/giftcards/payment.html')
ctx = {
'request': request,
'event': self.event,
**({'error': payment.info_data[
'error']} if 'error' in payment.info_data else {}),
**({'gift_card_secret': payment.info_data[
'gift_card_secret']} if 'gift_card_secret' in payment.info_data else {})
}
try:
ctx['gc'] = self.event.organizer.accepted_gift_cards.get(pk=payment.info_data.get('gift_card'))
except GiftCard.DoesNotExist:
pass
try:
gc = GiftCard.objects.get(pk=payment.info_data.get('gift_card'))
ctx = {
'gc': gc,
}
except GiftCard.DoesNotExist:
pass
finally:
return template.render(ctx)
if any(key in ctx for key in ('gc', 'gift_card_secret', 'error')):
return template.render(ctx)
def payment_control_render_short(self, payment: OrderPayment) -> str:
d = payment.info_data
@@ -1572,10 +1567,9 @@ class GiftCardPayment(BasePaymentProvider):
d = refund.info_data
return d.get('gift_card_secret', d.get('gift_card_code', self.public_name))
def api_payment_details(self, payment: OrderPayment):
from .models import GiftCard
def api_payment_details(self, payment: OrderPayment | OrderRefund):
try:
gc = GiftCard.objects.get(pk=payment.info_data.get('gift_card'))
gc = self.event.organizer.accepted_gift_cards.get(pk=payment.info_data.get('gift_card'))
except GiftCard.DoesNotExist:
return {
**({'error': payment.info_data[
@@ -1698,7 +1692,19 @@ class GiftCardPayment(BasePaymentProvider):
@transaction.atomic()
def execute_refund(self, refund: OrderRefund):
from .models import GiftCard
gc = GiftCard.objects.get(pk=refund.info_data.get('gift_card') or refund.payment.info_data.get('gift_card'))
try:
gc = self.event.organizer.accepted_gift_cards.get(
pk=refund.info_data.get('gift_card') or refund.payment.info_data.get('gift_card'),
currency=self.event.currency
)
except GiftCard.DoesNotExist:
raise PaymentException(_("Gift card not found."))
if gc.testmode != refund.order.testmode:
raise PaymentException(_("Only test gift card can be used in test mode and vice versa."))
if gc.expires and gc.expires < time_machine_now():
raise PaymentException(_("This gift card is no longer valid."))
trans = gc.transactions.create(
value=refund.amount,
order=refund.order,
+1 -1
View File
@@ -1091,7 +1091,7 @@ class Renderer:
fontsize = float(o['fontsize'])
height = float(o['height']) * mm
width = float(o['width']) * mm
while True:
for _i in range(25): # try adapting the font size at most 25 times
p, ad, lineheight = self._text_paragraph(op, order, o, override_fontsize=fontsize)
w, h = p.wrapOn(canvas, width, 1000 * mm)
widths = p.getActualLineWidths0()
+1
View File
@@ -330,5 +330,6 @@ def register_default_organizer_permissions(sender, **kwargs):
PermissionOption(actions=tuple(), label=pgettext_lazy("permission_level", "No access")),
PermissionOption(actions=("read",), label=pgettext_lazy("permission_level", "View")),
],
help_text=_("View access includes the option to e.g. abort pending emails or retry failed emails."),
),
]
+1 -1
View File
@@ -22,9 +22,9 @@
import os
import sys
from enum import Enum
from importlib import metadata
from typing import List
import importlib_metadata as metadata
from django.apps import AppConfig, apps
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
+6 -3
View File
@@ -54,7 +54,7 @@ from celery.exceptions import MaxRetriesExceededError
from django.conf import settings
from django.core.files.storage import default_storage
from django.core.mail import EmailMultiAlternatives, SafeMIMEMultipart
from django.core.mail.message import SafeMIMEText
from django.core.mail.message import SafeMIMEText, utf8_charset_qp
from django.db import connection, transaction
from django.db.models import Q
from django.dispatch import receiver
@@ -316,6 +316,7 @@ def mail(email: Union[str, Sequence[str]], subject: Union[str, FormattedString],
body_html = None
m = OutgoingMail.objects.create(
guid=guid,
organizer=organizer,
event=event,
order=order,
@@ -380,6 +381,8 @@ def mail(email: Union[str, Sequence[str]], subject: Union[str, FormattedString],
class CustomEmail(EmailMultiAlternatives):
encoding = utf8_charset_qp
def _create_mime_attachment(self, content, mimetype):
"""
Convert the content, mimetype pair into a MIME attachment object.
@@ -449,9 +452,9 @@ def mail_send_task(self, **kwargs) -> bool:
# Rewrite all <img> tags from real URLs or data URLs to inline attachments referred to by content ID
if outgoing_mail.body_html is not None:
html_message = SafeMIMEMultipart(_subtype='related', encoding=settings.DEFAULT_CHARSET)
html_message = SafeMIMEMultipart(_subtype='related')
html_with_cid, cid_images = replace_images_with_cid_paths(outgoing_mail.body_html)
html_message.attach(SafeMIMEText(html_with_cid, 'html', settings.DEFAULT_CHARSET))
html_message.attach(SafeMIMEText(html_with_cid, 'html', utf8_charset_qp))
attach_cid_images(html_message, cid_images, verify_ssl=True)
email.attach_alternative(html_message, "multipart/related")
+37 -18
View File
@@ -34,7 +34,9 @@ from pretix.base.models import (
from pretix.base.notifications import Notification, get_all_notification_types
from pretix.base.services.mail import mail_send_task
from pretix.base.services.tasks import ProfiledTask, TransactionAwareTask
from pretix.base.signals import notification
from pretix.base.signals import (
event_notification_sent, organizer_notification_sent,
)
from pretix.celery_app import app
from pretix.helpers.celery import get_task_priority
from pretix.helpers.urls import mainreverse_absolute
@@ -47,40 +49,47 @@ def notify(logentry_ids: list):
logentry_ids = [logentry_ids]
qs = LogEntry.all.select_related(
'event', 'event__organizer'
'event', 'event__organizer', 'organizer'
).order_by(
'action_type', 'event_id',
'action_type', 'event_id', 'organizer_id',
).filter(id__in=logentry_ids)
_event, _at, notify_specific, notify_global = None, None, None, None
_event, _organizer, _at, notify_specific, notify_global = None, None, None, None, None
for logentry in qs:
if not logentry.event:
break # Ignore, we only have event-related notifications right now
if not logentry.event and not logentry.organizer:
break # Ignore, we only have event- or organizer-related notifications right now
notification_type = logentry.notification_type
if not notification_type:
break # No suitable plugin
if _event != logentry.event or _at != logentry.action_type or notify_global is None:
if _event != logentry.event or _organizer != logentry.organizer or _at != logentry.action_type or notify_global is None:
_event = logentry.event
_organizer = logentry.organizer
_at = logentry.action_type
event_or_organizer = logentry.event or logentry.organizer
# All users that have the permission to get the notification
users = logentry.event.get_users_with_permission(
users = event_or_organizer.get_users_with_permission(
notification_type.required_permission
).filter(notifications_send=True, is_active=True)
if logentry.user:
users = users.exclude(pk=logentry.user.pk)
# Get all notification settings, both specific to this event as well as global
notify_specific = {
(ns.user, ns.method): ns.enabled
for ns in NotificationSetting.objects.filter(
event=logentry.event,
action_type=notification_type.action_type,
user__pk__in=users.values_list('pk', flat=True)
)
}
if logentry.event:
notify_specific = {
(ns.user, ns.method): ns.enabled
for ns in NotificationSetting.objects.filter(
event=logentry.event,
action_type=notification_type.action_type,
user__pk__in=users.values_list('pk', flat=True)
)
}
else:
notify_specific = {}
notify_global = {
(ns.user, ns.method): ns.enabled
for ns in NotificationSetting.objects.filter(
@@ -106,7 +115,10 @@ def notify(logentry_ids: list):
priority=get_task_priority("notifications", logentry.organizer_id),
)
notification.send(logentry.event, logentry_id=logentry.id, notification_type=notification_type.action_type)
if logentry.event:
event_notification_sent.send(logentry.event, logentry_id=logentry.id, notification_type=notification_type.action_type)
elif logentry.organizer:
organizer_notification_sent.send(logentry.organizer, logentry_id=logentry.id, notification_type=notification_type.action_type)
@app.task(base=ProfiledTask, acks_late=True, max_retries=9, default_retry_delay=900)
@@ -158,13 +170,20 @@ def send_notification_mail(notification: Notification, user: User):
body_plain = tpl_plain.render(ctx)
guid = uuid.uuid4()
settings_holder = notification.event or notification.organizer
prefix = settings_holder.settings.mail_prefix
if not prefix:
if notification.event:
prefix = notification.event.slug.upper()
elif notification.organizer:
prefix = notification.organizer.name
m = OutgoingMail.objects.create(
guid=guid,
user=user,
to=[user.email],
subject='[{}] {}: {}'.format(
settings.PRETIX_INSTANCE_NAME,
notification.event.settings.mail_prefix or notification.event.slug.upper(),
prefix,
notification.title
),
body_plain=body_plain,
+40 -12
View File
@@ -359,7 +359,8 @@ def mark_order_refunded(order, user=None, auth=None, api_token=None):
def mark_order_expired(order, user=None, auth=None):
"""
Mark this order as expired. This sets the payment status and returns the order object.
Mark this order as expired. This sets the order status, generates an invoice cancellation
and returns the order object.
:param order: The order to change
:param user: The user that performed the change
"""
@@ -969,7 +970,7 @@ def _apply_rounding_and_fees(positions: List[CartPosition], payment_requests: Li
gift_cards = [] # for backwards compatibility
for p in payment_requests:
if p['provider'] == 'giftcard':
gift_cards.append(GiftCard.objects.get(pk=p['info_data']['gift_card']))
gift_cards.extend(event.organizer.accepted_gift_cards.filter(pk=p['info_data']['gift_card']))
for recv, resp in order_fee_calculation.send(sender=event, invoice_address=address, total=total, payment_requests=payment_requests,
meta_info=meta_info, positions=positions, gift_cards=gift_cards):
@@ -2175,7 +2176,8 @@ class OrderChangeManager:
subevent=a.subevent,
voucher=None,
base_qs=Item.objects.filter(pk=a.item.pk),
allow_addons=True
allow_addons=True,
ignore_hide_sold_out_for_item_ids={a.item.pk}
)
if (not items) or items[0].current_unavailability_reason:
return False
@@ -2474,7 +2476,11 @@ class OrderChangeManager:
self.order.log_action('pretix.event.order.changed.feevalue', user=self.user, auth=self.auth, data={
'fee': fee.pk,
'old_price': fee.value,
'new_price': op.value.gross
'new_price': op.value.gross,
'old_tax_rate': fee.tax_rate,
'new_tax_rate': op.value.rate,
'old_tax_value': fee.tax_value,
'new_tax_value': op.value.tax,
})
fee.value = op.value.gross
fee._calculate_tax()
@@ -2484,9 +2490,13 @@ class OrderChangeManager:
self.order.log_action('pretix.event.order.changed.price', user=self.user, auth=self.auth, data={
'position': position.pk,
'positionid': position.positionid,
'old_price': position.price,
'addon_to': position.addon_to_id,
'new_price': op.price.gross
'old_price': position.price,
'new_price': op.price.gross,
'old_tax_rate': position.tax_rate,
'new_tax_rate': op.price.rate,
'old_tax_value': position.tax_value,
'new_tax_value': op.price.tax,
})
position.price = op.price.gross
position.price_includes_rounding_correction = Decimal("0.00")
@@ -2501,25 +2511,43 @@ class OrderChangeManager:
elif isinstance(op, self.TaxRuleOperation):
if isinstance(op.position, OrderPosition):
position = position_cache.setdefault(op.position.pk, op.position)
self.order.log_action('pretix.event.order.changed.tax_rule', user=self.user, auth=self.auth, data={
log = {
'position': position.pk,
'positionid': position.positionid,
'addon_to': position.addon_to_id,
'old_taxrule': position.tax_rule.pk if position.tax_rule else None,
'new_taxrule': op.tax_rule.pk
})
'new_taxrule': op.tax_rule.pk,
'old_price': position.price,
'old_tax_rate': position.tax_rate,
'old_tax_value': position.tax_value,
}
position._calculate_tax(op.tax_rule)
position.save()
log.update({
'new_price': position.price,
'new_tax_rate': position.tax_rate,
'new_tax_value': position.tax_value,
})
self.order.log_action('pretix.event.order.changed.tax_rule', user=self.user, auth=self.auth, data=log)
elif isinstance(op.position, OrderFee):
fee = fee_cache.setdefault(op.position.pk, op.position)
self.order.log_action('pretix.event.order.changed.tax_rule', user=self.user, auth=self.auth, data={
log = {
'fee': fee.pk,
'fee_type': fee.fee_type,
'old_taxrule': fee.tax_rule.pk if fee.tax_rule else None,
'new_taxrule': op.tax_rule.pk
})
'new_taxrule': op.tax_rule.pk,
'old_price': fee.value,
'old_tax_rate': fee.tax_rate,
'old_tax_value': fee.tax_value,
}
fee._calculate_tax(op.tax_rule)
fee.save()
log.update({
'new_price': fee.value,
'new_tax_rate': fee.tax_rate,
'new_tax_value': fee.tax_value,
})
self.order.log_action('pretix.event.order.changed.tax_rule', user=self.user, auth=self.auth, data=log)
elif isinstance(op, self.CancelFeeOperation):
fee = fee_cache.setdefault(op.fee.pk, op.fee)
self.order.log_action('pretix.event.order.changed.cancelfee', user=self.user, auth=self.auth, data={
+5
View File
@@ -752,6 +752,11 @@ def base_placeholders(sender, **kwargs):
lambda position_or_address: concatenation_for_salutation(get_best_name(position_or_address, parts=True)),
lambda event: concatenation_for_salutation(name_scheme['sample']),
))
ph.append(SimpleFunctionalTextPlaceholder(
"attendee_name_for_salutation", ["position"],
lambda position: concatenation_for_salutation(position.attendee_name_parts),
lambda event: concatenation_for_salutation(name_scheme['sample']),
))
for f, l, w in name_scheme['fields']:
if f == 'full_name':
+2 -2
View File
@@ -126,10 +126,10 @@ def generate_seats(event, subevent, plan, mapping, blocked_guids=None):
for s in current_seats.values():
if s.has_op:
raise SeatProtected(_('You can not change the plan since seat "%s" is not present in the new plan and is '
'already sold.', s.name))
'already sold.'), s.name)
if s.has_v:
raise SeatProtected(_('You can not change the plan since seat "%s" is not present in the new plan and is '
'already used in a voucher.', s.name))
'already used in a voucher.'), s.name)
Seat.objects.bulk_create(create_seats)
CartPosition.objects.filter(addon_to__seat__in=[s.pk for s in current_seats.values()]).delete()
-4
View File
@@ -3767,10 +3767,6 @@ Your {organizer} team""")) # noqa: W291
'default': "7B227073704964223A2239373943394538343346343131343044463144313834343232393232313734313034353044314339464446394437384337313531303944334643463542433731222C2276657273696F6E223A312C22637265617465644F6E223A313536363233343735303036312C227369676E6174757265223A22333038303036303932613836343838366637306430313037303261303830333038303032303130313331306633303064303630393630383634383031363530333034303230313035303033303830303630393261383634383836663730643031303730313030303061303830333038323033653333303832303338386130303330323031303230323038346333303431343935313964353433363330306130363038326138363438636533643034303330323330376133313265333032633036303335353034303330633235343137303730366336353230343137303730366336393633363137343639366636653230343936653734363536373732363137343639366636653230343334313230326432303437333333313236333032343036303335353034306230633164343137303730366336353230343336353732373436393636363936333631373436393666366532303431373537343638366637323639373437393331313333303131303630333535303430613063306134313730373036633635323034393665363332653331306233303039303630333535303430363133303235353533333031653137306433313339333033353331333833303331333333323335333735613137306433323334333033353331333633303331333333323335333735613330356633313235333032333036303335353034303330633163363536333633326437333664373032643632373236663662363537323264373336393637366535663535343333343264353035323466343433313134333031323036303335353034306230633062363934663533323035333739373337343635366437333331313333303131303630333535303430613063306134313730373036633635323034393665363332653331306233303039303630333535303430363133303235353533333035393330313330363037326138363438636533643032303130363038326138363438636533643033303130373033343230303034633231353737656465626436633762323231386636386464373039306131323138646337623062643666326332383364383436303935643934616634613534313162383334323065643831316633343037653833333331663163353463336637656233323230643662616435643465666634393238393839336537633066313361333832303231313330383230323064333030633036303335353164313330313031666630343032333030303330316630363033353531643233303431383330313638303134323366323439633434663933653465663237653663346636323836633366613262626664326534623330343530363038326230363031303530353037303130313034333933303337333033353036303832623036303130353035303733303031383632393638373437343730336132663266366636333733373032653631373037303663363532653633366636643266366636333733373033303334326436313730373036633635363136393633363133333330333233303832303131643036303335353164323030343832303131343330383230313130333038323031306330363039326138363438383666373633363430353031333038316665333038316333303630383262303630313035303530373032303233303831623630633831623335323635366336393631366536333635323036663665323037343638363937333230363336353732373436393636363936333631373436353230363237393230363136653739323037303631373237343739323036313733373337353664363537333230363136333633363537303734363136653633363532303666363632303734363836353230373436383635366532303631373037303663363936333631363236633635323037333734363136653634363137323634323037343635373236643733323036313665363432303633366636653634363937343639366636653733323036663636323037353733363532633230363336353732373436393636363936333631373436353230373036663663363936333739323036313665363432303633363537323734363936363639363336313734363936663665323037303732363136333734363936333635323037333734363137343635366436353665373437333265333033363036303832623036303130353035303730323031313632613638373437343730336132663266373737373737326536313730373036633635326536333666366432663633363537323734363936363639363336313734363536313735373436383666373236393734373932663330333430363033353531643166303432643330326233303239613032376130323538363233363837343734373033613266326636333732366332653631373037303663363532653633366636643266363137303730366336353631363936333631333332653633373236633330316430363033353531643065303431363034313439343537646236666435373438313836383938393736326637653537383530376537396235383234333030653036303335353164306630313031666630343034303330323037383033303066303630393261383634383836663736333634303631643034303230353030333030613036303832613836343863653364303430333032303334393030333034363032323130306265303935373166653731653165373335623535653561666163623463373266656234343566333031383532323263373235313030326236316562643666353530323231303064313862333530613564643664643665623137343630333562313165623263653837636661336536616636636264383338303839306463383263646461613633333038323032656533303832303237356130303330323031303230323038343936643266626633613938646139373330306130363038326138363438636533643034303330323330363733313162333031393036303335353034303330633132343137303730366336353230353236663666373432303433343132303264323034373333333132363330323430363033353530343062306331643431373037303663363532303433363537323734363936363639363336313734363936663665323034313735373436383666373236393734373933313133333031313036303335353034306130633061343137303730366336353230343936653633326533313Line truncated
'type': str,
},
'widget_vue2_origins': {
'default': '',
'type': str,
},
}
PERSON_NAME_TITLE_GROUPS = OrderedDict([
('english_common', (_('Most common English titles'), (
+17 -6
View File
@@ -605,15 +605,14 @@ subclass of pretix.base.ticketoutput.BaseTicketOutput
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""
register_notification_types = EventPluginSignal()
register_notification_types = GlobalSignal()
"""
This signal is sent out to get all known notification types. Receivers should return an
instance of a subclass of pretix.base.notifications.NotificationType or a list of such
instances.
As with all event-plugin signals, the ``sender`` keyword argument will contain the event,
however for this signal, the ``sender`` **may also be None** to allow creating the general
notification settings!
When called for actually sending notifications, ``sender`` will be the event or organizer,
depending on context.
"""
register_event_permission_groups = GlobalSignal()
@@ -628,7 +627,7 @@ This signal is sent out to get all known permissions. Receivers should return an
instance of pretix.base.permissions.PermissionGroup or a list of such instances.
"""
notification = EventPluginSignal()
event_notification_sent = EventPluginSignal()
"""
Arguments: ``logentry_id``, ``notification_type``
@@ -637,6 +636,15 @@ This signal is sent out when a notification is sent.
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""
organizer_notification_sent = OrganizerPluginSignal()
"""
Arguments: ``logentry_id``, ``notification_type``
This signal is sent out when a notification is sent.
As with all organizer-plugin signals, the ``sender`` keyword argument will contain the organizer.
"""
register_sales_channel_types = GlobalSignal()
"""
This signal is sent out to get all known sales channels types. Receivers should return an
@@ -1191,11 +1199,14 @@ The ``sender`` keyword argument will contain the organizer.
customer_signed_in = OrganizerPluginSignal(allow_legacy_plugins=True)
"""
Arguments: ``customer``
Arguments: ``customer``, ``profile``
This signal is sent out every time a customer signs in. The ``customer`` object
is given as the first argument.
In case of SSO login, the full claims will be passed in the ``profile`` argument,
e.g. as ``oidc_claims`` for OIDC. Otherwise, ``profile`` will be ``None``.
The ``sender`` keyword argument will contain the organizer.
"""
+1 -1
View File
@@ -23,10 +23,10 @@ import json
import logging
import pathlib
import re
from importlib import metadata
from urllib.parse import urljoin
from urllib.request import urlopen
import importlib_metadata as metadata
from django import template
from django.conf import settings
from django.utils.safestring import mark_safe
+2 -2
View File
@@ -21,8 +21,8 @@
#
import contextvars
from contextlib import contextmanager
from datetime import datetime
from dateutil.parser import parse
from django.utils.timezone import now
from pretix.base.auth import has_event_access_permission
@@ -34,7 +34,7 @@ timemachine_now_var = contextvars.ContextVar('timemachine_now', default=None)
def time_machine_now_assigned_from_request(request):
if hasattr(request, 'event') and f'timemachine_now_dt:{request.event.pk}' in request.session and \
request.event.testmode and has_event_access_permission(request):
request.now_dt = parse(request.session[f'timemachine_now_dt:{request.event.pk}'])
request.now_dt = datetime.fromisoformat(request.session[f'timemachine_now_dt:{request.event.pk}'])
request.now_dt_is_fake = True
else:
request.now_dt = now()
+16
View File
@@ -20,6 +20,7 @@
# <https://www.gnu.org/licenses/>.
#
import logging
import multiprocessing
import os
from celery import Celery, signals
@@ -54,6 +55,21 @@ def on_task_received(sender, request, **kwargs):
logger.info(f"Task {request.id} has trace {trace}")
@receiver(signals.after_setup_task_logger)
def on_after_setup_task_logger(sender, logger, loglevel, logfile, format, colorize, **kwargs):
# This hack seems to be required to get celery to log internal events from eg billiard/pool.py such as
# "worker killed because it used too much memory"
# You can test that it is working by starting a celery worker with a low value like
# --max-memory-per-child 300000
# and then trigger a task. Result should look like this:
# [2026-09-23 10:42:26,234: WARNING/ForkPoolWorker-16]: [???:???] child process exiting after exceeding memory limit (394540KiB / 300000KiB)
# The ???:??? are likely because by copying the handlers, we are also copying the format, but I was unable to find
# a better compatible way.
multi_logger = multiprocessing.get_logger()
multi_logger.setLevel(logging.WARNING)
multi_logger.handlers = logger.handlers
@receiver(signals.task_prerun)
def on_task_prerun(sender, task_id, task, **kwargs):
from pretix.helpers.logs import local
+1 -1
View File
@@ -172,7 +172,7 @@ class CachedFileInput(forms.ClearableFileInput):
from ...base.models import CachedFile
v = super().value_from_datadict(data, files, name)
if v is None and data.get(name + '-cachedfile'): # An explicit "[x] clear" would be False, not None
v = CachedFile.objects.filter(id=data[name + '-cachedfile']).first()
v = CachedFile.objects.filter(id=data[name + '-cachedfile'], web_download=True).first()
if not v.allowed_for_session(self.request):
v = None
return v
+4 -3
View File
@@ -838,9 +838,10 @@ class CancelSettingsForm(SettingsForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.obj.settings.giftcard_expiry_years is not None:
self.fields['cancel_allow_user_paid_refund_as_giftcard'].help_text = gettext(
'You have configured gift cards to be valid {} years plus the year the gift card is issued in.'
).format(self.obj.settings.giftcard_expiry_years)
self.fields['cancel_allow_user_paid_refund_as_giftcard'].help_text = format_html(
gettext('You have configured gift cards to be valid {} years plus the year the gift card is issued in.'),
self.obj.settings.giftcard_expiry_years
)
class PaymentSettingsForm(EventSettingsValidationMixin, SettingsForm):
@@ -105,13 +105,6 @@ class GlobalSettingsForm(SettingsForm):
domain=settings.SITE_URL
)
)),
('widget_vue2_origins', forms.CharField(
widget=forms.Textarea(attrs={'rows': '3'}),
required=False,
# Not translated on purpose, this is a temporary feature and contains too many special case words
label="Vue2 widget origins",
help_text="One origin per line (e.g. https://example.com). Requests from these origins will be served the old vue2-based widget.",
))
])
responses = register_global_settings.send(self)
for r, response in sorted(responses, key=lambda r: str(r[0])):
+2 -2
View File
@@ -22,7 +22,7 @@
from django import forms
from django.core.exceptions import ValidationError
from django.utils.functional import lazy
from django.utils.html import format_html
from django.utils.html import conditional_escape, format_html
from django.utils.translation import gettext_lazy as _
from pretix.base.modelimport_orders import get_order_import_columns
@@ -66,7 +66,7 @@ class ProcessForm(forms.Form):
widget=forms.Select(
attrs={'data-static': 'true'}
),
help_text=c.help_text,
help_text=conditional_escape(c.help_text or ""),
)
def get_columns(self):
+22 -20
View File
@@ -38,7 +38,6 @@ from urllib.parse import urlparse
from django import forms
from django.conf import settings
from django.core.exceptions import ValidationError
from django.db.models import Q
from django.forms import formset_factory, inlineformset_factory
from django.forms.utils import ErrorDict
from django.urls import reverse
@@ -70,9 +69,9 @@ from pretix.base.forms.widgets import (
SplitDateTimePickerWidget, format_placeholders_help_text,
)
from pretix.base.models import (
Customer, Device, Event, EventMetaProperty, Gate, GiftCard,
GiftCardAcceptance, Membership, MembershipType, OrderPosition, Organizer,
ReusableMedium, SalesChannel, Team,
Customer, Device, Event, EventMetaProperty, Gate, GiftCard, Membership,
MembershipType, OrderPosition, Organizer, ReusableMedium, SalesChannel,
Team,
)
from pretix.base.models.customers import CustomerSSOClient, CustomerSSOProvider
from pretix.base.models.organizer import OrganizerFooterLink, TeamQuerySet
@@ -364,7 +363,7 @@ class TeamForm(forms.ModelForm):
for opt in pg.options
],
label=pg.label,
help_text=pg.help_text,
help_text=conditional_escape(pg.help_text or ""),
initial=initial,
widget=forms.RadioSelect,
)
@@ -389,7 +388,7 @@ class TeamForm(forms.ModelForm):
for opt in pg.options
],
label=pg.label,
help_text=pg.help_text,
help_text=conditional_escape(pg.help_text or ""),
initial=initial,
widget=forms.RadioSelect,
)
@@ -894,15 +893,7 @@ class GiftCardCreateForm(forms.ModelForm):
def clean_secret(self):
s = self.cleaned_data['secret']
if GiftCard.objects.filter(
secret__iexact=s
).filter(
Q(issuer=self.organizer) |
Q(issuer__in=GiftCardAcceptance.objects.filter(
acceptor=self.organizer,
active=True,
).values_list('issuer', flat=True))
).exists():
if self.organizer.accepted_gift_cards.filter(secret__iexact=s).exists():
raise ValidationError(
_('A gift card with the same secret already exists in your or an affiliated organizer account.')
)
@@ -1198,7 +1189,7 @@ OrganizerFooterLinkFormset = inlineformset_factory(
class SSOProviderForm(I18nModelForm):
config_oidc_base_url = forms.URLField(
label=pgettext_lazy('sso_oidc', 'Base URL'),
label=pgettext_lazy('sso_oidc', 'Base URL / issuer'),
required=False,
)
config_oidc_client_id = forms.CharField(
@@ -1295,6 +1286,14 @@ class SSOProviderForm(I18nModelForm):
class SSOClientForm(I18nModelForm):
disp_base_url = forms.CharField(
label=_('Base URL / issuer'),
disabled=True,
)
disp_client_id = forms.CharField(
label=_('Client ID'),
disabled=True,
)
regenerate_client_secret = forms.BooleanField(
label=_('Invalidate old client secret and generate a new one'),
required=False,
@@ -1302,7 +1301,8 @@ class SSOClientForm(I18nModelForm):
class Meta:
model = CustomerSSOClient
fields = ['is_active', 'name', 'client_id', 'client_type', 'authorization_grant_type', 'redirect_uris',
fields = ['is_active', 'name', 'disp_base_url', 'disp_client_id', 'regenerate_client_secret',
'client_type', 'authorization_grant_type', 'redirect_uris',
'allowed_scopes', 'require_pkce']
widgets = {
'authorization_grant_type': forms.RadioSelect,
@@ -1317,13 +1317,15 @@ class SSOClientForm(I18nModelForm):
help_text=self.fields['allowed_scopes'].help_text,
required=self.fields['allowed_scopes'].required,
initial=self.fields['allowed_scopes'].initial,
choices=CustomerSSOClient.SCOPE_CHOICES,
choices=[(val, format_html('<code>{}</code> &ndash; {}', val, label)) for val, label in CustomerSSOClient.SCOPE_CHOICES],
widget=forms.CheckboxSelectMultiple
)
organizer = kwargs['event']
self.initial['disp_base_url'] = eventreverse_absolute(organizer, 'presale:organizer.index', {}).strip('/')
if self.instance and self.instance.pk:
self.fields['client_id'].disabled = True
self.initial['disp_client_id'] = self.instance.client_id
else:
del self.fields['client_id']
self.initial['disp_client_id'] = _('(will be generated)')
del self.fields['regenerate_client_secret']
+21 -1
View File
@@ -153,7 +153,7 @@ class SubEventBulkEditForm(I18nModelForm):
self.fields[k].widget.is_required = False
self.fields[k].required = False
for k in ('date_from', 'date_to', 'date_admission', 'presale_start', 'presale_end'):
for k in ('date_from', 'date_to'):
self.fields[k + '_day'] = forms.DateField(
label=self._meta.model._meta.get_field(k).verbose_name,
help_text=self._meta.model._meta.get_field(k).help_text,
@@ -167,6 +167,14 @@ class SubEventBulkEditForm(I18nModelForm):
required=False,
)
for k in ('date_admission', 'presale_start', 'presale_end'):
self.fields[k + '_rel'] = RelativeDateTimeField(
label=self._meta.model._meta.get_field(k).verbose_name,
help_text=self._meta.model._meta.get_field(k).help_text,
required=False,
limit_choices=('event__date_from',),
)
class Meta:
model = SubEvent
localized_fields = '__all__'
@@ -247,6 +255,18 @@ class SubEventBulkEditForm(I18nModelForm):
)
setattr(obj, k.replace('_time', ''), newval)
fields.add(k.replace('_time', ''))
elif k.endswith('_rel'):
target_key = k[:-4]
for obj in objs:
cval = self.cleaned_data[k]
if cval is None:
newval = None
if not self._meta.model._meta.get_field(target_key).null:
continue
else:
newval = cval.datetime(obj)
setattr(obj, target_key, newval)
fields.add(target_key)
else:
fields.add(k)
for obj in objs:
+2 -1
View File
@@ -44,6 +44,7 @@ from django.db.models import Count, F, Max
from django.db.models.functions import Upper
from django.forms.utils import ErrorDict
from django.urls import reverse
from django.utils.html import escape
from django.utils.timezone import now
from django.utils.translation import gettext_lazy as _, pgettext_lazy
from django_scopes.forms import SafeModelChoiceField
@@ -176,7 +177,7 @@ class VoucherForm(I18nModelForm):
required=False,
widget=forms.TextInput(attrs={'data-seat-guid-field': '1'}),
initial=self.instance.seat.seat_guid if self.instance.seat else '',
help_text=str(self.instance.seat) if self.instance.seat else '',
help_text=escape(str(self.instance.seat) if self.instance.seat else ''),
)
def parse_itemvar(self, data):
@@ -16,6 +16,7 @@
<link rel="stylesheet" type="text/x-scss" href="{% static "pretixcontrol/scss/main.scss" %}" />
<link rel="stylesheet" type="text/x-scss" href="{% static "lightbox/css/lightbox.scss" %}" />
{% endcompress %}
{% vite_importmap %}
{% if DEBUG %}
<script type="text/javascript" src="{% url 'javascript-catalog' lang=request.LANGUAGE_CODE %}"></script>
{% else %}
@@ -87,7 +88,6 @@
<meta name="theme-color" content="#3b1c4a">
<meta name="referrer" content="origin">
{% vite_importmap %}
{% block custom_header %}{% endblock %}
</head>
<body data-datetimeformat="{{ js_datetime_format }}" data-timeformat="{{ js_time_format }}"
@@ -33,7 +33,7 @@
</div>
<div class="slug-length alert alert-warning helper-display-none-soft">
{% blocktrans trimmed %}
We strongly recommend against using short forms of more then 16 characters.
We strongly recommend against using short forms of more than 16 characters.
{% endblocktrans %}
</div>
</div>
@@ -1,22 +1,24 @@
{% load i18n %}
<dl class="dl-horizontal">
<dt>{% trans "Gift card code" %}</dt>
<dd>
{% if gc %}
<a href="{% url "control:organizer.giftcard" organizer=gc.issuer.slug giftcard=gc.pk %}">
{{ gc.secret }}
</a>
{% if gc.issuer.slug != request.organizer %}
<span class="text-muted">
<br>
<span class="fa fa-group"></span> {{ gc.issuer }}
</span>
{% if gc or gift_card_secret %}
<dt>{% trans "Gift card code" %}</dt>
<dd>
{% if gc %}
<a href="{% url "control:organizer.giftcard" organizer=gc.issuer.slug giftcard=gc.pk %}">
{{ gc.secret }}
</a>
{% if gc.issuer.slug != request.organizer %}
<span class="text-muted">
<br>
<span class="fa fa-group"></span> {{ gc.issuer }}
</span>
{% endif %}
{% elif gift_card_secret %}
{{ gift_card_secret }}
{% endif %}
{% elif gift_card_secret %}
{{ gift_card_secret }}
{% endif %}
</dd>
</dd>
{% endif %}
{% if gc %}
<dt>{% trans "Issuer" %}</dt>
<dd>{{ gc.issuer }}</dd>
@@ -25,4 +27,4 @@
<dt>{% trans "Error" %}</dt>
<dd>{{ error }}</dd>
{% endif %}
</dl>
</dl>
@@ -1,12 +1,29 @@
{% extends "pretixcontrol/organizers/base.html" %}
{% load i18n %}
{% load bootstrap3 %}
{% block title %}
{% if client %}
{% trans "SSO client:" %} {{ client.name }}
{% else %}
{% trans "Create credentials for a new SSO client" %}
{% endif %}
{% endblock %}
{% block inner %}
{% if client %}
<h1>{% trans "SSO client:" %} {{ client.name }}</h1>
{% else %}
<h1>{% trans "Create a new SSO client" %}</h1>
<h1>{% trans "Create credentials for a new SSO client" %}</h1>
<p>
{% blocktrans trimmed %}
After submitting this form, client credentials for your SSO client will be generated.
{% endblocktrans %}
</p>
{% endif %}
<p>
{% blocktrans trimmed with url="https://docs.pretix.eu/guides/customer-accounts/#using-pretix-as-an-sso-provider" %}
For more information, refer to our documentation on <a href="{{ url }}">Using pretix as an SSO provider with external SSO clients</a>.
{% endblocktrans %}
</p>
<form class="form-horizontal" action="" method="post">
{% csrf_token %}
{% bootstrap_form form layout="control" %}
@@ -3,16 +3,23 @@
{% load bootstrap3 %}
{% block title %}{% trans "SSO clients" %}{% endblock %}
{% block inner %}
<h1>{% trans "SSO clients" %}</h1>
<h1>{% trans "SSO clients" %} <small> &mdash; {% blocktrans %}
"Login with pretix" in external systems
{% endblocktrans %}</small></h1>
<p>
{% blocktrans trimmed %}
You can allow your customers to log into other systems using their customer account credentials by setting up
your other systems as a Single-Sign-On (SSO) client based on OpenID Connect.
{% endblocktrans %}
</p>
<p>
{% blocktrans trimmed with url="https://docs.pretix.eu/guides/customer-accounts/#using-pretix-as-an-sso-provider" %}
For more information, refer to our documentation on <a href="{{ url }}">Using pretix as an SSO provider with external SSO clients</a>.
{% endblocktrans %}
</p>
<a href="{% url "control:organizer.ssoclient.add" organizer=request.organizer.slug %}" class="btn btn-default">
<span class="fa fa-plus"></span>
{% trans "Create a new SSO client" %}
{% trans "Create credentials for a new SSO client" %}
</a>
<table class="table table-condensed table-hover">
<thead>
@@ -1,12 +1,24 @@
{% extends "pretixcontrol/organizers/base.html" %}
{% load i18n %}
{% load bootstrap3 %}
{% block title %}
{% if provider %}
{% trans "External SSO provider:" %} {{ provider.name }}
{% else %}
{% trans "Connect to an external SSO provider" %}
{% endif %}
{% endblock %}
{% block inner %}
{% if provider %}
<h1>{% trans "SSO provider:" %} {{ provider.name }}</h1>
<h1>{% trans "External SSO provider:" %} {{ provider.name }}</h1>
{% else %}
<h1>{% trans "Create a new SSO provider" %}</h1>
<h1>{% trans "Connect to an external SSO provider" %}</h1>
{% endif %}
<p>
{% blocktrans trimmed with url="https://docs.pretix.eu/guides/customer-accounts/#using-pretix-as-an-sso-client" %}
For more information, refer to our documentation on <a href="{{ url }}" target="_blank">Using pretix as an SSO client</a>.
{% endblocktrans %}
</p>
<form class="form-horizontal" action="" method="post">
{% csrf_token %}
{% bootstrap_form form layout="control" %}
@@ -3,16 +3,23 @@
{% load bootstrap3 %}
{% block title %}{% trans "SSO providers" %}{% endblock %}
{% block inner %}
<h1>{% trans "SSO providers" %}</h1>
<h1>{% trans "SSO providers" %} <small> &mdash; {% blocktrans %}
Connect to an external login provider
{% endblocktrans %}</small></h1>
<p>
{% blocktrans trimmed %}
You can connect existing Single-Sign-On (SSO) providers to allow your customers to log in using your own
account system.
{% endblocktrans %}
</p>
<p>
{% blocktrans trimmed with url="https://docs.pretix.eu/guides/customer-accounts/#using-pretix-as-an-sso-client" %}
For more information, refer to our documentation on <a href="{{ url }}" target="_blank">Using pretix as an SSO client</a>.
{% endblocktrans %}
</p>
<a href="{% url "control:organizer.ssoprovider.add" organizer=request.organizer.slug %}" class="btn btn-default">
<span class="fa fa-plus"></span>
{% trans "Create a new SSO provider" %}
{% trans "Connect to an external SSO provider" %}
</a>
<table class="table table-condensed table-hover">
<thead>
@@ -225,6 +225,14 @@
</div>
</div>
<div class="col-md-3" id="editor-toolbox-area">
{% if checkin_qr_warning %}
<div class="alert alert-warning" id="nocheckin-notice">
{% blocktrans trimmed %}
This layout does not contain a QR code that can be used to scan tickets at check-in.
{% endblocktrans %}
</div>
{% endif %}
<div class="panel panel-default" id="toolbox">
<div class="panel-heading">
<span id="toolbox-heading">
@@ -116,39 +116,9 @@
{% bootstrap_field form.date_to_time layout="bulkedit_inline" form_group_class="" %}
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label" for="{{ form.date_admission_day.id_for_label }}">
{{ form.date_admission_day.label }}
</label>
<div class="col-md-5">
{% bootstrap_field form.date_admission_day layout="bulkedit_inline" form_group_class="" %}
</div>
<div class="col-md-4">
{% bootstrap_field form.date_admission_time layout="bulkedit_inline" form_group_class="" %}
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label" for="{{ form.presale_start_day.id_for_label }}">
{{ form.presale_start_day.label }}
</label>
<div class="col-md-5">
{% bootstrap_field form.presale_start_day layout="bulkedit_inline" form_group_class="" %}
</div>
<div class="col-md-4">
{% bootstrap_field form.presale_start_time layout="bulkedit_inline" form_group_class="" %}
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label" for="{{ form.presale_end_day.id_for_label }}">
{{ form.presale_end_day.label }}
</label>
<div class="col-md-5">
{% bootstrap_field form.presale_end_day layout="bulkedit_inline" form_group_class="" %}
</div>
<div class="col-md-4">
{% bootstrap_field form.presale_end_time layout="bulkedit_inline" form_group_class="" %}
</div>
</div>
{% bootstrap_field form.date_admission_rel layout="bulkedit" %}
{% bootstrap_field form.presale_start_rel layout="bulkedit" %}
{% bootstrap_field form.presale_end_rel layout="bulkedit" %}
</fieldset>
<fieldset>
<legend>{% trans "Item prices" %}</legend>
+5 -2
View File
@@ -402,9 +402,12 @@ def event_index_widgets_lazy(request, organizer, event):
except SubEvent.DoesNotExist:
pass
can_view_orders = request.user.has_event_permission(request.organizer, request.event, 'event.orders:read',
request=request)
widgets = []
for r, result in event_dashboard_widgets.send(sender=request.event, subevent=subevent, lazy=False):
widgets.extend(result)
if can_view_orders:
for r, result in event_dashboard_widgets.send(sender=request.event, subevent=subevent, lazy=False):
widgets.extend(result)
return build_json_response(widgets)
+2 -1
View File
@@ -31,7 +31,8 @@
# Unless required by applicable law or agreed to in writing, software distributed under the Apache License 2.0 is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under the License.
import importlib_metadata as metadata
from importlib import metadata as metadata
from django.conf import settings
from django.contrib import messages
from django.db import transaction
+16 -7
View File
@@ -2202,7 +2202,7 @@ class ExportView(OrganizerPermissionRequiredMixin, ExportMixin, ListView):
owner=self.request.user,
timezone=str(get_current_timezone()),
)
if not self.scheduled:
if not self.scheduled and not self.scheduled_copy_from:
initial = {
"mail_subject": gettext("Export: {title}").format(title=self.exporter.verbose_name),
"mail_template": gettext(
@@ -2817,10 +2817,15 @@ class SSOProviderCreateView(OrganizerDetailViewMixin, OrganizerPermissionRequire
return get_object_or_404(CustomerSSOProvider, organizer=self.request.organizer, pk=self.kwargs.get('provider'))
def get_success_url(self):
return reverse('control:organizer.ssoproviders', kwargs={
'organizer': self.request.organizer.slug,
return reverse('control:organizer.ssoprovider.edit', kwargs={
'organizer': self.request.organizer.slug, 'provider': self.object.pk,
})
def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
ctx['redirect_uri'] = _('(will be generated)')
return ctx
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['event'] = self.request.organizer
@@ -2950,8 +2955,11 @@ class SSOClientCreateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredM
secret = form.instance.set_client_secret()
messages.success(
self.request,
_('The SSO client has been created. Please note down the following client secret, it will never be shown '
'again: {secret}').format(secret=secret)
_('The SSO client has been created.') + ' ' +
_('Please note down the following client secret, it will never be shown again.') + '\n\n' +
_('Base URL / issuer') + f': {form.initial["disp_base_url"]}\n\n' +
_('Client ID') + f': {form.instance.client_id}\n\n' +
_('Client secret') + f': {secret}'
)
form.instance.organizer = self.request.organizer
ret = super().form_valid(form)
@@ -3000,8 +3008,9 @@ class SSOClientUpdateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredM
secret = form.instance.set_client_secret()
messages.success(
self.request,
_('Your changes have been saved. Please note down the following client secret, it will never be shown '
'again: {secret}').format(secret=secret)
_('Your changes have been saved.') + ' ' +
_('Please note down the following client secret, it will never be shown again.') + '\n\n' +
_('Client secret') + f': {secret}'
)
else:
messages.success(
+5 -1
View File
@@ -65,6 +65,7 @@ class BaseEditorView(EventPermissionRequiredMixin, TemplateView):
)
maxfilesize = settings.FILE_UPLOAD_MAX_SIZE_IMAGE
minfilesize = 10
checkin_qr_warning = False
title = None
def get(self, request, *args, **kwargs):
@@ -250,6 +251,8 @@ class BaseEditorView(EventPermissionRequiredMixin, TemplateView):
if request.POST.get("background", "").strip():
try:
cf = CachedFile.objects.get(id=request.POST.get("background"), web_download=True)
if not cf.allowed_for_session(request, "ticketoutput-pdf-background"):
cf = None
except CachedFile.DoesNotExist:
pass
@@ -290,6 +293,7 @@ class BaseEditorView(EventPermissionRequiredMixin, TemplateView):
ctx['title'] = self.title
ctx['locales'] = [p for p in settings.LANGUAGES if p[0] in self.request.event.settings.locales]
ctx['maxfilesize'] = self.maxfilesize
ctx['checkin_qr_warning'] = self.checkin_qr_warning
return ctx
@@ -305,7 +309,7 @@ class FontsCSSView(TemplateView):
class PdfView(TemplateView):
def get(self, request, *args, **kwargs):
cf = get_object_or_404(CachedFile, id=kwargs.get("filename"), filename="background_preview.pdf")
cf = get_object_or_404(CachedFile, id=kwargs.get("filename"), filename="background_preview.pdf", web_download=True)
if not cf.allowed_for_session(request, "ticketoutput-pdf-background"):
raise PermissionDenied()
resp = FileResponse(cf.file, filename=cf.filename, content_type='application/pdf')
+62 -22
View File
@@ -85,6 +85,7 @@ from pretix.control.views import PaginationMixin
from pretix.control.views.event import MetaDataEditorMixin
from pretix.helpers import GroupConcat
from pretix.helpers.compat import CompatDeleteView
from pretix.helpers.database import UnixTimestamp
from pretix.helpers.i18n import get_format_without_seconds
from pretix.helpers.models import modelcopy
@@ -1583,21 +1584,6 @@ class SubEventBulkEdit(SubEventQueryMixin, EventPermissionRequiredMixin, FormVie
mixed_values = set()
qs = self.get_queryset()
qs = qs.annotate(
**{
# TODO: Once we're on Django 3.2, pass a tzinfo parameter
# Before Django 3.2, it uses the current timezone, which is hopefully fine
# as well in all cases we are concerned about
# See also: https://code.djangoproject.com/ticket/31948
k + '_day': TruncDate(k)
for k in ('date_from', 'date_to', 'date_admission', 'presale_start', 'presale_end')
},
**{
k + '_time': TruncTime(k)
for k in ('date_from', 'date_to', 'date_admission', 'presale_start', 'presale_end')
},
)
fields = {
'name',
'location',
@@ -1611,21 +1597,75 @@ class SubEventBulkEdit(SubEventQueryMixin, EventPermissionRequiredMixin, FormVie
'date_from_time',
'date_to_day',
'date_to_time',
'date_admission_day',
'date_admission_time',
'presale_start_day',
'presale_start_time',
'presale_end_day',
'presale_end_time',
}
rel_fields = {'date_admission', 'presale_start', 'presale_end'}
qs = qs.annotate(
**{
k + '_day': TruncDate(k, tzinfo=self.request.event.timezone)
for k in ('date_from', 'date_to', 'date_admission')
},
**{
k + '_time': TruncTime(k, tzinfo=self.request.event.timezone)
for k in ('date_from', 'date_to', 'date_admission')
},
**{
k + '_rel_min': (UnixTimestamp('date_from') - UnixTimestamp(k)) / 60
for k in rel_fields
},
**{
k + '_rel_days': TruncDate('date_from', tzinfo=self.request.event.timezone) - TruncDate(k, tzinfo=self.request.event.timezone)
for k in rel_fields
}
)
for k in fields:
existing_values = list(qs.order_by(k).values(k).annotate(c=Count('*')))
existing_values = list(qs.order_by(k).values(k).distinct())
if len(existing_values) == 1:
initial[k] = existing_values[0][k]
elif len(existing_values) > 1:
mixed_values.add(k)
initial[k] = None
for k in rel_fields:
existing_fixed_values = list(qs.order_by(k).values(k).distinct())
existing_rel_days_values = list(qs.order_by(f'{k}_rel_days').values(f'{k}_rel_days').distinct())
existing_rel_min_values = list(qs.order_by(f'{k}_rel_min').values(f'{k}_rel_min').distinct())
if len(existing_fixed_values) == 1:
if existing_fixed_values[0][k]:
initial[f"{k}_rel"] = RelativeDateWrapper(existing_fixed_values[0][k])
else:
initial[f"{k}_rel"] = None
elif len(existing_rel_min_values) == 1:
if rel_min := existing_rel_min_values[0][f'{k}_rel_min']:
initial[f"{k}_rel"] = RelativeDateWrapper(RelativeDate(
days=0,
base_date_name='event__date_from',
time=None,
minutes=abs(rel_min),
is_after=rel_min < 0,
))
else:
initial[f"{k}_rel"] = None
elif len(existing_rel_days_values) == 1:
if rel_days := existing_rel_days_values[0][f'{k}_rel_days']:
initial[f"{k}_rel"] = RelativeDateWrapper(RelativeDate(
days=abs(rel_days.days),
base_date_name='event__date_from',
time=None,
minutes=None,
is_after=rel_days.days < 0,
))
else:
initial[f"{k}_rel"] = None
elif len(existing_fixed_values) > 1 or len(existing_rel_days_values) > 1 or len(existing_rel_min_values) > 1:
mixed_values.add(k)
initial[k] = None
kwargs = super().get_form_kwargs()
kwargs['event'] = self.request.event
kwargs['prefix'] = 'bulkedit'
+1 -1
View File
@@ -342,7 +342,7 @@ def nav_context_list(request):
max_to=Max('subevents__date_to'),
max_fromto=Greatest(Max('subevents__date_to'), Max('subevents__date_from'))
).annotate(
order_from=Coalesce('min_from', 'date_from'),
order_from=Coalesce('max_from', 'date_from'),
).order_by('-order_from', 'slug')
if request.user.has_active_staff_session(request.session.session_key):
+2 -1
View File
@@ -761,6 +761,7 @@ class UserNotificationsEditView(TemplateView):
{k: a.get(t) for k, a in self.global_set.items()},
)
for t, tv in self.types.items()
if tv.is_event_level or not self.event
]
ctx['event'] = self.event
if self.event:
@@ -946,7 +947,7 @@ class UserEmailConfirmView(FormView):
@transaction.atomic()
def form_valid(self, form):
reason = self.request.GET['reason']
reason = self.request.GET.get('reason')
if reason not in ('email_change', 'email_verify'):
raise PermissionDenied
try:
+12 -1
View File
@@ -26,7 +26,8 @@ from django.contrib.postgres.indexes import BrinIndex
from django.core.exceptions import FieldDoesNotExist, ImproperlyConfigured
from django.db import connection, transaction
from django.db.models import (
Aggregate, Expression, F, Field, JSONField, Lookup, OrderBy, Value,
Aggregate, Expression, F, Field, Func, IntegerField, JSONField, Lookup,
OrderBy, Value,
)
from django.utils.functional import lazy
@@ -313,3 +314,13 @@ class IgnoreOnSQLiteMixin:
class BrinIndexIgnoredOnSQLite(IgnoreOnSQLiteMixin, BrinIndex):
pass
class UnixTimestamp(Func):
output_field = IntegerField()
def as_postgresql(self, compiler, connection):
return self.as_sql(compiler, connection, template="EXTRACT(epoch from %(expressions)s)")
def as_sqlite(self, compiler, connection):
return self.as_sql(compiler, connection, template="CAST(strftime('%%%%s', datetime(%(expressions)s)) AS INT)")
+18
View File
@@ -27,6 +27,7 @@ from http import cookies
from django.conf import settings
from django.core.exceptions import SuspiciousFileOperation
from django.middleware.csrf import CsrfViewMiddleware as BaseCsrfMiddleware
from PIL import Image
from requests.adapters import HTTPAdapter
from urllib3.connection import HTTPConnection, HTTPSConnection
@@ -42,6 +43,7 @@ from urllib3.util.timeout import _DEFAULT_TIMEOUT
from pretix.helpers.reportlab import ThumbnailingImageReader
from pretix.helpers.ssrf import should_block_access
from pretix.multidomain.middlewares import CsrfViewMiddleware
def monkeypatch_vobject_performance():
@@ -242,6 +244,20 @@ def monkeypatch_reportlab_imagereader():
utils.ImageReader.__init__ = new_init
def monkeypatch_csrf_middleware():
# Some views from django or plugins use the middleware or the derived decorators directly,
# so we have to also patch the stock middleware
BaseCsrfMiddleware._get_secret = CsrfViewMiddleware._get_secret
BaseCsrfMiddleware._set_csrf_cookie = CsrfViewMiddleware._set_csrf_cookie
def monkeypatch_json_constants():
from json.decoder import _CONSTANTS # noqa
del _CONSTANTS['-Infinity']
del _CONSTANTS['Infinity']
del _CONSTANTS['NaN']
def monkeypatch_all_at_ready():
monkeypatch_vobject_performance()
monkeypatch_pillow_safer()
@@ -249,3 +265,5 @@ def monkeypatch_all_at_ready():
monkeypatch_urllib3_ssrf_protection()
monkeypatch_cookie_morsel()
monkeypatch_reportlab_imagereader()
monkeypatch_csrf_middleware()
monkeypatch_json_constants()
File diff suppressed because it is too large. Load diff
+1 -84
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-07 09:33+0000\n"
"POT-Creation-Date: 2026-09-30 07:26+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
@@ -765,194 +765,163 @@ msgstr ""
msgid "Google Pay"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Quantity"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Decrease quantity"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Increase quantity"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Filter events by"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Filter"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Price"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "Original price: %s"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "New price: %s"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Select"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "Select %s"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "Select variant %s"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Sold out"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Buy"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Register"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Reserved"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "FREE"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "from %(currency)s %(price)s"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "Image of %s"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "incl. %(rate)s% %(taxname)s"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "plus %(rate)s% %(taxname)s"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "incl. taxes"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "plus taxes"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "currently available: %s"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Only available with a voucher"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Not yet available"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Not available anymore"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Currently not available"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "minimum amount to order: %s"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Close ticket shop"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "The ticket shop could not be loaded."
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid ""
@@ -960,25 +929,21 @@ msgid ""
"in a new tab to continue."
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Open ticket shop"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Checkout"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "The cart could not be created. Please try again later"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid ""
@@ -986,13 +951,11 @@ msgid ""
"this ticket shop. Please click \"Continue\" to retry in a new tab."
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Waiting list"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid ""
@@ -1000,115 +963,96 @@ msgid ""
"products, they will be added to your existing cart."
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Resume checkout"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Redeem a voucher"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Redeem"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Voucher code"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Close"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Close checkout"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "You cannot cancel this operation. Please wait for loading to finish."
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Continue"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Show variants"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Hide variants"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Choose a different event"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Choose a different date"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Back"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Next month"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Previous month"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Next week"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Previous week"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Open seat selection"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid ""
@@ -1117,138 +1061,111 @@ msgid ""
"again."
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Load more"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Mo"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Tu"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "We"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Th"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Fr"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Sa"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Su"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Monday"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Tuesday"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Wednesday"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Thursday"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Friday"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Saturday"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Sunday"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "January"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "February"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "March"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "April"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "May"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "June"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "July"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "August"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "September"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "October"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "November"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "December"
msgstr ""
File diff suppressed because it is too large. Load diff
+1 -84
View File
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-06 15:52+0000\n"
"POT-Creation-Date: 2026-09-30 07:26+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -766,194 +766,163 @@ msgstr ""
msgid "Google Pay"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Quantity"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Decrease quantity"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Increase quantity"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Filter events by"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Filter"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Price"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "Original price: %s"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "New price: %s"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Select"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "Select %s"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "Select variant %s"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Sold out"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Buy"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Register"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Reserved"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "FREE"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "from %(currency)s %(price)s"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "Image of %s"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "incl. %(rate)s% %(taxname)s"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "plus %(rate)s% %(taxname)s"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "incl. taxes"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "plus taxes"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "currently available: %s"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Only available with a voucher"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Not yet available"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Not available anymore"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Currently not available"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "minimum amount to order: %s"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Close ticket shop"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "The ticket shop could not be loaded."
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid ""
@@ -961,25 +930,21 @@ msgid ""
"in a new tab to continue."
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Open ticket shop"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Checkout"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "The cart could not be created. Please try again later"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid ""
@@ -987,13 +952,11 @@ msgid ""
"this ticket shop. Please click \"Continue\" to retry in a new tab."
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Waiting list"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid ""
@@ -1001,115 +964,96 @@ msgid ""
"products, they will be added to your existing cart."
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Resume checkout"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Redeem a voucher"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Redeem"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Voucher code"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Close"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Close checkout"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "You cannot cancel this operation. Please wait for loading to finish."
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Continue"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Show variants"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Hide variants"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Choose a different event"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Choose a different date"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Back"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Next month"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Previous month"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Next week"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Previous week"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Open seat selection"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid ""
@@ -1118,138 +1062,111 @@ msgid ""
"again."
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Load more"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Mo"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Tu"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "We"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Th"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Fr"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Sa"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Su"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Monday"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Tuesday"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Wednesday"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Thursday"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Friday"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Saturday"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Sunday"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "January"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "February"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "March"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "April"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "May"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "June"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "July"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "August"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "September"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "October"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "November"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "December"
msgstr ""
File diff suppressed because it is too large. Load diff
+7 -89
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-06 15:52+0000\n"
"POT-Creation-Date: 2026-09-30 07:26+0000\n"
"PO-Revision-Date: 2026-07-13 11:28+0000\n"
"Last-Translator: ahmed badr <ahmedbadr@oma.com.eg>\n"
"Language-Team: Arabic <https://translate.pretix.eu/projects/pretix/pretix-js/"
@@ -648,7 +648,8 @@ msgstr "خطأ غير معروف."
#: pretix/static/pretixcontrol/js/ui/main.js
msgid "Your color has great contrast and will provide excellent accessibility."
msgstr "يتميز لونك بتباين رائع ويسهل قراءته للغاية! وسيوفر إمكانية وصول ممتازة."
msgstr ""
"يتميز لونك بتباين رائع ويسهل قراءته للغاية! وسيوفر إمكانية وصول ممتازة."
#: pretix/static/pretixcontrol/js/ui/main.js
msgid ""
@@ -663,8 +664,8 @@ msgid ""
"Your color has insufficient contrast to white. Accessibility of your site "
"will be impacted."
msgstr ""
"اللون الذي اخترته لا يتمتع بتباين كافٍ مع اللون الأبيض. وسيؤثر ذلك على إمكانية "
"الوصول إلى موقعك."
"اللون الذي اخترته لا يتمتع بتباين كافٍ مع اللون الأبيض. وسيؤثر ذلك على "
"إمكانية الوصول إلى موقعك."
#: pretix/static/pretixcontrol/js/ui/main.js
msgid "Search query"
@@ -794,194 +795,163 @@ msgstr "التوقيت المحلي:"
msgid "Google Pay"
msgstr "Google Pay"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Quantity"
msgstr "الكمية"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Decrease quantity"
msgstr "تقليل الكمية"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Increase quantity"
msgstr "زيادة الكمية"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Filter events by"
msgstr "تصفية الأحداث حسب"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Filter"
msgstr "فلتر"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Price"
msgstr "السعر"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "Original price: %s"
msgstr "السعر الأصلي: %s"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "New price: %s"
msgstr "السعر الجديد: %s"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Select"
msgstr "المختارة فقط"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "Select %s"
msgstr "تم اختيار %s فقط"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "Select variant %s"
msgstr "اختر النوع %s"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Sold out"
msgstr "تم البيع بالكامل"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Buy"
msgstr "اشتري"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Register"
msgstr "سجل"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Reserved"
msgstr "محجوز"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "FREE"
msgstr "مجاني"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "from %(currency)s %(price)s"
msgstr "من %(currency) s %(price)s"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "Image of %s"
msgstr "صورة لـ %s"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "incl. %(rate)s% %(taxname)s"
msgstr "يشمل %(rate)s% %(taxname)s"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "plus %(rate)s% %(taxname)s"
msgstr "بالإضافة إلى %(rate)s% %(taxname)s"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "incl. taxes"
msgstr "شامل الضريبة"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "plus taxes"
msgstr "بالإضافة إلى الضرائب"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "currently available: %s"
msgstr "متوفر حاليا: %s"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Only available with a voucher"
msgstr "متوفرة مع القسيمة فقط"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Not yet available"
msgstr "حاليًا غير متوفر: %s"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Not available anymore"
msgstr "لم يعد متوفراً"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Currently not available"
msgstr "غير متوفر حاليًا: %s"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "minimum amount to order: %s"
msgstr "الحد الأدنى للطلب: %s"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Close ticket shop"
msgstr "إغلاق متجر التذاكر"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "The ticket shop could not be loaded."
msgstr "لا يمكن تحميل متجر التذاكر."
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid ""
@@ -991,25 +961,21 @@ msgstr ""
"يوجد حالياً عدد كبير من المستخدمين في متجر التذاكر هذا. يرجى فتح المتجر في "
"علامة تبويب جديدة للمتابعة."
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Open ticket shop"
msgstr "إغلاق/فتح متجر التذاكر"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Checkout"
msgstr "استئناف عملية الدفع"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "The cart could not be created. Please try again later"
msgstr "لا يمكن إنشاء سلة التسوق. الرجاء المحاولة مرة أخرى في وقت لاحق"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid ""
@@ -1017,16 +983,14 @@ msgid ""
"this ticket shop. Please click \"Continue\" to retry in a new tab."
msgstr ""
"لم نتمكن من إنشاء سلة التسوق الخاصة بك، نظرًا لوجود عدد كبير جدًّا من "
"المستخدمين حاليًّا في متجر التذاكر هذا. يرجى النقر على «متابعة» لإعادة المحاولة "
"في علامة تبويب جديدة."
"المستخدمين حاليًّا في متجر التذاكر هذا. يرجى النقر على «متابعة» لإعادة "
"المحاولة في علامة تبويب جديدة."
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Waiting list"
msgstr "قائمة الإنتظار"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid ""
@@ -1036,115 +1000,96 @@ msgstr ""
"لديك الآن سلة تسوق مفعلة لهذا الحدث. إذا قمت باختيار منتجات أخرى سيتم "
"إضافتها إلى سلة التسوق الموجودة حالياً."
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Resume checkout"
msgstr "استئناف الدفع"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Redeem a voucher"
msgstr "استبدال قسيمة"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Redeem"
msgstr "استبدال"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Voucher code"
msgstr "رمز القسيمة"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Close"
msgstr "إغلاق"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Close checkout"
msgstr "إغلاق عملية الدفع"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "You cannot cancel this operation. Please wait for loading to finish."
msgstr "لا يمكنك إلغاء هذه العملية. يرجى الانتظار حتى ينتهي التحميل."
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Continue"
msgstr "استمرار"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Show variants"
msgstr "انظر الاختلافات"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Hide variants"
msgstr "إخفاء الاختلافات"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Choose a different event"
msgstr "اختر فعالية أخرى"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Choose a different date"
msgstr "اختر تاريخا آخر"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Back"
msgstr "العودة"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Next month"
msgstr "الشهر القادم"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Previous month"
msgstr "الشهر السابق"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Next week"
msgstr "الأسبوع القادم"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Previous week"
msgstr "الأسبوع السابق"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Open seat selection"
msgstr "خيارات المقاعد"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid ""
@@ -1155,138 +1100,111 @@ msgstr ""
"تم بيع جميع فئات التذاكر أو بعضها حاليًا. إذا أردت، يمكنك إضافة اسمك إلى "
"قائمة الانتظار. وسنقوم بإخطارك إذا توفرت مقاعد مرة أخرى."
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Load more"
msgstr "تحميل المزيد"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Mo"
msgstr "الإثنين"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Tu"
msgstr "الثلاثاء"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "We"
msgstr "الأربعاء"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Th"
msgstr "الخميس"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Fr"
msgstr "الجمعة"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Sa"
msgstr "السبت"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Su"
msgstr "الأحد"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Monday"
msgstr "الاثنين"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Tuesday"
msgstr "الثلاثاء"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Wednesday"
msgstr "الأربعاء"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Thursday"
msgstr "الخميس"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Friday"
msgstr "الجمعة"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Saturday"
msgstr "السبت"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Sunday"
msgstr "الأحد"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "January"
msgstr "يناير"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "February"
msgstr "فبراير"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "March"
msgstr "مارس"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "April"
msgstr "أبريل"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "May"
msgstr "هناك"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "June"
msgstr "يونيو"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "July"
msgstr "يوليو"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "August"
msgstr "أغسطس"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "September"
msgstr "سبتمبر"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "October"
msgstr "أكتوبر"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "November"
msgstr "نوفمبر"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "December"
msgstr "ديسمبر"
File diff suppressed because it is too large. Load diff
+1 -84
View File
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-06 15:52+0000\n"
"POT-Creation-Date: 2026-09-30 07:26+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -766,194 +766,163 @@ msgstr ""
msgid "Google Pay"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Quantity"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Decrease quantity"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Increase quantity"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Filter events by"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Filter"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Price"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "Original price: %s"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "New price: %s"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Select"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "Select %s"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "Select variant %s"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Sold out"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Buy"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Register"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Reserved"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "FREE"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "from %(currency)s %(price)s"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "Image of %s"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "incl. %(rate)s% %(taxname)s"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "plus %(rate)s% %(taxname)s"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "incl. taxes"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "plus taxes"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "currently available: %s"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Only available with a voucher"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Not yet available"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Not available anymore"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Currently not available"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "minimum amount to order: %s"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Close ticket shop"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "The ticket shop could not be loaded."
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid ""
@@ -961,25 +930,21 @@ msgid ""
"in a new tab to continue."
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Open ticket shop"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Checkout"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "The cart could not be created. Please try again later"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid ""
@@ -987,13 +952,11 @@ msgid ""
"this ticket shop. Please click \"Continue\" to retry in a new tab."
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Waiting list"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid ""
@@ -1001,115 +964,96 @@ msgid ""
"products, they will be added to your existing cart."
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Resume checkout"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Redeem a voucher"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Redeem"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Voucher code"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Close"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Close checkout"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "You cannot cancel this operation. Please wait for loading to finish."
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Continue"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Show variants"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Hide variants"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Choose a different event"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Choose a different date"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Back"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Next month"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Previous month"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Next week"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Previous week"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Open seat selection"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid ""
@@ -1118,138 +1062,111 @@ msgid ""
"again."
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Load more"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Mo"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Tu"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "We"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Th"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Fr"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Sa"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Su"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Monday"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Tuesday"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Wednesday"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Thursday"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Friday"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Saturday"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Sunday"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "January"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "February"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "March"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "April"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "May"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "June"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "July"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "August"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "September"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "October"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "November"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "December"
msgstr ""
File diff suppressed because it is too large. Load diff
+1 -84
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-06 15:52+0000\n"
"POT-Creation-Date: 2026-09-30 07:26+0000\n"
"PO-Revision-Date: 2025-10-31 17:00+0000\n"
"Last-Translator: Núria Masclans <nuriamasclansserrat@gmail.com>\n"
"Language-Team: Catalan <https://translate.pretix.eu/projects/pretix/pretix-"
@@ -787,194 +787,163 @@ msgstr "La teva hora local:"
msgid "Google Pay"
msgstr "Google Pay"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Quantity"
msgstr "Quantitat"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Decrease quantity"
msgstr "Disminueix quantitat"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Increase quantity"
msgstr "Augmenta quantitat"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Filter events by"
msgstr "Filtra els esdeveniments per"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Filter"
msgstr "Filtra"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Price"
msgstr "Preu"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "Original price: %s"
msgstr "Preu original: %s"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "New price: %s"
msgstr "Nou preu: %s"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Select"
msgstr "Selecciona"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "Select %s"
msgstr "Selecciona %s"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "Select variant %s"
msgstr "Selecciona la variant %s"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Sold out"
msgstr "Esgotat"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Buy"
msgstr "Compra"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Register"
msgstr "Registrar-vos"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Reserved"
msgstr "Reservat"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "FREE"
msgstr "GRATUÏT"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "from %(currency)s %(price)s"
msgstr "des de %(price)s %(currency)s"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "Image of %s"
msgstr "Imatge de %s"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "incl. %(rate)s% %(taxname)s"
msgstr "Inclòs %(rate)s% %(taxname)s"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "plus %(rate)s% %(taxname)s"
msgstr "més %(rate)s% %(taxname)s"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "incl. taxes"
msgstr "incl. impostos"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "plus taxes"
msgstr "més impostos"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "currently available: %s"
msgstr "disponibles: %s"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Only available with a voucher"
msgstr "Només disponible amb un cupó"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Not yet available"
msgstr "Encara no disponible"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Not available anymore"
msgstr "Ja no està disponible"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Currently not available"
msgstr "No disponible"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "minimum amount to order: %s"
msgstr "Comanda mínima: %s"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Close ticket shop"
msgstr "Tanca la botiga d'entrades"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "The ticket shop could not be loaded."
msgstr "No s'ha pogut carregar la botiga d'entrades."
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid ""
@@ -982,25 +951,21 @@ msgid ""
"in a new tab to continue."
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Open ticket shop"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Checkout"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "The cart could not be created. Please try again later"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid ""
@@ -1008,13 +973,11 @@ msgid ""
"this ticket shop. Please click \"Continue\" to retry in a new tab."
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Waiting list"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid ""
@@ -1022,115 +985,96 @@ msgid ""
"products, they will be added to your existing cart."
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Resume checkout"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Redeem a voucher"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Redeem"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Voucher code"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Close"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Close checkout"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "You cannot cancel this operation. Please wait for loading to finish."
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Continue"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Show variants"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Hide variants"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Choose a different event"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Choose a different date"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Back"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Next month"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Previous month"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Next week"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Previous week"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Open seat selection"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid ""
@@ -1139,138 +1083,111 @@ msgid ""
"again."
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Load more"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Mo"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Tu"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "We"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Th"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Fr"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Sa"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Su"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Monday"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Tuesday"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Wednesday"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Thursday"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Friday"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Saturday"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Sunday"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "January"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "February"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "March"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "April"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "May"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "June"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "July"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "August"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "September"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "October"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "November"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "December"
msgstr ""
File diff suppressed because it is too large. Load diff
+1 -84
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-06 15:52+0000\n"
"POT-Creation-Date: 2026-09-30 07:26+0000\n"
"PO-Revision-Date: 2026-01-08 04:00+0000\n"
"Last-Translator: Jiří Pastrňák <jiri@pastrnak.email>\n"
"Language-Team: Czech <https://translate.pretix.eu/projects/pretix/pretix-js/"
@@ -801,194 +801,163 @@ msgstr "Místní čas:"
msgid "Google Pay"
msgstr "Google Pay"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Quantity"
msgstr "Počet"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Decrease quantity"
msgstr "Snížit počet"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Increase quantity"
msgstr "Zvýšit počet"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Filter events by"
msgstr "Filtrovat události"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Filter"
msgstr "Filtrovat"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Price"
msgstr "Cena"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "Original price: %s"
msgstr "Původní cena: %s"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "New price: %s"
msgstr "Nová cena: %s"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Select"
msgstr "Vybrat"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "Select %s"
msgstr "Vybrat %s"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "Select variant %s"
msgstr "Vybrat variantu %s"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Sold out"
msgstr "Vyprodáno"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Buy"
msgstr "Koupit"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Register"
msgstr "Zaregistrovat"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Reserved"
msgstr "Rezervováno"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "FREE"
msgstr "ZDARMA"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "from %(currency)s %(price)s"
msgstr "od %(currency)s %(price)s"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "Image of %s"
msgstr "Obrázek%s"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "incl. %(rate)s% %(taxname)s"
msgstr "včetně %(rate)s% %(taxname)s"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "plus %(rate)s% %(taxname)s"
msgstr "plus %(rate)s% %(taxname)s"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "incl. taxes"
msgstr "včetně daní"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "plus taxes"
msgstr "plus daně"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "currently available: %s"
msgstr "aktuálně k dispozici: %s"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Only available with a voucher"
msgstr "K dispozici pouze s poukazem"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Not yet available"
msgstr "Zatím není k dispozici"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Not available anymore"
msgstr "Již není k dispozici"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Currently not available"
msgstr "Momentálně není k dispozici"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, javascript-format
msgctxt "widget"
msgid "minimum amount to order: %s"
msgstr "minimální množství pro objednávku: %s"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Close ticket shop"
msgstr "Zavřít obchod"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "The ticket shop could not be loaded."
msgstr "Obchod vstupenek nemohl být načten."
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid ""
@@ -998,25 +967,21 @@ msgstr ""
"V současné době je v tomto obchodě s vstupenkami mnoho uživatelů. Otevřete "
"prosím obchod v nové kartě."
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Open ticket shop"
msgstr "Obchod vstupenek otevřit"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Checkout"
msgstr "Přejít k platbě"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "The cart could not be created. Please try again later"
msgstr "Nákupní košík se nepodařilo vytvořit. Zkuste to prosím znovu"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid ""
@@ -1027,13 +992,11 @@ msgstr ""
"mnoho uživatelů. Klikněte prosím na \"Pokračovat\" a zkuste to znovu na nové "
"kartě."
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Waiting list"
msgstr "Čekací listina"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid ""
@@ -1043,37 +1006,31 @@ msgstr ""
"V současné době máte aktivní košík pro tuto událost. Pokud vyberete další "
"produkty, budou přidány do vašeho košíku."
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Resume checkout"
msgstr "Obnovit checkout"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Redeem a voucher"
msgstr "Uplatnit poukázku"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Redeem"
msgstr "Uplatnit"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Voucher code"
msgstr "Kód poukázky"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Close"
msgstr "Zavřít"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
#, fuzzy
#| msgctxt "widget"
@@ -1082,79 +1039,66 @@ msgctxt "widget"
msgid "Close checkout"
msgstr "Obnovit checkout"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "You cannot cancel this operation. Please wait for loading to finish."
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Continue"
msgstr "Pokračovat"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Show variants"
msgstr "Zobrazit možnosti"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Hide variants"
msgstr "Skrýt možnosti"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Choose a different event"
msgstr "Vybrat jinou událost"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Choose a different date"
msgstr "Vybrat jiný datum"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Back"
msgstr "Zpět"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Next month"
msgstr "Následující měsíc"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Previous month"
msgstr "Předchozí měsíc"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Next week"
msgstr "Příští týden"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Previous week"
msgstr "Předchozí týden"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Open seat selection"
msgstr "Otevřete výběr míst"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid ""
@@ -1166,138 +1110,111 @@ msgstr ""
"Pokud chcete, můžete se přidat na čekací listinu. Poté vás budeme "
"informovat, pokud budou místa opět volná."
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Load more"
msgstr "Načíst více"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Mo"
msgstr "Po"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Tu"
msgstr "Út"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "We"
msgstr "St"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Th"
msgstr "Čt"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Fr"
msgstr "Pá"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Sa"
msgstr "So"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Su"
msgstr "Ne"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Monday"
msgstr "Pondělí"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Tuesday"
msgstr "Úterý"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Wednesday"
msgstr "Středa"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Thursday"
msgstr "Čtvrtek"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Friday"
msgstr "Pátek"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Saturday"
msgstr "Sobota"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "Sunday"
msgstr "Neděle"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "January"
msgstr "Leden"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "February"
msgstr "Únor"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "March"
msgstr "Březen"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "April"
msgstr "Duben"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "May"
msgstr "Květen"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "June"
msgstr "červen"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "July"
msgstr "Červenec"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "August"
msgstr "Srpen"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "September"
msgstr "Září"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "October"
msgstr "Říjen"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "November"
msgstr "Listopad"
#: pretix/static/pretixpresale/js/widget/widget.js
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgid "December"
msgstr "Prosinec"
Loaded 100 of 288 files, more files were not shown because too many files have changed in this diff. Show more