mirror of
https://github.com/pretix/pretix.git
synced 2025-12-07 22:42:26 +00:00
Compare commits
3 Commits
v3.0.0
...
release/1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3410389b5e | ||
|
|
699c097971 | ||
|
|
1739da5cf0 |
35
.codecov.yml
35
.codecov.yml
@@ -1,35 +0,0 @@
|
||||
codecov:
|
||||
notify:
|
||||
require_ci_to_pass: yes
|
||||
|
||||
coverage:
|
||||
precision: 2
|
||||
round: down
|
||||
range: "60...100"
|
||||
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
target: auto
|
||||
threshold: 2%
|
||||
base: auto
|
||||
patch:
|
||||
default:
|
||||
target: auto
|
||||
threshold: 2%
|
||||
base: auto
|
||||
changes: no
|
||||
|
||||
parsers:
|
||||
gcov:
|
||||
branch_detection:
|
||||
conditional: yes
|
||||
loop: yes
|
||||
method: no
|
||||
macro: no
|
||||
|
||||
comment:
|
||||
require_changes: yes
|
||||
layout: "header, diff, files"
|
||||
behavior: default
|
||||
require_changes: no
|
||||
30
.gitattributes
vendored
30
.gitattributes
vendored
@@ -1,24 +1,6 @@
|
||||
src/pretix/static/fontawesome/* linguist-vendored
|
||||
src/pretix/static/lightbox/* linguist-vendored
|
||||
src/pretix/static/typeahead/* linguist-vendored
|
||||
src/pretix/static/moment/* linguist-vendored
|
||||
src/pretix/static/datetimepicker/* linguist-vendored
|
||||
src/pretix/static/colorpicker/* linguist-vendored
|
||||
src/pretix/static/fileupload/* linguist-vendored
|
||||
src/pretix/static/vuejs/* linguist-vendored
|
||||
src/pretix/static/select2/* linguist-vendored
|
||||
src/pretix/static/charts/* linguist-vendored
|
||||
src/pretix/static/rrule/* linguist-vendored
|
||||
src/pretix/static/iframeresizer/* linguist-vendored
|
||||
src/pretix/static/pdfjs/* linguist-vendored
|
||||
src/pretix/static/fabric/* linguist-vendored
|
||||
|
||||
# Denote all files that are truly binary and should not be modified.
|
||||
*.eot binary
|
||||
*.otf binary
|
||||
*.ttf binary
|
||||
*.woff binary
|
||||
*.zip binary
|
||||
*.png binary
|
||||
*.gif binary
|
||||
*.jpg binary
|
||||
src/static/fontawesome/* linguist-vendored
|
||||
src/static/lightbox/* linguist-vendored
|
||||
src/static/typeahead/* linguist-vendored
|
||||
src/static/moment/* linguist-vendored
|
||||
src/static/datetimepicker/* linguist-vendored
|
||||
src/static/charts/* linguist-vendored
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -21,6 +21,4 @@ pretixeu/
|
||||
local/
|
||||
.project
|
||||
.pydevproject
|
||||
.DS_Store
|
||||
|
||||
|
||||
|
||||
@@ -2,37 +2,11 @@ before_script:
|
||||
tests:
|
||||
stage: test
|
||||
script:
|
||||
- virtualenv env
|
||||
- virtualenv-3.4 env
|
||||
- source env/bin/activate
|
||||
- pip install -U pip wheel setuptools
|
||||
- XDG_CACHE_HOME=/cache bash .travis.sh style
|
||||
- XDG_CACHE_HOME=/cache bash .travis.sh tests
|
||||
- XDG_CACHE_HOME=/cache bash .travis.sh doctests
|
||||
tags:
|
||||
- python3
|
||||
except:
|
||||
- pypi
|
||||
pypi:
|
||||
stage: release
|
||||
script:
|
||||
- cp /keys/.pypirc ~/.pypirc
|
||||
- virtualenv env
|
||||
- source env/bin/activate
|
||||
- pip install -U pip wheel setuptools
|
||||
- XDG_CACHE_HOME=/cache pip3 install -Ur src/requirements.txt -r src/requirements/dev.txt
|
||||
- cd src
|
||||
- python setup.py sdist
|
||||
- pip install dist/pretix-*.tar.gz
|
||||
- python -m pretix migrate
|
||||
- python -m pretix check
|
||||
- python setup.py sdist upload
|
||||
- python setup.py bdist_wheel upload
|
||||
tags:
|
||||
- python3
|
||||
only:
|
||||
- pypi
|
||||
artifacts:
|
||||
paths:
|
||||
- src/dist/
|
||||
stages:
|
||||
- test
|
||||
- build
|
||||
- release
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
-r src/requirements/py34.txt
|
||||
-r doc/requirements.txt
|
||||
|
||||
51
.travis.sh
51
.travis.sh
@@ -4,65 +4,28 @@ set -x
|
||||
|
||||
echo "Executing job $1"
|
||||
|
||||
if [ "$PRETIX_CONFIG_FILE" == "tests/travis_mysql.cfg" ]; then
|
||||
mysql -u root -e 'CREATE DATABASE pretix DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;'
|
||||
pip3 install -Ur src/requirements/mysql.txt
|
||||
fi
|
||||
|
||||
if [ "$PRETIX_CONFIG_FILE" == "tests/travis_postgres.cfg" ]; then
|
||||
psql -c 'create database travis_ci_test;' -U postgres
|
||||
fi
|
||||
|
||||
if [ "$1" == "style" ]; then
|
||||
XDG_CACHE_HOME=/cache pip3 install -Ur src/requirements.txt -r src/requirements/dev.txt
|
||||
XDG_CACHE_HOME=/cache pip3 install -Ur src/requirements.txt -r src/requirements/dev.txt -r src/requirements/py34.txt
|
||||
cd src
|
||||
flake8 .
|
||||
isort -c -rc -df .
|
||||
isort -c -rc .
|
||||
fi
|
||||
if [ "$1" == "doctests" ]; then
|
||||
XDG_CACHE_HOME=/cache pip3 install -Ur doc/requirements.txt
|
||||
XDG_CACHE_HOME=/cache pip3 install -Ur doc/requirements.txt -r src/requirements/py34.txt
|
||||
cd doc
|
||||
make doctest
|
||||
fi
|
||||
if [ "$1" == "doc-spelling" ]; then
|
||||
XDG_CACHE_HOME=/cache pip3 install -Ur doc/requirements.txt
|
||||
cd doc
|
||||
make spelling
|
||||
if [ -s _build/spelling/output.txt ]; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
if [ "$1" == "translation-spelling" ]; then
|
||||
XDG_CACHE_HOME=/cache pip3 install -Ur src/requirements/dev.txt
|
||||
cd src
|
||||
potypo
|
||||
fi
|
||||
if [ "$1" == "tests" ]; then
|
||||
pip3 install -r src/requirements.txt -Ur src/requirements/dev.txt
|
||||
pip3 install -r src/requirements.txt -Ur src/requirements/dev.txt -r src/requirements/py34.txt
|
||||
cd src
|
||||
python manage.py check
|
||||
make all compress
|
||||
py.test --reruns 5 -n 3 tests
|
||||
coverage run -m py.test --rerun 5 tests && coverage report
|
||||
fi
|
||||
if [ "$1" == "tests-cov" ]; then
|
||||
pip3 install -r src/requirements.txt -Ur src/requirements/dev.txt
|
||||
pip3 install -r src/requirements.txt -Ur src/requirements/dev.txt -r src/requirements/py34.txt
|
||||
cd src
|
||||
python manage.py check
|
||||
make all compress
|
||||
coverage run -m py.test --reruns 5 tests && codecov
|
||||
fi
|
||||
if [ "$1" == "plugins" ]; then
|
||||
pip3 install -r src/requirements.txt -Ur src/requirements/dev.txt
|
||||
cd src
|
||||
python setup.py develop
|
||||
make all compress
|
||||
|
||||
pushd ~
|
||||
git clone --depth 1 https://github.com/pretix/pretix-cartshare.git
|
||||
cd pretix-cartshare
|
||||
python setup.py develop
|
||||
make
|
||||
py.test --reruns 5 tests
|
||||
popd
|
||||
|
||||
coverage run -m py.test --rerun 5 tests && coveralls
|
||||
fi
|
||||
|
||||
50
.travis.yml
50
.travis.yml
@@ -1,45 +1,15 @@
|
||||
language: python
|
||||
dist: xenial
|
||||
sudo: false
|
||||
python:
|
||||
- "3.4"
|
||||
install:
|
||||
- pip install -U pip wheel setuptools
|
||||
- pip install -U pip wheel setuptools==28.6.1
|
||||
script:
|
||||
- bash .travis.sh $JOB
|
||||
- bash .travis.sh $JOB
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.cache/pip
|
||||
services:
|
||||
- mysql
|
||||
- postgresql
|
||||
matrix:
|
||||
include:
|
||||
- python: 3.7
|
||||
env: JOB=tests PRETIX_CONFIG_FILE=tests/travis_sqlite.cfg
|
||||
- python: 3.7
|
||||
env: JOB=tests-cov PRETIX_CONFIG_FILE=tests/travis_postgres.cfg
|
||||
- python: 3.7
|
||||
env: JOB=style
|
||||
- python: 3.7
|
||||
env: JOB=tests PRETIX_CONFIG_FILE=tests/travis_mysql.cfg
|
||||
- python: 3.7
|
||||
env: JOB=tests PRETIX_CONFIG_FILE=tests/travis_postgres.cfg
|
||||
- python: 3.5
|
||||
env: JOB=tests PRETIX_CONFIG_FILE=tests/travis_postgres.cfg
|
||||
- python: 3.7
|
||||
env: JOB=doc-spelling
|
||||
- python: 3.7
|
||||
env: JOB=translation-spelling
|
||||
addons:
|
||||
postgresql: "9.4"
|
||||
mariadb: '10.3'
|
||||
apt:
|
||||
packages:
|
||||
- enchant
|
||||
- myspell-de-de
|
||||
- aspell-en
|
||||
- sqlite3
|
||||
sources:
|
||||
- travis-ci/sqlite3
|
||||
branches:
|
||||
except:
|
||||
- /^weblate-.*/
|
||||
directories:
|
||||
- $HOME/.cache/pip
|
||||
env:
|
||||
- JOB=style
|
||||
- JOB=doctests
|
||||
- JOB=tests-cov
|
||||
|
||||
17
AUTHORS
17
AUTHORS
@@ -3,31 +3,18 @@ people who have submitted patches, reported bugs, added translations, helped
|
||||
answer newbie questions, improved the documentation, and generally made pretix
|
||||
an awesome project. Thank you all!
|
||||
|
||||
Adam K. Sumner <asumner101@gmail.com>
|
||||
Ahrdie <robert.deppe@me.com>
|
||||
Alexander Brock <Brock.Alexander@web.de>
|
||||
Brandon Pineda
|
||||
Bolutife Lawrence
|
||||
Ben Oswald
|
||||
Christian Franke <nobody@nowhere.ws>
|
||||
Christopher Dambamuromo <me@chridam.com>
|
||||
chotee <chotee@openended.eu>
|
||||
Cpt. Foo
|
||||
Daniel Rosenblüh
|
||||
Enrique Saez
|
||||
Flavia Bastos
|
||||
informancer <informancer@web.de>
|
||||
Jakob Schnell <github@ezelo.de>
|
||||
Jan Felix Wiebe <git@jfwie.be>
|
||||
Jan Weiß
|
||||
Jason Estibeiro <jasonestibeiro@live.com>
|
||||
jlwt90
|
||||
Jan Weiß
|
||||
Jonas Große Sundrup <cherti@letopolis.de>
|
||||
Kevin Nelson
|
||||
Leah Oswald
|
||||
Lukas Martini
|
||||
Nathan Mattes
|
||||
Nicole Klünder
|
||||
Marc-Pascal Clement
|
||||
Martin Gross <martin@pc-coholic.de>
|
||||
Raphael Michel <mail@raphaelmichel.de>
|
||||
Team MRMCD
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
Code of Conduct
|
||||
===============
|
||||
|
||||
We have a [Code of Conduct](https://docs.pretix.eu/en/latest/development/contribution/codeofconduct.html)
|
||||
in place that applies to all project contributions, including issues, pull requests, etc.
|
||||
48
Dockerfile
48
Dockerfile
@@ -1,26 +1,12 @@
|
||||
FROM python:3.6
|
||||
FROM debian:jessie
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
build-essential \
|
||||
default-libmysqlclient-dev \
|
||||
gettext \
|
||||
git \
|
||||
libffi-dev \
|
||||
libjpeg-dev \
|
||||
libmemcached-dev \
|
||||
libpq-dev \
|
||||
libssl-dev \
|
||||
libxml2-dev \
|
||||
libxslt1-dev \
|
||||
locales \
|
||||
nginx \
|
||||
python-dev \
|
||||
python-virtualenv \
|
||||
python3-dev \
|
||||
sudo \
|
||||
supervisor \
|
||||
zlib1g-dev && \
|
||||
apt-get install -y python3 git python3-pip \
|
||||
libxml2-dev libxslt1-dev python-dev python-virtualenv locales libffi-dev \
|
||||
build-essential python3-dev zlib1g-dev libssl-dev gettext \
|
||||
libpq-dev libmysqlclient-dev libmemcached-dev libjpeg-dev \
|
||||
aqbanking-tools supervisor nginx sudo \
|
||||
--no-install-recommends && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/* && \
|
||||
dpkg-reconfigure locales && \
|
||||
@@ -35,22 +21,6 @@ RUN apt-get update && \
|
||||
ENV LC_ALL=C.UTF-8 \
|
||||
DJANGO_SETTINGS_MODULE=production_settings
|
||||
|
||||
# To copy only the requirements files needed to install from PIP
|
||||
COPY src/requirements /pretix/src/requirements
|
||||
COPY src/requirements.txt /pretix/src
|
||||
RUN pip3 install -U \
|
||||
pip \
|
||||
setuptools \
|
||||
wheel && \
|
||||
cd /pretix/src && \
|
||||
pip3 install \
|
||||
-r requirements.txt \
|
||||
-r requirements/memcached.txt \
|
||||
-r requirements/mysql.txt \
|
||||
-r requirements/redis.txt \
|
||||
gunicorn && \
|
||||
rm -rf ~/.cache/pip
|
||||
|
||||
COPY deployment/docker/pretix.bash /usr/local/bin/pretix
|
||||
COPY deployment/docker/supervisord.conf /etc/supervisord.conf
|
||||
COPY deployment/docker/nginx.conf /etc/nginx/nginx.conf
|
||||
@@ -59,8 +29,12 @@ COPY src /pretix/src
|
||||
|
||||
RUN chmod +x /usr/local/bin/pretix && \
|
||||
rm /etc/nginx/sites-enabled/default && \
|
||||
pip3 install -U pip wheel setuptools && \
|
||||
cd /pretix/src && \
|
||||
rm -f pretix.cfg && \
|
||||
pip3 install -r requirements.txt -r requirements/mysql.txt -r requirements/postgres.txt \
|
||||
-r requirements/memcached.txt -r requirements/redis.txt \
|
||||
-r requirements/py34.txt gunicorn && \
|
||||
mkdir -p data && \
|
||||
chown -R pretixuser:pretixuser /pretix /data data && \
|
||||
sudo -u pretixuser make production
|
||||
|
||||
16
README.rst
16
README.rst
@@ -10,12 +10,11 @@ pretix
|
||||
.. image:: https://travis-ci.org/pretix/pretix.svg?branch=master
|
||||
:target: https://travis-ci.org/pretix/pretix
|
||||
|
||||
.. image:: https://codecov.io/gh/pretix/pretix/branch/master/graph/badge.svg
|
||||
:target: https://codecov.io/gh/pretix/pretix
|
||||
.. image:: https://coveralls.io/repos/github/pretix/pretix/badge.svg?branch=master
|
||||
:target: https://coveralls.io/r/pretix/pretix
|
||||
|
||||
|
||||
|
||||
Reinventing ticket presales, one ticket at a time.
|
||||
Reinventing ticket presales, one bit at a time.
|
||||
|
||||
Project status & release cycle
|
||||
------------------------------
|
||||
@@ -40,14 +39,6 @@ Contributing
|
||||
If you want to contribute to pretix, please read the `developer documentation`_
|
||||
in our documentation. If you have any further questions, please do not hesitate to ask!
|
||||
|
||||
.. image:: https://translate.pretix.eu/widgets/pretix/-/pretix/multi-blue.svg
|
||||
:target: https://translate.pretix.eu/engage/pretix/
|
||||
|
||||
Code of Conduct
|
||||
---------------
|
||||
We have a `Code of Conduct`_ in place that applies to all project contributions,
|
||||
including issues, pull requests, etc.
|
||||
|
||||
License
|
||||
-------
|
||||
The code in this repository is published under the terms of the Apache License.
|
||||
@@ -58,6 +49,5 @@ AUTHORS file for a list of all the awesome folks who contributed to this project
|
||||
|
||||
.. _installation guide: https://docs.pretix.eu/en/latest/admin/installation/index.html
|
||||
.. _developer documentation: https://docs.pretix.eu/en/latest/development/index.html
|
||||
.. _Code of Conduct: https://docs.pretix.eu/en/latest/development/contribution/codeofconduct.html
|
||||
.. _pretix.eu: https://pretix.eu
|
||||
.. _blog: https://pretix.eu/about/en/blog/
|
||||
|
||||
@@ -22,11 +22,9 @@ http {
|
||||
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
add_header X-Content-Type-Options nosniff;
|
||||
|
||||
access_log /var/log/nginx/access.log private;
|
||||
error_log /var/log/nginx/error.log;
|
||||
add_header Referrer-Policy same-origin;
|
||||
|
||||
gzip on;
|
||||
gzip_disable "msie6";
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
cd /pretix/src
|
||||
export DJANGO_SETTINGS_MODULE=production_settings
|
||||
export DATA_DIR=/data/
|
||||
export HOME=/pretix
|
||||
export NUM_WORKERS=$((2 * $(nproc --all)))
|
||||
NUM_WORKERS=10
|
||||
|
||||
if [ ! -d /data/logs ]; then
|
||||
mkdir /data/logs;
|
||||
|
||||
@@ -23,7 +23,6 @@ autostart=true
|
||||
autorestart=true
|
||||
priority=5
|
||||
user=pretixuser
|
||||
environment=HOME=/pretix
|
||||
|
||||
[program:pretixtask]
|
||||
command=/usr/local/bin/pretix taskworker
|
||||
|
||||
@@ -175,9 +175,3 @@ pseudoxml:
|
||||
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
|
||||
@echo
|
||||
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
|
||||
|
||||
spelling:
|
||||
$(SPHINXBUILD) -b spelling $(ALLSPHINXOPTS) $(BUILDDIR)/spelling
|
||||
@echo
|
||||
@echo "Spelling check finished, look at the results in " \
|
||||
"$(BUILDDIR)/spelling/output.txt."
|
||||
|
||||
160
doc/_templates/index.html
vendored
160
doc/_templates/index.html
vendored
@@ -1,160 +0,0 @@
|
||||
{% extends "layout.html" %}
|
||||
{% set title = 'Overview' %}
|
||||
{% block body %}
|
||||
<h1>Welcome to pretix' documentation!</h1>
|
||||
<p>
|
||||
We work hard to make this website contain all information that you need to use, run, understand, and improve
|
||||
pretix. Of course, this documentation will never be perfect or complete, but if there is anything unclear
|
||||
or anything specific that you miss here, that's a bug and we'd be happy if you'd
|
||||
<a href="https://github.com/pretix/pretix/issues/new">let us know</a>.
|
||||
</p>
|
||||
|
||||
<h2>Documentation structure</h2>
|
||||
|
||||
<div class="sectionbox">
|
||||
<div class="icon">
|
||||
<a href="user/index.html">
|
||||
<span class="fa fa-user fa-fw"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="text">
|
||||
<a href="user/index.html">
|
||||
<strong>User Guide</strong>
|
||||
</a>
|
||||
<p>Go here to find information on how to configure and use pretix as an event organizer.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sectionbox">
|
||||
<div class="icon">
|
||||
<a href="admin/index.html">
|
||||
<span class="fa fa-server fa-fw"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="text">
|
||||
<a href="admin/index.html">
|
||||
<strong>Administrator docs</strong>
|
||||
</a>
|
||||
<p>Find out how to install pretix on your own server and how to maintain an installation of pretix.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
<div class="sectionbox">
|
||||
<div class="icon">
|
||||
<a href="api/index.html">
|
||||
<span class="fa fa-plug fa-fw"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="text">
|
||||
<a href="api/index.html">
|
||||
<strong>REST API</strong>
|
||||
</a>
|
||||
<p>
|
||||
Documentation and reference of the RESTful API exposed by pretix for interaction with external
|
||||
components.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sectionbox">
|
||||
<div class="icon">
|
||||
<a href="development/index.html">
|
||||
<span class="fa fa-wrench fa-fw"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="text">
|
||||
<a href="development/index.html">
|
||||
<strong>Developer docs</strong>
|
||||
</a>
|
||||
<p>Get information on how to contribute to pretix itself and how to build plugins that interact with
|
||||
pretix.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
<div class="sectionbox">
|
||||
<div class="icon">
|
||||
<a href="plugins/index.html">
|
||||
<span class="fa fa-puzzle-piece fa-fw"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="text">
|
||||
<a href="plugins/index.html">
|
||||
<strong>Plugin docs</strong>
|
||||
</a>
|
||||
<p>Documentation and details on plugins that ship with pretix or are officially supported.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sectionbox">
|
||||
<div class="icon">
|
||||
<a href="contents.html">
|
||||
<span class="fa fa-list fa-fw"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="text">
|
||||
<a href="contents.html">
|
||||
<strong>Table of contents</strong>
|
||||
</a>
|
||||
<p>Detailled overview of everything contained in this documentation.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
|
||||
<h2>Useful links</h2>
|
||||
|
||||
<div class="sectionbox">
|
||||
<div class="icon">
|
||||
<a href="https://pretix.eu" target="_blank">
|
||||
<span class="fa fa-globe fa-fw"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="text">
|
||||
<a href="https://pretix.eu" target="_blank">
|
||||
<strong>Project website</strong>
|
||||
</a>
|
||||
<p>pretix.eu is the central entry-point to the pretix project and also the home of the commercial hosting
|
||||
service available.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sectionbox">
|
||||
<div class="icon">
|
||||
<a href="https://github.com/pretix/pretix" target="_blank">
|
||||
<span class="fa fa-github fa-fw"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="text">
|
||||
<a href="https://github.com/pretix/pretix" target="_blank">
|
||||
<strong>GitHub repository</strong>
|
||||
</a>
|
||||
<p>Our main source code repository contains all code that is part of pretix as well as some plugins and the
|
||||
source for this documentation.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
<div class="sectionbox">
|
||||
<div class="icon">
|
||||
<a href="https://pretix.eu/about/en/blog/" target="_blank">
|
||||
<span class="fa fa-newspaper-o fa-fw"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="text">
|
||||
<a href="https://pretix.eu/about/en/blog/" target="_blank">
|
||||
<strong>Project blog</strong>
|
||||
</a>
|
||||
<p>This important information source contains all release notes for all stable releases of pretix as well as
|
||||
general news on pretix as a project.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sectionbox">
|
||||
<div class="icon">
|
||||
<a href="https://twitter.com/pretixeu" target="_blank">
|
||||
<span class="fa fa-twitter fa-fw"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="text">
|
||||
<a href="https://twitter.com/pretixeu" target="_blank">
|
||||
<strong>Twitter</strong>
|
||||
</a>
|
||||
<p>Keep in touch and stay up to date by following our project account on Twitter.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
|
||||
{% endblock %}
|
||||
16
doc/_themes/pretix_theme/__init__.py
vendored
16
doc/_themes/pretix_theme/__init__.py
vendored
@@ -1,16 +0,0 @@
|
||||
"""pretix sphinx theme.
|
||||
|
||||
Based on sphinx-rtd-theme
|
||||
Based on https://github.com/ryan-roemer/sphinx-bootstrap-theme.
|
||||
|
||||
"""
|
||||
import os
|
||||
|
||||
__version__ = '0.1.0'
|
||||
__version_full__ = __version__
|
||||
|
||||
|
||||
def get_html_theme_path():
|
||||
"""Return list of HTML theme paths."""
|
||||
cur_dir = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
|
||||
return cur_dir
|
||||
82
doc/_themes/pretix_theme/breadcrumbs.html
vendored
82
doc/_themes/pretix_theme/breadcrumbs.html
vendored
@@ -1,82 +0,0 @@
|
||||
{# Support for Sphinx 1.3+ page_source_suffix, but don't break old builds. #}
|
||||
|
||||
{% if page_source_suffix %}
|
||||
{% set suffix = page_source_suffix %}
|
||||
{% else %}
|
||||
{% set suffix = source_suffix %}
|
||||
{% endif %}
|
||||
|
||||
{% if meta is defined and meta is not none %}
|
||||
{% set check_meta = True %}
|
||||
{% else %}
|
||||
{% set check_meta = False %}
|
||||
{% endif %}
|
||||
|
||||
{% if check_meta and 'github_url' in meta %}
|
||||
{% set display_github = True %}
|
||||
{% endif %}
|
||||
|
||||
{% if check_meta and 'bitbucket_url' in meta %}
|
||||
{% set display_bitbucket = True %}
|
||||
{% endif %}
|
||||
|
||||
{% if check_meta and 'gitlab_url' in meta %}
|
||||
{% set display_gitlab = True %}
|
||||
{% endif %}
|
||||
|
||||
<div role="navigation" aria-label="breadcrumbs navigation">
|
||||
|
||||
<ul class="wy-breadcrumbs">
|
||||
{% block breadcrumbs %}
|
||||
<li><a href="{{ pathto(master_doc) }}">{{ _('Docs') }}</a> »</li>
|
||||
{% for doc in parents %}
|
||||
<li><a href="{{ doc.link|e }}">{{ doc.title }}</a> »</li>
|
||||
{% endfor %}
|
||||
<li>{{ title }}</li>
|
||||
{% endblock %}
|
||||
{% block breadcrumbs_aside %}
|
||||
<li class="wy-breadcrumbs-aside">
|
||||
{% if pagename != "search" %}
|
||||
{% if display_github %}
|
||||
{% if check_meta and 'github_url' in meta %}
|
||||
<!-- User defined GitHub URL -->
|
||||
<a href="{{ meta['github_url'] }}" class="fa fa-github"> {{ _('Edit on GitHub') }}</a>
|
||||
{% else %}
|
||||
<a href="https://{{ github_host|default("github.com") }}/{{ github_user }}/{{ github_repo }}/blob/{{ github_version }}{{ conf_py_path }}{{ pagename }}{{ suffix }}" class="fa fa-github"> {{ _('Edit on GitHub') }}</a>
|
||||
{% endif %}
|
||||
{% elif display_bitbucket %}
|
||||
{% if check_meta and 'bitbucket_url' in meta %}
|
||||
<!-- User defined Bitbucket URL -->
|
||||
<a href="{{ meta['bitbucket_url'] }}" class="fa fa-bitbucket"> {{ _('Edit on Bitbucket') }}</a>
|
||||
{% else %}
|
||||
<a href="https://bitbucket.org/{{ bitbucket_user }}/{{ bitbucket_repo }}/src/{{ bitbucket_version}}{{ conf_py_path }}{{ pagename }}{{ suffix }}" class="fa fa-bitbucket"> {{ _('Edit on Bitbucket') }}</a>
|
||||
{% endif %}
|
||||
{% elif display_gitlab %}
|
||||
{% if check_meta and 'gitlab_url' in meta %}
|
||||
<!-- User defined GitLab URL -->
|
||||
<a href="{{ meta['gitlab_url'] }}" class="fa fa-gitlab"> {{ _('Edit on GitLab') }}</a>
|
||||
{% else %}
|
||||
<a href="https://{{ gitlab_host|default("gitlab.com") }}/{{ gitlab_user }}/{{ gitlab_repo }}/blob/{{ gitlab_version }}{{ conf_py_path }}{{ pagename }}{{ suffix }}" class="fa fa-gitlab"> {{ _('Edit on GitLab') }}</a>
|
||||
{% endif %}
|
||||
{% elif show_source and source_url_prefix %}
|
||||
<a href="{{ source_url_prefix }}{{ pagename }}{{ suffix }}">{{ _('View page source') }}</a>
|
||||
{% elif show_source and has_source and sourcename %}
|
||||
<a href="{{ pathto('_sources/' + sourcename, true)|e }}" rel="nofollow"> {{ _('View page source') }}</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endblock %}
|
||||
</ul>
|
||||
|
||||
{% if (theme_prev_next_buttons_location == 'top' or theme_prev_next_buttons_location == 'both') and (next or prev) %}
|
||||
<div class="rst-breadcrumbs-buttons" role="navigation" aria-label="breadcrumb navigation">
|
||||
{% if next %}
|
||||
<a href="{{ next.link|e }}" class="btn btn-neutral float-right" title="{{ next.title|striptags|e }}" accesskey="n">Next <span class="fa fa-arrow-circle-right"></span></a>
|
||||
{% endif %}
|
||||
{% if prev %}
|
||||
<a href="{{ prev.link|e }}" class="btn btn-neutral" title="{{ prev.title|striptags|e }}" accesskey="p"><span class="fa fa-arrow-circle-left"></span> Previous</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<hr/>
|
||||
</div>
|
||||
52
doc/_themes/pretix_theme/footer.html
vendored
52
doc/_themes/pretix_theme/footer.html
vendored
@@ -1,52 +0,0 @@
|
||||
<footer>
|
||||
{% if (theme_prev_next_buttons_location == 'bottom' or theme_prev_next_buttons_location == 'both') and (next or prev) %}
|
||||
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
|
||||
{% if next %}
|
||||
<a href="{{ next.link|e }}" class="btn btn-neutral float-right" title="{{ next.title|striptags|e }}" accesskey="n" rel="next">{{ _('Next') }} <span class="fa fa-arrow-circle-right"></span></a>
|
||||
{% endif %}
|
||||
{% if prev %}
|
||||
<a href="{{ prev.link|e }}" class="btn btn-neutral" title="{{ prev.title|striptags|e }}" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left"></span> {{ _('Previous') }}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<hr/>
|
||||
|
||||
<div role="contentinfo">
|
||||
<p>
|
||||
{%- if show_copyright %}
|
||||
{%- if hasdoc('copyright') %}
|
||||
{% trans path=pathto('copyright'), copyright=copyright|e %}© <a href="{{ path }}">Copyright</a> {{ copyright }}.{% endtrans %}
|
||||
{%- else %}
|
||||
{% trans copyright=copyright|e %}© Copyright {{ copyright }}.{% endtrans %}
|
||||
{%- endif %}
|
||||
{%- endif %}
|
||||
|
||||
{%- if build_id and build_url %}
|
||||
{% trans build_url=build_url, build_id=build_id %}
|
||||
<span class="build">
|
||||
Build
|
||||
<a href="{{ build_url }}">{{ build_id }}</a>.
|
||||
</span>
|
||||
{% endtrans %}
|
||||
{%- elif commit %}
|
||||
{% trans commit=commit %}
|
||||
<span class="commit">
|
||||
Revision <code>{{ commit }}</code>.
|
||||
</span>
|
||||
{% endtrans %}
|
||||
{%- elif last_updated %}
|
||||
{% trans last_updated=last_updated|e %}Last updated on {{ last_updated }}.{% endtrans %}
|
||||
{%- endif %}
|
||||
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{%- if show_sphinx %}
|
||||
<small>{% trans %}Built with <a href="http://sphinx-doc.org/">Sphinx</a> using a theme that is based on a <a href="https://github.com/snide/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>{% endtrans %}.</small>
|
||||
{%- endif %}
|
||||
|
||||
{%- block extrafooter %} {% endblock %}
|
||||
|
||||
</footer>
|
||||
|
||||
211
doc/_themes/pretix_theme/layout.html
vendored
211
doc/_themes/pretix_theme/layout.html
vendored
@@ -1,211 +0,0 @@
|
||||
{# TEMPLATE VAR SETTINGS #}
|
||||
{%- set url_root = pathto('', 1) %}
|
||||
{%- if url_root == '#' %}{% set url_root = '' %}{% endif %}
|
||||
{%- if not embedded and docstitle %}
|
||||
{%- set titlesuffix = " — "|safe + docstitle|e %}
|
||||
{%- else %}
|
||||
{%- set titlesuffix = "" %}
|
||||
{%- endif %}
|
||||
|
||||
<!DOCTYPE html>
|
||||
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
|
||||
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
{{ metatags }}
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
{% block htmltitle %}
|
||||
<title>{{ title|striptags|e }}{{ titlesuffix }}</title>
|
||||
{% endblock %}
|
||||
|
||||
{# FAVICON #}
|
||||
{% if favicon %}
|
||||
<link rel="shortcut icon" href="{{ pathto('_static/' + favicon, 1) }}"/>
|
||||
{% endif %}
|
||||
{# CANONICAL URL #}
|
||||
{% if theme_canonical_url %}
|
||||
<link rel="canonical" href="{{ theme_canonical_url }}{{ pagename }}.html"/>
|
||||
{% endif %}
|
||||
|
||||
{# CSS #}
|
||||
|
||||
{# OPENSEARCH #}
|
||||
{% if not embedded %}
|
||||
{% if use_opensearch %}
|
||||
<link rel="search" type="application/opensearchdescription+xml" title="{% trans docstitle=docstitle|e %}Search within {{ docstitle }}{% endtrans %}" href="{{ pathto('_static/opensearch.xml', 1) }}"/>
|
||||
{% endif %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
{# RTD hosts this file, so just load on non RTD builds #}
|
||||
<link rel="stylesheet" href="{{ pathto('_static/' + style, 1) }}" type="text/css" />
|
||||
|
||||
{% for cssfile in css_files %}
|
||||
<link rel="stylesheet" href="{{ pathto(cssfile, 1) }}" type="text/css" />
|
||||
{% endfor %}
|
||||
|
||||
{% for cssfile in extra_css_files %}
|
||||
<link rel="stylesheet" href="{{ pathto(cssfile, 1) }}" type="text/css" />
|
||||
{% endfor %}
|
||||
|
||||
{%- block linktags %}
|
||||
{%- if hasdoc('about') %}
|
||||
<link rel="author" title="{{ _('About these documents') }}"
|
||||
href="{{ pathto('about') }}"/>
|
||||
{%- endif %}
|
||||
{%- if hasdoc('genindex') %}
|
||||
<link rel="index" title="{{ _('Index') }}"
|
||||
href="{{ pathto('genindex') }}"/>
|
||||
{%- endif %}
|
||||
{%- if hasdoc('search') %}
|
||||
<link rel="search" title="{{ _('Search') }}" href="{{ pathto('search') }}"/>
|
||||
{%- endif %}
|
||||
{%- if hasdoc('copyright') %}
|
||||
<link rel="copyright" title="{{ _('Copyright') }}" href="{{ pathto('copyright') }}"/>
|
||||
{%- endif %}
|
||||
<link rel="top" title="{{ docstitle|e }}" href="{{ pathto('index') }}"/>
|
||||
{%- if parents %}
|
||||
<link rel="up" title="{{ parents[-1].title|striptags|e }}" href="{{ parents[-1].link|e }}"/>
|
||||
{%- endif %}
|
||||
{%- if next %}
|
||||
<link rel="next" title="{{ next.title|striptags|e }}" href="{{ next.link|e }}"/>
|
||||
{%- endif %}
|
||||
{%- if prev %}
|
||||
<link rel="prev" title="{{ prev.title|striptags|e }}" href="{{ prev.link|e }}"/>
|
||||
{%- endif %}
|
||||
{%- endblock %}
|
||||
{%- block extrahead %} {% endblock %}
|
||||
|
||||
{# Keep modernizr in head - http://modernizr.com/docs/#installing #}
|
||||
<script src="{{ pathto('_static/js/modernizr.min.js', 1) }}"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body class="wy-body-for-nav" role="document">
|
||||
|
||||
{% block extrabody %} {% endblock %}
|
||||
<div class="wy-grid-for-nav">
|
||||
|
||||
{# SIDE NAV, TOGGLES ON MOBILE #}
|
||||
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
|
||||
<div class="wy-side-scroll">
|
||||
<div class="wy-side-nav-search">
|
||||
{% block sidebartitle %}
|
||||
|
||||
{% if logo and theme_logo_only %}
|
||||
<a href="{{ pathto('index') }}">
|
||||
{% else %}
|
||||
<a href="{{ pathto('index') }}" class="icon icon-home"> {{ project }}
|
||||
{% endif %}
|
||||
|
||||
{% if logo %}
|
||||
{# Not strictly valid HTML, but it's the only way to display/scale it properly, without weird scripting or heaps of work #}
|
||||
<img src="{{ pathto('_static/' + logo, 1) }}" class="logo" />
|
||||
{% endif %}
|
||||
</a>
|
||||
|
||||
{% include "searchbox.html" %}
|
||||
|
||||
{% endblock %}
|
||||
</div>
|
||||
|
||||
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
|
||||
{% block menu %}
|
||||
{#
|
||||
The singlehtml builder doesn't handle this toctree call when the
|
||||
toctree is empty. Skip building this for now.
|
||||
#}
|
||||
{% if 'singlehtml' not in builder %}
|
||||
{% set global_toc = toctree(maxdepth=theme_navigation_depth|int, collapse=theme_collapse_navigation, includehidden=True) %}
|
||||
{% endif %}
|
||||
{% if global_toc %}
|
||||
{{ global_toc }}
|
||||
{% else %}
|
||||
<!-- Local TOC -->
|
||||
<div class="local-toc">{{ toc }}</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
|
||||
{% if theme_display_version %}
|
||||
{%- set nav_version = version %}
|
||||
{% if READTHEDOCS and current_version %}
|
||||
{%- set nav_version = current_version %}
|
||||
{% endif %}
|
||||
{% if nav_version %}
|
||||
<div class="version">
|
||||
{{ nav_version }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
|
||||
|
||||
{# MOBILE NAV, TRIGGLES SIDE NAV ON TOGGLE #}
|
||||
<nav class="wy-nav-top" role="navigation" aria-label="top navigation">
|
||||
{% block mobile_nav %}
|
||||
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
|
||||
<a href="{{ pathto('index') }}">{{ project }}</a>
|
||||
{% endblock %}
|
||||
</nav>
|
||||
|
||||
|
||||
{# PAGE CONTENT #}
|
||||
<div class="wy-nav-content">
|
||||
<div class="rst-content">
|
||||
{% include "breadcrumbs.html" %}
|
||||
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
|
||||
<div itemprop="articleBody">
|
||||
{% block body %}{% endblock %}
|
||||
</div>
|
||||
<div class="articleComments">
|
||||
{% block comments %}{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
{% include "footer.html" %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
</div>
|
||||
{% include "versions.html" %}
|
||||
|
||||
{% if not embedded %}
|
||||
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT:'{{ url_root }}',
|
||||
VERSION:'{{ release|e }}',
|
||||
COLLAPSE_INDEX:false,
|
||||
FILE_SUFFIX:'{{ '' if no_search_suffix else file_suffix }}',
|
||||
HAS_SOURCE: {{ has_source|lower }},
|
||||
SOURCELINK_SUFFIX: '{{ sourcelink_suffix }}'
|
||||
};
|
||||
</script>
|
||||
{%- for scriptfile in script_files %}
|
||||
<script type="text/javascript" src="{{ pathto(scriptfile, 1) }}"></script>
|
||||
{%- endfor %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
{# RTD hosts this file, so just load on non RTD builds #}
|
||||
{% if not READTHEDOCS %}
|
||||
<script type="text/javascript" src="{{ pathto('_static/js/theme.js', 1) }}"></script>
|
||||
{% endif %}
|
||||
|
||||
{# STICKY NAVIGATION #}
|
||||
{% if theme_sticky_navigation %}
|
||||
<script type="text/javascript">
|
||||
jQuery(function () {
|
||||
SphinxRtdTheme.StickyNav.enable();
|
||||
});
|
||||
</script>
|
||||
{% endif %}
|
||||
|
||||
{%- block footer %} {% endblock %}
|
||||
|
||||
</body>
|
||||
</html>
|
||||
209
doc/_themes/pretix_theme/layout_old.html
vendored
209
doc/_themes/pretix_theme/layout_old.html
vendored
@@ -1,209 +0,0 @@
|
||||
{#
|
||||
basic/layout.html
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
Master layout template for Sphinx themes.
|
||||
|
||||
:copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
#}
|
||||
{%- block doctype -%}
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
{%- endblock %}
|
||||
{%- set reldelim1 = reldelim1 is not defined and ' »' or reldelim1 %}
|
||||
{%- set reldelim2 = reldelim2 is not defined and ' |' or reldelim2 %}
|
||||
{%- set render_sidebar = (not embedded) and (not theme_nosidebar|tobool) and
|
||||
(sidebars != []) %}
|
||||
{%- set url_root = pathto('', 1) %}
|
||||
{# XXX necessary? #}
|
||||
{%- if url_root == '#' %}{% set url_root = '' %}{% endif %}
|
||||
{%- if not embedded and docstitle %}
|
||||
{%- set titlesuffix = " — "|safe + docstitle|e %}
|
||||
{%- else %}
|
||||
{%- set titlesuffix = "" %}
|
||||
{%- endif %}
|
||||
|
||||
{%- macro relbar() %}
|
||||
<div class="related">
|
||||
<h3>{{ _('Navigation') }}</h3>
|
||||
<ul>
|
||||
{%- for rellink in rellinks %}
|
||||
<li class="right" {% if loop.first %}style="margin-right: 10px"{% endif %}>
|
||||
<a href="{{ pathto(rellink[0]) }}" title="{{ rellink[1]|striptags|e }}"
|
||||
{{ accesskey(rellink[2]) }}>{{ rellink[3] }}</a>
|
||||
{%- if not loop.first %}{{ reldelim2 }}{% endif %}</li>
|
||||
{%- endfor %}
|
||||
{%- block rootrellink %}
|
||||
<li><a href="{{ pathto(master_doc) }}">{{ shorttitle|e }}</a>{{ reldelim1 }}</li>
|
||||
{%- endblock %}
|
||||
{%- for parent in parents %}
|
||||
<li><a href="{{ parent.link|e }}" {% if loop.last %}{{ accesskey("U") }}{% endif %}>{{ parent.title }}</a>{{ reldelim1 }}</li>
|
||||
{%- endfor %}
|
||||
{%- block relbaritems %} {% endblock %}
|
||||
</ul>
|
||||
</div>
|
||||
{%- endmacro %}
|
||||
|
||||
{%- macro sidebar() %}
|
||||
{%- if render_sidebar %}
|
||||
<div class="sphinxsidebar">
|
||||
<div class="sphinxsidebarwrapper">
|
||||
{%- block sidebarlogo %}
|
||||
{%- if logo %}
|
||||
<p class="logo"><a href="{{ pathto(master_doc) }}">
|
||||
<img class="logo" src="{{ pathto('_static/' + logo, 1) }}" alt="Logo"/>
|
||||
</a></p>
|
||||
{%- endif %}
|
||||
{%- endblock %}
|
||||
{%- if sidebars != None %}
|
||||
{#- new style sidebar: explicitly include/exclude templates #}
|
||||
{%- for sidebartemplate in sidebars %}
|
||||
{%- include sidebartemplate %}
|
||||
{%- endfor %}
|
||||
{%- else %}
|
||||
{#- old style sidebars: using blocks -- should be deprecated #}
|
||||
{%- block sidebartoc %}
|
||||
{%- include "localtoc.html" %}
|
||||
{%- endblock %}
|
||||
{%- block sidebarrel %}
|
||||
{%- include "relations.html" %}
|
||||
{%- endblock %}
|
||||
{%- block sidebarsourcelink %}
|
||||
{%- include "sourcelink.html" %}
|
||||
{%- endblock %}
|
||||
{%- if customsidebar %}
|
||||
{%- include customsidebar %}
|
||||
{%- endif %}
|
||||
{%- block sidebarsearch %}
|
||||
{%- include "searchbox.html" %}
|
||||
{%- endblock %}
|
||||
{%- endif %}
|
||||
</div>
|
||||
</div>
|
||||
{%- endif %}
|
||||
{%- endmacro %}
|
||||
|
||||
{%- macro script() %}
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT: '{{ url_root }}',
|
||||
VERSION: '{{ release|e }}',
|
||||
COLLAPSE_INDEX: false,
|
||||
FILE_SUFFIX: '{{ '' if no_search_suffix else file_suffix }}',
|
||||
HAS_SOURCE: {{ has_source|lower }},
|
||||
SOURCELINK_SUFFIX: '{{ sourcelink_suffix }}'
|
||||
};
|
||||
</script>
|
||||
{%- for scriptfile in script_files %}
|
||||
<script type="text/javascript" src="{{ pathto(scriptfile, 1) }}"></script>
|
||||
{%- endfor %}
|
||||
{%- endmacro %}
|
||||
|
||||
{%- macro css() %}
|
||||
<link rel="stylesheet" href="{{ pathto('_static/' + style, 1) }}" type="text/css" />
|
||||
<link rel="stylesheet" href="{{ pathto('_static/pygments.css', 1) }}" type="text/css" />
|
||||
{%- for cssfile in css_files %}
|
||||
<link rel="stylesheet" href="{{ pathto(cssfile, 1) }}" type="text/css" />
|
||||
{%- endfor %}
|
||||
{%- endmacro %}
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset={{ encoding }}" />
|
||||
{{ metatags }}
|
||||
{%- block htmltitle %}
|
||||
<title>{{ title|striptags|e }}{{ titlesuffix }}</title>
|
||||
{%- endblock %}
|
||||
{{ css() }}
|
||||
{%- if not embedded %}
|
||||
{{ script() }}
|
||||
{%- if use_opensearch %}
|
||||
<link rel="search" type="application/opensearchdescription+xml"
|
||||
title="{% trans docstitle=docstitle|e %}Search within {{ docstitle }}{% endtrans %}"
|
||||
href="{{ pathto('_static/opensearch.xml', 1) }}"/>
|
||||
{%- endif %}
|
||||
{%- if favicon %}
|
||||
<link rel="shortcut icon" href="{{ pathto('_static/' + favicon, 1) }}"/>
|
||||
{%- endif %}
|
||||
{%- if theme_canonical_url %}
|
||||
<link rel="canonical" href="{{ theme_canonical_url }}{{ pagename }}.html"/>
|
||||
{%- endif %}
|
||||
{%- endif %}
|
||||
{%- block linktags %}
|
||||
{%- if hasdoc('about') %}
|
||||
<link rel="author" title="{{ _('About these documents') }}" href="{{ pathto('about') }}" />
|
||||
{%- endif %}
|
||||
{%- if hasdoc('genindex') %}
|
||||
<link rel="index" title="{{ _('Index') }}" href="{{ pathto('genindex') }}" />
|
||||
{%- endif %}
|
||||
{%- if hasdoc('search') %}
|
||||
<link rel="search" title="{{ _('Search') }}" href="{{ pathto('search') }}" />
|
||||
{%- endif %}
|
||||
{%- if hasdoc('copyright') %}
|
||||
<link rel="copyright" title="{{ _('Copyright') }}" href="{{ pathto('copyright') }}" />
|
||||
{%- endif %}
|
||||
<link rel="top" title="{{ docstitle|e }}" href="{{ pathto('index') }}" />
|
||||
{%- if parents %}
|
||||
<link rel="up" title="{{ parents[-1].title|striptags|e }}" href="{{ parents[-1].link|e }}" />
|
||||
{%- endif %}
|
||||
{%- if next %}
|
||||
<link rel="next" title="{{ next.title|striptags|e }}" href="{{ next.link|e }}" />
|
||||
{%- endif %}
|
||||
{%- if prev %}
|
||||
<link rel="prev" title="{{ prev.title|striptags|e }}" href="{{ prev.link|e }}" />
|
||||
{%- endif %}
|
||||
{%- endblock %}
|
||||
{%- block extrahead %} {% endblock %}
|
||||
</head>
|
||||
<body>
|
||||
{%- block header %}{% endblock %}
|
||||
|
||||
{%- block relbar1 %}{{ relbar() }}{% endblock %}
|
||||
|
||||
{%- block content %}
|
||||
{%- block sidebar1 %} {# possible location for sidebar #} {% endblock %}
|
||||
|
||||
<div class="document">
|
||||
{%- block document %}
|
||||
<div class="documentwrapper">
|
||||
{%- if render_sidebar %}
|
||||
<div class="bodywrapper">
|
||||
{%- endif %}
|
||||
<div class="body">
|
||||
{% block body %} {% endblock %}
|
||||
</div>
|
||||
{%- if render_sidebar %}
|
||||
</div>
|
||||
{%- endif %}
|
||||
</div>
|
||||
{%- endblock %}
|
||||
|
||||
{%- block sidebar2 %}{{ sidebar() }}{% endblock %}
|
||||
<div class="clearer"></div>
|
||||
</div>
|
||||
{%- endblock %}
|
||||
|
||||
{%- block relbar2 %}{{ relbar() }}{% endblock %}
|
||||
|
||||
{%- block footer %}
|
||||
<div class="footer">
|
||||
{%- if show_copyright %}
|
||||
{%- if hasdoc('copyright') %}
|
||||
{% trans path=pathto('copyright'), copyright=copyright|e %}© <a href="{{ path }}">Copyright</a> {{ copyright }}.{% endtrans %}
|
||||
{%- else %}
|
||||
{% trans copyright=copyright|e %}© Copyright {{ copyright }}.{% endtrans %}
|
||||
{%- endif %}
|
||||
{%- endif %}
|
||||
{%- if last_updated %}
|
||||
{% trans last_updated=last_updated|e %}Last updated on {{ last_updated }}.{% endtrans %}
|
||||
{%- endif %}
|
||||
{%- if show_sphinx %}
|
||||
{% trans sphinx_version=sphinx_version|e %}Created using <a href="http://sphinx-doc.org/">Sphinx</a> {{ sphinx_version }}.{% endtrans %}
|
||||
{%- endif %}
|
||||
</div>
|
||||
<p>asdf asdf asdf asdf 22</p>
|
||||
{%- endblock %}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
50
doc/_themes/pretix_theme/search.html
vendored
50
doc/_themes/pretix_theme/search.html
vendored
@@ -1,50 +0,0 @@
|
||||
{#
|
||||
basic/search.html
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
Template for the search page.
|
||||
|
||||
:copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
#}
|
||||
{%- extends "layout.html" %}
|
||||
{% set title = _('Search') %}
|
||||
{% set script_files = script_files + ['_static/searchtools.js'] %}
|
||||
{% block footer %}
|
||||
<script type="text/javascript">
|
||||
jQuery(function() { Search.loadIndex("{{ pathto('searchindex.js', 1) }}"); });
|
||||
</script>
|
||||
{# this is used when loading the search index using $.ajax fails,
|
||||
such as on Chrome for documents on localhost #}
|
||||
<script type="text/javascript" id="searchindexloader"></script>
|
||||
{{ super() }}
|
||||
{% endblock %}
|
||||
{% block body %}
|
||||
<noscript>
|
||||
<div id="fallback" class="admonition warning">
|
||||
<p class="last">
|
||||
{% trans %}Please activate JavaScript to enable the search
|
||||
functionality.{% endtrans %}
|
||||
</p>
|
||||
</div>
|
||||
</noscript>
|
||||
|
||||
{% if search_performed %}
|
||||
<h2>{{ _('Search Results') }}</h2>
|
||||
{% if not search_results %}
|
||||
<p>{{ _('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.') }}</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<div id="search-results">
|
||||
{% if search_results %}
|
||||
<ul>
|
||||
{% for href, caption, context in search_results %}
|
||||
<li>
|
||||
<a href="{{ pathto(item.href) }}">{{ caption }}</a>
|
||||
<p class="context">{{ context|e }}</p>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
9
doc/_themes/pretix_theme/searchbox.html
vendored
9
doc/_themes/pretix_theme/searchbox.html
vendored
@@ -1,9 +0,0 @@
|
||||
{%- if builder != 'singlehtml' %}
|
||||
<div role="search">
|
||||
<form id="rtd-search-form" class="wy-form" action="{{ pathto('search') }}" method="get">
|
||||
<input type="text" name="q" placeholder="{{ _('Search docs') }}" />
|
||||
<input type="hidden" name="check_keywords" value="yes" />
|
||||
<input type="hidden" name="area" value="default" />
|
||||
</form>
|
||||
</div>
|
||||
{%- endif %}
|
||||
@@ -1,2 +0,0 @@
|
||||
.fa:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-weight:normal;font-style:normal;src:url("../font/fontawesome_webfont.eot");src:url("../font/fontawesome_webfont.eot?#iefix") format("embedded-opentype"),url("../font/fontawesome_webfont.woff") format("woff"),url("../font/fontawesome_webfont.ttf") format("truetype"),url("../font/fontawesome_webfont.svg#FontAwesome") format("svg")}.fa:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .fa{display:inline-block;text-decoration:inherit}li .fa{display:inline-block}li .fa-large:before,li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-0.8em}ul.fas li .fa{width:0.8em}ul.fas li .fa-large:before,ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before{content:""}.icon-book:before{content:""}.fa-caret-down:before{content:""}.icon-caret-down:before{content:""}.fa-caret-up:before{content:""}.icon-caret-up:before{content:""}.fa-caret-left:before{content:""}.icon-caret-left:before{content:""}.fa-caret-right:before{content:""}.icon-caret-right:before{content:""}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;border-top:solid 10px #343131;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;z-index:400}.rst-versions a{color:#2980B9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27AE60;*zoom:1}.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book{float:left}.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#E74C3C;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#F1C40F;color:#000}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge .fa-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book{float:left}.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width: 768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}
|
||||
/*# sourceMappingURL=badge_only.css.map */
|
||||
6101
doc/_themes/pretix_theme/static/css/pretix.css
vendored
6101
doc/_themes/pretix_theme/static/css/pretix.css
vendored
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
169
doc/_themes/pretix_theme/static/js/theme.js
vendored
169
doc/_themes/pretix_theme/static/js/theme.js
vendored
@@ -1,169 +0,0 @@
|
||||
require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({"sphinx-rtd-theme":[function(require,module,exports){
|
||||
var jQuery = (typeof(window) != 'undefined') ? window.jQuery : require('jquery');
|
||||
|
||||
// Sphinx theme nav state
|
||||
function ThemeNav () {
|
||||
|
||||
var nav = {
|
||||
navBar: null,
|
||||
win: null,
|
||||
winScroll: false,
|
||||
winResize: false,
|
||||
linkScroll: false,
|
||||
winPosition: 0,
|
||||
winHeight: null,
|
||||
docHeight: null,
|
||||
isRunning: false
|
||||
};
|
||||
|
||||
nav.enable = function () {
|
||||
var self = this;
|
||||
|
||||
if (!self.isRunning) {
|
||||
self.isRunning = true;
|
||||
jQuery(function ($) {
|
||||
self.init($);
|
||||
|
||||
self.reset();
|
||||
self.win.on('hashchange', self.reset);
|
||||
|
||||
// Set scroll monitor
|
||||
self.win.on('scroll', function () {
|
||||
if (!self.linkScroll) {
|
||||
self.winScroll = true;
|
||||
}
|
||||
});
|
||||
setInterval(function () { if (self.winScroll) self.onScroll(); }, 25);
|
||||
|
||||
// Set resize monitor
|
||||
self.win.on('resize', function () {
|
||||
self.winResize = true;
|
||||
});
|
||||
setInterval(function () { if (self.winResize) self.onResize(); }, 25);
|
||||
self.onResize();
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
nav.init = function ($) {
|
||||
var doc = $(document),
|
||||
self = this;
|
||||
|
||||
this.navBar = $('div.wy-side-scroll:first');
|
||||
this.win = $(window);
|
||||
|
||||
// Set up javascript UX bits
|
||||
$(document)
|
||||
// Shift nav in mobile when clicking the menu.
|
||||
.on('click', "[data-toggle='wy-nav-top']", function() {
|
||||
$("[data-toggle='wy-nav-shift']").toggleClass("shift");
|
||||
$("[data-toggle='rst-versions']").toggleClass("shift");
|
||||
})
|
||||
|
||||
// Nav menu link click operations
|
||||
.on('click', ".wy-menu-vertical .current ul li a", function() {
|
||||
var target = $(this);
|
||||
// Close menu when you click a link.
|
||||
$("[data-toggle='wy-nav-shift']").removeClass("shift");
|
||||
$("[data-toggle='rst-versions']").toggleClass("shift");
|
||||
// Handle dynamic display of l3 and l4 nav lists
|
||||
self.toggleCurrent(target);
|
||||
self.hashChange();
|
||||
})
|
||||
.on('click', "[data-toggle='rst-current-version']", function() {
|
||||
$("[data-toggle='rst-versions']").toggleClass("shift-up");
|
||||
})
|
||||
|
||||
// Make tables responsive
|
||||
$("table.docutils:not(.field-list)")
|
||||
.wrap("<div class='wy-table-responsive'></div>");
|
||||
|
||||
// Add expand links to all parents of nested ul
|
||||
$('.wy-menu-vertical ul').not('.simple').siblings('a').each(function () {
|
||||
var link = $(this);
|
||||
expand = $('<span class="toctree-expand"></span>');
|
||||
expand.on('click', function (ev) {
|
||||
self.toggleCurrent(link);
|
||||
ev.stopPropagation();
|
||||
return false;
|
||||
});
|
||||
link.prepend(expand);
|
||||
});
|
||||
};
|
||||
|
||||
nav.reset = function () {
|
||||
// Get anchor from URL and open up nested nav
|
||||
var anchor = encodeURI(window.location.hash);
|
||||
if (anchor) {
|
||||
try {
|
||||
var link = $('.wy-menu-vertical')
|
||||
.find('[href="' + anchor + '"]');
|
||||
// If we didn't find a link, it may be because we clicked on
|
||||
// something that is not in the sidebar (eg: when using
|
||||
// sphinxcontrib.httpdomain it generates headerlinks but those
|
||||
// aren't picked up and placed in the toctree). So let's find
|
||||
// the closest header in the document and try with that one.
|
||||
if (link.length === 0) {
|
||||
var doc_link = $('.document a[href="' + anchor + '"]');
|
||||
var closest_section = doc_link.closest('div.section');
|
||||
// Try again with the closest section entry.
|
||||
link = $('.wy-menu-vertical')
|
||||
.find('[href="#' + closest_section.attr("id") + '"]');
|
||||
|
||||
}
|
||||
$('.wy-menu-vertical li.toctree-l1 li.current')
|
||||
.removeClass('current');
|
||||
link.closest('li.toctree-l2').addClass('current');
|
||||
link.closest('li.toctree-l3').addClass('current');
|
||||
link.closest('li.toctree-l4').addClass('current');
|
||||
}
|
||||
catch (err) {
|
||||
console.log("Error expanding nav for anchor", err);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
nav.onScroll = function () {
|
||||
this.winScroll = false;
|
||||
var newWinPosition = this.win.scrollTop(),
|
||||
winBottom = newWinPosition + this.winHeight,
|
||||
navPosition = this.navBar.scrollTop(),
|
||||
newNavPosition = navPosition + (newWinPosition - this.winPosition);
|
||||
if (newWinPosition < 0 || winBottom > this.docHeight) {
|
||||
return;
|
||||
}
|
||||
this.navBar.scrollTop(newNavPosition);
|
||||
this.winPosition = newWinPosition;
|
||||
};
|
||||
|
||||
nav.onResize = function () {
|
||||
this.winResize = false;
|
||||
this.winHeight = this.win.height();
|
||||
this.docHeight = $(document).height();
|
||||
};
|
||||
|
||||
nav.hashChange = function () {
|
||||
this.linkScroll = true;
|
||||
this.win.one('hashchange', function () {
|
||||
this.linkScroll = false;
|
||||
});
|
||||
};
|
||||
|
||||
nav.toggleCurrent = function (elem) {
|
||||
var parent_li = elem.closest('li');
|
||||
parent_li.siblings('li.current').removeClass('current');
|
||||
parent_li.siblings().find('li.current').removeClass('current');
|
||||
parent_li.find('> ul li.current').removeClass('current');
|
||||
parent_li.toggleClass('current');
|
||||
}
|
||||
|
||||
return nav;
|
||||
};
|
||||
|
||||
module.exports.ThemeNav = ThemeNav();
|
||||
|
||||
if (typeof(window) != 'undefined') {
|
||||
window.SphinxRtdTheme = { StickyNav: module.exports.ThemeNav };
|
||||
}
|
||||
|
||||
},{"jquery":"jquery"}]},{},["sphinx-rtd-theme"]);
|
||||
14
doc/_themes/pretix_theme/theme.conf
vendored
14
doc/_themes/pretix_theme/theme.conf
vendored
@@ -1,14 +0,0 @@
|
||||
[theme]
|
||||
inherit = basic
|
||||
stylesheet = css/pretix.css
|
||||
|
||||
[options]
|
||||
typekit_id = hiw1hhg
|
||||
analytics_id =
|
||||
sticky_navigation = False
|
||||
logo_only =
|
||||
collapse_navigation = False
|
||||
display_version = True
|
||||
navigation_depth = 4
|
||||
prev_next_buttons_location = bottom
|
||||
canonical_url =
|
||||
37
doc/_themes/pretix_theme/versions.html
vendored
37
doc/_themes/pretix_theme/versions.html
vendored
@@ -1,37 +0,0 @@
|
||||
{% if READTHEDOCS %}
|
||||
{# Add rst-badge after rst-versions for small badge style. #}
|
||||
<div class="rst-versions" data-toggle="rst-versions" role="note" aria-label="versions">
|
||||
<span class="rst-current-version" data-toggle="rst-current-version">
|
||||
<span class="fa fa-book"> Read the Docs</span>
|
||||
v: {{ current_version }}
|
||||
<span class="fa fa-caret-down"></span>
|
||||
</span>
|
||||
<div class="rst-other-versions">
|
||||
<dl>
|
||||
<dt>{{ _('Versions') }}</dt>
|
||||
{% for slug, url in versions %}
|
||||
<dd><a href="{{ url }}">{{ slug }}</a></dd>
|
||||
{% endfor %}
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>{{ _('Downloads') }}</dt>
|
||||
{% for type, url in downloads %}
|
||||
<dd><a href="{{ url }}">{{ type }}</a></dd>
|
||||
{% endfor %}
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>{{ _('On Read the Docs') }}</dt>
|
||||
<dd>
|
||||
<a href="//{{ PRODUCTION_DOMAIN }}/projects/{{ slug }}/?fromdocs={{ slug }}">{{ _('Project Home') }}</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="//{{ PRODUCTION_DOMAIN }}/builds/{{ slug }}/?fromdocs={{ slug }}">{{ _('Builds') }}</a>
|
||||
</dd>
|
||||
</dl>
|
||||
<hr/>
|
||||
{% trans %}Free document hosting provided by <a href="http://www.readthedocs.org">Read the Docs</a>.{% endtrans %}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
.. _`config`:
|
||||
|
||||
.. spelling:: Galera
|
||||
|
||||
Configuration file
|
||||
==================
|
||||
|
||||
@@ -12,10 +10,9 @@ at the following locations. It will try to read the file from the specified path
|
||||
the following order. The file that is found *last* will override the settings from
|
||||
the files found before.
|
||||
|
||||
1. ``PRETIX_CONFIG_FILE`` environment variable
|
||||
2. ``/etc/pretix/pretix.cfg``
|
||||
3. ``~/.pretix.cfg``
|
||||
4. ``pretix.cfg`` in the current working directory
|
||||
1. ``/etc/pretix/pretix.cfg``
|
||||
2. ``~/.pretix.cfg``
|
||||
3. ``pretix.cfg`` in the current working directory
|
||||
|
||||
The file is expected to be in the INI format as specified in the `Python documentation`_.
|
||||
|
||||
@@ -47,16 +44,12 @@ Example::
|
||||
|
||||
``datadir``
|
||||
The local path to a data directory that will be used for storing user uploads and similar
|
||||
data. Defaults to the value of the environment variable ``DATA_DIR`` or ``data``.
|
||||
data. Defaults to thea value of the environment variable ``DATA_DIR`` or ``data``.
|
||||
|
||||
``plugins_default``
|
||||
A comma-separated list of plugins that are enabled by default for all new events.
|
||||
Defaults to ``pretix.plugins.sendmail,pretix.plugins.statistics``.
|
||||
|
||||
``plugins_exclude``
|
||||
A comma-separated list of plugins that are not available even though they are installed.
|
||||
Defaults to an empty string.
|
||||
|
||||
``cookie_domain``
|
||||
The cookie domain to be set. Defaults to ``None``.
|
||||
|
||||
@@ -66,27 +59,6 @@ Example::
|
||||
``password_reset``
|
||||
Enables or disables password reset. Defaults to ``on``.
|
||||
|
||||
``long_sessions``
|
||||
Enables or disables the "keep me logged in" button. Defaults to ``on``.
|
||||
|
||||
``ecb_rates``
|
||||
By default, pretix periodically downloads a XML file from the European Central Bank to retrieve exchange rates
|
||||
that are used to print tax amounts in the customer currency on invoices for some currencies. Set to ``off`` to
|
||||
disable this feature. Defaults to ``on``.
|
||||
|
||||
``audit_comments``
|
||||
Enables or disables nagging staff users for leaving comments on their sessions for auditability.
|
||||
Defaults to ``off``.
|
||||
|
||||
``obligatory_2fa``
|
||||
Enables or disables obligatory usage of Two-Factor Authentication for users of the pretix backend.
|
||||
Defaults to ``False``
|
||||
|
||||
``trust_x_forwarded_for``
|
||||
Specifies whether the ``X-Forwarded-For`` header can be trusted. Only set to ``on`` if you have a reverse
|
||||
proxy that actively removes and re-adds the header to make sure the correct client IP is the first value.
|
||||
Defaults to ``off``.
|
||||
|
||||
|
||||
Locale settings
|
||||
---------------
|
||||
@@ -130,31 +102,6 @@ Example::
|
||||
``user``, ``password``, ``host``, ``port``
|
||||
Connection details for the database connection. Empty by default.
|
||||
|
||||
``galera``
|
||||
Indicates if the database backend is a MySQL/MariaDB Galera cluster and
|
||||
turns on some optimizations/special case handlers. Default: ``False``
|
||||
|
||||
.. _`config-replica`:
|
||||
|
||||
Database replica settings
|
||||
-------------------------
|
||||
|
||||
If you use a replicated database setup, pretix expects that the default database connection always points to the primary database node.
|
||||
Routing read queries to a replica on database layer is **strongly** discouraged since this can lead to inaccurate such as more tickets
|
||||
being sold than are actually available.
|
||||
|
||||
However, pretix can still make use of a database replica to keep some expensive queries with that can tolerate some latency from your
|
||||
primary database, such as backend search queries. The ``replica`` configuration section can have the same settings as the ``database``
|
||||
section (except for the ``backend`` setting) and will default back to the ``database`` settings for all values that are not given. This
|
||||
way, you just need to specify the settings that are different for the replica.
|
||||
|
||||
Example::
|
||||
|
||||
[replica]
|
||||
host=192.168.0.2
|
||||
|
||||
.. _`config-urls`:
|
||||
|
||||
URLs
|
||||
----
|
||||
|
||||
@@ -204,17 +151,20 @@ Example::
|
||||
``admins``
|
||||
Comma-separated list of email addresses that should receive a report about every error code 500 thrown by pretix.
|
||||
|
||||
.. _`django-settings`:
|
||||
|
||||
Django settings
|
||||
---------------
|
||||
|
||||
Example::
|
||||
|
||||
[django]
|
||||
hosts=localhost
|
||||
secret=j1kjps5a5&4ilpn912s7a1!e2h!duz^i3&idu@_907s$wrz@x-
|
||||
debug=off
|
||||
|
||||
``hosts``
|
||||
Comma-separated list of allowed host names for this installation.
|
||||
Default: ``localhost``
|
||||
|
||||
``secret``
|
||||
The secret to be used by Django for signing and verification purposes. If this
|
||||
setting is not provided, pretix will generate a random secret on the first start
|
||||
@@ -225,11 +175,6 @@ Example::
|
||||
|
||||
.. WARNING:: Never set this to ``True`` in production!
|
||||
|
||||
``profile``
|
||||
Enable code profiling for a random subset of requests. Disabled by default, see
|
||||
:ref:`perf-monitoring` for details.
|
||||
|
||||
.. _`metrics-settings`:
|
||||
|
||||
Metrics
|
||||
-------
|
||||
@@ -282,24 +227,6 @@ to speed up various operations::
|
||||
If redis is not configured, pretix will store sessions and locks in the database. If memcached
|
||||
is configured, memcached will be used for caching instead of redis.
|
||||
|
||||
Translations
|
||||
------------
|
||||
|
||||
pretix comes with a number of translations. Some of them are marked as "incubating", which means
|
||||
they can usually only be selected in development mode. If you want to use them nevertheless, you
|
||||
can activate them like this::
|
||||
|
||||
[languages]
|
||||
allow_incubating=pt-br,da
|
||||
|
||||
You can also tell pretix about additional paths where it will search for translations::
|
||||
|
||||
[languages]
|
||||
path=/path/to/my/translations
|
||||
|
||||
For a given language (e.g. ``pt-br``), pretix will then look in the
|
||||
specific sub-folder, e.g. ``/path/to/my/translations/pt_BR/LC_MESSAGES/django.po``.
|
||||
|
||||
Celery task queue
|
||||
-----------------
|
||||
|
||||
@@ -343,13 +270,5 @@ various places like order codes, secrets in the ticket QR codes, etc. Example::
|
||||
; Voucher code needs to be < 255 characters, default is 16
|
||||
voucher_code=16
|
||||
|
||||
External tools
|
||||
--------------
|
||||
|
||||
pretix can make use of some external tools if they are installed. Currently, they are all optional. Example::
|
||||
|
||||
[tools]
|
||||
pdftk=/usr/bin/pdftk
|
||||
|
||||
.. _Python documentation: https://docs.python.org/3/library/configparser.html?highlight=configparser#supported-ini-file-structure
|
||||
.. _Celery documentation: http://docs.celeryproject.org/en/latest/userguide/configuration.html
|
||||
.. _Celery documentation: http://docs.celeryproject.org/en/latest/configuration.html
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
.. _`admindocs`:
|
||||
|
||||
Administrator documentation
|
||||
===========================
|
||||
|
||||
This documentation is for everyone who wants to install pretix on a server.
|
||||
|
||||
Contents:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
installation/index
|
||||
config
|
||||
maintainance
|
||||
scaling
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
.. highlight:: none
|
||||
|
||||
Installing a development version
|
||||
================================
|
||||
|
||||
If you want to use a feature of pretix that is not yet contained in the last monthly release, you can also
|
||||
install a development version with pretix.
|
||||
|
||||
.. warning:: When in production, we strongly recommend only installing released versions. Development versions might
|
||||
be broken, incompatible to plugins, or in rare cases incompatible to upgrade later on.
|
||||
|
||||
|
||||
Manual installation
|
||||
-------------------
|
||||
|
||||
You can use ``pip`` to update pretix directly to the development branch. Then, upgrade as usual::
|
||||
|
||||
$ source /var/pretix/venv/bin/activate
|
||||
(venv)$ pip3 install -U "git+https://github.com/pretix/pretix.git#egg=pretix&subdirectory=src"
|
||||
(venv)$ python -m pretix migrate
|
||||
(venv)$ python -m pretix rebuild
|
||||
(venv)$ python -m pretix updatestyles
|
||||
# systemctl restart pretix-web pretix-worker
|
||||
|
||||
Docker installation
|
||||
-------------------
|
||||
|
||||
To use the latest development version with Docker, first pull it from Docker Hub::
|
||||
|
||||
$ docker pull pretix/standalone:latest
|
||||
|
||||
|
||||
Then change your ``/etc/systemd/system/pretix.service`` file to use the ``:latest`` tag instead of ``:stable`` as well
|
||||
and upgrade as usual::
|
||||
|
||||
$ systemctl restart pretix.service
|
||||
$ docker exec -it pretix.service pretix upgrade
|
||||
@@ -26,7 +26,7 @@ installation guides):
|
||||
* `Docker`_
|
||||
* A SMTP server to send out mails, e.g. `Postfix`_ on your machine or some third-party server you have credentials for
|
||||
* A HTTP reverse proxy, e.g. `nginx`_ or Apache to allow HTTPS connections
|
||||
* A `PostgreSQL`_, `MySQL`_ 5.7+, or MariaDB 10.2.7+ database server
|
||||
* A `MySQL`_ or `PostgreSQL`_ database server
|
||||
* A `redis`_ server
|
||||
|
||||
We also recommend that you use a firewall, although this is not a pretix-specific recommendation. If you're new to
|
||||
@@ -36,9 +36,6 @@ Linux and firewalls, we recommend that you start with `ufw`_.
|
||||
SSL certificates can be obtained for free these days. We also *do not* provide support for HTTP-only
|
||||
installations except for evaluation purposes.
|
||||
|
||||
.. warning:: We recommend **PostgreSQL**. If you go for MySQL, make sure you run **MySQL 5.7 or newer** or
|
||||
**MariaDB 10.2.7 or newer**.
|
||||
|
||||
On this guide
|
||||
-------------
|
||||
|
||||
@@ -58,29 +55,16 @@ Database
|
||||
--------
|
||||
|
||||
Next, we need a database and a database user. We can create these with any kind of database managing tool or directly on
|
||||
our database's shell. For PostgreSQL, we would do::
|
||||
our database's shell, e.g. for MySQL::
|
||||
|
||||
# sudo -u postgres createuser -P pretix
|
||||
# sudo -u postgres createdb -O pretix pretix
|
||||
$ mysql -u root -p
|
||||
mysql> CREATE DATABASE pretix DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;
|
||||
mysql> GRANT ALL PRIVILEGES ON pretix.* TO pretix@'localhost' IDENTIFIED BY '*********';
|
||||
mysql> FLUSH PRIVILEGES;
|
||||
|
||||
Make sure that your database listens on the network. If PostgreSQL on the same same host as docker, but not inside a docker container, we recommend that you just listen on the Docker interface by changing the following line in ``/etc/postgresql/<version>/main/postgresql.conf``::
|
||||
|
||||
listen_addresses = 'localhost,172.17.0.1'
|
||||
|
||||
You also need to add a new line to ``/etc/postgresql/<version>/main/pg_hba.conf`` to allow network connections to this user and database::
|
||||
|
||||
host pretix pretix 172.17.0.1/16 md5
|
||||
|
||||
Restart PostgreSQL after you changed these files::
|
||||
|
||||
# systemctl restart postgresql
|
||||
|
||||
If you have a firewall running, you should also make sure that port 5432 is reachable from the ``172.17.0.1/16`` subnet.
|
||||
|
||||
For MySQL, you can either also use network-based connections or mount the ``/var/run/mysqld/mysqld.sock`` socket into the docker container.
|
||||
When using MySQL, make sure you set the character set of the database to ``utf8mb4``, e.g. like this::
|
||||
|
||||
mysql > CREATE DATABASE pretix DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci;
|
||||
Replace the asterisks with a password of your own. For MySQL, we will use a unix domain socket to connect to the
|
||||
database. For PostgreSQL, be sure to configure the interface binding and your firewall so that the docker container
|
||||
can reach PostgreSQL.
|
||||
|
||||
Redis
|
||||
-----
|
||||
@@ -127,16 +111,13 @@ Fill the configuration file ``/etc/pretix/pretix.cfg`` with the following conten
|
||||
datadir=/data
|
||||
|
||||
[database]
|
||||
; Replace postgresql with mysql for MySQL
|
||||
backend=postgresql
|
||||
; Replace mysql with postgresql_psycopg2 for PostgreSQL
|
||||
backend=mysql
|
||||
name=pretix
|
||||
user=pretix
|
||||
; Replace with the password you chose above
|
||||
password=*********
|
||||
; In most docker setups, 172.17.0.1 is the address of the docker host. Adjuts
|
||||
; this to wherever your database is running, e.g. the name of a linked container
|
||||
; or of a mounted MySQL socket.
|
||||
host=172.17.0.1
|
||||
; Replace with host IP address for PostgreSQL
|
||||
host=/var/run/mysqld/mysqld.sock
|
||||
|
||||
[mail]
|
||||
; See config file documentation for more options
|
||||
@@ -160,9 +141,9 @@ See :ref:`email configuration <mail-settings>` to learn more about configuring m
|
||||
Docker image and service
|
||||
------------------------
|
||||
|
||||
First of all, download the latest stable pretix image by running::
|
||||
First of all, download the latest pretix image by running::
|
||||
|
||||
$ docker pull pretix/standalone:stable
|
||||
$ docker pull pretix/standalone:latest
|
||||
|
||||
We recommend starting the docker container using systemd to make sure it runs correctly after a reboot. Create a file
|
||||
named ``/etc/systemd/system/pretix.service`` with the following content::
|
||||
@@ -180,15 +161,14 @@ named ``/etc/systemd/system/pretix.service`` with the following content::
|
||||
-v /var/pretix-data:/data \
|
||||
-v /etc/pretix:/etc/pretix \
|
||||
-v /var/run/redis:/var/run/redis \
|
||||
pretix/standalone:stable all
|
||||
-v /var/run/mysqld:/var/run/mysqld \
|
||||
pretix/standalone all
|
||||
ExecStop=/usr/bin/docker stop %n
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
When using MySQL and socket mounting, you'll need the additional flag ``-v /var/run/mysqld:/var/run/mysqld`` in the command.
|
||||
|
||||
You can now run the following commands
|
||||
You can leave the MySQL socket volume out if you're using PostgreSQL. You can now run the following commands
|
||||
to enable and start the service::
|
||||
|
||||
# systemctl daemon-reload
|
||||
@@ -242,8 +222,6 @@ Yay, you are done! You should now be able to reach pretix at https://pretix.your
|
||||
*admin@localhost* with a password of *admin*. Don't forget to change that password! Create an organizer first, then
|
||||
create an event and start selling tickets!
|
||||
|
||||
You should probably read :ref:`maintainance` next.
|
||||
|
||||
Updates
|
||||
-------
|
||||
|
||||
@@ -251,15 +229,11 @@ Updates
|
||||
|
||||
Updates are fairly simple, but require at least a short downtime::
|
||||
|
||||
# docker pull pretix/standalone:stable
|
||||
# docker pull pretix/standalone
|
||||
# systemctl restart pretix.service
|
||||
# docker exec -it pretix.service pretix upgrade
|
||||
|
||||
Restarting the service can take a few seconds, especially if the update requires changes to the database.
|
||||
Replace ``stable`` above with a specific version number like ``1.0`` or with ``latest`` for the development
|
||||
version, if you want to.
|
||||
|
||||
.. _`docker_plugininstall`:
|
||||
|
||||
Install a plugin
|
||||
----------------
|
||||
@@ -268,11 +242,11 @@ To install a plugin, you need to build your own docker image. To do so, create a
|
||||
named ``Dockerfile`` in it. The Dockerfile could look like this (replace ``pretix-passbook`` with the plugins of your
|
||||
choice)::
|
||||
|
||||
FROM pretix/standalone:stable
|
||||
FROM pretix/standalone
|
||||
USER root
|
||||
RUN pip3 install pretix-passbook
|
||||
USER pretixuser
|
||||
RUN cd /pretix/src && make production
|
||||
RUN make production
|
||||
|
||||
Then, go to that directory and build the image::
|
||||
|
||||
@@ -288,8 +262,8 @@ to re-build your custom image after you pulled ``pretix/standalone`` if you want
|
||||
.. _pretix.eu: https://pretix.eu/
|
||||
.. _MySQL: https://dev.mysql.com/doc/refman/5.7/en/linux-installation-apt-repo.html
|
||||
.. _PostgreSQL: https://www.digitalocean.com/community/tutorials/how-to-install-and-use-postgresql-9-4-on-debian-8
|
||||
.. _redis: https://blog.programster.org/debian-8-install-redis-server/
|
||||
.. _redis: http://blog.programster.org/debian-8-install-redis-server/
|
||||
.. _ufw: https://en.wikipedia.org/wiki/Uncomplicated_Firewall
|
||||
.. _redis website: https://redis.io/topics/security
|
||||
.. _redis website: http://redis.io/topics/security
|
||||
.. _redis in docker: https://hub.docker.com/r/_/redis/
|
||||
.. _strong encryption settings: https://mozilla.github.io/server-side-tls/ssl-config-generator/
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
.. highlight:: none
|
||||
|
||||
Installing pretix Enterprise plugins
|
||||
====================================
|
||||
|
||||
If you want to use a feature of pretix that is part of our commercial offering pretix Enterprise, you need to follow
|
||||
some extra steps. Installation works similar to normal pretix plugins, but involves a few extra steps.
|
||||
|
||||
Buying the license
|
||||
------------------
|
||||
|
||||
To obtain a license, please get in touch at sales@pretix.eu. Please let us know how many tickets you roughly intend
|
||||
to sell per year and how many servers you want to use the plugin on. We recommend having a look at our `price list`_
|
||||
first.
|
||||
|
||||
|
||||
Manual installation
|
||||
-------------------
|
||||
|
||||
First, generate an SSH key for the system user that you install pretix as. In our tutorial, that would be the user
|
||||
``pretix``. Choose an empty passphrase::
|
||||
|
||||
# su pretix
|
||||
$ ssh-keygen
|
||||
Generating public/private rsa key pair.
|
||||
Enter file in which to save the key (/var/pretix/.ssh/id_rsa):
|
||||
Enter passphrase (empty for no passphrase):
|
||||
Enter same passphrase again:
|
||||
Your identification has been saved in /var/pretix/.ssh/id_rsa.
|
||||
Your public key has been saved in /var/pretix/.ssh/id_rsa.pub.
|
||||
|
||||
Next, send the content of the *public* key to your sales representative at pretix::
|
||||
|
||||
$ cat /var/pretix/.ssh/id_rsa.pub
|
||||
ssh-rsa AAAAB3N...744HZawHlD pretix@foo
|
||||
|
||||
After we configured your key in our system, you can install the plugin directly using ``pip`` from the URL we told
|
||||
you, for example::
|
||||
|
||||
$ source /var/pretix/venv/bin/activate
|
||||
(venv)$ pip3 install -U "git+ssh://git@code.rami.io:10022/pretix/pretix-slack.git@stable#egg=pretix-slack"
|
||||
(venv)$ python -m pretix migrate
|
||||
(venv)$ python -m pretix rebuild
|
||||
# systemctl restart pretix-web pretix-worker
|
||||
|
||||
Docker installation
|
||||
-------------------
|
||||
|
||||
To install a plugin, you need to build your own docker image. To do so, create a new directory to work in. As a first
|
||||
step, generate a new SSH key in that directory to use for authentication with us::
|
||||
|
||||
$ cd /home/me/mypretixdocker
|
||||
$ ssh-keygen -N "" -f id_pretix_enterprise
|
||||
|
||||
Next, send the content of the *public* key to your sales representative at pretix::
|
||||
|
||||
$ cat id_pretix_enterprise.pub
|
||||
ssh-rsa AAAAB3N...744HZawHlD pretix@foo
|
||||
|
||||
After we configured your key in our system, you can add a ``Dockerfile`` in your directory that includes the newly
|
||||
generated key and installs the plugin from the URL we told you::
|
||||
|
||||
FROM pretix/standalone:stable
|
||||
USER root
|
||||
COPY id_pretix_enterprise /root/.ssh/id_rsa
|
||||
COPY id_pretix_enterprise.pub /root/.ssh/id_rsa.pub
|
||||
RUN chmod -R 0600 /root/.ssh && \
|
||||
mkdir -p /etc/ssh && \
|
||||
ssh-keyscan -t rsa -p 10022 code.rami.io >> /root/.ssh/known_hosts && \
|
||||
echo StrictHostKeyChecking=no >> /root/.ssh/config && \
|
||||
pip3 install -Ue "git+ssh://git@code.rami.io:10022/pretix/pretix-slack.git@stable#egg=pretix-slack" && \
|
||||
cd /pretix/src && \
|
||||
sudo -u pretixuser make production
|
||||
USER pretixuser
|
||||
|
||||
Then, build the image for docker::
|
||||
|
||||
$ docker build -t mypretix
|
||||
|
||||
You can now use that image ``mypretix`` instead of ``pretix/standalone:stable`` in your ``/etc/systemd/system/pretix.service``
|
||||
service file. Be sure to re-build your custom image after you pulled ``pretix/standalone`` if you want to perform an
|
||||
update to a new version of pretix.
|
||||
|
||||
.. _price list: https://pretix.eu/about/en/pricing
|
||||
@@ -1,13 +1,11 @@
|
||||
.. highlight:: ini
|
||||
|
||||
.. spelling:: SQL
|
||||
|
||||
General remarks
|
||||
===============
|
||||
|
||||
Requirements
|
||||
------------
|
||||
To use pretix, you will need the following things:
|
||||
To use pretix, you wull need the following things:
|
||||
|
||||
* **pretix** and the python packages it depends on
|
||||
|
||||
@@ -21,9 +19,6 @@ To use pretix, you will need the following things:
|
||||
|
||||
.. warning:: Do not ever use SQLite in production. It will break.
|
||||
|
||||
.. warning:: We recommend **PostgreSQL**. If you go for MySQL, make sure you run **MySQL 5.7 or newer** or
|
||||
**MariaDB 10.2.7 or newer**.
|
||||
|
||||
* A **reverse proxy**. pretix needs to deliver some static content to your users (e.g. CSS, images, ...). While pretix
|
||||
is capable of doing this, having this handled by a proper web server like **nginx** or **Apache** will be much
|
||||
faster. Also, you need a proxying web server in front to provide SSL encryption.
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
.. _`installation`:
|
||||
|
||||
Installation guide
|
||||
==================
|
||||
|
||||
@@ -12,5 +10,3 @@ for your needs.
|
||||
general
|
||||
docker_smallscale
|
||||
manual_smallscale
|
||||
dev_version
|
||||
enterprise
|
||||
|
||||
@@ -23,7 +23,7 @@ installation guides):
|
||||
|
||||
* A SMTP server to send out mails, e.g. `Postfix`_ on your machine or some third-party server you have credentials for
|
||||
* A HTTP reverse proxy, e.g. `nginx`_ or Apache to allow HTTPS connections
|
||||
* A `PostgreSQL`_, `MySQL`_ 5.7+, or MariaDB 10.2.7+ database server
|
||||
* A `MySQL`_ or `PostgreSQL`_ database server
|
||||
* A `redis`_ server
|
||||
|
||||
We also recommend that you use a firewall, although this is not a pretix-specific recommendation. If you're new to
|
||||
@@ -33,9 +33,6 @@ Linux and firewalls, we recommend that you start with `ufw`_.
|
||||
SSL certificates can be obtained for free these days. We also *do not* provide support for HTTP-only
|
||||
installations except for evaluation purposes.
|
||||
|
||||
.. warning:: We recommend **PostgreSQL**. If you go for MySQL, make sure you run **MySQL 5.7 or newer** or
|
||||
**MariaDB 10.2.7 or newer**.
|
||||
|
||||
Unix user
|
||||
---------
|
||||
|
||||
@@ -50,23 +47,21 @@ Database
|
||||
--------
|
||||
|
||||
Having the database server installed, we still need a database and a database user. We can create these with any kind
|
||||
of database managing tool or directly on our database's shell. For PostgreSQL, we would do::
|
||||
of database managing tool or directly on our database's shell, e.g. for MySQL::
|
||||
|
||||
# sudo -u postgres createuser pretix
|
||||
# sudo -u postgres createdb -O pretix pretix
|
||||
|
||||
When using MySQL, make sure you set the character set of the database to ``utf8mb4``, e.g. like this::
|
||||
|
||||
mysql > CREATE DATABASE pretix DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci;
|
||||
$ mysql -u root -p
|
||||
mysql> CREATE DATABASE pretix DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;
|
||||
mysql> GRANT ALL PRIVILEGES ON pretix.* TO pretix@'localhost' IDENTIFIED BY '*********';
|
||||
mysql> FLUSH PRIVILEGES;
|
||||
|
||||
Package dependencies
|
||||
--------------------
|
||||
|
||||
To build and run pretix, you will need the following debian packages::
|
||||
|
||||
# apt-get install git build-essential python-dev python3-venv python3 python3-pip \
|
||||
# apt-get install git build-essential python-dev python-virtualenv python3 python3-pip \
|
||||
python3-dev libxml2-dev libxslt1-dev libffi-dev zlib1g-dev libssl-dev \
|
||||
gettext libpq-dev libmariadbclient-dev libjpeg-dev libopenjp2-7-dev
|
||||
gettext libpq-dev libmysqlclient-dev libjpeg-dev
|
||||
|
||||
Config file
|
||||
-----------
|
||||
@@ -87,18 +82,13 @@ Fill the configuration file ``/etc/pretix/pretix.cfg`` with the following conten
|
||||
datadir=/var/pretix/data
|
||||
|
||||
[database]
|
||||
; For MySQL, replace with "mysql"
|
||||
backend=postgresql
|
||||
; Replace mysql with postgresql_psycopg2 for PostgreSQL
|
||||
backend=mysql
|
||||
name=pretix
|
||||
user=pretix
|
||||
; For MySQL, enter the user password. For PostgreSQL on the same host,
|
||||
; we don't need one because we can use peer authentification if our
|
||||
; PostgreSQL user matches our unix user.
|
||||
password=
|
||||
; For MySQL, use local socket, e.g. /var/run/mysqld/mysqld.sock
|
||||
; For a remote host, supply an IP address
|
||||
; For local postgres authentication, you can leave it empty
|
||||
host=
|
||||
password=*********
|
||||
; Replace with host IP address for PostgreSQL
|
||||
host=/var/run/mysqld/mysqld.sock
|
||||
|
||||
[mail]
|
||||
; See config file documentation for more options
|
||||
@@ -122,16 +112,17 @@ Now we will install pretix itself. The following steps are to be executed as the
|
||||
actually install pretix, we will create a virtual environment to isolate the python packages from your global
|
||||
python installation::
|
||||
|
||||
$ python3 -m venv /var/pretix/venv
|
||||
$ virtualenv -p python3 /var/pretix/venv
|
||||
$ source /var/pretix/venv/bin/activate
|
||||
(venv)$ pip3 install -U pip setuptools wheel
|
||||
|
||||
We now install pretix, its direct dependencies and gunicorn. Replace ``postgres`` with ``mysql`` in the following
|
||||
command if you're running MySQL::
|
||||
We now install pretix, its direct dependencies and gunicorn. Replace ``mysql`` with ``postgres`` in the following
|
||||
command if you're running PostgreSQL::
|
||||
|
||||
(venv)$ pip3 install "pretix[postgres]" gunicorn
|
||||
(venv)$ pip3 install "pretix[mysql]" gunicorn
|
||||
|
||||
Note that you need Python 3.5 or newer. You can find out your Python version using ``python -V``.
|
||||
If you are running Python 3.4, you also need to ``pip3 install typing``. This is not required on 3.5 or newer.
|
||||
You can find out your Python version using ``python -V``.
|
||||
|
||||
We also need to create a data directory::
|
||||
|
||||
@@ -186,7 +177,7 @@ For background tasks we need a second service ``/etc/systemd/system/pretix-worke
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
You can now run the following commands to enable and start the services::
|
||||
You can now run the following comamnds to enable and start the services::
|
||||
|
||||
# systemctl daemon-reload
|
||||
# systemctl enable pretix-web pretix-worker
|
||||
@@ -199,7 +190,7 @@ Cronjob
|
||||
You need to set up a cronjob that runs the management command ``runperiodic``. The exact interval is not important
|
||||
but should be something between every minute and every hour. You could for example configure cron like this::
|
||||
|
||||
15,45 * * * * export PATH=/var/pretix/venv/bin:$PATH && cd /var/pretix && python -m pretix runperiodic
|
||||
15,45 * * * * export PATH=/var/pretix/venv/bin:$PATH && cd /var/pretix/source/src && python -m pretix runperiodic
|
||||
|
||||
The cronjob should run as the ``pretix`` user (``crontab -e -u pretix``).
|
||||
|
||||
@@ -222,9 +213,6 @@ The following snippet is an example on how to configure a nginx proxy for pretix
|
||||
ssl_certificate /path/to/cert.chain.pem;
|
||||
ssl_certificate_key /path/to/key.pem;
|
||||
|
||||
add_header Referrer-Policy same-origin;
|
||||
add_header X-Content-Type-Options nosniff;
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:8345/;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
@@ -248,15 +236,13 @@ The following snippet is an example on how to configure a nginx proxy for pretix
|
||||
}
|
||||
|
||||
location /static/ {
|
||||
alias /var/pretix/venv/lib/python3.5/site-packages/pretix/static.dist/;
|
||||
alias /var/pretix/source/src/pretix/static.dist/;
|
||||
access_log off;
|
||||
expires 365d;
|
||||
add_header Cache-Control "public";
|
||||
}
|
||||
}
|
||||
|
||||
.. note:: Remember to replace the ``python3.5`` in the ``/static/`` path in the config
|
||||
above with your python version.
|
||||
|
||||
We recommend reading about setting `strong encryption settings`_ for your web server.
|
||||
|
||||
@@ -267,26 +253,22 @@ Yay, you are done! You should now be able to reach pretix at https://pretix.your
|
||||
*admin@localhost* with a password of *admin*. Don't forget to change that password! Create an organizer first, then
|
||||
create an event and start selling tickets!
|
||||
|
||||
You should probably read :ref:`maintainance` next.
|
||||
|
||||
Updates
|
||||
-------
|
||||
|
||||
.. warning:: While we try hard not to break things, **please perform a backup before every upgrade**.
|
||||
|
||||
To upgrade to a new pretix release, pull the latest code changes and run the following commands (again, replace
|
||||
``postgres`` with ``mysql`` if necessary)::
|
||||
``mysql`` with ``postgres`` if necessary)::
|
||||
|
||||
$ source /var/pretix/venv/bin/activate
|
||||
(venv)$ pip3 install -U pretix[postgres] gunicorn
|
||||
(venv)$ pip3 install -U pretix[mysql] gunicorn
|
||||
(venv)$ python -m pretix migrate
|
||||
(venv)$ python -m pretix rebuild
|
||||
(venv)$ python -m pretix updatestyles
|
||||
# systemctl restart pretix-web pretix-worker
|
||||
|
||||
|
||||
.. _`manual_plugininstall`:
|
||||
|
||||
Install a plugin
|
||||
----------------
|
||||
|
||||
@@ -307,6 +289,6 @@ example::
|
||||
.. _pretix.eu: https://pretix.eu/
|
||||
.. _MySQL: https://dev.mysql.com/doc/refman/5.7/en/linux-installation-apt-repo.html
|
||||
.. _PostgreSQL: https://www.digitalocean.com/community/tutorials/how-to-install-and-use-postgresql-9-4-on-debian-8
|
||||
.. _redis: https://blog.programster.org/debian-8-install-redis-server/
|
||||
.. _redis: http://blog.programster.org/debian-8-install-redis-server/
|
||||
.. _ufw: https://en.wikipedia.org/wiki/Uncomplicated_Firewall
|
||||
.. _strong encryption settings: https://mozilla.github.io/server-side-tls/ssl-config-generator/
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
.. highlight:: ini
|
||||
|
||||
.. _`maintainance`:
|
||||
|
||||
Backups and Monitoring
|
||||
======================
|
||||
|
||||
If you host your own pretix instance, you also need to care about the availability
|
||||
of your service and the safety of your data yourself. This page gives you some
|
||||
information that you might need to do so properly.
|
||||
|
||||
Backups
|
||||
-------
|
||||
|
||||
There are essentially two things which you should create backups of:
|
||||
|
||||
Database
|
||||
Your SQL database (MySQL or PostgreSQL). This is critical and you should **absolutely
|
||||
always create automatic backups of your database**. There are tons of tutorials on the
|
||||
internet on how to do this, and the exact process depends on the choice of your database.
|
||||
For MySQL, see ``mysqldump`` and for PostgreSQL, see the ``pg_dump`` tool. You probably
|
||||
want to create a cronjob that does the backups for you on a regular schedule.
|
||||
|
||||
Data directory
|
||||
The data directory of your pretix configuration might contain some things that you should
|
||||
back up. If you did not specify a secret in your config file, back up the ``.secret`` text
|
||||
file in the data directory. If you lose your secret, all currently active user sessions,
|
||||
password reset links and similar things will be rendered invalid. Also, you probably want
|
||||
to backup the ``media`` subdirectory of the data directory which contains all user-uploaded
|
||||
and generated files. This includes files you could in theory regenerate (ticket downloads)
|
||||
but also files that you might be legally required to keep (invoice PDFs) or files that you
|
||||
would need to re-upload (event logos, product pictures, etc.). It is up to you if you
|
||||
create regular backups of this data, but we strongly advise you to do so. You can create
|
||||
backups e.g. using ``rsync``. There is a lot of information on the internet on how to create
|
||||
backups of folders on a Linux machine.
|
||||
|
||||
There is no need to create backups of the redis database, if you use it. We only use it for
|
||||
non-critical, temporary or cached data.
|
||||
|
||||
Uptime monitoring
|
||||
-----------------
|
||||
|
||||
To monitor whether your pretix instance is running, you can issue a GET request to
|
||||
``https://pretix.mydomain.com/healthcheck/``. This endpoint tests if the connection to the
|
||||
database, to the configured cache and to redis (if used) is working correctly. If everything
|
||||
appears to work fine, an empty response with status code ``200`` is returned.
|
||||
If there is a problem, a status code in the ``5xx`` range will be returned.
|
||||
|
||||
.. _`perf-monitoring`:
|
||||
|
||||
Performance monitoring
|
||||
----------------------
|
||||
|
||||
If you want to generate detailed performance statistics of your pretix installation, there is an
|
||||
endpoint at ``https://pretix.mydomain.com/metrics`` (no slash at the end) which returns a
|
||||
number of values in the text format understood by monitoring tools like Prometheus_. This data
|
||||
is only collected and exposed if you enable it in the :ref:`metrics-settings` section of your
|
||||
pretix configuration. You can also configure basic auth credentials there to protect your
|
||||
statistics against unauthorized access. The data is temporarily collected in redis, so the
|
||||
performance impact of this feature depends on the connection to your redis database.
|
||||
|
||||
Currently, mostly response times of HTTP requests and background tasks are exposed.
|
||||
|
||||
If you want to go even further, you can set the ``profile`` option in the :ref:`django-settings`
|
||||
section to a value between 0 and 1. If you set it for example to 0.1, then 10% of your requests
|
||||
(randomly selected) will be run with cProfile_ activated. The profiling results will be saved
|
||||
to your data directory. As this might impact performance significantly and writes a lot of data
|
||||
to disk, we recommend to only enable it for a small number of requests -- and only if you are
|
||||
really interested in the results.
|
||||
|
||||
Available metrics
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
The metrics available in pretix follow the standard `metric types`_ from the Prometheus world.
|
||||
Currently, the following metrics are exported:
|
||||
|
||||
pretix_view_requests_total
|
||||
Counter. Counts requests to Django views, labeled with the resolved ``url_name``, the used
|
||||
HTTP ``method`` and the ``status_code`` returned.
|
||||
|
||||
pretix_view_durations_seconds
|
||||
Histogram. Measures duration of requests to Django views, labeled with the resolved
|
||||
``url_name``, the used HTTP ``method`` and the ``status_code`` returned.
|
||||
|
||||
pretix_task_runs_total
|
||||
Counter. Counts executions of background tasks, labeled with the ``task_name`` and the
|
||||
``status``. The latter can be ``success``, ``error`` or ``expected-error``.
|
||||
|
||||
pretix_task_duration_seconds
|
||||
Histogram. Measures duration of successful background task executions, labeled with the
|
||||
``task_name``.
|
||||
|
||||
pretix_model_instances
|
||||
Gauge. Measures number of instances of a certain model within the database, labeled with
|
||||
the ``model`` name.
|
||||
|
||||
.. _metric types: https://prometheus.io/docs/concepts/metric_types/
|
||||
.. _Prometheus: https://prometheus.io/
|
||||
.. _cProfile: https://docs.python.org/3/library/profile.html
|
||||
@@ -1,236 +0,0 @@
|
||||
.. _`scaling`:
|
||||
|
||||
Scaling guide
|
||||
=============
|
||||
|
||||
Our :ref:`installation guide <installation>` only covers "small-scale" setups, by which we mostly mean
|
||||
setups that run on a **single (virtual) machine** and do not encounter large traffic peaks.
|
||||
|
||||
We do not offer an installation guide for larger-scale setups of pretix, mostly because we believe that
|
||||
there is no one-size-fits-all solution for this and the desired setup highly depends on your use case,
|
||||
the platform you run pretix on, and your technical capabilities. We do not recommend trying set up pretix
|
||||
in a multi-server environment if you do not already have experience with managing server clusters.
|
||||
|
||||
This document is intended to give you a general idea on what issues you will encounter when you scale up
|
||||
and what you should think of.
|
||||
|
||||
.. tip::
|
||||
|
||||
If you require more help on this, we're happy to help. Our pretix Enterprise support team has built
|
||||
and helped building, scaling and load-testing pretix installations at any scale and we're looking
|
||||
forward to work with you on fine-tuning your system. If you intend to sell **more than a thousand
|
||||
tickets in a very short amount of time**, we highly recommend reaching out and at least talking this
|
||||
through. Just get in touch at sales@pretix.eu!
|
||||
|
||||
Scaling reasons
|
||||
---------------
|
||||
|
||||
There's mainly two reasons to scale up a pretix installation beyond a single server:
|
||||
|
||||
* **Availability:** Distributing pretix over multiple servers can allow you to survive failure of one or more single machines, leading to a higher uptime and reliability of your system.
|
||||
|
||||
* **Traffic and throughput:** Distributing pretix over multiple servers can allow you to process more web requests and ticket sales at the same time.
|
||||
|
||||
You are very unlikely to require scaling for other reasons, such as having too much data in your database.
|
||||
|
||||
Components
|
||||
----------
|
||||
|
||||
A pretix installation usually consists of the following components which run performance-relevant processes:
|
||||
|
||||
* ``pretix-web`` is the Django-based web application that serves all user interaction.
|
||||
|
||||
* ``pretix-worker`` is a Celery-based application that processes tasks that should be run asynchronously outside of the web application process.
|
||||
|
||||
* A **SQL database** keeps all the important data and processes the actual transactions. We recommend using PostgreSQL, but MySQL/MariaDB works as well.
|
||||
|
||||
* A **web server** that terminates TLS and HTTP connections and forwards them to ``pretix-web``. In some cases, e.g. when serving static files, the web servers might return a response directly. We recommend using ``nginx``.
|
||||
|
||||
* A **redis** server responsible for the communication between ``pretix-web`` and ``pretix-worker``, as well as for caching.
|
||||
|
||||
* A directory of **media files** such as user-uploaded files or generated files (tickets, invoices, …) that are created and used by ``pretix-web``, ``pretix-worker`` and the web server.
|
||||
|
||||
In the following, we will discuss the scaling behavior of every component individually. In general, you can run all of the components
|
||||
on the same server, but you can just as well distribute every component to its own server, or even use multiple servers for some single
|
||||
components.
|
||||
|
||||
.. warning::
|
||||
|
||||
When setting up your system, don't forget about security. In a multi-server environment,
|
||||
you need to take special care to ensure that no unauthorized access to your database
|
||||
is possible through the network and that it's not easy to wiretap your connections. We
|
||||
recommend a rigorous use of firewalls and encryption on all communications. You can
|
||||
ensure this either on an application level (such as using the TLS support in your
|
||||
database) or on a network level with a VPN solution.
|
||||
|
||||
Web server
|
||||
""""""""""
|
||||
|
||||
Your web server is at the very front of your installation. It will need to absorb all of the traffic, and it should be able to
|
||||
at least show a decent error message, even when everything else fails. Luckily, web servers are really fast these days, so this
|
||||
can be achieved without too much work.
|
||||
|
||||
We recommend reading up on tuning your web server for high concurrency. For nginx, this means thinking about the number of worker
|
||||
processes and the number of connections each worker process accepts. Double-check that TLS session caching works, because TLS
|
||||
handshakes can get really expensive.
|
||||
|
||||
During a traffic peak, your web server will be able to make us of more CPU resources, while memory usage will stay comparatively low,
|
||||
so if you invest in more hardware here, invest in more and faster CPU cores.
|
||||
|
||||
Make sure that pretix' static files (such as CSS and JavaScript assets) as well as user-uploaded media files (event logos, etc)
|
||||
are served directly by your web server and your web server caches them in-memory (nginx does it by default) and sets useful
|
||||
headers for client-side caching. As an additional performance improvement, you can turn of access logging for these types of files.
|
||||
If you want, you can even farm out serving static files to a different web server entirely and :ref:`configure pretix to reference
|
||||
them from a different URL <config-urls>`.
|
||||
|
||||
.. tip::
|
||||
|
||||
If you expect *really high traffic* for your very popular event, you might want to do some rate limiting on this layer, or,
|
||||
if you want to ensure a fair and robust first-come-first-served experience and prefer letting users wait over showing them
|
||||
errors, consider a queuing solution. We're happy to provide you with such systems, just get in touch at sales@pretix.eu.
|
||||
|
||||
pretix-web
|
||||
""""""""""
|
||||
|
||||
The ``pretix-web`` process does not carry any internal state can be easily started on as many machines as you like, and you can
|
||||
use the load balancing features of your frontend web server to redirect to all of them.
|
||||
|
||||
You can adjust the number of processes in the ``gunicorn`` command line, and we recommend choosing roughly two times the number
|
||||
of CPU cores available. Under load, the memory consumption of ``pretix-web`` will stay comparatively constant, while the CPU usage
|
||||
will increase a lot. Therefore, if you can add more or faster CPU cores, you will be able to serve more users.
|
||||
|
||||
pretix-worker
|
||||
"""""""""""""
|
||||
|
||||
The ``pretix-worker`` process performs all operations that are not directly executed in the request-response-cycle of ``pretix-web``.
|
||||
Just like ``pretix-web`` you can easily start up as many instances as you want on different machines to share the work. As long as they
|
||||
all talk to the same redis server, they will all receive tasks from ``pretix-web``, work on them and post their result back.
|
||||
You can configure the number of threads that run tasks in parallel through the ``--concurrency`` command line option of ``celery``.
|
||||
|
||||
Just like ``pretix-web``, this process is mostly heavy on CPU, disk IO and network IO, although memory peaks can occur e.g. during the
|
||||
generation of large PDF files, so we recommend having some reserves here.
|
||||
|
||||
``pretix-worker`` performs a variety of tasks which are of different importance.
|
||||
Some of them are mission-critical and need to be run quickly even during high load (such as
|
||||
creating a cart or an order), others are irrelevant and can easily run later (such as
|
||||
distributing tickets on the waiting list). You can fine-tune the capacity you assign to each
|
||||
of these tasks by running ``pretix-worker`` processes that only work on a specific **queue**.
|
||||
For example, you could have three servers dedicated only to process order creations and one
|
||||
server dedicated only to sending emails. This allows you to set priorities and also protects
|
||||
you from e.g. a slow email server lowering your ticket throughput.
|
||||
|
||||
You can do so by specifying one or more queues on the ``celery`` command line of this process, such as ``celery -A pretix.celery_app worker -Q notifications,mail``. Currently,
|
||||
the following queues exist:
|
||||
|
||||
* ``checkout`` -- This queue handles everything related to carts and orders and thereby everything required to process a sale. This includes adding and deleting items from carts as well as creating and canceling orders.
|
||||
|
||||
* ``mail`` -- This queue handles sending of outgoing emails.
|
||||
|
||||
* ``notifications`` -- This queue handles the processing of any outgoing notifications, such as email notifications to admin users (except for the actual sending) or API notifications to registered webhooks.
|
||||
|
||||
* ``background`` -- This queue handles tasks that are expected to take long or have no human waiting for their result immediately, such as refreshing caches, re-generating CSS files, assigning tickets on the waiting list or parsing bank data files.
|
||||
|
||||
* ``default`` -- This queue handles everything else with "medium" or unassigned priority, most prominently the generation of files for tickets, invoices, badges, admin exports, etc.
|
||||
|
||||
Media files
|
||||
"""""""""""
|
||||
|
||||
Both ``pretix-web``, ``pretix-worker`` and in some cases your webserver need to work with
|
||||
media files. Media files are all files generated *at runtime* by the software. This can
|
||||
include files uploaded by the event organizers, such as the event logo, files uploaded by
|
||||
ticket buyers (if you use such features) or files generated by the software, such as
|
||||
ticket files, invoice PDFs, data exports or customized CSS files.
|
||||
|
||||
Those files are by default stored to the ``media/`` sub-folder of the data directory given
|
||||
in the ``pretix.cfg`` configuration file. Inside that ``media/`` folder, you will find a
|
||||
``pub/`` folder containing the subset of files that should be publicly accessible through
|
||||
the web server. Everything else only needs to be accessible by ``pretix-web`` and
|
||||
``pretix-worker`` themselves.
|
||||
|
||||
If you distribute ``pretix-web`` or ``pretix-worker`` across more than one machine, you
|
||||
**must** make sure that they all have access to a shared storage to read and write these
|
||||
files, otherwise you **will** run into errors with the user interface.
|
||||
|
||||
The easiest solution for this is probably to store them on a NFS server that you mount
|
||||
on each of the other servers.
|
||||
|
||||
Since we use Django's file storage mechanism internally, you can in theory also use a object-storage solution like Amazon S3, Ceph, or Minio to store these files, although we currently do not expose this through pretix' configuration file and this would require you to ship your own variant of ``pretix/settings.py`` and reference it through the ``DJANGO_SETTINGS_MODULE`` environment variable.
|
||||
|
||||
At pretix.eu, we use a custom-built `object storage cluster`_.
|
||||
|
||||
SQL database
|
||||
""""""""""""
|
||||
|
||||
One of the most critical parts of the whole setup is the SQL database -- and certainly the
|
||||
hardest to scale. Tuning relational databases is an art form, and while there's lots of
|
||||
material on it on the internet, there's not a single recipe that you can apply to every case.
|
||||
|
||||
As a general rule of thumb, the more resources you can give your databases, the better.
|
||||
Most databases will happily use all CPU cores available, but only use memory up to an amount
|
||||
you configure, so make sure to set this memory usage as high as you can afford. Having more
|
||||
memory available allows your database to make more use of caching, which is usually good.
|
||||
|
||||
Scaling your database to multiple machines needs to be treated with great caution. It's a
|
||||
good to have a replica of your database for availability reasons. In case your primary
|
||||
database server fails, you can easily switch over to the replica and continue working.
|
||||
|
||||
However, using database replicas for performance gains is much more complicated. When using
|
||||
replicated database systems, you are always trading in consistency or availability to get
|
||||
additional performance and the consequences of this can be subtle and it is important
|
||||
that you have a deep understanding of the semantics of your replication mechanism.
|
||||
|
||||
.. warning::
|
||||
|
||||
Using an off-the-shelf database proxy solution that redirects read queries to your
|
||||
replicas and write queries to your primary database **will lead to very nasty bugs.**
|
||||
|
||||
As an example, if you buy a ticket, pretix first needs to calculate how many tickets
|
||||
are left to sell. If this calculation is done on a database replica that lags behind
|
||||
even for fractions of a second, the decision to allow selling the ticket will be made
|
||||
on out-of-data data and you can end up with more tickets sold than configured. Similarly,
|
||||
you could imagine situations leading to double payments etc.
|
||||
|
||||
If you do have a replica, you *can* tell pretix about it :ref:`in your configuration <config-replica>`.
|
||||
This way, pretix can offload complex read-only queries to the replica when it is safe to do so.
|
||||
As of pretix 2.7, this is mainly used for search queries in the backend and for rendering the
|
||||
product list and event lists in the frontend, but we plan on expanding this in the future.
|
||||
|
||||
Therefore, for now our clear recommendation is: Try to scale your database vertically and put
|
||||
it on the most powerful machine you have available.
|
||||
|
||||
redis
|
||||
"""""
|
||||
|
||||
While redis is a very important part that glues together some of the components, it isn't used
|
||||
heavily and can usually handle a fairly large pretix installation easily on a single modern
|
||||
CPU core.
|
||||
Having some memory available is good in case of e.g. lots of tasks queuing up during a traffic peak, but we wouldn't expect ever needing more than a gigabyte of it.
|
||||
|
||||
Feel free to set up a redis cluster for availability – but you won't need it for performance in a long time.
|
||||
|
||||
The limitations
|
||||
---------------
|
||||
|
||||
Up to a certain point, pretix scales really well. However, there are a few things that we consider
|
||||
even more important than scalability, and those are correctness and reliability. We want you to be
|
||||
able to trust that pretix will not sell more tickets than you intended or run into similar error
|
||||
cases.
|
||||
|
||||
Combined with pretix' flexibility and complexity, especially around vouchers and quotas, this creates
|
||||
some hard issues. In many cases, we need to fall back to event-global locking for some actions which
|
||||
are likely to run with high concurrency and cause harm.
|
||||
|
||||
For every event, only one of these locking actions can be run at the same time. Examples for this are
|
||||
adding products limited by a quota to a cart, adding items to a cart using a voucher or placing an order
|
||||
consisting of cart positions that don't have a valid reservation for much longer. In these cases, it is
|
||||
currently not realistically possible to exceed selling **approx. 500 orders per minute per event**, even
|
||||
if you add more hardware.
|
||||
If you have an unlimited number of tickets, we can apply fewer locking and we've reached **approx.
|
||||
1500 orders per minute per event** in benchmarks, although even more should be possible.
|
||||
|
||||
We're working to reduce the number of cases in which this is relevant and thereby improve the possible
|
||||
throughput. If you want to use pretix for an event with 10,000+ tickets that are likely to be sold out
|
||||
within minutes, please get in touch to discuss possible solutions. We'll work something out for you!
|
||||
|
||||
|
||||
.. _object storage cluster: https://behind.pretix.eu/2018/03/20/high-available-cdn/
|
||||
@@ -1,9 +0,0 @@
|
||||
Authentication
|
||||
==============
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
tokenauth
|
||||
oauth
|
||||
deviceauth
|
||||
@@ -1,137 +0,0 @@
|
||||
.. _`rest-deviceauth`:
|
||||
|
||||
Device authentication
|
||||
=====================
|
||||
|
||||
Initializing a new device
|
||||
-------------------------
|
||||
|
||||
Users can create new devices in the "Device" section of their organizer settings. When creating
|
||||
a new device, users can specify a list of events the device is allowed to access. After a new
|
||||
device is created, users will be presented initialization instructions, consisting of an URL
|
||||
and an initialization token. They will also be shown as a QR code with the following contents::
|
||||
|
||||
{"handshake_version": 1, "url": "https://pretix.eu", "token": "kpp4jn8g2ynzonp6"}
|
||||
|
||||
Your application should be able to scan a QR code of this type, or allow to enter the URL and the
|
||||
initialization token manually. The handshake version is not used for manual initialization. When a
|
||||
QR code is scanned with a higher handshake version than you support, you should reject the request
|
||||
and prompt the user to update the client application.
|
||||
|
||||
After your application received the token, you need to call the initialization endpoint to obtain
|
||||
a proper API token. At this point, you need to identify the name and version of your application,
|
||||
as well as the type of underlying hardware. Example:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/device/initialize HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"token": "kpp4jn8g2ynzonp6",
|
||||
"hardware_brand": "Samsung",
|
||||
"hardware_model": "Galaxy S",
|
||||
"software_brand": "pretixdroid",
|
||||
"software_version": "4.0.0"
|
||||
}
|
||||
|
||||
Every initialization token can only be used once. On success, you will receive a response containing
|
||||
information on your device as well as your API token:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"organizer": "foo",
|
||||
"device_id": 5,
|
||||
"unique_serial": "HHZ9LW9JWP390VFZ",
|
||||
"api_token": "1kcsh572fonm3hawalrncam4l1gktr2rzx25a22l8g9hx108o9oi0rztpcvwnfnd",
|
||||
"name": "Bar"
|
||||
}
|
||||
|
||||
Please make sure that you store this ``api_token`` value. We also recommend storing your device ID, your assigned
|
||||
``unique_serial``, and the ``organizer`` you have access to, but that's up to you.
|
||||
|
||||
In case of an error, the response will look like this:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 400 Bad Request
|
||||
Content-Type: application/json
|
||||
|
||||
{"token":["This initialization token has already been used."]}
|
||||
|
||||
|
||||
Performing API requests
|
||||
-----------------------
|
||||
|
||||
You need to include the API token with every request to pretix' API in the ``Authorization`` header
|
||||
like the following:
|
||||
|
||||
.. sourcecode:: http
|
||||
:emphasize-lines: 3
|
||||
|
||||
GET /api/v1/organizers/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Authorization: Device 1kcsh572fonm3hawalrncam4l1gktr2rzx25a22l8g9hx108o9oi0rztpcvwnfnd
|
||||
|
||||
Updating the software version
|
||||
-----------------------------
|
||||
|
||||
If your application is updated, we ask you to tell the server about the new version in use. You can do this at the
|
||||
following endpoint:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/device/update HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Content-Type: application/json
|
||||
Authorization: Device 1kcsh572fonm3hawalrncam4l1gktr2rzx25a22l8g9hx108o9oi0rztpcvwnfnd
|
||||
|
||||
{
|
||||
"hardware_brand": "Samsung",
|
||||
"hardware_model": "Galaxy S",
|
||||
"software_brand": "pretixdroid",
|
||||
"software_version": "4.1.0"
|
||||
}
|
||||
|
||||
Creating a new API key
|
||||
----------------------
|
||||
|
||||
If you think your API key might have leaked or just want to be extra cautious, the API allows you to create a new key.
|
||||
The old API key will be invalid immediately. A request for a new key looks like this:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/device/roll HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Authorization: Device 1kcsh572fonm3hawalrncam4l1gktr2rzx25a22l8g9hx108o9oi0rztpcvwnfnd
|
||||
|
||||
The response will look like the response to the initialization request.
|
||||
|
||||
Removing a device
|
||||
-----------------
|
||||
|
||||
If you want implement a way to to deprovision a device in your software, you can call the ``revoke`` endpoint to
|
||||
invalidate your API key. There is no way to reverse this operation.
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/device/revoke HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Authorization: Device 1kcsh572fonm3hawalrncam4l1gktr2rzx25a22l8g9hx108o9oi0rztpcvwnfnd
|
||||
|
||||
This can also be done by the user through the web interface.
|
||||
|
||||
Permissions
|
||||
-----------
|
||||
|
||||
Device authentication is currently hardcoded to grant the following permissions:
|
||||
|
||||
* View event meta data and products etc.
|
||||
* View and change orders
|
||||
|
||||
Devices cannot change events or products and cannot access vouchers.
|
||||
@@ -1,217 +0,0 @@
|
||||
Basic concepts
|
||||
==============
|
||||
|
||||
This page describes basic concepts and definition that you need to know to interact
|
||||
with pretix' REST API, such as authentication, pagination and similar definitions.
|
||||
|
||||
.. _`rest-auth`:
|
||||
|
||||
Authentication
|
||||
--------------
|
||||
|
||||
To access the API, you need to present valid authentication credentials. pretix currently
|
||||
supports the following authorization schemes:
|
||||
|
||||
* :ref:`rest-tokenauth`: This is the simplest way and recommended for server-side applications
|
||||
that interact with pretix without user interaction.
|
||||
* :ref:`rest-oauth`: This is the recommended way to use if you write a third-party application
|
||||
that users can connect with their pretix account. It provides the best user experience, but
|
||||
requires user interaction and slightly more implementation effort.
|
||||
* :ref:`rest-deviceauth`: This is the recommended way if you build apps or hardware devices that can
|
||||
connect to pretix, e.g. for processing check-ins or to sell tickets offline. It provides a way
|
||||
to uniquely identify devices and allows for a quick configuration flow inside your software.
|
||||
* Authentication using browser sessions: This is used by the pretix web interface and it is *not*
|
||||
officially supported for use by third-party applications. It might change or be removed at any
|
||||
time without prior notice. If you use it, you need to comply with Django's `CSRF policies`_.
|
||||
|
||||
Permissions
|
||||
-----------
|
||||
|
||||
The API follows pretix team based permissions model. Each organizer can have several teams
|
||||
each with it's own set of permissions. Each team can have any number of API keys attached.
|
||||
|
||||
To access a given endpoint the team the API key belongs to needs to have the corresponding
|
||||
permission for the organizer/event being accessed.
|
||||
|
||||
Possible permissions are:
|
||||
|
||||
* Can create events
|
||||
* Can change event settings
|
||||
* Can change product settings
|
||||
* Can view orders
|
||||
* Can change orders
|
||||
* Can view vouchers
|
||||
* Can change vouchers
|
||||
|
||||
Compatibility
|
||||
-------------
|
||||
|
||||
We currently see pretix' API as a beta-stage feature. We therefore do not give any guarantees
|
||||
for compatibility between feature releases of pretix (such as 1.5 and 1.6). However, as always,
|
||||
we try not to break things when we don't need to. Any backwards-incompatible changes will be
|
||||
prominently noted in the release notes.
|
||||
|
||||
We treat the following types of changes as *backwards-compatible* so we ask you to make sure
|
||||
that your clients can deal with them properly:
|
||||
|
||||
* Support of new API endpoints
|
||||
* Support of new HTTP methods for a given API endpoint
|
||||
* Support of new query parameters for a given API endpoint
|
||||
* New fields contained in API responses
|
||||
|
||||
We treat the following types of changes as *backwards-incompatible*:
|
||||
|
||||
* Type changes of fields in API responses
|
||||
* New required input fields for an API endpoint
|
||||
* New required type for input fields of an API endpoint
|
||||
* Removal of endpoints, API methods or fields
|
||||
|
||||
Pagination
|
||||
----------
|
||||
|
||||
Most lists of objects returned by pretix' API will be paginated. The response will take
|
||||
the form of:
|
||||
|
||||
.. sourcecode:: javascript
|
||||
|
||||
{
|
||||
"count": 117,
|
||||
"next": "https://pretix.eu/api/v1/organizers/?page=2",
|
||||
"previous": null,
|
||||
"results": […],
|
||||
}
|
||||
|
||||
As you can see, the response contains the total number of results in the field ``count``.
|
||||
The fields ``next`` and ``previous`` contain links to the next and previous page of results,
|
||||
respectively, or ``null`` if there is no such page. You can use those URLs to retrieve the
|
||||
respective page.
|
||||
|
||||
The field ``results`` contains a list of objects representing the first results. For most
|
||||
objects, every page contains 50 results.
|
||||
|
||||
Conditional fetching
|
||||
--------------------
|
||||
|
||||
If you pull object lists from pretix' APIs regularly, we ask you to implement conditional fetching
|
||||
to avoid unnecessary data traffic. This is not supported on all resources and we currently implement
|
||||
two different mechanisms for different resources, which is necessary because we can only obtain best
|
||||
efficiency for resources that do not support deletion operations.
|
||||
|
||||
Object-level conditional fetching
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The :ref:`rest-orders` resource list contains an HTTP header called ``X-Page-Generated`` containing the
|
||||
current time on the server in ISO 8601 format. On your next request, you can pass this header
|
||||
(as is, without any modifications necessary) as the ``modified_since`` query parameter and you will receive
|
||||
a list containing only objects that have changed in the time since your last request.
|
||||
|
||||
List-level conditional fetching
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
If modification checks are not possible with this granularity, you can instead check for the full list.
|
||||
In this case, the list of objects may contain a regular HTTP header ``Last-Modified`` with the date of the
|
||||
last modification to any item of that resource. You can then pass this date back in your next request in the
|
||||
``If-Modified-Since`` header. If the any object has changed in the meantime, you will receive back a full list
|
||||
(if something it missing, this means the object has been deleted). If nothing happened, we'll send back a
|
||||
``304 Not Modified`` return code.
|
||||
|
||||
This is currently implemented on the following resources:
|
||||
|
||||
* :ref:`rest-categories`
|
||||
* :ref:`rest-items`
|
||||
* :ref:`rest-questions`
|
||||
* :ref:`rest-quotas`
|
||||
* :ref:`rest-subevents`
|
||||
* :ref:`rest-taxrules`
|
||||
|
||||
Errors
|
||||
------
|
||||
|
||||
Error responses (of type 400-499) are returned in one of the following forms, depending on
|
||||
the type of error. General errors look like:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 405 Method Not Allowed
|
||||
Content-Type: application/json
|
||||
Content-Length: 42
|
||||
|
||||
{"detail": "Method 'DELETE' not allowed."}
|
||||
|
||||
Field specific input errors include the name of the offending fields as keys in the response:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 400 Bad Request
|
||||
Content-Type: application/json
|
||||
Content-Length: 94
|
||||
|
||||
{"amount": ["A valid integer is required."], "description": ["This field may not be blank."]}
|
||||
|
||||
If you see errors of type ``429 Too Many Requests``, you should read our documentation on :ref:`rest-ratelimit`.
|
||||
|
||||
Data types
|
||||
----------
|
||||
|
||||
All structured API responses are returned in JSON format using standard JSON data types such
|
||||
as integers, floating point numbers, strings, lists, objects and booleans. Most fields can
|
||||
be ``null`` as well.
|
||||
|
||||
The following table shows some data types that have no native JSON representation and how
|
||||
we serialize them to JSON.
|
||||
|
||||
===================== ============================ ===================================
|
||||
Internal pretix type JSON representation Examples
|
||||
===================== ============================ ===================================
|
||||
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"}``
|
||||
Money String with decimal number ``"23.42"``
|
||||
Currency String with ISO 4217 code ``"EUR"``, ``"USD"``
|
||||
===================== ============================ ===================================
|
||||
|
||||
Query parameters
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
Most list endpoints allow a filtering of the results using query parameters. In this case, booleans should be passed
|
||||
as the string values ``true`` and ``false``.
|
||||
|
||||
If the ``ordering`` parameter is documented for a resource, you can use it to sort the result set by one of the allowed
|
||||
fields. Prepend a ``-`` to the field name to reverse the sort order.
|
||||
|
||||
|
||||
Idempotency
|
||||
-----------
|
||||
|
||||
Our API supports an idempotency mechanism to make sure you can safely retry operations without accidentally performing
|
||||
them twice. This is useful if an API call experiences interruptions in transit, e.g. due to a network failure, and you
|
||||
do not know if it completed successfully.
|
||||
|
||||
To perform an idempotent request, add a ``X-Idempotency-Key`` header with a random string value (we recommend a version
|
||||
4 UUID) to your request. If we see a second request with the same ``X-Idempotency-Key`` and the same ``Authorization``
|
||||
and ``Cookie`` headers, we will not perform the action for a second time but return the exact same response instead.
|
||||
|
||||
Please note that this also goes for most error responses. For example, if we returned you a ``403 Permission Denied``
|
||||
error and you retry with the same ``X-Idempotency-Key``, you will get the same error again, even if you were granted
|
||||
permission in the meantime! This includes internal server errors on our side that might have been fixed in the meantime.
|
||||
|
||||
There are only three exceptions to the rule:
|
||||
|
||||
* Responses with status code ``409 Conflict`` are not cached. If you send the request again, it will be executed as a
|
||||
new request, since these responses are intended to be retried.
|
||||
|
||||
* Rate-limited responses with status code ``429 Too Many Requests`` are not cached and you can safely retry them.
|
||||
|
||||
* Responses with status code ``503 Service Unavailable`` are not cached and you can safely retry them.
|
||||
|
||||
If you send a request with an ``X-Idempotency-Key`` header that we have seen before but that has not yet received a
|
||||
response, you will receive a response with status code ``409 Conflict`` and are asked to retry after five seconds.
|
||||
|
||||
We store idempotency keys for 24 hours, so you should never retry a request after a longer time period.
|
||||
|
||||
All ``POST``, ``PUT``, ``PATCH``, or ``DELETE`` api calls support idempotency keys. Adding an idempotency key to a
|
||||
``GET``, ``HEAD``, or ``OPTIONS`` request has no effect.
|
||||
|
||||
.. _CSRF policies: https://docs.djangoproject.com/en/1.11/ref/csrf/#ajax
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 9.6 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 20 KiB |
@@ -1,20 +0,0 @@
|
||||
.. _`rest-api`:
|
||||
|
||||
REST API
|
||||
========
|
||||
|
||||
This part of the documentation contains information about the REST-style API
|
||||
exposed by pretix since version 1.5 that can be used by third-party programs
|
||||
to interact with pretix and its data structures.
|
||||
|
||||
Currently, the API provides mostly read-only capabilities, but it will be extended
|
||||
in functionality over time.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
fundamentals
|
||||
auth
|
||||
resources/index
|
||||
ratelimit
|
||||
webhooks
|
||||
@@ -1,207 +0,0 @@
|
||||
.. _`rest-oauth`:
|
||||
|
||||
OAuth authentication / "Connect with pretix"
|
||||
============================================
|
||||
|
||||
In addition to static tokens, pretix supports `OAuth2`_-based authentication starting with
|
||||
pretix 1.16. This allows you to put a "Connect with pretix" button into your website or tool
|
||||
that allows the user to easily set up a connection between the two systems.
|
||||
|
||||
If you haven't worked with OAuth before, have a look at the `OAuth2 Simplified`_ tutorial.
|
||||
|
||||
Registering an application
|
||||
--------------------------
|
||||
|
||||
To use OAuth, you need to register your application with the pretix instance you want to connect to.
|
||||
In order to do this, log in to your pretix account and go to your user settings. Click on "Authorized applications"
|
||||
first and then on "Manage your own apps". From there, you can "Create a new application".
|
||||
|
||||
You should fill in a descriptive name of your application that allows users to recognize who you are. You also need to
|
||||
give a list of fully-qualified URLs that users will be redirected to after a successful authorization. After you pressed
|
||||
"Save", you will be presented with a client ID and a client secret. Please note them down and treat the client secret
|
||||
like a password; it should not become available to your users.
|
||||
|
||||
Obtaining an authorization grant
|
||||
--------------------------------
|
||||
|
||||
To authorize a new user, link or redirect them to the ``authorize`` endpoint, passing your client ID as a query
|
||||
parameter. Additionally, you can pass a scope (currently either ``read``, ``write``, or ``read write``)
|
||||
and an URL the user should be redirected to after successful or failed authorization. You also need to pass the
|
||||
``response_type`` parameter with a value of ``code``. Example::
|
||||
|
||||
https://pretix.eu/api/v1/oauth/authorize?client_id=lsLi0hNL0vk53mEdYjNJxHUn1PcO1R6wVg81dLNT&response_type=code&scope=read+write&redirect_uri=https://pretalx.com
|
||||
|
||||
To prevent CSRF attacks, you can also optionally pass a ``state`` parameter with a random string. Later, when
|
||||
redirecting back to your application, we will pass the same ``state`` parameter back to you, so you can compare if they
|
||||
match.
|
||||
|
||||
After the user granted or denied access, they will be redirected back either to the ``redirect_url`` you passed in the
|
||||
query or to the first redirect URL configured in your application settings.
|
||||
|
||||
On successful registration, we will append the query parameter ``code`` to the URL containing an authorization code.
|
||||
For example, we might redirect the user to this URL::
|
||||
|
||||
https://pretalx.com/?code=eYBBf8gmeD4E01HLoj0XflqO4Lg3Cw&state=e3KCh9mfx07qxU4bRpXk
|
||||
|
||||
You will need this ``code`` parameter to perform the next step.
|
||||
|
||||
On a failed registration, a query string like ``?error=access_denied`` will be appended to the redirection URL.
|
||||
|
||||
.. note:: In this step, the user is allowed to restrict your access to certain organizer accounts. If you try to
|
||||
re-authenticate the user later, the user might be instantly redirected back to you if authorization is already
|
||||
given and would therefore be unable to review their organizer restriction settings. You can append the
|
||||
``approval_prompt=force`` query parameter if you want to make sure the user actively needs to confirm the
|
||||
authorization.
|
||||
|
||||
Getting an access token
|
||||
-----------------------
|
||||
|
||||
Using the ``code`` value you obtained above and your client ID, you can now request an access token that actually gives
|
||||
access to the API. The ``token`` endpoint expects you to authenticate using `HTTP Basic authentication`_ using your client
|
||||
ID as a username and your client secret as a password. You are also required to again supply the same ``redirect_uri``
|
||||
parameter that you used for the authorization.
|
||||
|
||||
.. http:get:: /api/v1/oauth/token
|
||||
|
||||
Request a new access token
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/oauth/token HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Authorization: Basic bHNMaTBoTkwwdms1M21FZFlqTkp4SFVuMVBjTzFSNndWZzgxZExOVDplSmpzZVA0UjJMN0hMcjBiS0p1b3BmbnJtT2cyY3NDeTdYaFVVZ0FoalhUU0NhZHhRTjk3cVNvMkpPaXlWTFpQOEozaTVQd1FVdFIwNUNycG5ac2Z0bXJjdmNTbkZ1SkFmb2ZsUTdZUDRpSjZNTWFYTHIwQ0FpNlhIRFJjV1Awcg==
|
||||
|
||||
grant_type=authorization_code&code=eYBBf8gmeD4E01HLoj0XflqO4Lg3Cw&redirect_uri=https://pretalx.com
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"access_token": "i3ytqTSRWsKp16fqjekHXa4tdM4qNC",
|
||||
"expires_in": 86400,
|
||||
"token_type": "Bearer",
|
||||
"scope": "read write",
|
||||
"refresh_token": "XBK0r8z4A4TTeR9LyMUyU2AM5rqpXp"
|
||||
}
|
||||
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
|
||||
|
||||
As you can see, you receive two types of tokens: One "access token", and one "refresh token". The access token is valid
|
||||
for a day and can be used to actually access the API. The refresh token does not have an expiration date and can be used
|
||||
to obtain a new access_token after a day, so you should make sure to store the access token safely if you need long-term
|
||||
access.
|
||||
|
||||
Using the API with an access token
|
||||
----------------------------------
|
||||
|
||||
You can supply a valid access token as a ``Bearer``-type token in the ``Authorization`` header to get API access.
|
||||
|
||||
.. sourcecode:: http
|
||||
:emphasize-lines: 3
|
||||
|
||||
GET /api/v1/organizers/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Authorization: Bearer i3ytqTSRWsKp16fqjekHXa4tdM4qNC
|
||||
|
||||
Refreshing an access token
|
||||
--------------------------
|
||||
|
||||
You can obtain a new access token using your refresh token any time. This can be done using the same ``token`` endpoint
|
||||
used to obtain the first access token above, but with a different set of parameters:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/oauth/token HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Authorization: Basic bHNMaTBoTkwwdms1M21FZFlqTkp4SFVuMVBjTzFSNndWZzgxZExOVDplSmpzZVA0UjJMN0hMcjBiS0p1b3BmbnJtT2cyY3NDeTdYaFVVZ0FoalhUU0NhZHhRTjk3cVNvMkpPaXlWTFpQOEozaTVQd1FVdFIwNUNycG5ac2Z0bXJjdmNTbkZ1SkFmb2ZsUTdZUDRpSjZNTWFYTHIwQ0FpNlhIRFJjV1Awcg==
|
||||
|
||||
grant_type=refresh_token&refresh_token=XBK0r8z4A4TTeR9LyMUyU2AM5rqpXp
|
||||
|
||||
The previous access token will instantly become invalid.
|
||||
|
||||
Revoking a token
|
||||
----------------
|
||||
|
||||
If you don't need a token any more or if you believe it may have been compromised, you can use the ``revoke_token``
|
||||
endpoint to revoke it.
|
||||
|
||||
.. http:get:: /api/v1/oauth/revoke_token
|
||||
|
||||
Revoke an access or refresh token. If you revoke an access token, you can still create a new one using the refresh token. If you
|
||||
revoke a refresh token, the connected access token will also be revoked.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/oauth/revoke_token HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Authorization: Basic bHNMaTBoTkwwdms1M21FZFlqTkp4SFVuMVBjTzFSNndWZzgxZExOVDplSmpzZVA0UjJMN0hMcjBiS0p1b3BmbnJtT2cyY3NDeTdYaFVVZ0FoalhUU0NhZHhRTjk3cVNvMkpPaXlWTFpQOEozaTVQd1FVdFIwNUNycG5ac2Z0bXJjdmNTbkZ1SkFmb2ZsUTdZUDRpSjZNTWFYTHIwQ0FpNlhIRFJjV1Awcg==
|
||||
|
||||
token=XBK0r8z4A4TTeR9LyMUyU2AM5rqpXp
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
|
||||
If you want to revoke your client secret, you can generate a new one in the list of your managed applications in the
|
||||
pretix user interface.
|
||||
|
||||
Fetching the user profile
|
||||
-------------------------
|
||||
|
||||
If you need the user's meta data, you can fetch it here:
|
||||
|
||||
.. http:get:: /api/v1/me
|
||||
|
||||
Returns the profile of the authenticated user
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/me HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Authorization: Bearer i3ytqTSRWsKp16fqjekHXa4tdM4qNC
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
email: "admin@localhost",
|
||||
fullname: "John Doe",
|
||||
locale: "de",
|
||||
timezone: "Europe/Berlin"
|
||||
}
|
||||
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
|
||||
.. _OAuth2: https://en.wikipedia.org/wiki/OAuth
|
||||
.. _OAuth2 Simplified: https://aaronparecki.com/oauth-2-simplified/
|
||||
.. _HTTP Basic authentication: https://en.wikipedia.org/wiki/Basic_access_authentication
|
||||
@@ -1,31 +0,0 @@
|
||||
.. _`rest-ratelimit`:
|
||||
|
||||
Rate limiting
|
||||
=============
|
||||
|
||||
.. note:: This page only applies to the pretix Hosted service at pretix.eu. APIs of custom pretix installations do not
|
||||
enforce any rate limiting by default.
|
||||
|
||||
All authenticated requests to pretix' API are rate limited. If you exceed the limits, you will receive a response
|
||||
with HTTP status code ``429 Too Many Requests``. This response will have a ``Retry-After`` header, containing the number
|
||||
of seconds you are supposed to wait until you try again. We expect that all API clients respect this. If you continue
|
||||
to burst requests after a ``429`` status code, we might get in touch with you or, in extreme cases, disable your API
|
||||
access.
|
||||
|
||||
Currently, the following rate limits apply:
|
||||
|
||||
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== =================================================================================
|
||||
Authentication method Rate limit
|
||||
===================================== =================================================================================
|
||||
:ref:`rest-deviceauth` 360 requests per minute per device
|
||||
:ref:`rest-tokenauth` 360 requests per minute per organizer account
|
||||
:ref:`rest-oauth` 360 requests per minute per combination of accessed organizer and OAuth application
|
||||
Session authentication *Not an officially supported authentication method for external access*
|
||||
===================================== =================================================================================
|
||||
|
||||
If you require a higher rate limit, please get in touch at support@pretix.eu and tell us about your use case, we are
|
||||
sure we can work something out.
|
||||
@@ -1,131 +0,0 @@
|
||||
pretix Hosted billing invoices
|
||||
==============================
|
||||
|
||||
This endpoint allows you to access invoices you received for pretix Hosted. It only contains invoices created starting
|
||||
November 2017.
|
||||
|
||||
.. note:: Only available on pretix Hosted, not on self-hosted pretix instances.
|
||||
|
||||
Resource description
|
||||
--------------------
|
||||
|
||||
The resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
invoice_number string Invoice number
|
||||
date_issued date Invoice date
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/billing_invoices/
|
||||
|
||||
Returns a list of all invoices to a given organizer.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/billing_invoices/ 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": [
|
||||
{
|
||||
"invoice_number": "R2019002",
|
||||
"date_issued": "2019-06-03"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
: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 ``date_issued`` and
|
||||
its reverse, ``-date_issued``. Default: ``date_issued``.
|
||||
:param organizer: The ``slug`` field of the organizer 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)/billing_invoices/(invoice_number)/
|
||||
|
||||
Returns information on one invoice, identified by its invoice number.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/billing_invoices/R2019002/ 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
|
||||
|
||||
{
|
||||
"invoice_number": "R2019002",
|
||||
"date_issued": "2019-06-03"
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param invoice_number: The ``invoice_number`` field of the invoice 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)/billing_invoices/(invoice_number)/download/
|
||||
|
||||
Download an invoice in PDF format.
|
||||
|
||||
.. warning:: After we created the invoices, they are placed in review with our accounting department. You will
|
||||
already see them in the API at this point, but you are not able to download them until they completed
|
||||
review and are sent to you via email. This usually takes a few hours. If you try to download them
|
||||
in this time frame, you will receive a status code :http:statuscode:`423`.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/billing_invoices/R2019002/download/ 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/pdf
|
||||
|
||||
...
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param invoice_number: The ``invoice_number`` field of the invoice 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.
|
||||
:statuscode 423: The file is not yet ready and will now be prepared. Retry the request after waiting for a few
|
||||
seconds.
|
||||
@@ -1,275 +0,0 @@
|
||||
.. _rest-carts:
|
||||
|
||||
Cart positions
|
||||
==============
|
||||
|
||||
The API provides limited access to the cart position data model. This API currently only allows creating and deleting
|
||||
cart positions to reserve quota.
|
||||
|
||||
Cart position resource
|
||||
----------------------
|
||||
|
||||
The cart position resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Internal ID of the cart position
|
||||
cart_id string Identifier of the cart this belongs to. Needs to end
|
||||
in "@api" for API-created positions.
|
||||
datetime datetime Time of creation
|
||||
expires datetime The cart position will expire at this time and no longer block quota
|
||||
item integer ID of the item
|
||||
variation integer ID of the variation (or ``null``)
|
||||
price money (string) Price of this position
|
||||
attendee_name string Specified attendee name for this position (or ``null``)
|
||||
attendee_name_parts object of strings Composition of attendee name (i.e. first name, last name, …)
|
||||
attendee_email string Specified attendee email address for this position (or ``null``)
|
||||
voucher integer Internal ID of the voucher used for this position (or ``null``)
|
||||
addon_to integer Internal ID of the position this position is an add-on for (or ``null``)
|
||||
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
|
||||
├ 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
|
||||
seat objects The assigned seat. Can be ``null``.
|
||||
├ id integer Internal ID of the seat instance
|
||||
├ name string Human-readable seat name
|
||||
└ seat_guid string Identifier of the seat within the seating plan
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
.. versionchanged:: 1.17
|
||||
|
||||
This resource has been added.
|
||||
|
||||
.. versionchanged:: 3.0
|
||||
|
||||
This ``seat`` attribute has been added.
|
||||
|
||||
|
||||
Cart position endpoints
|
||||
-----------------------
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/cartpositions/
|
||||
|
||||
Returns a list of API-created cart positions.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/cartpositions/ 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
|
||||
X-Page-Generated: 2017-12-01T10:00:00Z
|
||||
|
||||
{
|
||||
"count": 1,
|
||||
"next": null,
|
||||
"previous": null,
|
||||
"results": [
|
||||
{
|
||||
"id": 1,
|
||||
"cart_id": "XwokV8FojQviD9jhtDzKvHFdlLRNMhlfo3cNjGbuK6MUTQDT@api",
|
||||
"item": 1,
|
||||
"variation": null,
|
||||
"price": "23.00",
|
||||
"attendee_name": null,
|
||||
"attendee_name_parts": {},
|
||||
"attendee_email": null,
|
||||
"voucher": null,
|
||||
"addon_to": null,
|
||||
"subevent": null,
|
||||
"datetime": "2018-06-11T10:00:00Z",
|
||||
"expires": "2018-06-11T10:00:00Z",
|
||||
"includes_tax": true,
|
||||
"seat": null,
|
||||
"answers": []
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
: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)/cartpositions/(id)/
|
||||
|
||||
Returns information on one cart position, identified by its internal ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/cartpositions/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,
|
||||
"cart_id": "XwokV8FojQviD9jhtDzKvHFdlLRNMhlfo3cNjGbuK6MUTQDT@api",
|
||||
"item": 1,
|
||||
"variation": null,
|
||||
"price": "23.00",
|
||||
"attendee_name": null,
|
||||
"attendee_name_parts": {},
|
||||
"attendee_email": null,
|
||||
"voucher": null,
|
||||
"addon_to": null,
|
||||
"subevent": null,
|
||||
"datetime": "2018-06-11T10:00:00Z",
|
||||
"expires": "2018-06-11T10:00:00Z",
|
||||
"includes_tax": true,
|
||||
"seat": null,
|
||||
"answers": []
|
||||
}
|
||||
|
||||
: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 position 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.
|
||||
:statuscode 404: The requested cart position does not exist.
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/cartpositions/
|
||||
|
||||
Creates a new cart position.
|
||||
|
||||
.. warning:: This endpoint is considered **experimental**. It might change at any time without prior notice.
|
||||
|
||||
.. warning::
|
||||
|
||||
This endpoint is intended for advanced users. It is not designed to be used to build your own shop frontend.
|
||||
There is a lot that it does not or can not do, and you will need to be careful using it.
|
||||
It allows to bypass many of the restrictions imposed when creating a cart through the
|
||||
regular shop.
|
||||
|
||||
Specifically, this endpoint currently
|
||||
|
||||
* does not validate if products are only to be sold in a specific time frame
|
||||
|
||||
* does not validate if the event's ticket sales are already over or haven't started
|
||||
|
||||
* does not support add-on products at the moment
|
||||
|
||||
* does not check or calculate prices but believes any prices you send
|
||||
|
||||
* does not support the redemption of vouchers
|
||||
|
||||
* does not prevent you from buying items that can only be bought with a voucher
|
||||
|
||||
* does not support file upload questions
|
||||
|
||||
You can supply the following fields of the resource:
|
||||
|
||||
* ``cart_id`` (optional, needs to end in ``@api``)
|
||||
* ``item``
|
||||
* ``variation`` (optional)
|
||||
* ``price``
|
||||
* ``seat`` (The ``seat_guid`` attribute of a seat. Required when the specified ``item`` requires a seat, otherwise must be ``null``.)
|
||||
* ``attendee_name`` **or** ``attendee_name_parts`` (optional)
|
||||
* ``attendee_email`` (optional)
|
||||
* ``subevent`` (optional)
|
||||
* ``expires`` (optional)
|
||||
* ``includes_tax`` (optional)
|
||||
* ``answers``
|
||||
|
||||
* ``question``
|
||||
* ``answer``
|
||||
* ``options``
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/cartpositions/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"item": 1,
|
||||
"variation": null,
|
||||
"price": "23.00",
|
||||
"attendee_name_parts": {
|
||||
"given_name": "Peter",
|
||||
"family_name": "Miller"
|
||||
},
|
||||
"attendee_email": null,
|
||||
"answers": [
|
||||
{
|
||||
"question": 1,
|
||||
"answer": "23",
|
||||
"options": []
|
||||
}
|
||||
],
|
||||
"subevent": null
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
(Full cart position resource, see above.)
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer of the event to create a position for
|
||||
:param event: The ``slug`` field of the event to create a position for
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The item could not be created due to invalid submitted data or lack of quota.
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to create this
|
||||
order.
|
||||
|
||||
.. http:delete:: /api/v1/organizers/(organizer)/events/(event)/cartpositions/(id)/
|
||||
|
||||
Deletes a cart position, identified by its internal ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/events/sampleconf/cartpositions/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 204 No Content
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
: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 position to delete
|
||||
: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.
|
||||
:statuscode 404: The requested cart position does not exist.
|
||||
@@ -1,239 +0,0 @@
|
||||
.. _`rest-categories`:
|
||||
|
||||
Item categories
|
||||
===============
|
||||
|
||||
Resource description
|
||||
--------------------
|
||||
|
||||
Categories provide grouping for items (better known as products).
|
||||
The category resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Internal ID of the category
|
||||
name multi-lingual string The category's visible name
|
||||
internal_name string An optional name that is only used in the backend
|
||||
description multi-lingual string A public description (might include markdown, can
|
||||
be ``null``)
|
||||
position integer An integer, used for sorting the categories
|
||||
is_addon boolean If ``true``, items within this category are not on sale
|
||||
on their own but the category provides a source for
|
||||
defining add-ons for other products.
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
.. versionchanged:: 1.14
|
||||
|
||||
The operations POST, PATCH, PUT and DELETE have been added.
|
||||
|
||||
.. versionchanged:: 1.16
|
||||
|
||||
The field ``internal_name`` has been added.
|
||||
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/categories/
|
||||
|
||||
Returns a list of all categories within a given event.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/categories/ 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,
|
||||
"name": {"en": "Tickets"},
|
||||
"internal_name": "",
|
||||
"description": {"en": "Tickets are what you need to get in."},
|
||||
"position": 1,
|
||||
"is_addon": false
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
:query boolean is_addon: If set to ``true`` or ``false``, only categories with this value for the field ``is_addon`` will be
|
||||
returned.
|
||||
:query string ordering: Manually set the ordering of results. Valid fields to be used are ``id`` and ``position``.
|
||||
Default: ``position``
|
||||
: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)/categories/(id)/
|
||||
|
||||
Returns information on one category, identified by its ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/categories/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,
|
||||
"name": {"en": "Tickets"},
|
||||
"internal_name": "",
|
||||
"description": {"en": "Tickets are what you need to get in."},
|
||||
"position": 1,
|
||||
"is_addon": false
|
||||
}
|
||||
|
||||
: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 category 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)/categories/
|
||||
|
||||
Creates a new category
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/categories/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": {"en": "Tickets"},
|
||||
"internal_name": "",
|
||||
"description": {"en": "Tickets are what you need to get in."},
|
||||
"position": 1,
|
||||
"is_addon": false
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"name": {"en": "Tickets"},
|
||||
"internal_name": "",
|
||||
"description": {"en": "Tickets are what you need to get in."},
|
||||
"position": 1,
|
||||
"is_addon": false
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer of the event to create a category for
|
||||
:param event: The ``slug`` field of the event to create a category for
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The category 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)/categories/(id)/
|
||||
|
||||
Update a category. 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/categories/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 94
|
||||
|
||||
{
|
||||
"is_addon": true
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"name": {"en": "Tickets"},
|
||||
"internal_name": "",
|
||||
"description": {"en": "Tickets are what you need to get in."},
|
||||
"position": 1,
|
||||
"is_addon": true
|
||||
}
|
||||
|
||||
: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 category to modify
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The category 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)/category/(id)/
|
||||
|
||||
Delete a category.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/events/sampleconf/categories/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 category 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.
|
||||
@@ -1,679 +0,0 @@
|
||||
Check-in lists
|
||||
==============
|
||||
|
||||
Resource description
|
||||
--------------------
|
||||
|
||||
You can create check-in lists that you can use e.g. at the entrance of your event to track who is coming and if they
|
||||
actually bought a ticket.
|
||||
|
||||
You can create multiple check-in lists to separate multiple parts of your event, for example if you have separate
|
||||
entries for multiple ticket types. Different check-in lists are completely independent: If a ticket shows up on two
|
||||
lists, it is valid once on every list. This might be useful if you run a festival with festival passes that allow
|
||||
access to every or multiple performances as well as tickets only valid for single performances.
|
||||
|
||||
The check-in list resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Internal ID of the check-in list
|
||||
name string The internal name of the check-in list
|
||||
all_products boolean If ``true``, the check-in lists contains tickets of all products in this event. The ``limit_products`` field is ignored in this case.
|
||||
limit_products list of integers List of item IDs to include in this list.
|
||||
subevent integer ID of the date inside an event series this list belongs to (or ``null``).
|
||||
position_count integer Number of tickets that match this list (read-only).
|
||||
checkin_count integer Number of check-ins performed on this list (read-only).
|
||||
include_pending boolean If ``true``, the check-in list also contains tickets from orders in pending state.
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
.. versionchanged:: 1.10
|
||||
|
||||
This resource has been added.
|
||||
|
||||
.. versionchanged:: 1.11
|
||||
|
||||
The ``positions`` endpoints have been added.
|
||||
|
||||
.. versionchanged:: 1.13
|
||||
|
||||
The ``include_pending`` field has been added.
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
.. versionchanged:: 1.15
|
||||
|
||||
The ``../status/`` detail endpoint has been added.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/checkinlists/
|
||||
|
||||
Returns a list of all check-in lists within a given event.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/checkinlists/ 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,
|
||||
"name": "Default list",
|
||||
"checkin_count": 123,
|
||||
"position_count": 456,
|
||||
"all_products": true,
|
||||
"limit_products": [],
|
||||
"include_pending": false,
|
||||
"subevent": null
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
:query integer subevent: Only return check-in lists of the sub-event with the given ID
|
||||
: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)/checkinlists/(id)/
|
||||
|
||||
Returns information on one check-in list, identified by its ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/checkinlists/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,
|
||||
"name": "Default list",
|
||||
"checkin_count": 123,
|
||||
"position_count": 456,
|
||||
"all_products": true,
|
||||
"limit_products": [],
|
||||
"include_pending": false,
|
||||
"subevent": null
|
||||
}
|
||||
|
||||
: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 check-in list 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)/checkinlists/(id)/status/
|
||||
|
||||
Returns detailed status information on a check-in list, identified by its ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/checkinlists/1/status/ 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
|
||||
|
||||
{
|
||||
"checkin_count": 17,
|
||||
"position_count": 42,
|
||||
"event": {
|
||||
"name": "Demo Conference"
|
||||
},
|
||||
"items": [
|
||||
{
|
||||
"name": "T-Shirt",
|
||||
"id": 1,
|
||||
"checkin_count": 1,
|
||||
"admission": false,
|
||||
"position_count": 1,
|
||||
"variations": [
|
||||
{
|
||||
"value": "Red",
|
||||
"id": 1,
|
||||
"checkin_count": 1,
|
||||
"position_count": 12
|
||||
},
|
||||
{
|
||||
"value": "Blue",
|
||||
"id": 2,
|
||||
"checkin_count": 4,
|
||||
"position_count": 8
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Ticket",
|
||||
"id": 2,
|
||||
"checkin_count": 15,
|
||||
"admission": true,
|
||||
"position_count": 22,
|
||||
"variations": []
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
: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 check-in list 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)/checkinlists/
|
||||
|
||||
Creates a new check-in list.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/checkinlists/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": "VIP entry",
|
||||
"all_products": false,
|
||||
"limit_products": [1, 2],
|
||||
"subevent": null
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 2,
|
||||
"name": "VIP entry",
|
||||
"checkin_count": 0,
|
||||
"position_count": 0,
|
||||
"all_products": false,
|
||||
"limit_products": [1, 2],
|
||||
"include_pending": false,
|
||||
"subevent": null
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer of the event/item to create a list for
|
||||
:param event: The ``slug`` field of the event to create a list for
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The list 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)/checkinlists/(id)/
|
||||
|
||||
Update a check-in list. 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 and the ``checkin_count`` and ``position_count``
|
||||
fields.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
PATCH /api/v1/organizers/bigevents/events/sampleconf/checkinlists/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 94
|
||||
|
||||
{
|
||||
"name": "Backstage",
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Backstage",
|
||||
"checkin_count": 23,
|
||||
"position_count": 42,
|
||||
"all_products": false,
|
||||
"limit_products": [1, 2],
|
||||
"include_pending": false,
|
||||
"subevent": null
|
||||
}
|
||||
|
||||
: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 list to modify
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The list 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)/checkinlist/(id)/
|
||||
|
||||
Delete a check-in list. Note that this also deletes the information on all check-ins performed via this list.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/events/sampleconf/checkinlist/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 check-in list 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.
|
||||
|
||||
|
||||
Order position endpoints
|
||||
------------------------
|
||||
|
||||
.. versionchanged:: 1.15
|
||||
|
||||
The order positions endpoint has been extended by the filter queries ``item__in``, ``variation__in``,
|
||||
``order__status__in``, ``subevent__in``, ``addon_to__in``, and ``search``. The search for attendee names and order
|
||||
codes is now case-insensitive.
|
||||
|
||||
The ``.../redeem/`` endpoint has been added.
|
||||
|
||||
.. versionchanged:: 2.0
|
||||
|
||||
The order positions endpoint has been extended by the filter queries ``voucher`` and ``voucher__code``.
|
||||
|
||||
.. versionchanged:: 2.7
|
||||
|
||||
The resource now contains the new attributes ``require_attention`` and ``order__status`` and accepts the new
|
||||
``ignore_status`` filter. The ``attendee_name`` field is now "smart" (see below) and the redemption endpoint
|
||||
returns ``400`` instead of ``404`` on tickets which are known but not paid.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/checkinlists/(list)/positions/
|
||||
|
||||
Returns a list of all order positions within a given event. The result is the same as
|
||||
the :ref:`order-position-resource`, with the following differences:
|
||||
|
||||
* The ``checkins`` value will only include check-ins for the selected list.
|
||||
|
||||
* An additional boolean property ``require_attention`` will inform you whether either the order or the item
|
||||
have the ``checkin_attention`` flag set.
|
||||
|
||||
* If ``attendee_name`` is empty, it will automatically fall back to values from a parent product or from invoice
|
||||
addresses.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/checkinlists/1/positions/ 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": 23442,
|
||||
"order": "ABC12",
|
||||
"positionid": 1,
|
||||
"item": 1345,
|
||||
"variation": null,
|
||||
"price": "23.00",
|
||||
"attendee_name": "Peter",
|
||||
"attendee_name_parts": {
|
||||
"full_name": "Peter",
|
||||
},
|
||||
"attendee_email": null,
|
||||
"voucher": null,
|
||||
"tax_rate": "0.00",
|
||||
"tax_rule": null,
|
||||
"tax_value": "0.00",
|
||||
"secret": "z3fsn8jyufm5kpk768q69gkbyr5f4h6w",
|
||||
"addon_to": null,
|
||||
"subevent": null,
|
||||
"pseudonymization_id": "MQLJvANO3B",
|
||||
"seat": null,
|
||||
"checkins": [
|
||||
{
|
||||
"list": 1,
|
||||
"datetime": "2017-12-25T12:45:23Z"
|
||||
}
|
||||
],
|
||||
"answers": [
|
||||
{
|
||||
"question": 12,
|
||||
"answer": "Foo",
|
||||
"options": []
|
||||
}
|
||||
],
|
||||
"downloads": [
|
||||
{
|
||||
"output": "pdf",
|
||||
"url": "https://pretix.eu/api/v1/organizers/bigevents/events/sampleconf/orderpositions/23442/download/pdf/"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
:query string ignore_status: If set to ``true``, results will be returned regardless of the state of
|
||||
the order they belong to and you will need to do your own filtering by order status.
|
||||
:query string ordering: Manually set the ordering of results. Valid fields to be used are ``order__code``,
|
||||
``order__datetime``, ``positionid``, ``attendee_name``, ``last_checked_in`` and ``order__email``. Default:
|
||||
``attendee_name,positionid``
|
||||
:query string order: Only return positions of the order with the given order code
|
||||
:query string search: Fuzzy search matching the attendee name, order code, invoice address name as well as to the beginning of the secret.
|
||||
:query integer item: Only return positions with the purchased item matching the given ID.
|
||||
:query integer item__in: Only return positions with the purchased item matching one of the given comma-separated IDs.
|
||||
:query integer variation: Only return positions with the purchased item variation matching the given ID.
|
||||
:query integer variation__in: Only return positions with one of the purchased item variation matching the given
|
||||
comma-separated IDs.
|
||||
:query string attendee_name: Only return positions with the given value in the attendee_name field. Also, add-on
|
||||
products positions are shown if they refer to an attendee with the given name.
|
||||
:query string secret: Only return positions with the given ticket secret.
|
||||
:query string order__status: Only return positions with the given order status.
|
||||
:query string order__status__in: Only return positions with one the given comma-separated order status.
|
||||
:query boolean has_checkin: If set to ``true`` or ``false``, only return positions that have or have not been
|
||||
checked in already.
|
||||
:query integer subevent: Only return positions of the sub-event with the given ID
|
||||
:query integer subevent__in: Only return positions of one of the sub-events with the given comma-separated IDs
|
||||
:query integer addon_to: Only return positions that are add-ons to the position with the given ID.
|
||||
:query integer addon_to__in: Only return positions that are add-ons to one of the positions with the given
|
||||
comma-separated IDs.
|
||||
:query string voucher: Only return positions with a specific voucher.
|
||||
:query string voucher__code: Only return positions with a specific voucher code.
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:param list: The ID of the check-in list to look for
|
||||
: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.
|
||||
:statuscode 404: The requested check-in list does not exist.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/checkinlists/(list)/positions/(id)/
|
||||
|
||||
Returns information on one order position, identified by its internal ID.
|
||||
The result is the same as the :ref:`order-position-resource`, with the following differences:
|
||||
|
||||
* The ``checkins`` value will only include check-ins for the selected list.
|
||||
|
||||
* An additional boolean property ``require_attention`` will inform you whether either the order or the item
|
||||
have the ``checkin_attention`` flag set.
|
||||
|
||||
* If ``attendee_name`` is empty, it will automatically fall back to values from a parent product or from invoice
|
||||
addresses.
|
||||
|
||||
**Instead of an ID, you can also use the ``secret`` field as the lookup parameter.**
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/checkinlists/1/positions/23442/ 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": 23442,
|
||||
"order": "ABC12",
|
||||
"positionid": 1,
|
||||
"item": 1345,
|
||||
"variation": null,
|
||||
"price": "23.00",
|
||||
"attendee_name": "Peter",
|
||||
"attendee_name_parts": {
|
||||
"full_name": "Peter",
|
||||
},
|
||||
"attendee_email": null,
|
||||
"voucher": null,
|
||||
"tax_rate": "0.00",
|
||||
"tax_rule": null,
|
||||
"tax_value": "0.00",
|
||||
"secret": "z3fsn8jyufm5kpk768q69gkbyr5f4h6w",
|
||||
"addon_to": null,
|
||||
"subevent": null,
|
||||
"pseudonymization_id": "MQLJvANO3B",
|
||||
"seat": null,
|
||||
"checkins": [
|
||||
{
|
||||
"list": 1,
|
||||
"datetime": "2017-12-25T12:45:23Z"
|
||||
}
|
||||
],
|
||||
"answers": [
|
||||
{
|
||||
"question": 12,
|
||||
"answer": "Foo",
|
||||
"options": []
|
||||
}
|
||||
],
|
||||
"downloads": [
|
||||
{
|
||||
"output": "pdf",
|
||||
"url": "https://pretix.eu/api/v1/organizers/bigevents/events/sampleconf/orderpositions/23442/download/pdf/"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:param list: The ID of the check-in list to look for
|
||||
:param id: The ``id`` field of the order position 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.
|
||||
:statuscode 404: The requested order position or check-in list does not exist.
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/checkinlists/(list)/positions/(id)/redeem/
|
||||
|
||||
Tries to redeem an order position, identified by its internal ID, i.e. checks the attendee in. This endpoint
|
||||
accepts a number of optional requests in the body.
|
||||
|
||||
**Instead of an ID, you can also use the ``secret`` field as the lookup parameter.**
|
||||
|
||||
:<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
|
||||
returned. Otherwise, canceled orders will return ``unpaid``.
|
||||
:<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 previous check-ins or required
|
||||
questions that have not been filled. Defaults to ``false``.
|
||||
:<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
|
||||
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
|
||||
answers, the string should contain the (comma-separated) IDs of the selected options.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/checkinlists/1/positions/234/redeem/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
{
|
||||
"force": false,
|
||||
"ignore_unpaid": false,
|
||||
"nonce": "Pvrk50vUzQd0DhdpNRL4I4OcXsvg70uA",
|
||||
"datetime": null,
|
||||
"questions_supported": true,
|
||||
"canceled_supported": true,
|
||||
"answers": {
|
||||
"4": "XS"
|
||||
}
|
||||
}
|
||||
|
||||
**Example successful response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"status": "ok",
|
||||
"position": {
|
||||
…
|
||||
}
|
||||
}
|
||||
|
||||
**Example response with required questions**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 400 Bad Request
|
||||
Content-Type: text/json
|
||||
|
||||
{
|
||||
"status": "incomplete",
|
||||
"position": {
|
||||
…
|
||||
},
|
||||
"questions": [
|
||||
{
|
||||
"id": 1,
|
||||
"question": {"en": "T-Shirt size"},
|
||||
"type": "C",
|
||||
"required": false,
|
||||
"items": [1, 2],
|
||||
"position": 1,
|
||||
"identifier": "WY3TP9SL",
|
||||
"ask_during_checkin": true,
|
||||
"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"}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
**Example error response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: text/json
|
||||
|
||||
{
|
||||
"status": "error",
|
||||
"reason": "unpaid",
|
||||
"position": {
|
||||
…
|
||||
}
|
||||
}
|
||||
|
||||
Possible error reasons:
|
||||
|
||||
* ``unpaid`` - Ticket is not paid for
|
||||
* ``canceled`` – Ticket is canceled or expired. This reason is only sent when your request sets
|
||||
``canceled_supported`` to ``true``, otherwise these orders return ``unpaid``.
|
||||
* ``already_redeemed`` - Ticket already has been redeemed
|
||||
* ``product`` - Tickets with this product may not be scanned at this device
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:param list: The ID of the check-in list to look for
|
||||
:param id: The ``id`` field of the order position to fetch
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: Invalid or incomplete request, see above
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
|
||||
:statuscode 404: The requested order position or check-in list does not exist.
|
||||
@@ -1,442 +0,0 @@
|
||||
Events
|
||||
======
|
||||
|
||||
Resource description
|
||||
--------------------
|
||||
|
||||
The event resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
name multi-lingual string The event's full name
|
||||
slug string A short form of the name, used e.g. in URLs.
|
||||
live boolean If ``true``, the event ticket shop is publicly
|
||||
available.
|
||||
testmode boolean If ``true``, the ticket shop is in test mode.
|
||||
currency string The currency this event is handled in.
|
||||
date_from datetime The event's start date
|
||||
date_to datetime The event's end date (or ``null``)
|
||||
date_admission datetime The event's admission date (or ``null``)
|
||||
is_public boolean If ``true``, the event shows up in places like the
|
||||
organizer's public list of events
|
||||
presale_start datetime The date at which the ticket shop opens (or ``null``)
|
||||
presale_end datetime The date at which the ticket shop closes (or ``null``)
|
||||
location multi-lingual string The event location (or ``null``)
|
||||
has_subevents boolean ``true`` if the event series feature is active for this
|
||||
event. Cannot change after event is created.
|
||||
meta_data object Values set for organizer-specific meta data parameters.
|
||||
plugins list A list of package names of the enabled plugins for this
|
||||
event.
|
||||
seating_plan integer If reserved seating is in use, the ID of a seating
|
||||
plan. Otherwise ``null``.
|
||||
seat_category_mapping object An object mapping categories of the seating plan
|
||||
(strings) to items in the event (integers or ``null``).
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
|
||||
.. versionchanged:: 1.7
|
||||
|
||||
The ``meta_data`` field has been added.
|
||||
|
||||
.. versionchanged:: 1.15
|
||||
|
||||
The ``plugins`` field has been added.
|
||||
The operations POST, PATCH, PUT and DELETE have been added.
|
||||
|
||||
.. versionchanged:: 2.1
|
||||
|
||||
Filters have been added to the list of events.
|
||||
|
||||
.. versionchanged:: 2.5
|
||||
|
||||
The ``testmode`` attribute has been added.
|
||||
|
||||
.. versionchanged:: 2.8
|
||||
|
||||
When cloning events, the ``testmode`` attribute will now be cloned, too.
|
||||
|
||||
.. versionchanged:: 3.0
|
||||
|
||||
The attributes ``seating_plan`` and ``seat_category_mapping`` have been added.
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/
|
||||
|
||||
Returns a list of all events within a given organizer the authenticated user/token has access to.
|
||||
|
||||
Permission required: "Can change event settings"
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/ 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": [
|
||||
{
|
||||
"name": {"en": "Sample Conference"},
|
||||
"slug": "sampleconf",
|
||||
"live": false,
|
||||
"testmode": false,
|
||||
"currency": "EUR",
|
||||
"date_from": "2017-12-27T10:00:00Z",
|
||||
"date_to": null,
|
||||
"date_admission": null,
|
||||
"is_public": null,
|
||||
"presale_start": null,
|
||||
"presale_end": null,
|
||||
"location": null,
|
||||
"has_subevents": false,
|
||||
"meta_data": {},
|
||||
"seating_plan": null,
|
||||
"seat_category_mapping": {},
|
||||
"plugins": [
|
||||
"pretix.plugins.banktransfer"
|
||||
"pretix.plugins.stripe"
|
||||
"pretix.plugins.paypal"
|
||||
"pretix.plugins.ticketoutputpdf"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query page: The page number in case of a multi-page result set, default is 1
|
||||
:query is_public: If set to ``true``/``false``, only events with a matching value of ``is_public`` are returned.
|
||||
:query live: If set to ``true``/``false``, only events with a matching value of ``live`` are returned.
|
||||
:query has_subevents: If set to ``true``/``false``, only events with a matching value of ``has_subevents`` are returned.
|
||||
:query is_future: If set to ``true`` (``false``), only events that happen currently or in the future are (not) returned. Event series are never (always) returned.
|
||||
:query is_past: If set to ``true`` (``false``), only events that are over are (not) returned. Event series are never (always) returned.
|
||||
:query ends_after: If set to a date and time, only events that happen during of after the given time are returned. Event series are never returned.
|
||||
:query string ordering: Manually set the ordering of results. Valid fields to be used are ``date_from`` and
|
||||
``slug``. Keep in mind that ``date_from`` of event series does not really tell you anything.
|
||||
Default: ``slug``.
|
||||
:param organizer: The ``slug`` field of a valid organizer
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to view it.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/
|
||||
|
||||
Returns information on one event, identified by its slug.
|
||||
|
||||
Permission required: "Can change event settings"
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/ 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
|
||||
|
||||
{
|
||||
"name": {"en": "Sample Conference"},
|
||||
"slug": "sampleconf",
|
||||
"live": false,
|
||||
"testmode": false,
|
||||
"currency": "EUR",
|
||||
"date_from": "2017-12-27T10:00:00Z",
|
||||
"date_to": null,
|
||||
"date_admission": null,
|
||||
"is_public": false,
|
||||
"presale_start": null,
|
||||
"presale_end": null,
|
||||
"location": null,
|
||||
"has_subevents": false,
|
||||
"seating_plan": null,
|
||||
"seat_category_mapping": {},
|
||||
"meta_data": {},
|
||||
"plugins": [
|
||||
"pretix.plugins.banktransfer"
|
||||
"pretix.plugins.stripe"
|
||||
"pretix.plugins.paypal"
|
||||
"pretix.plugins.ticketoutputpdf"
|
||||
]
|
||||
}
|
||||
|
||||
: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 it.
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/events/
|
||||
|
||||
Creates a new event
|
||||
|
||||
Please note that events cannot be created as 'live' using this endpoint. Quotas and payment must be added to the
|
||||
event before sales can go live.
|
||||
|
||||
Permission required: "Can create events"
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/events/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": {"en": "Sample Conference"},
|
||||
"slug": "sampleconf",
|
||||
"live": false,
|
||||
"testmode": false,
|
||||
"currency": "EUR",
|
||||
"date_from": "2017-12-27T10:00:00Z",
|
||||
"date_to": null,
|
||||
"date_admission": null,
|
||||
"is_public": false,
|
||||
"presale_start": null,
|
||||
"presale_end": null,
|
||||
"seating_plan": null,
|
||||
"seat_category_mapping": {},
|
||||
"location": null,
|
||||
"has_subevents": false,
|
||||
"meta_data": {},
|
||||
"plugins": [
|
||||
"pretix.plugins.stripe",
|
||||
"pretix.plugins.paypal"
|
||||
]
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": {"en": "Sample Conference"},
|
||||
"slug": "sampleconf",
|
||||
"live": false,
|
||||
"testmode": false,
|
||||
"currency": "EUR",
|
||||
"date_from": "2017-12-27T10:00:00Z",
|
||||
"date_to": null,
|
||||
"date_admission": null,
|
||||
"is_public": false,
|
||||
"presale_start": null,
|
||||
"presale_end": null,
|
||||
"location": null,
|
||||
"seating_plan": null,
|
||||
"seat_category_mapping": {},
|
||||
"has_subevents": false,
|
||||
"meta_data": {},
|
||||
"plugins": [
|
||||
"pretix.plugins.stripe",
|
||||
"pretix.plugins.paypal"
|
||||
]
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer of the event to create.
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The event could not be created due to invalid submitted data.
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to create this resource.
|
||||
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/clone/
|
||||
|
||||
Creates a new event with properties as set in the request body. The properties that are copied are: 'is_public',
|
||||
`testmode`, settings, plugin settings, items, variations, add-ons, quotas, categories, tax rules, questions.
|
||||
|
||||
If the 'plugins' and/or 'is_public' fields are present in the post body this will determine their value. Otherwise
|
||||
their value will be copied from the existing event.
|
||||
|
||||
Please note that you can only copy from events under the same organizer.
|
||||
|
||||
Permission required: "Can create events"
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/clone/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": {"en": "Sample Conference"},
|
||||
"slug": "sampleconf",
|
||||
"live": false,
|
||||
"testmode": false,
|
||||
"currency": "EUR",
|
||||
"date_from": "2017-12-27T10:00:00Z",
|
||||
"date_to": null,
|
||||
"date_admission": null,
|
||||
"is_public": false,
|
||||
"presale_start": null,
|
||||
"presale_end": null,
|
||||
"location": null,
|
||||
"seating_plan": null,
|
||||
"seat_category_mapping": {},
|
||||
"has_subevents": false,
|
||||
"meta_data": {},
|
||||
"plugins": [
|
||||
"pretix.plugins.stripe",
|
||||
"pretix.plugins.paypal"
|
||||
]
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": {"en": "Sample Conference"},
|
||||
"slug": "sampleconf",
|
||||
"live": false,
|
||||
"testmode": false,
|
||||
"currency": "EUR",
|
||||
"date_from": "2017-12-27T10:00:00Z",
|
||||
"date_to": null,
|
||||
"date_admission": null,
|
||||
"is_public": false,
|
||||
"presale_start": null,
|
||||
"presale_end": null,
|
||||
"location": null,
|
||||
"has_subevents": false,
|
||||
"seating_plan": null,
|
||||
"seat_category_mapping": {},
|
||||
"meta_data": {},
|
||||
"plugins": [
|
||||
"pretix.plugins.stripe",
|
||||
"pretix.plugins.paypal"
|
||||
]
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer of the event to create.
|
||||
:param event: The ``slug`` field of the event to copy settings and items from.
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The event could not be created due to invalid submitted data.
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to create this resource.
|
||||
|
||||
|
||||
.. http:patch:: /api/v1/organizers/(organizer)/events/(event)/
|
||||
|
||||
Updates an event
|
||||
|
||||
Permission required: "Can change event settings"
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
PATCH /api/v1/organizers/bigevents/events/sampleconf/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"plugins": [
|
||||
"pretix.plugins.banktransfer",
|
||||
"pretix.plugins.stripe",
|
||||
"pretix.plugins.paypal",
|
||||
"pretix.plugins.pretixdroid"
|
||||
]
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": {"en": "Sample Conference"},
|
||||
"slug": "sampleconf",
|
||||
"live": false,
|
||||
"testmode": false,
|
||||
"currency": "EUR",
|
||||
"date_from": "2017-12-27T10:00:00Z",
|
||||
"date_to": null,
|
||||
"date_admission": null,
|
||||
"is_public": false,
|
||||
"presale_start": null,
|
||||
"presale_end": null,
|
||||
"location": null,
|
||||
"has_subevents": false,
|
||||
"seating_plan": null,
|
||||
"seat_category_mapping": {},
|
||||
"meta_data": {},
|
||||
"plugins": [
|
||||
"pretix.plugins.banktransfer",
|
||||
"pretix.plugins.stripe",
|
||||
"pretix.plugins.paypal",
|
||||
"pretix.plugins.pretixdroid"
|
||||
]
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer of the event to update
|
||||
:param event: The ``slug`` field of the event to update
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The event 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:delete:: /api/v1/organizers/(organizer)/events/(event)/items/(id)/
|
||||
|
||||
Delete an event. Note that events with orders cannot be deleted to ensure data integrity.
|
||||
|
||||
Permission required: "Can change event settings"
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/events/sampleconf/ 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 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.
|
||||
@@ -1,27 +0,0 @@
|
||||
Resources and endpoints
|
||||
=======================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
organizers
|
||||
events
|
||||
subevents
|
||||
taxrules
|
||||
categories
|
||||
items
|
||||
item_variations
|
||||
item_bundles
|
||||
item_add-ons
|
||||
questions
|
||||
question_options
|
||||
quotas
|
||||
orders
|
||||
invoices
|
||||
vouchers
|
||||
checkinlists
|
||||
waitinglist
|
||||
carts
|
||||
webhooks
|
||||
seatingplans
|
||||
billing_invoices
|
||||
@@ -1,281 +0,0 @@
|
||||
Invoices
|
||||
========
|
||||
|
||||
Resource description
|
||||
--------------------
|
||||
|
||||
The invoice resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
number string Invoice number (with prefix)
|
||||
order string Order code of the order this invoice belongs to
|
||||
is_cancellation boolean ``true``, if this invoice is the cancellation of a
|
||||
different invoice.
|
||||
invoice_from string Sender address
|
||||
invoice_to string Receiver address
|
||||
date date Invoice date
|
||||
refers string Invoice number of an invoice this invoice refers to
|
||||
(for example a cancellation refers to the invoice it
|
||||
cancels) or ``null``.
|
||||
locale string Invoice locale
|
||||
introductory_text string Text to be printed above the product list
|
||||
additional_text string Text to be printed below the product list
|
||||
payment_provider_text string Text to be printed below the product list with
|
||||
payment information
|
||||
footer_text string Text to be printed in the page footer area
|
||||
lines list of objects The actual invoice contents
|
||||
├ description string Text representing the invoice line (e.g. product name)
|
||||
├ gross_value money (string) Price including taxes
|
||||
├ tax_value money (string) Tax amount included
|
||||
├ tax_name string Name of used tax rate (e.g. "VAT")
|
||||
└ tax_rate decimal (string) Used tax rate
|
||||
foreign_currency_display string If the invoice should also show the total and tax
|
||||
amount in a different currency, this contains the
|
||||
currency code (``null`` otherwise).
|
||||
foreign_currency_rate decimal (string) If ``foreign_currency_rate`` is set and the system
|
||||
knows the exchange rate to the event currency at
|
||||
invoicing time, it is stored here.
|
||||
foreign_currency_rate_date date If ``foreign_currency_rate`` is set, this signifies the
|
||||
date at which the currency rate was obtained.
|
||||
internal_reference string Customer's reference to be printed on the invoice.
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
|
||||
.. versionchanged:: 1.6
|
||||
|
||||
The attribute ``invoice_no`` has been dropped in favor of ``number`` which includes the number including the prefix,
|
||||
since the prefix can now vary. Also, invoices now need to be identified by their ``number`` instead of the raw
|
||||
number.
|
||||
|
||||
|
||||
.. versionchanged:: 1.7
|
||||
|
||||
The attributes ``lines.tax_name``, ``foreign_currency_display``, ``foreign_currency_rate``, and
|
||||
``foreign_currency_rate_date`` have been added.
|
||||
|
||||
|
||||
.. versionchanged:: 1.9
|
||||
|
||||
The attribute ``internal_reference`` has been added.
|
||||
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/invoices/
|
||||
|
||||
Returns a list of all invoices within a given event.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/invoices/ 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": [
|
||||
{
|
||||
"number": "SAMPLECONF-00001",
|
||||
"order": "ABC12",
|
||||
"is_cancellation": false,
|
||||
"invoice_from": "Big Events LLC\nDemo street 12\nDemo town",
|
||||
"invoice_to": "Sample company\nJohn Doe\nTest street 12\n12345 Testington\nTestikistan\nVAT ID: EU123456789",
|
||||
"date": "2017-12-01",
|
||||
"refers": null,
|
||||
"locale": "en",
|
||||
"introductory_text": "thank you for your purchase of the following items:",
|
||||
"internal_reference": "",
|
||||
"additional_text": "We are looking forward to see you on our conference!",
|
||||
"payment_provider_text": "Please transfer the money to our account ABC…",
|
||||
"footer_text": "Big Events LLC - Registration No. 123456 - VAT ID: EU0987654321",
|
||||
"lines": [
|
||||
{
|
||||
"description": "Budget Ticket",
|
||||
"gross_value": "23.00",
|
||||
"tax_value": "0.00",
|
||||
"tax_name": "VAT",
|
||||
"tax_rate": "0.00"
|
||||
}
|
||||
],
|
||||
"foreign_currency_display": "PLN",
|
||||
"foreign_currency_rate": "4.2408",
|
||||
"foreign_currency_rate_date": "2017-07-24"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
:query boolean is_cancellation: If set to ``true`` or ``false``, only invoices with this value for the field
|
||||
``is_cancellation`` will be returned.
|
||||
:query string order: If set, only invoices belonging to the order with the given order code will be returned.
|
||||
:query string refers: If set, only invoices referring to the given invoice will be returned.
|
||||
:query string locale: If set, only invoices with the given locale will be returned.
|
||||
:query string ordering: Manually set the ordering of results. Valid fields to be used are ``date`` and
|
||||
``nr`` (equals to ``number``). Default: ``nr``
|
||||
: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)/invoices/(number)/
|
||||
|
||||
Returns information on one invoice, identified by its invoice number.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/invoices/SAMPLECONF-00001/ 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
|
||||
|
||||
{
|
||||
"number": "SAMPLECONF-00001",
|
||||
"order": "ABC12",
|
||||
"is_cancellation": false,
|
||||
"invoice_from": "Big Events LLC\nDemo street 12\nDemo town",
|
||||
"invoice_to": "Sample company\nJohn Doe\nTest street 12\n12345 Testington\nTestikistan\nVAT ID: EU123456789",
|
||||
"date": "2017-12-01",
|
||||
"refers": null,
|
||||
"locale": "en",
|
||||
"introductory_text": "thank you for your purchase of the following items:",
|
||||
"internal_reference": "",
|
||||
"additional_text": "We are looking forward to see you on our conference!",
|
||||
"payment_provider_text": "Please transfer the money to our account ABC…",
|
||||
"footer_text": "Big Events LLC - Registration No. 123456 - VAT ID: EU0987654321",
|
||||
"lines": [
|
||||
{
|
||||
"description": "Budget Ticket",
|
||||
"gross_value": "23.00",
|
||||
"tax_value": "0.00",
|
||||
"tax_name": "VAT",
|
||||
"tax_rate": "0.00"
|
||||
}
|
||||
],
|
||||
"foreign_currency_display": "PLN",
|
||||
"foreign_currency_rate": "4.2408",
|
||||
"foreign_currency_rate_date": "2017-07-24"
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:param invoice_no: The ``invoice_no`` field of the invoice 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)/invoices/(invoice_no)/download/
|
||||
|
||||
Download an invoice in PDF format.
|
||||
|
||||
Note that in some cases the PDF file might not yet have been created. In that case, you will receive a status
|
||||
code :http:statuscode:`409` and you are expected to retry the request after a short period of waiting.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/invoices/00001/download/ 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/pdf
|
||||
|
||||
...
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:param invoice_no: The ``invoice_no`` field of the invoice 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.
|
||||
:statuscode 409: The file is not yet ready and will now be prepared. Retry the request after waiting for a few
|
||||
seconds.
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/invoices/(invoice_no)/reissue/
|
||||
|
||||
Cancels the invoice and creates a new one.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/invoices/00001/reissue/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 204 No Content
|
||||
Vary: Accept
|
||||
Content-Type: application/pdf
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:param invoice_no: The ``invoice_no`` field of the invoice to reissue
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The invoice has already been canceled
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to change this resource.
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/invoices/(invoice_no)/regenerate/
|
||||
|
||||
Re-generates the invoice from order data.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/invoices/00001/regenerate/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 204 No Content
|
||||
Vary: Accept
|
||||
Content-Type: application/pdf
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:param invoice_no: The ``invoice_no`` field of the invoice to regenerate
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The invoice has already been canceled
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to change this resource.
|
||||
@@ -1,246 +0,0 @@
|
||||
Item add-ons
|
||||
============
|
||||
|
||||
Resource description
|
||||
--------------------
|
||||
|
||||
With add-ons, you can specify products that can be bought as an addition to this specific product. For example, if you
|
||||
host a conference with a base conference ticket and a number of workshops, you could define the workshops as add-ons to
|
||||
the conference ticket. With this configuration, the workshops cannot be bought on their own but only in combination with
|
||||
a conference ticket. You can here specify categories of products that can be used as add-ons to this product. You can
|
||||
also specify the minimum and maximum number of add-ons of the given category that can or need to be chosen. The user can
|
||||
buy every add-on from the category at most once. If an add-on product has multiple variations, only one of them can be
|
||||
bought.
|
||||
The add-ons resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Internal ID of the add-on
|
||||
addon_category integer Internal ID of the item category the add-on can be
|
||||
chosen from.
|
||||
min_count integer The minimal number of add-ons that need to be chosen.
|
||||
max_count integer The maximal number of add-ons that can be chosen.
|
||||
position integer An integer, used for sorting
|
||||
price_included boolean Adding this add-on to the item is free
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
.. versionchanged:: 1.12
|
||||
|
||||
This resource has been added.
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/items/(item)/addons/
|
||||
|
||||
Returns a list of all add-ons for a given item.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/items/11/addons/ 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": 3,
|
||||
"addon_category": 1,
|
||||
"min_count": 0,
|
||||
"max_count": 10,
|
||||
"position": 0,
|
||||
"price_included": true
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"addon_category": 2,
|
||||
"min_count": 0,
|
||||
"max_count": 10,
|
||||
"position": 1,
|
||||
"price_included": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:param item: The ``id`` field of the item to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event/item does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/items/(item)/addons/(id)/
|
||||
|
||||
Returns information on one add-on, identified by its ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/items/1/addons/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": 3,
|
||||
"addon_category": 1,
|
||||
"min_count": 0,
|
||||
"max_count": 10,
|
||||
"position": 1,
|
||||
"price_included": true
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:param item: The ``id`` field of the item to fetch
|
||||
:param id: The ``id`` field of the add-on 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/bigevents/events/sampleconf/items/1/addons/
|
||||
|
||||
Creates a new add-on
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/(organizer)/events/(event)/items/(item)/addons/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"addon_category": 1,
|
||||
"min_count": 0,
|
||||
"max_count": 10,
|
||||
"position": 1,
|
||||
"price_included": true
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 3,
|
||||
"addon_category": 1,
|
||||
"min_count": 0,
|
||||
"max_count": 10,
|
||||
"position": 1,
|
||||
"price_included": true
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer of the event/item to create a add-on for
|
||||
:param event: The ``slug`` field of the event to create a add-on for
|
||||
:param item: The ``id`` field of the item to create a add-on for
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The add-on 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)/items/(item)/addon/(id)/
|
||||
|
||||
Update an add-on. 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/items/1/addons/3/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 94
|
||||
|
||||
{
|
||||
"min_count": 0,
|
||||
"max_count": 10
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 3,
|
||||
"addon_category": 1,
|
||||
"min_count": 0,
|
||||
"max_count": 10,
|
||||
"position": 1,
|
||||
"price_included": true
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param event: The ``slug`` field of the event to modify
|
||||
:param item: The ``id`` field of the item to modify
|
||||
:param id: The ``id`` field of the add-on to modify
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The add-on 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)/items/(id)/addons/(id)/
|
||||
|
||||
Delete an add-on.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/events/sampleconf/items/1/addons/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 item to modify
|
||||
:param id: The ``id`` field of the add-on 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.
|
||||
@@ -1,242 +0,0 @@
|
||||
Item bundles
|
||||
============
|
||||
|
||||
Resource description
|
||||
--------------------
|
||||
|
||||
With bundles, you can specify products that are included within other products. There are two premier use cases of this:
|
||||
|
||||
* Package discounts. For example, you could offer a discounted package that includes three tickets but can only be
|
||||
bought as a whole. With a bundle including three times the usual product, the package will automatically pull three
|
||||
sub-items into the cart, making sure of correct quota calculation and issuance of the correct number of tickets.
|
||||
|
||||
* Tax splitting. For example, if your conference ticket includes a part that is subject to different taxation and that
|
||||
you need to put on the invoice separately. When you putting a "designated price" on a bundled sub-item, pretix will
|
||||
use that price to show a split taxation.
|
||||
|
||||
The bundles resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Internal ID of the bundling configuration
|
||||
bundled_item integer Internal ID of the item that is included.
|
||||
bundled_variation integer Internal ID of the variation of the item (or ``null``).
|
||||
count integer Number of items included
|
||||
designated_price money (string) Designated price of the bundled product. This will be
|
||||
used to split the price of the base item e.g. for mixed
|
||||
taxation. This is not added to the price.
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
.. versionchanged:: 2.6
|
||||
|
||||
This resource has been added.
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/items/(item)/bundles/
|
||||
|
||||
Returns a list of all bundles for a given item.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/items/11/bundles/ 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": 3,
|
||||
"bundled_item": 3,
|
||||
"bundled_variation": null,
|
||||
"count": 1,
|
||||
"designated_price": "0.00"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"bundled_item": 3,
|
||||
"bundled_variation": null,
|
||||
"count": 2,
|
||||
"designated_price": "1.50"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:param item: The ``id`` field of the item to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event/item does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/items/(item)/bundles/(id)/
|
||||
|
||||
Returns information on one bundle configuration, identified by its ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/items/1/bundles/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": 3,
|
||||
"bundled_item": 3,
|
||||
"bundled_variation": null,
|
||||
"count": 2,
|
||||
"designated_price": "1.50"
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:param item: The ``id`` field of the item to fetch
|
||||
:param id: The ``id`` field of the bundle 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/bigevents/events/sampleconf/items/1/bundles/
|
||||
|
||||
Creates a new bundle configuration
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/(organizer)/events/(event)/items/(item)/bundles/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"bundled_item": 3,
|
||||
"bundled_variation": null,
|
||||
"count": 2,
|
||||
"designated_price": "1.50"
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 3,
|
||||
"bundled_item": 3,
|
||||
"bundled_variation": null,
|
||||
"count": 2,
|
||||
"designated_price": "1.50"
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer of the event/item to create a bundle-configuration for
|
||||
:param event: The ``slug`` field of the event to create a bundle configuration for
|
||||
:param item: The ``id`` field of the item to create a bundle configuration for
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The bundle 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)/items/(item)/bundles/(id)/
|
||||
|
||||
Update a bundle configuration. 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/items/1/bundles/3/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 94
|
||||
|
||||
{
|
||||
"count": 2
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 3,
|
||||
"bundled_item": 3,
|
||||
"bundled_variation": null,
|
||||
"count": 2,
|
||||
"designated_price": "1.50"
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param event: The ``slug`` field of the event to modify
|
||||
:param item: The ``id`` field of the item to modify
|
||||
:param id: The ``id`` field of the bundle to modify
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The bundle configuration 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)/items/(id)/bundles/(id)/
|
||||
|
||||
Delete a bundle configuration.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/events/sampleconf/items/1/bundles/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 item to modify
|
||||
:param id: The ``id`` field of the bundle 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.
|
||||
@@ -1,268 +0,0 @@
|
||||
Item variations
|
||||
===============
|
||||
|
||||
Resource description
|
||||
--------------------
|
||||
|
||||
Variations of items can be use for products (items) that are available in different sizes, colors or other variations
|
||||
of the same product.
|
||||
The variations resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Internal ID of the variation
|
||||
default_price money (string) The price set directly for this variation or ``null``
|
||||
price money (string) The price used for this variation. This is either the
|
||||
same as ``default_price`` if that value is set or equal
|
||||
to the item's ``default_price`` (read-only).
|
||||
original_price money (string) An original price, shown for comparison, not used
|
||||
for price calculations (or ``null``).
|
||||
active boolean If ``false``, this variation will not be sold or shown.
|
||||
description multi-lingual string A public description of the variation. May contain
|
||||
Markdown syntax or can be ``null``.
|
||||
position integer An integer, used for sorting
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
.. versionchanged:: 2.7
|
||||
|
||||
The attribute ``original_price`` has been added.
|
||||
|
||||
.. versionchanged:: 1.12
|
||||
|
||||
This resource has been added.
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/items/(item)/variations/
|
||||
|
||||
Returns a list of all variations for a given item.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/items/11/variations/ 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,
|
||||
"value": {
|
||||
"en": "S"
|
||||
},
|
||||
"active": true,
|
||||
"description": {
|
||||
"en": "Test2"
|
||||
},
|
||||
"position": 0,
|
||||
"default_price": "223.00",
|
||||
"price": 223.0,
|
||||
"original_price": null,
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"value": {
|
||||
"en": "L"
|
||||
},
|
||||
"active": true,
|
||||
"description": {},
|
||||
"position": 1,
|
||||
"default_price": null,
|
||||
"price": 15.0
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
: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 items 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 item: The ``id`` field of the item to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event/item does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/items/(item)/variations/(id)/
|
||||
|
||||
Returns information on one variation, identified by its ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/items/1/variations/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": 3,
|
||||
"value": {
|
||||
"en": "Student"
|
||||
},
|
||||
"default_price": "10.00",
|
||||
"price": "10.00",
|
||||
"original_price": null,
|
||||
"active": true,
|
||||
"description": null,
|
||||
"position": 0
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:param item: The ``id`` field of the item to fetch
|
||||
:param id: The ``id`` field of the variation 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)/items/(item)/variations/
|
||||
|
||||
Creates a new variation
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/items/1/variations/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"value": {"en": "Student"},
|
||||
"default_price": "10.00",
|
||||
"active": true,
|
||||
"description": null,
|
||||
"position": 0
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"value": {"en": "Student"},
|
||||
"default_price": "10.00",
|
||||
"price": "10.00",
|
||||
"original_price": null,
|
||||
"active": true,
|
||||
"description": null,
|
||||
"position": 0
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer of the event/item to create a variation for
|
||||
:param event: The ``slug`` field of the event to create a variation for
|
||||
:param item: The ``id`` field of the item to create a variation for
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The variation 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)/items/(item)/variations/(id)/
|
||||
|
||||
Update a variation. 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`` and the ``price`` field.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
PATCH /api/v1/organizers/bigevents/events/sampleconf/items/1/variations/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 94
|
||||
|
||||
{
|
||||
"active": false,
|
||||
"position": 1
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"value": {"en": "Student"},
|
||||
"default_price": "10.00",
|
||||
"price": "10.00",
|
||||
"original_price": null,
|
||||
"active": false,
|
||||
"description": null,
|
||||
"position": 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 item to modify
|
||||
:param id: The ``id`` field of the variation to modify
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The variation 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)/items/(id)/variations/(id)/
|
||||
|
||||
Delete a variation.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/events/sampleconf/items/1/variations/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 item to modify
|
||||
:param id: The ``id`` field of the variation 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.
|
||||
@@ -1,608 +0,0 @@
|
||||
.. _rest-items:
|
||||
|
||||
Items
|
||||
=====
|
||||
|
||||
Resource description
|
||||
--------------------
|
||||
|
||||
Items (better known as products) are the things that can be sold using pretix.
|
||||
The item resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Internal ID of the item
|
||||
name multi-lingual string The item's visible name
|
||||
internal_name string An optional name that is only used in the backend
|
||||
default_price money (string) The item price that is applied if the price is not
|
||||
overwritten by variations or other options.
|
||||
category integer The ID of the category this item belongs to
|
||||
(or ``null``).
|
||||
active boolean If ``false``, the item is hidden from all public lists
|
||||
and will not be sold.
|
||||
description multi-lingual string A public description of the item. May contain Markdown
|
||||
syntax or can be ``null``.
|
||||
free_price boolean If ``true``, customers can change the price at which
|
||||
they buy the product (however, the price can't be set
|
||||
lower than the price defined by ``default_price`` or
|
||||
otherwise).
|
||||
tax_rate decimal (string) The VAT rate to be applied for this item (read-only,
|
||||
set through ``tax_rule``).
|
||||
tax_rule integer The internal ID of the applied tax rule (or ``null``).
|
||||
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).
|
||||
position integer An integer, used for sorting
|
||||
picture string A product picture to be displayed in the shop
|
||||
(read-only, can be ``null``).
|
||||
sales_channels list of strings Sales channels this product is available on, such as
|
||||
``"web"`` or ``"resellers"``. Defaults to ``["web"]``.
|
||||
available_from datetime The first date time at which this item can be bought
|
||||
(or ``null``).
|
||||
available_until datetime The last date time at which this item can be bought
|
||||
(or ``null``).
|
||||
hidden_if_available integer The internal ID of a quota object, or ``null``. If
|
||||
set, this item won't be shown publicly as long as this
|
||||
quota is available.
|
||||
require_voucher boolean If ``true``, this item can only be bought using a
|
||||
voucher that is specifically assigned to this item.
|
||||
hide_without_voucher boolean If ``true``, this item is only shown during the voucher
|
||||
redemption process, but not in the normal shop
|
||||
frontend.
|
||||
allow_cancel boolean If ``false``, customers cannot cancel orders containing
|
||||
this item.
|
||||
min_per_order integer This product can only be bought if it is included at
|
||||
least this many times in the order (or ``null`` for no
|
||||
limitation).
|
||||
max_per_order integer This product can only be bought if it is included at
|
||||
most this many times in the order (or ``null`` for no
|
||||
limitation).
|
||||
checkin_attention boolean If ``true``, the check-in app should show a warning
|
||||
that this ticket requires special attention if such
|
||||
a product is being scanned.
|
||||
original_price money (string) An original price, shown for comparison, not used
|
||||
for price calculations (or ``null``).
|
||||
require_approval boolean If ``true``, orders with this product will need to be
|
||||
approved by the event organizer before they can be
|
||||
paid.
|
||||
require_bundling boolean If ``true``, this item is only available as part of bundles.
|
||||
generate_tickets boolean If ``false``, tickets are never generated for this
|
||||
product, regardless of other settings. If ``true``,
|
||||
tickets are generated even if this is a
|
||||
non-admission or add-on product, regardless of event
|
||||
settings. If this is ``null``, regular ticketing
|
||||
rules apply.
|
||||
allow_waitinglist boolean If ``false``, no waiting list will be shown for this
|
||||
product when it is sold out.
|
||||
show_quota_left boolean Publicly show how many tickets are still available.
|
||||
If this is ``null``, the event default is used.
|
||||
has_variations boolean Shows whether or not this item has variations.
|
||||
variations list of objects A list with one object for each variation of this item.
|
||||
Can be empty. Only writable during creation,
|
||||
use separate endpoint to modify this later.
|
||||
├ id integer Internal ID of the variation
|
||||
├ value multi-lingual string The "name" of the variation
|
||||
├ default_price money (string) The price set directly for this variation or ``null``
|
||||
├ price money (string) The price used for this variation. This is either the
|
||||
same as ``default_price`` if that value is set or equal
|
||||
to the item's ``default_price``.
|
||||
├ original_price money (string) An original price, shown for comparison, not used
|
||||
for price calculations (or ``null``).
|
||||
├ active boolean If ``false``, this variation will not be sold or shown.
|
||||
├ description multi-lingual string A public description of the variation. May contain
|
||||
Markdown syntax or can be ``null``.
|
||||
└ position integer An integer, used for sorting
|
||||
addons list of objects Definition of add-ons that can be chosen for this item.
|
||||
Only writable during creation,
|
||||
use separate endpoint to modify this later.
|
||||
├ addon_category integer Internal ID of the item category the add-on can be
|
||||
chosen from.
|
||||
├ min_count integer The minimal number of add-ons that need to be chosen.
|
||||
├ max_count integer The maximal number of add-ons that can be chosen.
|
||||
├ position integer An integer, used for sorting
|
||||
└ price_included boolean Adding this add-on to the item is free
|
||||
bundles list of objects Definition of bundles that are included in this item.
|
||||
Only writable during creation,
|
||||
use separate endpoint to modify this later.
|
||||
├ bundled_item integer Internal ID of the item that is included.
|
||||
├ bundled_variation integer Internal ID of the variation of the item (or ``null``).
|
||||
├ count integer Number of items included
|
||||
└ designated_price money (string) Designated price of the bundled product. This will be
|
||||
used to split the price of the base item e.g. for mixed
|
||||
taxation. This is not added to the price.
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
.. versionchanged:: 2.7
|
||||
|
||||
The attribute ``original_price`` has been added for ``variations``.
|
||||
|
||||
.. versionchanged:: 1.7
|
||||
|
||||
The attribute ``tax_rule`` has been added. ``tax_rate`` is kept for compatibility. The attribute
|
||||
``checkin_attention`` has been added.
|
||||
|
||||
.. versionchanged:: 1.12
|
||||
|
||||
The write operations ``POST``, ``PATCH``, ``PUT``, and ``DELETE`` have been added.
|
||||
The attribute ``price_included`` has been added to ``addons``.
|
||||
|
||||
.. versionchanged:: 1.16
|
||||
|
||||
The ``internal_name`` and ``original_price`` fields have been added.
|
||||
|
||||
.. versionchanged:: 2.0
|
||||
|
||||
The field ``require_approval`` has been added.
|
||||
|
||||
.. versionchanged:: 2.3
|
||||
|
||||
The ``sales_channels`` attribute has been added.
|
||||
|
||||
.. versionchanged:: 2.4
|
||||
|
||||
The ``generate_tickets`` attribute has been added.
|
||||
|
||||
.. versionchanged:: 2.6
|
||||
|
||||
The ``bundles`` and ``require_bundling`` attributes have been added.
|
||||
|
||||
.. versionchanged:: 3.0
|
||||
|
||||
The ``show_quota_left``, ``allow_waitinglist``, and ``hidden_if_available`` attributes have been added.
|
||||
|
||||
Notes
|
||||
-----
|
||||
|
||||
Please note that an item either always has variations or never has. Once created with variations the item can never
|
||||
change to an item without and vice versa. To create an item with variations ensure that you POST an item with at least
|
||||
one variation.
|
||||
|
||||
Also note that ``variations``, ``bundles``, and ``addons`` are only supported on ``POST``. To update/delete variations,
|
||||
bundles, and add-ons please use the dedicated nested endpoints. By design this endpoint does not support ``PATCH`` and ``PUT``
|
||||
with nested ``variations``, ``bundles`` and/or ``addons``.
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/items/
|
||||
|
||||
Returns a list of all items within a given event.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/items/ 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,
|
||||
"name": {"en": "Standard ticket"},
|
||||
"internal_name": "",
|
||||
"sales_channels": ["web"],
|
||||
"default_price": "23.00",
|
||||
"original_price": null,
|
||||
"category": null,
|
||||
"active": true,
|
||||
"description": null,
|
||||
"free_price": false,
|
||||
"tax_rate": "0.00",
|
||||
"tax_rule": 1,
|
||||
"admission": false,
|
||||
"position": 0,
|
||||
"picture": null,
|
||||
"available_from": null,
|
||||
"available_until": null,
|
||||
"hidden_if_available": null,
|
||||
"require_voucher": false,
|
||||
"hide_without_voucher": false,
|
||||
"allow_cancel": true,
|
||||
"min_per_order": null,
|
||||
"max_per_order": null,
|
||||
"checkin_attention": false,
|
||||
"has_variations": false,
|
||||
"generate_tickets": null,
|
||||
"allow_waitinglist": true,
|
||||
"show_quota_left": null,
|
||||
"require_approval": false,
|
||||
"require_bundling": false,
|
||||
"variations": [
|
||||
{
|
||||
"value": {"en": "Student"},
|
||||
"default_price": "10.00",
|
||||
"price": "10.00",
|
||||
"original_price": null,
|
||||
"active": true,
|
||||
"description": null,
|
||||
"position": 0
|
||||
},
|
||||
{
|
||||
"value": {"en": "Regular"},
|
||||
"default_price": null,
|
||||
"price": "23.00",
|
||||
"original_price": null,
|
||||
"active": true,
|
||||
"description": null,
|
||||
"position": 1
|
||||
}
|
||||
],
|
||||
"addons": [],
|
||||
"bundles": []
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
: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 items with this value for the field ``active`` will be
|
||||
returned.
|
||||
:query integer category: If set to the ID of a category, only items within that category will be returned.
|
||||
:query boolean admission: If set to ``true`` or ``false``, only items with this value for the field ``admission``
|
||||
will be returned.
|
||||
:query string tax_rate: If set to a decimal value, only items with this tax rate will be returned.
|
||||
:query boolean free_price: If set to ``true`` or ``false``, only items with this value for the field ``free_price``
|
||||
will be returned.
|
||||
:query string ordering: Manually set the ordering of results. Valid fields to be used are ``id`` and ``position``.
|
||||
Default: ``position``
|
||||
: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)/items/(id)/
|
||||
|
||||
Returns information on one item, identified by its ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/items/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,
|
||||
"name": {"en": "Standard ticket"},
|
||||
"internal_name": "",
|
||||
"sales_channels": ["web"],
|
||||
"default_price": "23.00",
|
||||
"original_price": null,
|
||||
"category": null,
|
||||
"active": true,
|
||||
"description": null,
|
||||
"free_price": false,
|
||||
"tax_rate": "0.00",
|
||||
"tax_rule": 1,
|
||||
"admission": false,
|
||||
"position": 0,
|
||||
"picture": null,
|
||||
"available_from": null,
|
||||
"available_until": null,
|
||||
"hidden_if_available": null,
|
||||
"require_voucher": false,
|
||||
"hide_without_voucher": false,
|
||||
"allow_cancel": true,
|
||||
"generate_tickets": null,
|
||||
"allow_waitinglist": true,
|
||||
"show_quota_left": null,
|
||||
"min_per_order": null,
|
||||
"max_per_order": null,
|
||||
"checkin_attention": false,
|
||||
"has_variations": false,
|
||||
"require_approval": false,
|
||||
"require_bundling": false,
|
||||
"variations": [
|
||||
{
|
||||
"value": {"en": "Student"},
|
||||
"default_price": "10.00",
|
||||
"price": "10.00",
|
||||
"original_price": null,
|
||||
"active": true,
|
||||
"description": null,
|
||||
"position": 0
|
||||
},
|
||||
{
|
||||
"value": {"en": "Regular"},
|
||||
"default_price": null,
|
||||
"price": "23.00",
|
||||
"original_price": null,
|
||||
"active": true,
|
||||
"description": null,
|
||||
"position": 1
|
||||
}
|
||||
],
|
||||
"addons": [],
|
||||
"bundles": []
|
||||
}
|
||||
|
||||
: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 item 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)/items/
|
||||
|
||||
Creates a new item
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/items/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"name": {"en": "Standard ticket"},
|
||||
"internal_name": "",
|
||||
"sales_channels": ["web"],
|
||||
"default_price": "23.00",
|
||||
"original_price": null,
|
||||
"category": null,
|
||||
"active": true,
|
||||
"description": null,
|
||||
"free_price": false,
|
||||
"tax_rate": "0.00",
|
||||
"tax_rule": 1,
|
||||
"admission": false,
|
||||
"position": 0,
|
||||
"picture": null,
|
||||
"available_from": null,
|
||||
"available_until": null,
|
||||
"hidden_if_available": null,
|
||||
"require_voucher": false,
|
||||
"hide_without_voucher": false,
|
||||
"allow_cancel": true,
|
||||
"generate_tickets": null,
|
||||
"allow_waitinglist": true,
|
||||
"show_quota_left": null,
|
||||
"min_per_order": null,
|
||||
"max_per_order": null,
|
||||
"checkin_attention": false,
|
||||
"require_approval": false,
|
||||
"require_bundling": false,
|
||||
"variations": [
|
||||
{
|
||||
"value": {"en": "Student"},
|
||||
"default_price": "10.00",
|
||||
"price": "10.00",
|
||||
"original_price": null,
|
||||
"active": true,
|
||||
"description": null,
|
||||
"position": 0
|
||||
},
|
||||
{
|
||||
"value": {"en": "Regular"},
|
||||
"default_price": null,
|
||||
"price": "23.00",
|
||||
"original_price": null,
|
||||
"active": true,
|
||||
"description": null,
|
||||
"position": 1
|
||||
}
|
||||
],
|
||||
"addons": [],
|
||||
"bundles": []
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"name": {"en": "Standard ticket"},
|
||||
"internal_name": "",
|
||||
"sales_channels": ["web"],
|
||||
"default_price": "23.00",
|
||||
"original_price": null,
|
||||
"category": null,
|
||||
"active": true,
|
||||
"description": null,
|
||||
"free_price": false,
|
||||
"tax_rate": "0.00",
|
||||
"tax_rule": 1,
|
||||
"admission": false,
|
||||
"position": 0,
|
||||
"picture": null,
|
||||
"available_from": null,
|
||||
"available_until": null,
|
||||
"hidden_if_available": null,
|
||||
"require_voucher": false,
|
||||
"hide_without_voucher": false,
|
||||
"allow_cancel": true,
|
||||
"min_per_order": null,
|
||||
"max_per_order": null,
|
||||
"generate_tickets": null,
|
||||
"allow_waitinglist": true,
|
||||
"show_quota_left": null,
|
||||
"checkin_attention": false,
|
||||
"has_variations": true,
|
||||
"require_approval": false,
|
||||
"require_bundling": false,
|
||||
"variations": [
|
||||
{
|
||||
"value": {"en": "Student"},
|
||||
"default_price": "10.00",
|
||||
"price": "10.00",
|
||||
"original_price": null,
|
||||
"active": true,
|
||||
"description": null,
|
||||
"position": 0
|
||||
},
|
||||
{
|
||||
"value": {"en": "Regular"},
|
||||
"default_price": null,
|
||||
"price": "23.00",
|
||||
"original_price": null,
|
||||
"active": true,
|
||||
"description": null,
|
||||
"position": 1
|
||||
}
|
||||
],
|
||||
"addons": [],
|
||||
"bundles": []
|
||||
}
|
||||
|
||||
: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)/items/(id)/
|
||||
|
||||
Update an item. 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 ``has_variations``, ``variations`` and the ``addon`` field. If
|
||||
you need to update/delete variations or add-ons please use the nested dedicated endpoints.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
PATCH /api/v1/organizers/bigevents/events/sampleconf/items/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 94
|
||||
|
||||
{
|
||||
"name": {"en": "Ticket"},
|
||||
"default_price": "25.00"
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"name": {"en": "Ticket"},
|
||||
"internal_name": "",
|
||||
"sales_channels": ["web"],
|
||||
"default_price": "25.00",
|
||||
"original_price": null,
|
||||
"category": null,
|
||||
"active": true,
|
||||
"description": null,
|
||||
"free_price": false,
|
||||
"tax_rate": "0.00",
|
||||
"tax_rule": 1,
|
||||
"admission": false,
|
||||
"position": 0,
|
||||
"picture": null,
|
||||
"available_from": null,
|
||||
"available_until": null,
|
||||
"hidden_if_available": null,
|
||||
"require_voucher": false,
|
||||
"hide_without_voucher": false,
|
||||
"generate_tickets": null,
|
||||
"allow_waitinglist": true,
|
||||
"show_quota_left": null,
|
||||
"allow_cancel": true,
|
||||
"min_per_order": null,
|
||||
"max_per_order": null,
|
||||
"checkin_attention": false,
|
||||
"has_variations": true,
|
||||
"require_approval": false,
|
||||
"require_bundling": false,
|
||||
"variations": [
|
||||
{
|
||||
"value": {"en": "Student"},
|
||||
"default_price": "10.00",
|
||||
"price": "10.00",
|
||||
"original_price": null,
|
||||
"active": true,
|
||||
"description": null,
|
||||
"position": 0
|
||||
},
|
||||
{
|
||||
"value": {"en": "Regular"},
|
||||
"default_price": null,
|
||||
"price": "23.00",
|
||||
"original_price": null,
|
||||
"active": true,
|
||||
"description": null,
|
||||
"position": 1
|
||||
}
|
||||
],
|
||||
"addons": [],
|
||||
"bundles": []
|
||||
}
|
||||
|
||||
: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 item to modify
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The item 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)/items/(id)/
|
||||
|
||||
Delete an item.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/events/sampleconf/items/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 item 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.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,92 +0,0 @@
|
||||
Organizers
|
||||
==========
|
||||
|
||||
Resource description
|
||||
--------------------
|
||||
|
||||
An organizers is an entity running any number of events. In pretix, every event belongs to one
|
||||
organizer and various settings, such as teams and permissions, are managed on organizer level.
|
||||
|
||||
The organizer resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
name string The organizer's full name, i.e. the name of an
|
||||
organization or company.
|
||||
slug string A short form of the name, used e.g. in URLs.
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
.. http:get:: /api/v1/organizers/
|
||||
|
||||
Returns a list of all organizers the authenticated user/token has access to.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/ 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": [
|
||||
{
|
||||
"name": "Big Events LLC",
|
||||
"slug": "Big Events",
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query 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 ``slug`` and
|
||||
``name``. Default: ``slug``.
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/
|
||||
|
||||
Returns information on one organizer account, identified by its slug.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/ 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
|
||||
|
||||
{
|
||||
"name": "Big Events LLC",
|
||||
"slug": "Big Events",
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to view it.
|
||||
@@ -1,233 +0,0 @@
|
||||
Question options
|
||||
================
|
||||
|
||||
Resource description
|
||||
--------------------
|
||||
|
||||
Questions of type "choice" or "multiple choice" can have different options attached.
|
||||
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
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
.. versionchanged:: 1.12
|
||||
|
||||
This resource has been added.
|
||||
|
||||
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.
|
||||
@@ -1,412 +0,0 @@
|
||||
.. spelling:: checkin
|
||||
|
||||
.. _rest-questions:
|
||||
|
||||
Questions
|
||||
=========
|
||||
|
||||
Resource description
|
||||
--------------------
|
||||
|
||||
Questions define additional fields that need to be filled out by customers during checkout.
|
||||
The question resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Internal ID of the question
|
||||
question multi-lingual string The field label shown to the customer
|
||||
type string The expected type of answer. 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)
|
||||
required boolean If ``true``, the question needs to be filled out.
|
||||
position integer An integer, used for sorting
|
||||
items list of integers List of item IDs this question is assigned to.
|
||||
identifier string An arbitrary string that can be used for matching with
|
||||
other sources.
|
||||
ask_during_checkin boolean If ``true``, this question will not be asked while
|
||||
buying the ticket, but will show up when redeeming
|
||||
the ticket instead.
|
||||
hidden boolean If ``true``, the question will only be shown in the
|
||||
backend.
|
||||
options list of objects In case of question type ``C`` or ``M``, this lists the
|
||||
available objects. Only writable during creation,
|
||||
use separate endpoint 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
|
||||
dependency_question integer Internal ID of a different question. The current
|
||||
question will only be shown if the question given in
|
||||
this attribute is set to the value given in
|
||||
``dependency_value``. This cannot be combined with
|
||||
``ask_during_checkin``.
|
||||
dependency_values list of strings If ``dependency_question`` is set to a boolean
|
||||
question, this should be ``["True"]`` or ``["False"]``.
|
||||
Otherwise, it should be a list of ``identifier`` values
|
||||
of question options.
|
||||
dependency_value string An old version of ``dependency_values`` that only allows
|
||||
for one value. **Deprecated.**
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
.. versionchanged:: 1.12
|
||||
|
||||
The values ``D``, ``H``, and ``W`` for the field ``type`` are now allowed and the ``ask_during_checkin`` field has
|
||||
been added.
|
||||
|
||||
.. versionchanged:: 1.14
|
||||
|
||||
Write methods have been added. The attribute ``identifier`` has been added to both the resource itself and the
|
||||
options resource. The ``position`` attribute has been added to the options resource.
|
||||
|
||||
.. versionchanged:: 2.7
|
||||
|
||||
The attribute ``hidden`` and the question type ``CC`` have been added.
|
||||
|
||||
.. versionchanged:: 3.0
|
||||
|
||||
The attribute ``dependency_values`` has been added.
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
.. versionchanged:: 1.15
|
||||
|
||||
The questions endpoint has been extended by the filter queries ``ask_during_checkin``, ``requred``, and
|
||||
``identifier``.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/questions/
|
||||
|
||||
Returns a list of all questions within a given event.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/questions/ 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,
|
||||
"question": {"en": "T-Shirt size"},
|
||||
"type": "C",
|
||||
"required": false,
|
||||
"items": [1, 2],
|
||||
"position": 1,
|
||||
"identifier": "WY3TP9SL",
|
||||
"ask_during_checkin": false,
|
||||
"hidden": false,
|
||||
"dependency_question": null,
|
||||
"dependency_value": null,
|
||||
"dependency_values": [],
|
||||
"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"}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
: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)/questions/(id)/
|
||||
|
||||
Returns information on one question, identified by its ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/questions/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,
|
||||
"question": {"en": "T-Shirt size"},
|
||||
"type": "C",
|
||||
"required": false,
|
||||
"items": [1, 2],
|
||||
"position": 1,
|
||||
"identifier": "WY3TP9SL",
|
||||
"ask_during_checkin": false,
|
||||
"hidden": false,
|
||||
"dependency_question": null,
|
||||
"dependency_value": null,
|
||||
"dependency_values": [],
|
||||
"options": [
|
||||
{
|
||||
"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"}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
: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)/questions/
|
||||
|
||||
Creates a new question
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/questions/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"question": {"en": "T-Shirt size"},
|
||||
"type": "C",
|
||||
"required": false,
|
||||
"items": [1, 2],
|
||||
"position": 1,
|
||||
"ask_during_checkin": false,
|
||||
"hidden": false,
|
||||
"dependency_question": null,
|
||||
"dependency_values": [],
|
||||
"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,
|
||||
"question": {"en": "T-Shirt size"},
|
||||
"type": "C",
|
||||
"required": false,
|
||||
"items": [1, 2],
|
||||
"position": 1,
|
||||
"identifier": "WY3TP9SL",
|
||||
"ask_during_checkin": false,
|
||||
"hidden": false,
|
||||
"dependency_question": null,
|
||||
"dependency_value": null,
|
||||
"dependency_values": [],
|
||||
"options": [
|
||||
{
|
||||
"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"}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
: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)/questions/(id)/
|
||||
|
||||
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.
|
||||
|
||||
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/items/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 94
|
||||
|
||||
{
|
||||
"position": 2
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"question": {"en": "T-Shirt size"},
|
||||
"type": "C",
|
||||
"required": false,
|
||||
"items": [1, 2],
|
||||
"position": 2,
|
||||
"identifier": "WY3TP9SL",
|
||||
"ask_during_checkin": false,
|
||||
"hidden": false,
|
||||
"dependency_question": null,
|
||||
"dependency_value": null,
|
||||
"dependency_values": [],
|
||||
"options": [
|
||||
{
|
||||
"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"}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
: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 item 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)/
|
||||
|
||||
Delete a question.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/events/sampleconf/items/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 item 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.
|
||||
@@ -1,298 +0,0 @@
|
||||
.. _rest-quotas:
|
||||
|
||||
Quotas
|
||||
======
|
||||
|
||||
Resource description
|
||||
--------------------
|
||||
|
||||
Quotas define how many times an item can be sold.
|
||||
The quota resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Internal ID of the quota
|
||||
name string The internal name of the quota
|
||||
size integer The size of the quota or ``null`` for unlimited
|
||||
items list of integers List of item IDs this quota acts on.
|
||||
variations list of integers List of item variation IDs this quota acts on.
|
||||
subevent integer ID of the date inside an event series this quota belongs to (or ``null``).
|
||||
close_when_sold_out boolean If ``true``, the quota will "close" as soon as it is
|
||||
sold out once. Even if tickets become available again,
|
||||
they will not be sold unless the quota is set to open
|
||||
again.
|
||||
closed boolean Whether the quota is currently closed (see above
|
||||
field).
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
.. versionchanged:: 1.10
|
||||
|
||||
The write operations ``POST``, ``PATCH``, ``PUT``, and ``DELETE`` have been added.
|
||||
|
||||
.. versionchanged:: 3.0
|
||||
|
||||
The attributes ``close_when_sold_out`` and ``closed`` have been added.
|
||||
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/quotas/
|
||||
|
||||
Returns a list of all quotas within a given event.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/quotas/ 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,
|
||||
"name": "Ticket Quota",
|
||||
"size": 200,
|
||||
"items": [1, 2],
|
||||
"variations": [1, 4, 5, 7],
|
||||
"subevent": null,
|
||||
"close_when_sold_out": false,
|
||||
"closed": false
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
: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 integer subevent: Only return quotas of the sub-event with the given ID
|
||||
: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)/quotas/(id)/
|
||||
|
||||
Returns information on one quota, identified by its ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/quotas/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,
|
||||
"name": "Ticket Quota",
|
||||
"size": 200,
|
||||
"items": [1, 2],
|
||||
"variations": [1, 4, 5, 7],
|
||||
"subevent": null,
|
||||
"close_when_sold_out": false,
|
||||
"closed": false
|
||||
}
|
||||
|
||||
: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 quota 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)/quotas/
|
||||
|
||||
Creates a new quota
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/quotas/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": "Ticket Quota",
|
||||
"size": 200,
|
||||
"items": [1, 2],
|
||||
"variations": [1, 4, 5, 7],
|
||||
"subevent": null,
|
||||
"close_when_sold_out": false,
|
||||
"closed": false
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Ticket Quota",
|
||||
"size": 200,
|
||||
"items": [1, 2],
|
||||
"variations": [1, 4, 5, 7],
|
||||
"subevent": null,
|
||||
"close_when_sold_out": false,
|
||||
"closed": false
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer of the event/item to create a quota for
|
||||
:param event: The ``slug`` field of the event to create a quota for
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The quota 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)/quotas/(id)/
|
||||
|
||||
Update a quota. 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/quotas/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 94
|
||||
|
||||
{
|
||||
"name": "New Ticket Quota",
|
||||
"size": 100,
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 2,
|
||||
"name": "New Ticket Quota",
|
||||
"size": 100,
|
||||
"items": [
|
||||
1,
|
||||
2
|
||||
],
|
||||
"variations": [
|
||||
1,
|
||||
2
|
||||
],
|
||||
"subevent": null,
|
||||
"close_when_sold_out": false,
|
||||
"closed": false
|
||||
}
|
||||
|
||||
: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 quota rule to modify
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The quota 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)/quota/(id)/
|
||||
|
||||
Delete a quota. Note that if you delete a quota the items the quota acts on might no longer be available for sale.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/events/sampleconf/quotas/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 quotas 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.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/quotas/(id)/availability/
|
||||
|
||||
Returns availability information on one quota, identified by its ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/quotas/1/availability/ 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
|
||||
|
||||
{
|
||||
"available": true,
|
||||
"available_number": 419,
|
||||
"total_size": 1000,
|
||||
"pending_orders": 25,
|
||||
"paid_orders": 423,
|
||||
"cart_positions": 7,
|
||||
"blocking_vouchers": 126,
|
||||
"waiting_list": 0
|
||||
}
|
||||
|
||||
Note that ``total_size`` and ``available_number`` are ``null`` in case of unlimited quotas.
|
||||
|
||||
: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 quota 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.
|
||||
@@ -1,209 +0,0 @@
|
||||
.. _`rest-seatingplans`:
|
||||
|
||||
Seating plans
|
||||
=============
|
||||
|
||||
Resource description
|
||||
--------------------
|
||||
|
||||
The seating plan resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Internal ID of the plan
|
||||
name string Human-readable name of the plan
|
||||
layout object JSON representation of the seating plan. These
|
||||
representations follow a JSON schema that currently
|
||||
still evolves. The version in use can be found `here`_.
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
.. versionchanged:: 3.0
|
||||
|
||||
This endpoint has been added.
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/seatingplans/
|
||||
|
||||
Returns a list of all seating plans within a given organizer.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/seatingplans/ 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": 2,
|
||||
"name": "Main plan",
|
||||
"layout": { … }
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/seatingplans/(id)/
|
||||
|
||||
Returns information on one plan, identified by its ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/seatingplans/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": 2,
|
||||
"name": "Main plan",
|
||||
"layout": { … }
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param id: The ``id`` field of the seating plan to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/seatingplans/
|
||||
|
||||
Creates a new seating plan
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/seatingplans/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": "Main plan",
|
||||
"layout": { … }
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Main plan",
|
||||
"layout": { … }
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to create a seating plan for
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The seating plan could not be created due to invalid submitted data.
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to create this resource.
|
||||
|
||||
.. http:patch:: /api/v1/organizers/(organizer)/seatingplans/(id)/
|
||||
|
||||
Update a plan. 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. **You can not change a plan while it is in use for
|
||||
any events.**
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
PATCH /api/v1/organizers/bigevents/seatingplans/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 94
|
||||
|
||||
{
|
||||
"name": "Old plan"
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Old plan",
|
||||
"layout": { … }
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param id: The ``id`` field of the plan to modify
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The plan could not be modified due to invalid submitted data
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to change this resource **or** the plan is currently in use.
|
||||
|
||||
.. http:delete:: /api/v1/organizers/(organizer)/seatingplans/(id)/
|
||||
|
||||
Delete a plan. You can not delete plans which are currently in use by any events.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/seatingplans/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 id: The ``id`` field of the plan to delete
|
||||
:statuscode 204: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to delete this resource **or** the plan is currently in use.
|
||||
|
||||
|
||||
.. _here: https://github.com/pretix/pretix/blob/master/src/pretix/static/seating/seating-plan.schema.json
|
||||
@@ -1,416 +0,0 @@
|
||||
.. _rest-subevents:
|
||||
|
||||
Event series dates / Sub-events
|
||||
===============================
|
||||
|
||||
Resource description
|
||||
--------------------
|
||||
|
||||
Events can represent whole event series if the ``has_subevents`` property of the event is active.
|
||||
In this case, many other resources are additionally connected to an event date (also called sub-event).
|
||||
The sub-event resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Internal ID of the sub-event
|
||||
name multi-lingual string The sub-event's full name
|
||||
event string The slug of the parent event
|
||||
active boolean If ``true``, the sub-event ticket shop is publicly
|
||||
available.
|
||||
is_public boolean If ``true``, the sub-event ticket shop is publicly
|
||||
shown in lists.
|
||||
date_from datetime The sub-event's start date
|
||||
date_to datetime The sub-event's end date (or ``null``)
|
||||
date_admission datetime The sub-event's admission date (or ``null``)
|
||||
presale_start datetime The sub-date at which the ticket shop opens (or ``null``)
|
||||
presale_end datetime The sub-date at which the ticket shop closes (or ``null``)
|
||||
location multi-lingual string The sub-event location (or ``null``)
|
||||
item_price_overrides list of objects List of items for which this sub-event overrides the
|
||||
default price
|
||||
├ item integer The internal item ID
|
||||
└ price money (string) The price or ``null`` for the default price
|
||||
variation_price_overrides list of objects List of variations for which this sub-event overrides
|
||||
the default price
|
||||
├ variation integer The internal variation ID
|
||||
└ price money (string) The price or ``null`` for the default price
|
||||
meta_data object Values set for organizer-specific meta data parameters.
|
||||
seating_plan integer If reserved seating is in use, the ID of a seating
|
||||
plan. Otherwise ``null``.
|
||||
seat_category_mapping object An object mapping categories of the seating plan
|
||||
(strings) to items in the event (integers or ``null``).
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
.. versionchanged:: 1.7
|
||||
|
||||
The ``meta_data`` field has been added.
|
||||
|
||||
.. versionchanged:: 2.1
|
||||
|
||||
The ``event`` field has been added, together with filters on the list of dates and an organizer-level list.
|
||||
|
||||
.. versionchanged:: 2.6
|
||||
The write operations ``POST``, ``PATCH``, ``PUT``, and ``DELETE`` have been added.
|
||||
|
||||
.. versionchanged:: 2.7
|
||||
|
||||
The attribute ``is_public`` has been added.
|
||||
|
||||
.. versionchanged:: 3.0
|
||||
|
||||
The attributes ``seating_plan`` and ``seat_category_mapping`` have been added.
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/subevents/
|
||||
|
||||
Returns a list of all sub-events of an event.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/subevents/ 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,
|
||||
"name": {"en": "First Sample Conference"},
|
||||
"event": "sampleconf",
|
||||
"active": false,
|
||||
"is_public": true,
|
||||
"date_from": "2017-12-27T10:00:00Z",
|
||||
"date_to": null,
|
||||
"date_admission": null,
|
||||
"presale_start": null,
|
||||
"presale_end": null,
|
||||
"seating_plan": null,
|
||||
"seat_category_mapping": {},
|
||||
"location": null,
|
||||
"item_price_overrides": [
|
||||
{
|
||||
"item": 2,
|
||||
"price": "12.00"
|
||||
}
|
||||
],
|
||||
"variation_price_overrides": [],
|
||||
"meta_data": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query page: The page number in case of a multi-page result set, default is 1
|
||||
:query active: If set to ``true``/``false``, only events with a matching value of ``active`` are returned.
|
||||
:query is_future: If set to ``true`` (``false``), only events that happen currently or in the future are (not) returned.
|
||||
:query is_past: If set to ``true`` (``false``), only events that are over are (not) returned.
|
||||
:query ends_after: If set to a date and time, only events that happen during of after the given time are returned.
|
||||
:param organizer: The ``slug`` field of a valid organizer
|
||||
:param event: The ``slug`` field of the main event
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to view it.
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/subevents/
|
||||
|
||||
Creates a new subevent.
|
||||
|
||||
Permission required: "Can create events"
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/subevents/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": {"en": "First Sample Conference"},
|
||||
"active": false,
|
||||
"is_public": true,
|
||||
"date_from": "2017-12-27T10:00:00Z",
|
||||
"date_to": null,
|
||||
"date_admission": null,
|
||||
"presale_start": null,
|
||||
"presale_end": null,
|
||||
"location": null,
|
||||
"seating_plan": null,
|
||||
"seat_category_mapping": {},
|
||||
"item_price_overrides": [
|
||||
{
|
||||
"item": 2,
|
||||
"price": "12.00"
|
||||
}
|
||||
],
|
||||
"variation_price_overrides": [],
|
||||
"meta_data": {}
|
||||
}
|
||||
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"name": {"en": "First Sample Conference"},
|
||||
"active": false,
|
||||
"is_public": true,
|
||||
"date_from": "2017-12-27T10:00:00Z",
|
||||
"date_to": null,
|
||||
"date_admission": null,
|
||||
"presale_start": null,
|
||||
"presale_end": null,
|
||||
"location": null,
|
||||
"seating_plan": null,
|
||||
"seat_category_mapping": {},
|
||||
"item_price_overrides": [
|
||||
{
|
||||
"item": 2,
|
||||
"price": "12.00"
|
||||
}
|
||||
],
|
||||
"variation_price_overrides": [],
|
||||
"meta_data": {}
|
||||
}
|
||||
|
||||
|
||||
:param organizer: The ``slug`` field of a valid organizer
|
||||
:param event: The ``slug`` field of the main event
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The sub-event could not be created due to invalid submitted data.
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to create this resource.
|
||||
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/subevents/(id)/
|
||||
|
||||
Returns information on one sub-event, identified by its ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/subevents/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,
|
||||
"name": {"en": "First Sample Conference"},
|
||||
"event": "sampleconf",
|
||||
"active": false,
|
||||
"is_public": true,
|
||||
"date_from": "2017-12-27T10:00:00Z",
|
||||
"date_to": null,
|
||||
"date_admission": null,
|
||||
"presale_start": null,
|
||||
"presale_end": null,
|
||||
"location": null,
|
||||
"seating_plan": null,
|
||||
"seat_category_mapping": {},
|
||||
"item_price_overrides": [
|
||||
{
|
||||
"item": 2,
|
||||
"price": "12.00"
|
||||
}
|
||||
],
|
||||
"variation_price_overrides": [],
|
||||
"meta_data": {}
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of a valid organizer
|
||||
:param event: The ``slug`` field of the main event
|
||||
:param id: The ``id`` field of the sub-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 it.
|
||||
|
||||
.. http:patch:: /api/v1/organizers/(organizer)/events/(event)/subevents/(id)/
|
||||
|
||||
Updates a sub-event, identified by its ID. 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.
|
||||
|
||||
Permission required: "Can change event settings"
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
PATCH /api/v1/organizers/bigevents/events/sampleconf/subevents/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": {"en": "New Subevent Name"},
|
||||
"item_price_overrides": [
|
||||
{
|
||||
"item": 2,
|
||||
"price": "23.42"
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"name": {"en": "New Subevent Name"},
|
||||
"event": "sampleconf",
|
||||
"active": false,
|
||||
"is_public": true,
|
||||
"date_from": "2017-12-27T10:00:00Z",
|
||||
"date_to": null,
|
||||
"date_admission": null,
|
||||
"presale_start": null,
|
||||
"presale_end": null,
|
||||
"location": null,
|
||||
"seating_plan": null,
|
||||
"seat_category_mapping": {},
|
||||
"item_price_overrides": [
|
||||
{
|
||||
"item": 2,
|
||||
"price": "23.42"
|
||||
}
|
||||
],
|
||||
"variation_price_overrides": [],
|
||||
"meta_data": {}
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of a valid organizer
|
||||
:param event: The ``slug`` field of the main event
|
||||
:param id: The ``id`` field of the sub-event to update
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The sub-event could not be created due to invalid submitted data.
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/sub-event does not exist **or** you have no permission to update this resource.
|
||||
|
||||
.. http:delete:: /api/v1/organizers/(organizer)/events/(event)/subevents/(id)/
|
||||
|
||||
Delete a sub-event. Note that events with orders cannot be deleted to ensure data integrity.
|
||||
|
||||
Permission required: "Can change event settings"
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/events/sampleconf/subevents/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 a valid organizer
|
||||
:param event: The ``slug`` field of the main event
|
||||
:param id: The ``id`` field of the sub-event to delete
|
||||
:statuscode 204: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/sub-event does not exist **or** you have no permission to delete this resource.
|
||||
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/subevents/
|
||||
|
||||
Returns a list of all sub-events of any event series you have access to within an organizer account.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/subevents/ 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,
|
||||
"name": {"en": "First Sample Conference"},
|
||||
"event": "sampleconf",
|
||||
"active": false,
|
||||
"is_public": true,
|
||||
"date_from": "2017-12-27T10:00:00Z",
|
||||
"date_to": null,
|
||||
"date_admission": null,
|
||||
"presale_start": null,
|
||||
"presale_end": null,
|
||||
"location": null,
|
||||
"seating_plan": null,
|
||||
"seat_category_mapping": {},
|
||||
"item_price_overrides": [
|
||||
{
|
||||
"item": 2,
|
||||
"price": "12.00"
|
||||
}
|
||||
],
|
||||
"variation_price_overrides": [],
|
||||
"meta_data": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query page: The page number in case of a multi-page result set, default is 1
|
||||
:query active: If set to ``true``/``false``, only events with a matching value of ``active`` are returned.
|
||||
:query event__live: If set to ``true``/``false``, only events with a matching value of ``live`` on the parent event are returned.
|
||||
:query is_future: If set to ``true`` (``false``), only events that happen currently or in the future are (not) returned.
|
||||
:query is_past: If set to ``true`` (``false``), only events that are over are (not) returned.
|
||||
:query ends_after: If set to a date and time, only events that happen during of after the given time are returned.
|
||||
:param organizer: The ``slug`` field of a valid organizer
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to view it.
|
||||
@@ -1,237 +0,0 @@
|
||||
.. _rest-taxrules:
|
||||
|
||||
Tax rules
|
||||
=========
|
||||
|
||||
Resource description
|
||||
--------------------
|
||||
|
||||
Tax rules specify how tax should be calculated for specific products. Custom taxation rule sets are currently to
|
||||
available via the API.
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Internal ID of the tax rule
|
||||
name multi-lingual string The tax rules' name
|
||||
rate decimal (string) Tax rate in percent
|
||||
price_includes_tax boolean If ``true`` (default), tax is assumed to be included in
|
||||
the specified product price
|
||||
eu_reverse_charge boolean If ``true``, EU reverse charge rules are applied
|
||||
home_country string Merchant country (required for reverse charge), can be
|
||||
``null`` or empty string
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
.. versionchanged:: 1.7
|
||||
|
||||
This resource has been added.
|
||||
|
||||
.. versionchanged:: 1.9
|
||||
|
||||
The write operations ``POST``, ``PATCH``, ``PUT``, and ``DELETE`` have been added.
|
||||
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/taxrules/
|
||||
|
||||
Returns a list of all tax rules configured for an event.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/taxrules/ 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,
|
||||
"name": {"en": "VAT"},
|
||||
"rate": "19.00",
|
||||
"price_includes_tax": true,
|
||||
"eu_reverse_charge": false,
|
||||
"home_country": "DE"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query page: The page number in case of a multi-page result set, default is 1
|
||||
:param organizer: The ``slug`` field of a valid organizer
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to view it.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/taxrules/(id)/
|
||||
|
||||
Returns information on one tax rule, identified by its ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/taxrules/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,
|
||||
"name": {"en": "VAT"},
|
||||
"rate": "19.00",
|
||||
"price_includes_tax": true,
|
||||
"eu_reverse_charge": false,
|
||||
"home_country": "DE"
|
||||
}
|
||||
|
||||
: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 tax rule to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event/rule does not exist **or** you have no permission to view it.
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/taxrules/
|
||||
|
||||
Create a new tax rule.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/taxrules/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 166
|
||||
|
||||
{
|
||||
"name": {"en": "VAT"},
|
||||
"rate": "19.00",
|
||||
"price_includes_tax": true,
|
||||
"eu_reverse_charge": false,
|
||||
"home_country": "DE"
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"name": {"en": "VAT"},
|
||||
"rate": "19.00",
|
||||
"price_includes_tax": true,
|
||||
"eu_reverse_charge": false,
|
||||
"home_country": "DE"
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to create a tax rule for
|
||||
:param event: The ``slug`` field of the event to create a tax rule for
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The tax rule 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 tax rules.
|
||||
|
||||
|
||||
.. http:patch:: /api/v1/organizers/(organizer)/events/(event)/taxrules/(id)/
|
||||
|
||||
Update a tax rule. 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.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
PATCH /api/v1/organizers/bigevents/events/sampleconf/taxrules/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 34
|
||||
|
||||
{
|
||||
"rate": "20.00",
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: text/javascript
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"name": {"en": "VAT"},
|
||||
"rate": "20.00",
|
||||
"price_includes_tax": true,
|
||||
"eu_reverse_charge": false,
|
||||
"home_country": "DE"
|
||||
}
|
||||
|
||||
: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 tax rule to modify
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The tax rule could not be modified due to invalid submitted data.
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event/rule does not exist **or** you have no permission to change it.
|
||||
|
||||
|
||||
.. http:delete:: /api/v1/organizers/(organizer)/events/(event)/taxrules/(id)/
|
||||
|
||||
Delete a tax rule. Note that tax rules can only be deleted if they are not in use for any products, settings
|
||||
or orders. If you cannot delete a tax rule, this method will return a ``403`` status code and you can only
|
||||
discontinue using it everywhere else.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/events/sampleconf/taxrules/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 tax rule to delete
|
||||
:statuscode 204: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event/rule does not exist **or** you have no permission to change it **or** this tax rule cannot be deleted since it is currently in use.
|
||||
@@ -1,391 +0,0 @@
|
||||
Vouchers
|
||||
========
|
||||
|
||||
Resource description
|
||||
--------------------
|
||||
|
||||
The voucher resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Internal ID of the voucher
|
||||
code string The voucher code that is required to redeem the voucher
|
||||
max_usages integer The maximum number of times this voucher can be
|
||||
redeemed (default: 1).
|
||||
redeemed integer The number of times this voucher already has been
|
||||
redeemed.
|
||||
valid_until datetime The voucher expiration date (or ``null``).
|
||||
block_quota boolean If ``true``, quota is blocked for this voucher.
|
||||
allow_ignore_quota boolean If ``true``, this voucher can be redeemed even if a
|
||||
product is sold out and even if quota is not blocked
|
||||
for this voucher.
|
||||
price_mode string Determines how this voucher affects product prices.
|
||||
Possible values:
|
||||
|
||||
* ``none`` – No effect on price
|
||||
* ``set`` – The product price is set to the given ``value``
|
||||
* ``subtract`` – The product price is determined by the original price *minus* the given ``value``
|
||||
* ``percent`` – The product price is determined by the original price reduced by the percentage given in ``value``
|
||||
value decimal (string) The value (see ``price_mode``)
|
||||
item integer An ID of an item this voucher is restricted to (or ``null``)
|
||||
variation integer An ID of a variation this voucher is restricted to (or ``null``)
|
||||
quota integer An ID of a quota this voucher is restricted to (or
|
||||
``null``). This is an exclusive alternative to
|
||||
``item`` and ``variation``: A voucher can be
|
||||
attached either to a specific product or to all
|
||||
products within one quota or it can be available
|
||||
for all items without restriction.
|
||||
tag string A string that is used for grouping vouchers
|
||||
comment string An internal comment on the voucher
|
||||
subevent integer ID of the date inside an event series this voucher belongs to (or ``null``).
|
||||
show_hidden_items boolean Only if set to ``true``, this voucher allows to buy products with the property ``hide_without_voucher``. Defaults to ``true``.
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
|
||||
.. versionchanged:: 1.9
|
||||
|
||||
The write operations ``POST``, ``PATCH``, ``PUT``, and ``DELETE`` have been added.
|
||||
|
||||
.. versionchanged:: 3.0
|
||||
|
||||
The attribute ``show_hidden_items`` has been added.
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/vouchers/
|
||||
|
||||
Returns a list of all vouchers within a given event.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/vouchers/ 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,
|
||||
"code": "43K6LKM37FBVR2YG",
|
||||
"max_usages": 1,
|
||||
"redeemed": 0,
|
||||
"valid_until": null,
|
||||
"block_quota": false,
|
||||
"allow_ignore_quota": false,
|
||||
"price_mode": "set",
|
||||
"value": "12.00",
|
||||
"item": 1,
|
||||
"variation": null,
|
||||
"quota": null,
|
||||
"tag": "testvoucher",
|
||||
"comment": "",
|
||||
"subevent": null
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
:query string code: Only show the voucher with the given voucher code.
|
||||
:query integer max_usages: Only show vouchers with the given maximal number of usages.
|
||||
:query integer redeemed: Only show vouchers with the given number of redemptions. Note that this doesn't tell you if
|
||||
the voucher can still be redeemed, as this also depends on ``max_usages``. See the
|
||||
``active`` query parameter as well.
|
||||
:query boolean block_quota: If set to ``true`` or ``false``, only vouchers with this value in the field
|
||||
``block_quota`` will be shown.
|
||||
:query boolean allow_ignore_quota: If set to ``true`` or ``false``, only vouchers with this value in the field
|
||||
``allow_ignore_quota`` will be shown.
|
||||
:query string price_mode: If set, only vouchers with this value in the field ``price_mode`` will be shown (see
|
||||
above).
|
||||
:query string value: If set, only vouchers with this value in the field ``value`` will be shown.
|
||||
:query integer item: If set, only vouchers attached to the item with the given ID will be shown.
|
||||
:query integer variation: If set, only vouchers attached to the variation with the given ID will be shown.
|
||||
:query integer quota: If set, only vouchers attached to the quota with the given ID will be shown.
|
||||
:query string tag: If set, only vouchers with the given tag will be shown.
|
||||
:query integer subevent: Only return vouchers of the sub-event with the given ID
|
||||
:query string ordering: Manually set the ordering of results. Valid fields to be used are ``id``, ``code``,
|
||||
``max_usages``, ``valid_until``, and ``value``. Default: ``id``
|
||||
: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)/vouchers/(id)/
|
||||
|
||||
Returns information on one voucher, identified by its internal ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/vouchers/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,
|
||||
"code": "43K6LKM37FBVR2YG",
|
||||
"max_usages": 1,
|
||||
"redeemed": 0,
|
||||
"valid_until": null,
|
||||
"block_quota": false,
|
||||
"allow_ignore_quota": false,
|
||||
"price_mode": "set",
|
||||
"value": "12.00",
|
||||
"item": 1,
|
||||
"variation": null,
|
||||
"quota": null,
|
||||
"tag": "testvoucher",
|
||||
"comment": "",
|
||||
"subevent": null
|
||||
}
|
||||
|
||||
: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 voucher 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)/vouchers/
|
||||
|
||||
Create a new voucher.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/vouchers/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 408
|
||||
|
||||
{
|
||||
"code": "43K6LKM37FBVR2YG",
|
||||
"max_usages": 1,
|
||||
"valid_until": null,
|
||||
"block_quota": false,
|
||||
"allow_ignore_quota": false,
|
||||
"price_mode": "set",
|
||||
"value": "12.00",
|
||||
"item": 1,
|
||||
"variation": null,
|
||||
"quota": null,
|
||||
"tag": "testvoucher",
|
||||
"comment": "",
|
||||
"subevent": null
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"code": "43K6LKM37FBVR2YG",
|
||||
"max_usages": 1,
|
||||
"redeemed": 0,
|
||||
"valid_until": null,
|
||||
"block_quota": false,
|
||||
"allow_ignore_quota": false,
|
||||
"price_mode": "set",
|
||||
"value": "12.00",
|
||||
"item": 1,
|
||||
"variation": null,
|
||||
"quota": null,
|
||||
"tag": "testvoucher",
|
||||
"comment": "",
|
||||
"subevent": null
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to create a voucher for
|
||||
:param event: The ``slug`` field of the event to create a voucher for
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The voucher 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.
|
||||
:statuscode 409: The server was unable to acquire a lock and could not process your request. You can try again after a short waiting period.
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/vouchers/batch_create/
|
||||
|
||||
Creates multiple new vouchers atomically.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/vouchers/batch_create/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 408
|
||||
|
||||
[
|
||||
{
|
||||
"code": "43K6LKM37FBVR2YG",
|
||||
"max_usages": 1,
|
||||
"valid_until": null,
|
||||
"block_quota": false,
|
||||
"allow_ignore_quota": false,
|
||||
"price_mode": "set",
|
||||
"value": "12.00",
|
||||
"item": 1,
|
||||
"variation": null,
|
||||
"quota": null,
|
||||
"tag": "testvoucher",
|
||||
"comment": "",
|
||||
"subevent": null
|
||||
},
|
||||
{
|
||||
"code": "ASDKLJCYXCASDASD",
|
||||
"max_usages": 1,
|
||||
"valid_until": null,
|
||||
"block_quota": false,
|
||||
"allow_ignore_quota": false,
|
||||
"price_mode": "set",
|
||||
"value": "12.00",
|
||||
"item": 1,
|
||||
"variation": null,
|
||||
"quota": null,
|
||||
"tag": "testvoucher",
|
||||
"comment": "",
|
||||
"subevent": null
|
||||
},
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"code": "43K6LKM37FBVR2YG",
|
||||
…
|
||||
}, …
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to create a vouchers for
|
||||
:param event: The ``slug`` field of the event to create a vouchers for
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The vouchers 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.
|
||||
:statuscode 409: The server was unable to acquire a lock and could not process your request. You can try again after a short waiting period.
|
||||
|
||||
.. http:patch:: /api/v1/organizers/(organizer)/events/(event)/vouchers/(id)/
|
||||
|
||||
Update a voucher. 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`` and ``redeemed`` fields.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
PATCH /api/v1/organizers/bigevents/events/sampleconf/vouchers/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 408
|
||||
|
||||
{
|
||||
"price_mode": "set",
|
||||
"value": "24.00"
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"code": "43K6LKM37FBVR2YG",
|
||||
"max_usages": 1,
|
||||
"redeemed": 0,
|
||||
"valid_until": null,
|
||||
"block_quota": false,
|
||||
"allow_ignore_quota": false,
|
||||
"price_mode": "set",
|
||||
"value": "24.00",
|
||||
"item": 1,
|
||||
"variation": null,
|
||||
"quota": null,
|
||||
"tag": "testvoucher",
|
||||
"comment": "",
|
||||
"subevent": null
|
||||
}
|
||||
|
||||
: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 voucher to modify
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The voucher 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.
|
||||
:statuscode 409: The server was unable to acquire a lock and could not process your request. You can try again after a short waiting period.
|
||||
|
||||
.. http:delete:: /api/v1/organizers/(organizer)/events/(event)/vouchers/(id)/
|
||||
|
||||
Delete a voucher. Note that you cannot delete a voucher if it already has been redeemed.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/events/sampleconf/vouchers/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 voucher 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.
|
||||
@@ -1,287 +0,0 @@
|
||||
Waiting list entries
|
||||
====================
|
||||
|
||||
Resource description
|
||||
--------------------
|
||||
|
||||
The waiting list entry resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Internal ID of the waiting list entry
|
||||
created datetime Creation date of the waiting list entry
|
||||
email string Email address of the user on the waiting list
|
||||
voucher integer Internal ID of the voucher sent to this user. If
|
||||
this field is set, the user has been sent a voucher
|
||||
and is no longer waiting. If it is ``null``, the
|
||||
user is still waiting.
|
||||
item integer An ID of an item the user is waiting to be available
|
||||
again
|
||||
variation integer An ID of a variation the user is waiting to be
|
||||
available again (or ``null``)
|
||||
locale string Locale of the waiting user
|
||||
subevent integer ID of the date inside an event series this entry belongs to (or ``null``).
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
|
||||
.. versionchanged:: 1.15
|
||||
|
||||
The write operations ``POST``, ``PATCH``, ``PUT``, and ``DELETE`` have been added as well as a method to send out
|
||||
vouchers.
|
||||
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/waitinglistentries/
|
||||
|
||||
Returns a list of all waiting list entries within a given event.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/waitinglistentries/ 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,
|
||||
"created": "2017-12-01T10:00:00Z",
|
||||
"email": "waiting@example.org",
|
||||
"voucher": null,
|
||||
"item": 2,
|
||||
"variation": null,
|
||||
"locale": "en",
|
||||
"subevent": null
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
:query string email: Only show waiting list entries created with the given email address.
|
||||
:query string locale: Only show waiting list entries created with the given locale.
|
||||
:query boolean has_voucher: If set to ``true`` or ``false``, only waiting list entries are returned that have or
|
||||
have not been sent a voucher.
|
||||
:query integer item: If set, only entries of users waiting for the item with the given ID will be shown.
|
||||
:query integer variation: If set, only entries of users waiting for the variation with the given ID will be shown.
|
||||
:query integer subevent: Only return entries of the sub-event with the given ID
|
||||
:query string ordering: Manually set the ordering of results. Valid fields to be used are ``id``, ``created``,
|
||||
``email``, ``item``. Default: ``created``
|
||||
: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)/waitinglistentries/(id)/
|
||||
|
||||
Returns information on one waiting list entry, identified by its internal ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/waitinglistentries/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,
|
||||
"created": "2017-12-01T10:00:00Z",
|
||||
"email": "waiting@example.org",
|
||||
"voucher": null,
|
||||
"item": 2,
|
||||
"variation": null,
|
||||
"locale": "en",
|
||||
"subevent": null
|
||||
}
|
||||
|
||||
: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 waiting list entry 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)/waitinglistentries/
|
||||
|
||||
Create a new entry.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/waitinglistentries/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 408
|
||||
|
||||
{
|
||||
"email": "waiting@example.org",
|
||||
"item": 3,
|
||||
"variation": null,
|
||||
"locale": "de",
|
||||
"subevent": null
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"created": "2017-12-01T10:00:00Z",
|
||||
"email": "waiting@example.org",
|
||||
"voucher": null,
|
||||
"item": 3,
|
||||
"variation": null,
|
||||
"locale": "de",
|
||||
"subevent": null
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to create an entry for
|
||||
:param event: The ``slug`` field of the event to create an entry for
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The voucher 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 **or** entries cannot be created for this item at this time.
|
||||
|
||||
.. http:patch:: /api/v1/organizers/(organizer)/events/(event)/waitinglistentries/(id)/
|
||||
|
||||
Update an entry. 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``, ``voucher`` and ``created`` fields. You can only change
|
||||
an entry as long as no ``voucher`` is set.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
PATCH /api/v1/organizers/bigevents/events/sampleconf/waitinglistentries/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 408
|
||||
|
||||
{
|
||||
"item": 4
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"created": "2017-12-01T10:00:00Z",
|
||||
"email": "waiting@example.org",
|
||||
"voucher": null,
|
||||
"item": 4,
|
||||
"variation": null,
|
||||
"locale": "de",
|
||||
"subevent": null
|
||||
}
|
||||
|
||||
: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 entry to modify
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The entry 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 create this
|
||||
resource **or** entries cannot be created for this item at this time **or** this entry already
|
||||
has a voucher assigned
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/waitinglistentries/(id)/send_voucher/
|
||||
|
||||
Manually sends a voucher to someone on the waiting list
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/waitinglistentries/1/send_voucher/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 0
|
||||
|
||||
**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 entry to modify
|
||||
:statuscode 204: no error
|
||||
:statuscode 400: The voucher could not be sent out, see body for details (e.g. voucher has already been sent or
|
||||
item is not available).
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to do this
|
||||
|
||||
.. http:delete:: /api/v1/organizers/(organizer)/events/(event)/waitinglistentries/(id)/
|
||||
|
||||
Delete an entry. Note that you cannot delete an entry once it is assigned a voucher.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/events/sampleconf/waitinglistentries/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 entry 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 **or** this entry already has a voucher assigned.
|
||||
@@ -1,242 +0,0 @@
|
||||
.. _`rest-webhooks`:
|
||||
|
||||
Webhooks
|
||||
========
|
||||
|
||||
.. note:: This page is about how to modify webhook settings themselves through the REST API. If you just want to know
|
||||
how webhooks work, go here: :ref:`webhooks`
|
||||
|
||||
Resource description
|
||||
--------------------
|
||||
|
||||
The webhook resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Internal ID of the webhook
|
||||
enabled boolean If ``false``, this webhook will not receive any notifications
|
||||
target_url string The URL to call
|
||||
all_events boolean If ``true``, this webhook will receive notifications
|
||||
on all events of this organizer
|
||||
limit_events list of strings If ``all_events`` is ``false``, this is a list of
|
||||
event slugs this webhook is active for
|
||||
action_types list of strings A list of action type filters that limit the
|
||||
notifications sent to this webhook. See below for
|
||||
valid values
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
The following values for ``action_types`` are valid with pretix core:
|
||||
|
||||
* ``pretix.event.order.placed``
|
||||
* ``pretix.event.order.paid``
|
||||
* ``pretix.event.order.canceled``
|
||||
* ``pretix.event.order.expired``
|
||||
* ``pretix.event.order.modified``
|
||||
* ``pretix.event.order.contact.changed``
|
||||
* ``pretix.event.order.changed.*``
|
||||
* ``pretix.event.order.refund.created.externally``
|
||||
* ``pretix.event.order.approved``
|
||||
* ``pretix.event.order.denied``
|
||||
* ``pretix.event.checkin``
|
||||
* ``pretix.event.checkin.reverted``
|
||||
|
||||
Installed plugins might register more valid values.
|
||||
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/webhooks/
|
||||
|
||||
Returns a list of all webhooks within a given organizer.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/webhooks/ 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": 2,
|
||||
"enabled": true,
|
||||
"target_url": "https://httpstat.us/200",
|
||||
"all_events": false,
|
||||
"limit_events": ["democon"],
|
||||
"action_types": ["pretix.event.order.modified", "pretix.event.order.changed.*"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/webhooks/(id)/
|
||||
|
||||
Returns information on one webhook, identified by its ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/webhooks/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": 2,
|
||||
"enabled": true,
|
||||
"target_url": "https://httpstat.us/200",
|
||||
"all_events": false,
|
||||
"limit_events": ["democon"],
|
||||
"action_types": ["pretix.event.order.modified", "pretix.event.order.changed.*"]
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param id: The ``id`` field of the webhook to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/webhooks/
|
||||
|
||||
Creates a new webhook
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/webhooks/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"enabled": true,
|
||||
"target_url": "https://httpstat.us/200",
|
||||
"all_events": false,
|
||||
"limit_events": ["democon"],
|
||||
"action_types": ["pretix.event.order.modified", "pretix.event.order.changed.*"]
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 3,
|
||||
"enabled": true,
|
||||
"target_url": "https://httpstat.us/200",
|
||||
"all_events": false,
|
||||
"limit_events": ["democon"],
|
||||
"action_types": ["pretix.event.order.modified", "pretix.event.order.changed.*"]
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to create a webhook for
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The webhook could not be created due to invalid submitted data.
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to create this resource.
|
||||
|
||||
.. http:patch:: /api/v1/organizers/(organizer)/webhooks/(id)/
|
||||
|
||||
Update a webhook. 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/webhooks/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 94
|
||||
|
||||
{
|
||||
"enabled": false
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"enabled": false,
|
||||
"target_url": "https://httpstat.us/200",
|
||||
"all_events": false,
|
||||
"limit_events": ["democon"],
|
||||
"action_types": ["pretix.event.order.modified", "pretix.event.order.changed.*"]
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param id: The ``id`` field of the webhook to modify
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The webhook could not be modified due to invalid submitted data
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to change this resource.
|
||||
|
||||
.. http:delete:: /api/v1/organizers/(organizer)/webhook/(id)/
|
||||
|
||||
Delete a webhook. Currently, this will not delete but just disable the webhook.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/webhooks/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 id: The ``id`` field of the webhook to delete
|
||||
:statuscode 204: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to delete this resource.
|
||||
@@ -1,36 +0,0 @@
|
||||
.. _`rest-tokenauth`:
|
||||
|
||||
Token-based authentication
|
||||
==========================
|
||||
|
||||
Obtaining an API token
|
||||
----------------------
|
||||
|
||||
To authenticate your API requests with Tokens, you need to obtain a team-level API token.
|
||||
You can create a token in the pretix web interface on the level of organizer teams. Create
|
||||
a new team or choose an existing team that has the level of permissions the token should
|
||||
have and create a new token using the form below the list of team members:
|
||||
|
||||
.. image:: img/token_form.png
|
||||
:class: screenshot
|
||||
|
||||
You can enter a description for the token to distinguish from other tokens later on.
|
||||
Once you click "Add", you will be provided with an API token in the success message.
|
||||
Copy this token, as you won't be able to retrieve it again.
|
||||
|
||||
.. image:: img/token_success.png
|
||||
:class: screenshot
|
||||
|
||||
Using an API token
|
||||
------------------
|
||||
|
||||
You need to include the API token with every request to pretix' API in the ``Authorization`` header
|
||||
like the following:
|
||||
|
||||
.. sourcecode:: http
|
||||
:emphasize-lines: 3
|
||||
|
||||
GET /api/v1/organizers/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Authorization: Token e1l6gq2ye72thbwkacj7jbri7a7tvxe614ojv8ybureain92ocub46t5gab5966k
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
.. _`webhooks`:
|
||||
|
||||
Webhooks
|
||||
========
|
||||
|
||||
pretix can send webhook calls to notify your application of any changes that happen inside pretix. This is especially
|
||||
useful for everything triggered by an actual user, such as a new ticket sale or the arrival of a payment.
|
||||
|
||||
You can register any number of webhook URLs that pretix will notify any time one of the supported events occurs inside
|
||||
your organizer account. A great example use case of webhooks would be to add the buyer to your mailing list every time
|
||||
a new order comes in.
|
||||
|
||||
Configuring webhooks
|
||||
--------------------
|
||||
|
||||
You can find the list of your active webhooks in the "Webhook" section of your organizer account:
|
||||
|
||||
.. thumbnail:: ../screens/organizer/webhook_list.png
|
||||
:align: center
|
||||
:class: screenshot
|
||||
|
||||
Click "Create webhook" if you want to add a new URL. You will then be able to enter the URL pretix shall call for
|
||||
notifications. You need to select any number of notification types that you want to receive and you can optionally
|
||||
filter the events you want to receive notifications for.
|
||||
|
||||
.. thumbnail:: ../screens/organizer/webhook_edit.png
|
||||
:align: center
|
||||
:class: screenshot
|
||||
|
||||
You can also configure webhooks :ref:`through the API itself <rest-webhooks>`.
|
||||
|
||||
Receiving webhooks
|
||||
------------------
|
||||
|
||||
Creating a webhook endpoint on your server is no different from creating any other page on your website. If your
|
||||
website is written in PHP, you might just create a new ``.php`` file on your server; if you use a web framework like
|
||||
Symfony or Django, you would just create a new route with the desired URL.
|
||||
|
||||
We will call your URL with a HTTP ``POST`` request with a ``JSON`` body. In PHP, you can parse this like this::
|
||||
|
||||
$input = @file_get_contents('php://input');
|
||||
$event_json = json_decode($input);
|
||||
// Do something with $event_json
|
||||
|
||||
In Django, you would create a view like this::
|
||||
|
||||
def my_webhook_view(request):
|
||||
event_json = json.loads(request.body)
|
||||
# Do something with event_json
|
||||
return HttpResponse(status=200)
|
||||
|
||||
More samples for the language of your choice are easy to find online.
|
||||
|
||||
The exact body of the request varies by notification type, but for the main types included with pretix core, such as
|
||||
those related to changes of an order, it will look like this::
|
||||
|
||||
{
|
||||
"notification_id": 123455,
|
||||
"organizer": "acmecorp",
|
||||
"event": "democon",
|
||||
"code": "ABC23",
|
||||
"action": "pretix.event.order.placed"
|
||||
}
|
||||
|
||||
Notifications regarding a check-in will contain more details like ``orderposition_id``
|
||||
and ``checkin_list``.
|
||||
|
||||
.. warning:: You should not trust data supplied to your webhook, but only use it as a trigger to fetch updated data.
|
||||
Anyone could send data there if they guess the correct URL and you won't be able to tell. Therefore, we
|
||||
only include the minimum amount of data necessary for you to fetch the changed objects from our
|
||||
:ref:`rest-api` in an authenticated way.
|
||||
|
||||
If you want to further prevent others from accessing your webhook URL, you can also use `Basic authentication`_ and
|
||||
supply the URL to us in the format of ``https://username:password@domain.com/path/``.
|
||||
We recommend that you use HTTPS for your webhook URL and might require it in the future. If HTTPS is used, we require
|
||||
that a valid certificate is in use.
|
||||
|
||||
.. note:: If you use a web framework that makes use of automatic CSRF protection, this protection might prevent us
|
||||
from calling your webhook URL. In this case, we recommend that you turn of CSRF protection selectively
|
||||
for that route. In Django, you can do this by putting the ``@csrf_exempt`` decorator on your view. In
|
||||
Rails, you can pass an ``except`` parameter to ``protect_from_forgery``.
|
||||
|
||||
|
||||
Responding to a webhook
|
||||
-----------------------
|
||||
|
||||
If you successfully received a webhook call, your endpoint should return a HTTP status code between ``200`` and ``299``.
|
||||
If any other status code is returned, we will assume you did not receive the call. This does mean that any redirection
|
||||
or ``304 Not Modified`` response will be treated as a failure. pretix will not follow any ``301`` or ``302`` redirect
|
||||
headers and pretix will ignore all other information in your response headers or body.
|
||||
|
||||
If we do not receive a status code in the range of ``200`` and ``299``, pretix will retry to deliver for up to three
|
||||
days with an exponential back off. Therefore, we recommend that you implement your endpoint in a way where calling it
|
||||
multiple times for the same event due to a perceived error does not do any harm.
|
||||
|
||||
There is only one exception: If status code ``410 Gone`` is returned, we will assume the
|
||||
endpoint does not exist any more and automatically disable the webhook.
|
||||
|
||||
.. note:: If you use a self-hosted version of pretix (i.e. not our SaaS offering at pretix.eu) and you did not
|
||||
configure a background task queue, failed webhooks will not be retried.
|
||||
|
||||
Debugging webhooks
|
||||
------------------
|
||||
|
||||
If you want to debug your webhooks, you can view a log of all sent notifications and the responses of your server for
|
||||
30 days right next to your configuration.
|
||||
|
||||
.. _Basic authentication: https://en.wikipedia.org/wiki/Basic_access_authentication
|
||||
@@ -1,11 +0,0 @@
|
||||
from enchant.tokenize import get_tokenizer, Filter, unit_tokenize
|
||||
|
||||
class CheckinFilter(Filter):
|
||||
""" If a word looks like checkin_count, it refers to a so-called variable in
|
||||
the code, and is treated as being spelled right."""
|
||||
|
||||
def _split(self, word):
|
||||
if word[:8] == "checkin_":
|
||||
return unit_tokenize(word[8:])
|
||||
|
||||
return unit_tokenize(word)
|
||||
79
doc/conf.py
79
doc/conf.py
@@ -13,31 +13,18 @@
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
from docutils.parsers.rst.directives.admonitions import BaseAdmonition
|
||||
from sphinx.util import compat
|
||||
compat.make_admonition = BaseAdmonition # See https://github.com/spinus/sphinxcontrib-images/issues/41
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
from datetime import date
|
||||
|
||||
sys.path.insert(0, os.path.abspath('../src'))
|
||||
|
||||
import django
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pretix.testutils.settings")
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pretix.settings")
|
||||
django.setup()
|
||||
|
||||
|
||||
try:
|
||||
import enchant
|
||||
HAS_PYENCHANT = True
|
||||
except:
|
||||
HAS_PYENCHANT = False
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
@@ -49,12 +36,10 @@ except:
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
'sphinx.ext.doctest',
|
||||
'sphinx.ext.todo',
|
||||
'sphinx.ext.coverage',
|
||||
'sphinxcontrib.httpdomain',
|
||||
'sphinxcontrib.images',
|
||||
]
|
||||
if HAS_PYENCHANT:
|
||||
extensions.append('sphinxcontrib.spelling')
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
@@ -70,17 +55,16 @@ master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = 'pretix'
|
||||
copyright = '2014-{}, Raphael Michel'.format(date.today().year)
|
||||
copyright = '2014-2016, Raphael Michel'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
from pretix import __version__
|
||||
version = '.'.join(__version__.split('.')[:2])
|
||||
version = '0.0.0'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = __version__
|
||||
release = '0.0.0'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
@@ -130,9 +114,7 @@ pygments_style = 'sphinx'
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
html_theme_options = {
|
||||
'logo_only': True,
|
||||
}
|
||||
#html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
#html_theme_path = []
|
||||
@@ -146,7 +128,7 @@ html_theme_options = {
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
html_logo = 'images/logo-white.svg'
|
||||
#html_logo = None
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
@@ -156,11 +138,7 @@ html_logo = 'images/logo-white.svg'
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = [
|
||||
'_static',
|
||||
os.path.abspath('../src/pretix/static/fonts/'),
|
||||
os.path.abspath('../src/pretix/static/fontawesome/fonts/'),
|
||||
]
|
||||
html_static_path = ['_static']
|
||||
|
||||
# Add any extra paths that contain custom files (such as robots.txt or
|
||||
# .htaccess) here, relative to this directory. These files are copied
|
||||
@@ -180,9 +158,7 @@ html_static_path = [
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
html_additional_pages = {
|
||||
'index': 'index.html'
|
||||
}
|
||||
#html_additional_pages = {}
|
||||
|
||||
# If false, no module index is generated.
|
||||
html_domain_indices = False
|
||||
@@ -194,7 +170,7 @@ html_use_index = False
|
||||
#html_split_index = False
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
html_show_sourcelink = True
|
||||
#html_show_sourcelink = True
|
||||
|
||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||
#html_show_sphinx = True
|
||||
@@ -213,8 +189,11 @@ html_show_sourcelink = True
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'pretixdoc'
|
||||
|
||||
html_theme = 'pretix_theme'
|
||||
html_theme_path = [os.path.abspath('_themes')]
|
||||
on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
|
||||
if not on_rtd: # only import and set the theme if we're building docs locally
|
||||
import sphinx_rtd_theme
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
|
||||
|
||||
|
||||
# -- Options for LaTeX output ---------------------------------------------
|
||||
@@ -294,31 +273,3 @@ texinfo_documents = [
|
||||
|
||||
# If true, do not generate a @detailmenu in the "Top" node's menu.
|
||||
#texinfo_no_detailmenu = False
|
||||
|
||||
|
||||
images_config = {
|
||||
'default_image_width': '250px'
|
||||
}
|
||||
|
||||
linkcheck_ignore = [
|
||||
r'http://localhost.*', r'.*yourdomain.*', r'https://en.wikipedia.org', 'https://pretix.eu/',
|
||||
]
|
||||
|
||||
# -- Options for Spelling output ------------------------------------------
|
||||
if HAS_PYENCHANT:
|
||||
# String specifying the language, as understood by PyEnchant and enchant.
|
||||
# Defaults to en_US for US English.
|
||||
spelling_lang = 'en_US'
|
||||
|
||||
# String specifying a file containing a list of words known to be spelled
|
||||
# correctly but that do not appear in the language dictionary selected by
|
||||
# spelling_lang. The file should contain one word per line.
|
||||
spelling_word_list_filename='spelling_wordlist.txt'
|
||||
|
||||
# Boolean controlling whether suggestions for misspelled words are printed.
|
||||
# Defaults to False.
|
||||
spelling_show_suggestions=True
|
||||
|
||||
# List of filter classes to be added to the tokenizer that produces words to be checked.
|
||||
from checkin_filter import CheckinFilter
|
||||
spelling_filters=[CheckinFilter]
|
||||
|
||||
@@ -25,7 +25,7 @@ If you want to add a custom view to the control area of an event, just register
|
||||
views.admin_view, name='backend'),
|
||||
]
|
||||
|
||||
It is required that your URL parameters are called ``organizer`` and ``event``. If you want to
|
||||
It is required that your URL paramaters are called ``organizer`` and ``event``. If you want to
|
||||
install a view on organizer level, you can leave out the ``event``.
|
||||
|
||||
You can then implement the view as you would normally do. Our middleware will automatically
|
||||
@@ -60,85 +60,7 @@ your views::
|
||||
def admin_view(request, organizer, event):
|
||||
...
|
||||
|
||||
Similarly, there is ``organizer_permission_required`` and ``OrganizerPermissionRequiredMixin``. In case of
|
||||
event-related views, there is also a signal that allows you to add the view to the event navigation like this::
|
||||
|
||||
|
||||
from django.urls import resolve, reverse
|
||||
from django.dispatch import receiver
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from pretix.control.signals import nav_event
|
||||
|
||||
|
||||
@receiver(nav_event, dispatch_uid='friends_tickets_nav')
|
||||
def navbar_info(sender, request, **kwargs):
|
||||
url = resolve(request.path_info)
|
||||
if not request.user.has_event_permission(request.organizer, request.event, 'can_change_vouchers'):
|
||||
return []
|
||||
return [{
|
||||
'label': _('My plugin view'),
|
||||
'icon': 'heart',
|
||||
'url': reverse('plugins:myplugin:index', kwargs={
|
||||
'event': request.event.slug,
|
||||
'organizer': request.organizer.slug,
|
||||
}),
|
||||
'active': url.namespace == 'plugins:myplugin' and url.url_name == 'review',
|
||||
}]
|
||||
|
||||
|
||||
Event settings view
|
||||
-------------------
|
||||
|
||||
A special case of a control panel view is a view hooked into the event settings page. For this case, there is a
|
||||
special navigation signal::
|
||||
|
||||
@receiver(nav_event_settings, dispatch_uid='friends_tickets_nav_settings')
|
||||
def navbar_settings(sender, request, **kwargs):
|
||||
url = resolve(request.path_info)
|
||||
return [{
|
||||
'label': _('My settings'),
|
||||
'url': reverse('plugins:myplugin:settings', kwargs={
|
||||
'event': request.event.slug,
|
||||
'organizer': request.organizer.slug,
|
||||
}),
|
||||
'active': url.namespace == 'plugins:myplugin' and url.url_name == 'settings',
|
||||
}]
|
||||
|
||||
Also, your view should inherit from ``EventSettingsViewMixin`` and your template from ``pretixcontrol/event/settings_base.html``
|
||||
for good integration. If you just want to display a form, you could do it like the following::
|
||||
|
||||
class MySettingsView(EventSettingsViewMixin, EventSettingsFormView):
|
||||
model = Event
|
||||
permission = 'can_change_settings'
|
||||
form_class = MySettingsForm
|
||||
template_name = 'my_plugin/settings.html'
|
||||
|
||||
def get_success_url(self, **kwargs):
|
||||
return reverse('plugins:myplugin:settings', kwargs={
|
||||
'organizer': self.request.event.organizer.slug,
|
||||
'event': self.request.event.slug,
|
||||
})
|
||||
|
||||
With this template::
|
||||
|
||||
{% extends "pretixcontrol/event/settings_base.html" %}
|
||||
{% load i18n %}
|
||||
{% load bootstrap3 %}
|
||||
{% block title %} {% trans "Friends Tickets Settings" %} {% endblock %}
|
||||
{% block inside %}
|
||||
<form action="" method="post" class="form-horizontal">
|
||||
{% csrf_token %}
|
||||
<fieldset>
|
||||
<legend>{% trans "Friends Tickets Settings" %}</legend>
|
||||
{% bootstrap_form form layout="horizontal" %}
|
||||
</fieldset>
|
||||
<div class="form-group submit-group">
|
||||
<button type="submit" class="btn btn-primary btn-save">
|
||||
{% trans "Save" %}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
Similarly, there is ``organizer_permission_required`` and ``OrganizerPermissionRequiredMixin``.
|
||||
|
||||
Frontend views
|
||||
--------------
|
||||
@@ -146,79 +68,31 @@ Frontend views
|
||||
Including a custom view into the participant-facing frontend is a little bit different as there is
|
||||
no path prefix like ``control/``.
|
||||
|
||||
First, define your URL in your ``urls.py``, but this time in the ``event_patterns`` section and wrapped by
|
||||
``event_url``::
|
||||
First, define your URL in your ``urls.py``, but this time in the ``event_patterns`` section::
|
||||
|
||||
from pretix.multidomain import event_url
|
||||
from django.conf.urls import url
|
||||
|
||||
from . import views
|
||||
|
||||
event_patterns = [
|
||||
event_url(r'^mypluginname/', views.frontend_view, name='frontend'),
|
||||
url(r'^mypluginname/', views.frontend_view, name='frontend'),
|
||||
]
|
||||
|
||||
You can then implement a view as you would normally do. It will be automatically ensured that:
|
||||
You can then implement a view as you would normally do, but you need to apply a decorator to your
|
||||
view if you want pretix's default behavior::
|
||||
|
||||
from pretix.presale.utils import event_view
|
||||
|
||||
@event_view
|
||||
def some_event_view(request, *args, **kwargs):
|
||||
...
|
||||
|
||||
This decorator will check the URL arguments for their ``event`` and ``organizer`` parameters and
|
||||
correctly ensure that:
|
||||
|
||||
* The requested event exists
|
||||
* The requested event is active (you can disable this check using ``event_url(…, require_live=True)``)
|
||||
* The requested event is activated (can be overridden by decorating with ``@event_view(require_live=False)``)
|
||||
* The event is accessed via the domain it should be accessed
|
||||
* The ``request.event`` attribute contains the correct ``Event`` object
|
||||
* The ``request.organizer`` attribute contains the correct ``Organizer`` object
|
||||
* Your plugin is enabled
|
||||
* The locale is set correctly
|
||||
|
||||
.. versionchanged:: 1.7
|
||||
|
||||
The ``event_url()`` wrapper has been added in 1.7 to replace the former ``@event_view`` decorator. The
|
||||
``event_url()`` wrapper is optional and using ``url()`` still works, but you will not be able to set the
|
||||
``require_live`` setting any more via the decorator. The ``@event_view`` decorator is now deprecated and
|
||||
does nothing.
|
||||
|
||||
REST API viewsets
|
||||
-----------------
|
||||
|
||||
Our REST API is built upon `Django REST Framework`_ (DRF). DRF has two important concepts that are different from
|
||||
standard Django request handling: There are `ViewSets`_ to group related views in a single class and `Routers`_ to
|
||||
automatically build URL configurations from them.
|
||||
|
||||
To integrate a custom viewset with pretix' REST API, you can just register with one of our routers within the
|
||||
``urls.py`` module of your plugin::
|
||||
|
||||
|
||||
from pretix.api.urls import event_router, router, orga_router
|
||||
|
||||
router.register('global_viewset', MyViewSet)
|
||||
orga_router.register('orga_level_viewset', MyViewSet)
|
||||
event_router.register('event_level_viewset', MyViewSet)
|
||||
|
||||
Routes registered with ``router`` are inserted into the global API space at ``/api/v1/``. Routes registered with
|
||||
``orga_router`` will be included at ``/api/v1/organizers/(organizer)/`` and routes registered with ``event_router``
|
||||
will be included at ``/api/v1/organizers/(organizer)/events/(event)/``.
|
||||
|
||||
In case of ``orga_router`` and ``event_router``, permission checking is done for you similarly as with custom views
|
||||
in the control panel. However, you need to make sure on your own only to return the correct subset of data! ``request
|
||||
.event`` and ``request.organizer`` are available as usual.
|
||||
|
||||
To require a special permission like ``can_view_orders``, you do not need to inherit from a special ViewSet base
|
||||
class, you can just set the ``permission`` attribute on your viewset::
|
||||
|
||||
class MyViewSet(ModelViewSet):
|
||||
permission = 'can_view_orders'
|
||||
...
|
||||
|
||||
If you want to check the permission only for some methods of your viewset, you have to do it yourself. Note here that
|
||||
API authentications can be done via user sessions or API tokens and you should therefore check something like the
|
||||
following::
|
||||
|
||||
|
||||
perm_holder = (request.auth if isinstance(request.auth, TeamAPIToken) else request.user)
|
||||
if perm_holder.has_event_permission(request.event.organizer, request.event, 'can_view_orders'):
|
||||
...
|
||||
|
||||
|
||||
.. warning:: It is important that you do this in the ``yourplugin.urls`` module, otherwise pretix will not find your
|
||||
routes early enough during system startup.
|
||||
|
||||
.. _Django REST Framework: http://www.django-rest-framework.org/
|
||||
.. _ViewSets: http://www.django-rest-framework.org/api-guide/viewsets/
|
||||
.. _Routers: http://www.django-rest-framework.org/api-guide/routers/
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
.. highlight:: python
|
||||
:linenothreshold: 5
|
||||
|
||||
Writing an HTML e-mail renderer plugin
|
||||
======================================
|
||||
|
||||
An email renderer class controls how the HTML part of e-mails sent by pretix is built.
|
||||
The creation of such a plugin is very similar to creating an export output.
|
||||
|
||||
Please read :ref:`Creating a plugin <pluginsetup>` first, if you haven't already.
|
||||
|
||||
Output registration
|
||||
-------------------
|
||||
|
||||
The email HTML renderer API does not make a lot of usage from signals, however, it
|
||||
does use a signal to get a list of all available email renderers. Your plugin
|
||||
should listen for this signal and return the subclass of ``pretix.base.email.BaseHTMLMailRenderer``
|
||||
that we'll provide in this plugin::
|
||||
|
||||
from django.dispatch import receiver
|
||||
|
||||
from pretix.base.signals import register_html_mail_renderers
|
||||
|
||||
|
||||
@receiver(register_html_mail_renderers, dispatch_uid="renderer_custom")
|
||||
def register_mail_renderers(sender, **kwargs):
|
||||
from .email import MyMailRenderer
|
||||
return MyMailRenderer
|
||||
|
||||
|
||||
The renderer class
|
||||
------------------
|
||||
|
||||
.. class:: pretix.base.email.BaseHTMLMailRenderer
|
||||
|
||||
The central object of each email renderer is the subclass of ``BaseHTMLMailRenderer``.
|
||||
|
||||
.. py:attribute:: BaseHTMLMailRenderer.event
|
||||
|
||||
The default constructor sets this property to the event we are currently
|
||||
working for.
|
||||
|
||||
.. autoattribute:: identifier
|
||||
|
||||
This is an abstract attribute, you **must** override this!
|
||||
|
||||
.. autoattribute:: verbose_name
|
||||
|
||||
This is an abstract attribute, you **must** override this!
|
||||
|
||||
.. autoattribute:: thumbnail_filename
|
||||
|
||||
This is an abstract attribute, you **must** override this!
|
||||
|
||||
.. autoattribute:: is_available
|
||||
|
||||
.. automethod:: render
|
||||
|
||||
This is an abstract method, you **must** implement this!
|
||||
|
||||
Helper class for template-base renderers
|
||||
----------------------------------------
|
||||
|
||||
The email renderer that ships with pretix is based on Django templates to generate HTML.
|
||||
In case you also want to render emails based on a template, we provided a ready-made base
|
||||
class ``TemplateBasedMailRenderer`` that you can re-use to perform the following steps:
|
||||
|
||||
* Convert the body text and the signature to HTML using our markdown renderer
|
||||
|
||||
* Render the template
|
||||
|
||||
* Call `inlinestyler`_ to convert all ``<style>`` style sheets to inline ``style=""``
|
||||
attributes for better compatibility
|
||||
|
||||
To use it, you just need to implement some variables::
|
||||
|
||||
class ClassicMailRenderer(TemplateBasedMailRenderer):
|
||||
verbose_name = _('pretix default')
|
||||
identifier = 'classic'
|
||||
thumbnail_filename = 'pretixbase/email/thumb.png'
|
||||
template_name = 'pretixbase/email/plainwrapper.html'
|
||||
|
||||
The template is passed the following context variables:
|
||||
|
||||
``site``
|
||||
Name of the pretix installation (``settings.PRETIX_INSTANCE_NAME``)
|
||||
|
||||
``site_url``
|
||||
Root URL of the pretix installation (``settings.SITE_URL``)
|
||||
|
||||
``body``
|
||||
The body as markdown (render with ``{{ body|safe }}``)
|
||||
|
||||
``subject``
|
||||
The email subject
|
||||
|
||||
``color``
|
||||
The primary color of the event
|
||||
|
||||
``event``
|
||||
The ``Event`` object
|
||||
|
||||
``signature`` (optional, only if configured)
|
||||
The signature with event organizer contact details as markdown (render with ``{{ signature|safe }}``)
|
||||
|
||||
``order`` (optional, only if applicable)
|
||||
The ``Order`` object
|
||||
|
||||
``position`` (optional, only if applicable)
|
||||
The ``OrderPosition`` object
|
||||
|
||||
.. _inlinestyler: https://pypi.org/project/inlinestyler/
|
||||
@@ -21,10 +21,10 @@ that we'll provide in this plugin::
|
||||
|
||||
from django.dispatch import receiver
|
||||
|
||||
from pretix.base.signals import register_data_exporters
|
||||
from pretix.base.signals import register_data_exporter
|
||||
|
||||
|
||||
@receiver(register_data_exporters, dispatch_uid="exporter_myexporter")
|
||||
@receiver(register_data_exporter, dispatch_uid="exporter_myexporter")
|
||||
def register_data_exporter(sender, **kwargs):
|
||||
from .exporter import MyExporter
|
||||
return MyExporter
|
||||
|
||||
@@ -11,8 +11,7 @@ Core
|
||||
----
|
||||
|
||||
.. automodule:: pretix.base.signals
|
||||
:members: periodic_task, event_live_issues, event_copy_data, email_filter, register_notification_types,
|
||||
item_copy_data, register_sales_channels, register_global_settings, quota_availability
|
||||
:members: periodic_task, event_live_issues
|
||||
|
||||
Order events
|
||||
""""""""""""
|
||||
@@ -20,13 +19,13 @@ Order events
|
||||
There are multiple signals that will be sent out in the ordering cycle:
|
||||
|
||||
.. automodule:: pretix.base.signals
|
||||
:members: validate_cart, validate_cart_addons, validate_order, order_fee_calculation, order_paid, order_placed, order_canceled, order_expired, order_modified, order_changed, order_approved, order_denied, order_fee_type_name, allow_ticket_download, order_split
|
||||
:members: validate_cart, order_paid, order_placed
|
||||
|
||||
Frontend
|
||||
--------
|
||||
|
||||
.. automodule:: pretix.presale.signals
|
||||
:members: html_head, html_footer, footer_link, front_page_top, front_page_bottom, fee_calculation_for_cart, contact_form_fields, question_form_fields, checkout_confirm_messages, checkout_confirm_page_content, checkout_all_optional, html_page_header, sass_preamble, sass_postamble, render_seating_plan, checkout_flow_steps, position_info
|
||||
:members: html_head, footer_links, front_page_top, front_page_bottom
|
||||
|
||||
|
||||
.. automodule:: pretix.presale.signals
|
||||
@@ -48,33 +47,20 @@ Backend
|
||||
-------
|
||||
|
||||
.. automodule:: pretix.control.signals
|
||||
:members: nav_event, html_head, html_page_start, quota_detail_html, nav_topbar, nav_global, nav_organizer, nav_event_settings,
|
||||
order_info, event_settings_widget, oauth_application_registered, order_position_buttons, subevent_forms, item_formsets
|
||||
:members: nav_event, html_head, quota_detail_html, nav_topbar, organizer_edit_tabs
|
||||
|
||||
|
||||
.. automodule:: pretix.base.signals
|
||||
:members: logentry_display, logentry_object_link, requiredaction_display, timeline_events
|
||||
:members: logentry_display, requiredaction_display
|
||||
|
||||
Vouchers
|
||||
""""""""
|
||||
|
||||
.. automodule:: pretix.control.signals
|
||||
:members: item_forms
|
||||
|
||||
Vouchers
|
||||
""""""""
|
||||
|
||||
.. automodule:: pretix.control.signals
|
||||
:members: voucher_form_class, voucher_form_html, voucher_form_validation
|
||||
:members: voucher_form_class, voucher_form_html
|
||||
|
||||
Dashboards
|
||||
""""""""""
|
||||
|
||||
.. automodule:: pretix.control.signals
|
||||
:members: event_dashboard_widgets, user_dashboard_widgets
|
||||
|
||||
Ticket designs
|
||||
""""""""""""""
|
||||
|
||||
.. automodule:: pretix.base.signals
|
||||
:members: layout_text_variables
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Plugin development
|
||||
==================
|
||||
Plugin hooks
|
||||
============
|
||||
|
||||
Contents:
|
||||
|
||||
@@ -10,10 +10,5 @@ Contents:
|
||||
exporter
|
||||
ticketoutput
|
||||
payment
|
||||
payment_2.0
|
||||
email
|
||||
invoice
|
||||
shredder
|
||||
customview
|
||||
general
|
||||
quality
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
.. highlight:: python
|
||||
:linenothreshold: 5
|
||||
|
||||
Writing an invoice renderer plugin
|
||||
==================================
|
||||
|
||||
An invoice renderer controls how invoice files are built.
|
||||
The creation of such a plugin is very similar to creating an export output.
|
||||
|
||||
Please read :ref:`Creating a plugin <pluginsetup>` first, if you haven't already.
|
||||
|
||||
Output registration
|
||||
-------------------
|
||||
|
||||
The invoice renderer API does not make a lot of usage from signals, however, it
|
||||
does use a signal to get a list of all available invoice renderers. Your plugin
|
||||
should listen for this signal and return the subclass of ``pretix.base.invoice.BaseInvoiceRenderer``
|
||||
that we'll provide in this plugin::
|
||||
|
||||
from django.dispatch import receiver
|
||||
|
||||
from pretix.base.signals import register_invoice_renderers
|
||||
|
||||
|
||||
@receiver(register_invoice_renderers, dispatch_uid="output_custom")
|
||||
def register_invoice_renderers(sender, **kwargs):
|
||||
from .invoice import MyInvoiceRenderer
|
||||
return MyInvoiceRenderer
|
||||
|
||||
|
||||
The renderer class
|
||||
------------------
|
||||
|
||||
.. class:: pretix.base.invoice.BaseInvoiceRenderer
|
||||
|
||||
The central object of each invoice renderer is the subclass of ``BaseInvoiceRenderer``.
|
||||
|
||||
.. py:attribute:: BaseInvoiceRenderer.event
|
||||
|
||||
The default constructor sets this property to the event we are currently
|
||||
working for.
|
||||
|
||||
.. autoattribute:: identifier
|
||||
|
||||
This is an abstract attribute, you **must** override this!
|
||||
|
||||
.. autoattribute:: verbose_name
|
||||
|
||||
This is an abstract attribute, you **must** override this!
|
||||
|
||||
.. automethod:: generate
|
||||
|
||||
Helper class for reportlab-base renderers
|
||||
-----------------------------------------
|
||||
|
||||
All PDF rendering that ships with pretix is based on reportlab. We recommend to read the
|
||||
`reportlab User Guide`_ to understand all the concepts used here.
|
||||
|
||||
If you want to implement a renderer that also uses report lab, this helper class might be
|
||||
convenient to you:
|
||||
|
||||
|
||||
.. class:: pretix.base.invoice.BaseReportlabInvoiceRenderer
|
||||
|
||||
.. py:attribute:: BaseReportlabInvoiceRenderer.pagesize
|
||||
|
||||
.. py:attribute:: BaseReportlabInvoiceRenderer.left_margin
|
||||
|
||||
.. py:attribute:: BaseReportlabInvoiceRenderer.right_margin
|
||||
|
||||
.. py:attribute:: BaseReportlabInvoiceRenderer.top_margin
|
||||
|
||||
.. py:attribute:: BaseReportlabInvoiceRenderer.bottom_margin
|
||||
|
||||
.. py:attribute:: BaseReportlabInvoiceRenderer.doc_template_class
|
||||
|
||||
.. py:attribute:: BaseReportlabInvoiceRenderer.invoice
|
||||
|
||||
.. automethod:: _init
|
||||
|
||||
.. automethod:: _get_stylesheet
|
||||
|
||||
.. automethod:: _register_fonts
|
||||
|
||||
.. automethod:: _on_first_page
|
||||
|
||||
.. automethod:: _on_other_page
|
||||
|
||||
.. automethod:: _get_first_page_frames
|
||||
|
||||
.. automethod:: _get_other_page_frames
|
||||
|
||||
.. automethod:: _build_doc
|
||||
|
||||
.. _reportlab User Guide: https://www.reportlab.com/docs/reportlab-userguide.pdf
|
||||
@@ -9,10 +9,6 @@ is very similar to creating an export output.
|
||||
|
||||
Please read :ref:`Creating a plugin <pluginsetup>` first, if you haven't already.
|
||||
|
||||
.. warning:: We changed our payment provider API a lot in pretix 2.x. Our documentation page on :ref:`payment2.0`
|
||||
might be insightful even if you do not have a payment provider to port, as it outlines the rationale
|
||||
behind the current design.
|
||||
|
||||
Provider registration
|
||||
---------------------
|
||||
|
||||
@@ -35,7 +31,7 @@ that the plugin will provide::
|
||||
The provider class
|
||||
------------------
|
||||
|
||||
.. py:class:: pretix.base.payment.BasePaymentProvider
|
||||
.. class:: pretix.base.payment.BasePaymentProvider
|
||||
|
||||
The central object of each payment provider is the subclass of ``BasePaymentProvider``.
|
||||
|
||||
@@ -58,63 +54,53 @@ The provider class
|
||||
|
||||
This is an abstract attribute, you **must** override this!
|
||||
|
||||
.. autoattribute:: public_name
|
||||
|
||||
.. autoattribute:: is_enabled
|
||||
|
||||
.. automethod:: calculate_fee
|
||||
|
||||
.. autoattribute:: settings_form_fields
|
||||
|
||||
.. automethod:: settings_form_clean
|
||||
|
||||
.. automethod:: settings_content_render
|
||||
|
||||
.. automethod:: is_allowed
|
||||
.. automethod:: render_invoice_text
|
||||
|
||||
.. automethod:: payment_form_render
|
||||
|
||||
.. automethod:: payment_form
|
||||
|
||||
.. automethod:: is_allowed
|
||||
|
||||
.. autoattribute:: payment_form_fields
|
||||
|
||||
.. automethod:: payment_is_valid_session
|
||||
|
||||
.. automethod:: checkout_prepare
|
||||
|
||||
.. automethod:: payment_is_valid_session
|
||||
|
||||
.. automethod:: checkout_confirm_render
|
||||
|
||||
This is an abstract method, you **must** override this!
|
||||
|
||||
.. automethod:: execute_payment
|
||||
|
||||
.. automethod:: calculate_fee
|
||||
.. automethod:: payment_perform
|
||||
|
||||
.. automethod:: order_pending_mail_render
|
||||
|
||||
.. automethod:: payment_pending_render
|
||||
.. automethod:: order_pending_render
|
||||
|
||||
.. autoattribute:: abort_pending_allowed
|
||||
|
||||
.. automethod:: render_invoice_text
|
||||
This is an abstract method, you **must** override this!
|
||||
|
||||
.. automethod:: order_change_allowed
|
||||
|
||||
.. automethod:: payment_prepare
|
||||
.. automethod:: order_can_retry
|
||||
|
||||
.. automethod:: payment_control_render
|
||||
.. automethod:: order_prepare
|
||||
|
||||
.. automethod:: payment_refund_supported
|
||||
.. automethod:: order_paid_render
|
||||
|
||||
.. automethod:: payment_partial_refund_supported
|
||||
.. automethod:: order_control_render
|
||||
|
||||
.. automethod:: execute_refund
|
||||
.. automethod:: order_control_refund_render
|
||||
|
||||
.. automethod:: shred_payment_info
|
||||
|
||||
.. autoattribute:: is_implicit
|
||||
|
||||
.. autoattribute:: is_meta
|
||||
|
||||
.. autoattribute:: test_mode_message
|
||||
.. automethod:: order_control_refund_perform
|
||||
|
||||
|
||||
Additional views
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
.. highlight:: python
|
||||
:linenothreshold: 5
|
||||
|
||||
.. _`payment2.0`:
|
||||
|
||||
Porting a payment provider from pretix 1.x to pretix 2.x
|
||||
========================================================
|
||||
|
||||
In pretix 2.x, we changed large parts of the payment provider API. This documentation details the changes we made
|
||||
and shows you how you can make an existing pretix 1.x payment provider compatible with pretix 2.x
|
||||
|
||||
Conceptual overview
|
||||
-------------------
|
||||
|
||||
In pretix 1.x, an order was always directly connected to a payment provider for the full life of an order. As long as
|
||||
an order was unpaid, this could still be changed in some cases, but once an order was paid, no changes to the payment
|
||||
provider were possible any more. Additionally, the internal state of orders allowed orders only to be fully paid or
|
||||
not paid at all. This leads to a couple of consequences:
|
||||
|
||||
* Payment-related functions (like "execute payment" or "do a refund") always operated on full orders.
|
||||
|
||||
* Changing the total of an order was basically impossible once an order was paid, since there was no concept of
|
||||
partial payments or partial refunds.
|
||||
|
||||
* Payment provider plugins needed to take complicated steps to detect cases that require human intervention, like e.g.
|
||||
|
||||
* An order has expired, no quota is left to revive it, but a payment has been received
|
||||
|
||||
* A payment has been received for a canceled order
|
||||
|
||||
* A payment has been received for an order that has already been paid with a different payment method
|
||||
|
||||
* An external payment service notified us of a refund/dispute
|
||||
|
||||
We noticed that we copied and repeated large portions of code in all our official payment provider plugins, just
|
||||
to deal with some of these cases.
|
||||
|
||||
* Sometimes, there is the need to mark an order as refunded within pretix, without automatically triggering a refund
|
||||
with an external API. Every payment method needed to implement a user interface for this independently.
|
||||
|
||||
* If a refund was not possible automatically, there was no way user to track which payments actually have been refunded
|
||||
manually and which are still left to do.
|
||||
|
||||
* When the payment with one payment provider failed and the user changed to a different payment provider, all
|
||||
information about the first payment was lost from the order object and could only be retrieved from order log data,
|
||||
which also made it hard to design a data shredder API to get rid of this data.
|
||||
|
||||
In pretix 2.x, we introduced two new models, :py:class:`OrderPayment <pretix.base.models.OrderPayment>` and
|
||||
:py:class:`OrderRefund <pretix.base.models.OrderRefund>`. Each instance of these is connected to an order and
|
||||
represents one single attempt to pay or refund a specific amount of money. Each one of these has an individual state,
|
||||
can individually fail or succeed, and carries an amount variable that can differ from the order total.
|
||||
|
||||
This has the following advantages:
|
||||
|
||||
* The system can now detect orders that are over- or underpaid, independent of the payment providers in use.
|
||||
|
||||
* Therefore, we can now allow partial payments, partial refunds, and changing paid orders, and automatically detect
|
||||
the cases listed above and notify the user.
|
||||
|
||||
Payment providers now interact with those payment and refund objects more than with orders.
|
||||
|
||||
Your to-do list
|
||||
---------------
|
||||
|
||||
Payment processing
|
||||
""""""""""""""""""
|
||||
|
||||
* The method ``BasePaymentProvider.order_pending_render`` has been removed and replaced by a new
|
||||
``BasePaymentProvider.payment_pending_render(request, payment)`` method that is passed an ``OrderPayment``
|
||||
object instead of an ``Order``.
|
||||
|
||||
* The method ``BasePaymentProvider.payment_form_render`` now receives a new ``total`` parameter.
|
||||
|
||||
* The method ``BasePaymentProvider.payment_perform`` has been removed and replaced by a new method
|
||||
``BasePaymentProvider.execute_payment(request, payment)`` that is passed an ``OrderPayment``
|
||||
object instead of an ``Order``.
|
||||
|
||||
* The function ``pretix.base.services.mark_order_paid`` has been removed, instead call ``payment.confirm()``
|
||||
on a pending ``OrderPayment`` object. If no further payments are required for this order, this will also
|
||||
mark the order as paid automatically. Note that ``payment.confirm()`` can still throw a ``QuotaExceededException``,
|
||||
however it will still mark the payment as complete (not the order!), so you should catch this exception and
|
||||
inform the user, but not abort the transaction.
|
||||
|
||||
* A new property ``BasePaymentProvider.abort_pending_allowed`` has been introduced. Only if set, the user will
|
||||
be able to retry a payment or switch the payment method when the order currently has a payment object in
|
||||
state ``"pending"``. This replaces ``BasePaymentProvider.order_can_retry``, which no longer exists.
|
||||
|
||||
* The methods ``BasePaymentProvider.retry_prepare`` and ``BasePaymentProvider.order_prepare`` have both been
|
||||
replaced by a new method ``BasePaymentProvider.payment_prepare(request, payment)`` that is passed an ``OrderPayment``
|
||||
object instead of an ``Order``. **Keep in mind that this payment object might have an amount property that
|
||||
differs from the order total, if the order is already partially paid.**
|
||||
|
||||
* The method ``BasePaymentProvider.order_paid_render`` has been removed.
|
||||
|
||||
* The method ``BasePaymentProvider.order_control_render`` has been removed and replaced by a new method
|
||||
``BasePaymentProvider.payment_control_render(request, payment)`` that is passed an ``OrderPayment``
|
||||
object instead of an ``Order``.
|
||||
|
||||
* There's no need to manually deal with excess payments or duplicate payments anymore, just setting the ``OrderPayment``
|
||||
methods to the correct state will do the job.
|
||||
|
||||
Creating refunds
|
||||
""""""""""""""""
|
||||
|
||||
* The methods ``BasePaymentProvider.order_control_refund_render`` and ``BasePaymentProvider.order_control_refund_perform``
|
||||
have been removed.
|
||||
|
||||
* Two new boolean methods ``BasePaymentProvider.payment_refund_supported(payment)`` and ``BasePaymentProvider.payment_partial_refund_supported(payment)``
|
||||
have been introduced. They should be set to return ``True`` if and only if the payment API allows to *automatically*
|
||||
transfer the money back to the customer.
|
||||
|
||||
* A new method ``BasePaymentProvider.execute_refund(refund)`` has been introduced. This method is called using a
|
||||
``OrderRefund`` object in ``"created"`` state and is expected to transfer the money back and confirm success with
|
||||
calling ``refund.done()``. This will only ever be called if either ``BasePaymentProvider.payment_refund_supported(payment)``
|
||||
or ``BasePaymentProvider.payment_partial_refund_supported(payment)`` return ``True``.
|
||||
|
||||
Processing external refunds
|
||||
"""""""""""""""""""""""""""
|
||||
|
||||
* If e.g. a webhook API notifies you that a payment has been disputed or refunded with the external API, you are
|
||||
expected to call ``OrderPayment.create_external_refund(self, amount, execution_date, info='{}')`` on this payment.
|
||||
This will create and return an appropriate ``OrderRefund`` object and send out a notification. However, it will not
|
||||
mark the order as refunded, but will ask the event organizer for a decision.
|
||||
|
||||
Data shredders
|
||||
""""""""""""""
|
||||
|
||||
* The method ``BasePaymentProvider.shred_payment_info`` is no longer passed an order, but instead **either**
|
||||
an ``OrderPayment`` **or** an ``OrderRefund``.
|
||||
@@ -1,10 +1,8 @@
|
||||
.. highlight:: python
|
||||
:linenothreshold: 5
|
||||
|
||||
.. _`pluginsetup`:
|
||||
|
||||
Creating a plugin
|
||||
=================
|
||||
Plugin basics
|
||||
=============
|
||||
|
||||
It is possible to extend pretix with custom Python code using the official plugin
|
||||
API. Every plugin has to be implemented as an independent Django 'app' living
|
||||
@@ -16,15 +14,10 @@ The communication between pretix and the plugins happens mostly using Django's
|
||||
``pretix.control`` and ``pretix.presale`` expose a number of signals which are documented
|
||||
on the next pages.
|
||||
|
||||
.. _`pluginsetup`:
|
||||
|
||||
To create a new plugin, create a new python package which must be a valid `Django app`_
|
||||
and must contain plugin metadata, as described below.
|
||||
There is some boilerplate that you will need for every plugin to get started. To save your
|
||||
time, we created a `cookiecutter`_ template that you can use like this::
|
||||
|
||||
$ pip install cookiecutter
|
||||
$ cookiecutter https://github.com/pretix/pretix-plugin-cookiecutter
|
||||
|
||||
This will ask you some questions and then create a project folder for your plugin.
|
||||
|
||||
The following pages go into detail about the several types of plugins currently
|
||||
supported. While these instructions don't assume that you know a lot about pretix,
|
||||
@@ -37,33 +30,35 @@ Plugin metadata
|
||||
The plugin metadata lives inside a ``PretixPluginMeta`` class inside your app's
|
||||
configuration class. The metadata class must define the following attributes:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
``name`` (``str``):
|
||||
The human-readable name of your plugin
|
||||
|
||||
================== ==================== ===========================================================
|
||||
Attribute Type Description
|
||||
================== ==================== ===========================================================
|
||||
name string The human-readable name of your plugin
|
||||
author string Your name
|
||||
version string A human-readable version code of your plugin
|
||||
description string A more verbose description of what your plugin does.
|
||||
visible boolean (optional) ``True`` by default, can hide a plugin so it cannot be normally activated.
|
||||
restricted boolean (optional) ``False`` by default, restricts a plugin such that it can only be enabled
|
||||
for an event by system administrators / superusers.
|
||||
compatibility string Specifier for compatible pretix versions.
|
||||
================== ==================== ===========================================================
|
||||
``author`` (``str``):
|
||||
Your name
|
||||
|
||||
``version`` (``str``):
|
||||
A human-readable version code of your plugin
|
||||
|
||||
``description`` (``str``):
|
||||
A more verbose description of what your plugin does.
|
||||
|
||||
``visible`` (``bool``):
|
||||
``True`` by default, can hide a plugin so it cannot be normally activated.
|
||||
|
||||
``restricted`` (``bool``):
|
||||
``False`` by default, restricts a plugin such that it can only be enabled for an event
|
||||
by system administrators / superusers.
|
||||
|
||||
A working example would be::
|
||||
|
||||
try:
|
||||
from pretix.base.plugins import PluginConfig
|
||||
except ImportError:
|
||||
raise RuntimeError("Please use pretix 2.7 or above to run this plugin!")
|
||||
# file: pretix/plugins/timerestriction/__init__.py
|
||||
from django.apps import AppConfig
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
||||
class PaypalApp(PluginConfig):
|
||||
name = 'pretix_paypal'
|
||||
verbose_name = _("PayPal")
|
||||
class PaypalApp(AppConfig):
|
||||
name = 'pretix.plugins.paypal'
|
||||
verbose_name = _("Stripe")
|
||||
|
||||
class PretixPluginMeta:
|
||||
name = _("PayPal")
|
||||
@@ -72,10 +67,10 @@ A working example would be::
|
||||
visible = True
|
||||
restricted = False
|
||||
description = _("This plugin allows you to receive payments via PayPal")
|
||||
compatibility = "pretix>=2.7.0"
|
||||
|
||||
|
||||
default_app_config = 'pretix_paypal.PaypalApp'
|
||||
default_app_config = 'pretix.plugins.paypal.PaypalApp'
|
||||
|
||||
|
||||
The ``AppConfig`` class may implement a property ``compatiblity_errors``, that checks
|
||||
whether the pretix installation meets all requirements of the plugin. If so,
|
||||
@@ -84,9 +79,6 @@ human-readable error messages. We recommend using the ``django.utils.functional.
|
||||
decorator, as it might get called a lot. You can also implement ``compatibility_warnings``,
|
||||
those will be displayed but not block the plugin execution.
|
||||
|
||||
The ``AppConfig`` class may implement a method ``is_available(event)`` that checks if a plugin
|
||||
is available for a specific event. If not, it will not be shown in the plugin list of that event.
|
||||
|
||||
Plugin registration
|
||||
-------------------
|
||||
|
||||
@@ -95,10 +87,11 @@ make use of the `entry point`_ feature of setuptools. To register a plugin that
|
||||
in a separate python package, your ``setup.py`` should contain something like this::
|
||||
|
||||
setup(
|
||||
args...,
|
||||
…
|
||||
|
||||
entry_points="""
|
||||
[pretix.plugin]
|
||||
pretix_paypal=pretix_paypal:PretixPluginMeta
|
||||
sampleplugin=sampleplugin:PretixPluginMeta
|
||||
"""
|
||||
)
|
||||
|
||||
@@ -116,25 +109,12 @@ pages. We suggest that you put your signal receivers into a ``signals`` submodul
|
||||
of your plugin. You should extend your ``AppConfig`` (see above) by the following
|
||||
method to make your receivers available::
|
||||
|
||||
class PaypalApp(AppConfig):
|
||||
class TimeRestrictionApp(AppConfig):
|
||||
…
|
||||
|
||||
def ready(self):
|
||||
from . import signals # NOQA
|
||||
|
||||
You can optionally specify code that is executed when your plugin is activated for an event
|
||||
in the ``installed`` method::
|
||||
|
||||
class PaypalApp(AppConfig):
|
||||
…
|
||||
|
||||
def installed(self, event):
|
||||
pass # Your code here
|
||||
|
||||
|
||||
Note that ``installed`` will *not* be called if the plugin in indirectly activated for an event
|
||||
because the event is created with settings copied from another event.
|
||||
|
||||
Views
|
||||
-----
|
||||
|
||||
@@ -150,5 +130,4 @@ your Django app label.
|
||||
.. _Django app: https://docs.djangoproject.com/en/1.7/ref/applications/
|
||||
.. _signal dispatcher: https://docs.djangoproject.com/en/1.7/topics/signals/
|
||||
.. _namespace packages: http://legacy.python.org/dev/peps/pep-0420/
|
||||
.. _entry point: https://setuptools.readthedocs.io/en/latest/pkg_resources.html#locating-plugins
|
||||
.. _cookiecutter: https://cookiecutter.readthedocs.io/en/latest/
|
||||
.. _entry point: https://pythonhosted.org/setuptools/setuptools.html#dynamic-discovery-of-services-and-plugins
|
||||
|
||||
@@ -1,125 +0,0 @@
|
||||
.. highlight:: python
|
||||
:linenothreshold: 5
|
||||
|
||||
.. _`pluginquality`:
|
||||
|
||||
Plugin quality checklist
|
||||
========================
|
||||
|
||||
If you want to write a high-quality pretix plugin, this is a list of things you should check before
|
||||
you publish it. This is also a list of things that we check, if we consider installing an externally
|
||||
developed plugin on our hosted infrastructure.
|
||||
|
||||
A. Meta
|
||||
-------
|
||||
|
||||
#. The plugin is clearly licensed under an appropriate license.
|
||||
|
||||
#. The plugin has an unambiguous name, description, and author metadata.
|
||||
|
||||
#. The plugin has a clear versioning scheme and the latest version of the plugin is kept compatible to the latest
|
||||
stable version of pretix.
|
||||
|
||||
#. The plugin is properly packaged using standard Python packaging tools.
|
||||
|
||||
#. The plugin correctly declares its external dependencies.
|
||||
|
||||
#. A contact address is provided in case of security issues.
|
||||
|
||||
B. Isolation
|
||||
------------
|
||||
|
||||
#. If any signal receivers use the `dispatch_uid`_ feature, the UIDs are prefixed by the plugin's name and do not
|
||||
clash with other plugins.
|
||||
|
||||
#. If any templates or static files are shipped, they are located in subdirectories with the name of the plugin and do
|
||||
not clash with other plugins or core files.
|
||||
|
||||
#. Any keys stored to the settings store are prefixed with the plugin's name and do not clash with other plugins or
|
||||
core.
|
||||
|
||||
#. Any keys stored to the user session are prefixed with the plugin's name and do not clash with other plugins or
|
||||
core.
|
||||
|
||||
#. Any registered URLs are unlikely to clash with other plugins or future core URLs.
|
||||
|
||||
C. Security
|
||||
-----------
|
||||
|
||||
#. All important actions are logged to the :ref:`shared log storage <logging>` and a signal receiver is registered to
|
||||
provide a human-readable representation of the log entry.
|
||||
|
||||
#. All views require appropriate permissions and use the ``event_urls`` mechanism if appropriate.
|
||||
:ref:`Read more <customview>`
|
||||
|
||||
#. Any session data for customers is stored in the cart session system if appropriate.
|
||||
|
||||
#. If the plugin is a payment provider:
|
||||
|
||||
#. No credit card numbers may be stored within pretix.
|
||||
|
||||
#. A notification/webhook system is implemented to notify pretix of any refunds.
|
||||
|
||||
#. If such a webhook system is implemented, contents of incoming webhooks are either verified using a cryptographic
|
||||
signature or are not being trusted and all data is fetched from an API instead.
|
||||
|
||||
D. Privacy
|
||||
----------
|
||||
|
||||
#. No personal data is stored that is not required for the plugin's functionality.
|
||||
|
||||
#. For any personal data that is saved to the database, an appropriate :ref:`data shredder <shredder>` is provided
|
||||
that offers the data for download and then removes it from the database (including log entries).
|
||||
|
||||
E. Internationalization
|
||||
-----------------------
|
||||
|
||||
#. All user-facing strings in templates, Python code, and templates are wrapped in `gettext calls`_.
|
||||
|
||||
#. No languages, time zones, date formats, or time formats are hardcoded.
|
||||
|
||||
#. Installing the plugin automatically compiles ``.po`` files to ``.mo`` files. This is fulfilled automatically if
|
||||
you use the ``setup.py`` file form our plugin cookiecutter.
|
||||
|
||||
F. Functionality
|
||||
----------------
|
||||
|
||||
#. If the plugin adds any database models or relationships from the settings storage to database models, it registers
|
||||
a receiver to the :py:attr:`pretix.base.signals.event_copy_data` or :py:attr:`pretix.base.signals.item_copy_data`
|
||||
signals.
|
||||
|
||||
#. If the plugin is a payment provider:
|
||||
|
||||
#. A webhook-like system is implemented if payment confirmations are not sent instantly.
|
||||
|
||||
#. Refunds are implemented, if possible.
|
||||
|
||||
#. In case of overpayment or external refunds, a "required action" is created to notify the event organizer.
|
||||
|
||||
#. If the plugin adds steps to the checkout process, it has been tested in combination with the pretix widget.
|
||||
|
||||
G. Code quality
|
||||
---------------
|
||||
|
||||
#. `isort`_ and `flake8`_ are used to ensure consistent code styling.
|
||||
|
||||
#. Unit tests are provided for important pieces of business logic.
|
||||
|
||||
#. Functional tests are provided for important interface parts.
|
||||
|
||||
#. Tests are provided to check that permission checks are working.
|
||||
|
||||
#. Continuous Integration is set up to check that tests are passing and styling is consistent.
|
||||
|
||||
H. Specific to pretix.eu
|
||||
------------------------
|
||||
|
||||
#. pretix.eu integrates the data stored by this plugin with its data report features.
|
||||
|
||||
#. pretix.eu integrates this plugin in its generated privacy statements, if necessary.
|
||||
|
||||
|
||||
.. _isort: https://www.google.de/search?q=isort&oq=isort&aqs=chrome..69i57j0j69i59j69i60l2j69i59.599j0j4&sourceid=chrome&ie=UTF-8
|
||||
.. _flake8: http://flake8.pycqa.org/en/latest/
|
||||
.. _gettext calls: https://docs.djangoproject.com/en/2.0/topics/i18n/translation/
|
||||
.. _dispatch_uid: https://docs.djangoproject.com/en/2.0/topics/signals/#django.dispatch.Signal.connect
|
||||
@@ -1,94 +0,0 @@
|
||||
.. highlight:: python
|
||||
:linenothreshold: 5
|
||||
|
||||
.. _`shredder`:
|
||||
|
||||
Writing a data shredder
|
||||
=======================
|
||||
|
||||
If your plugin adds the ability to store personal data within pretix, you should also implement a "data shredder"
|
||||
to anonymize or pseudonymize the data later.
|
||||
|
||||
Shredder registration
|
||||
---------------------
|
||||
|
||||
The data shredder API does not make a lot of usage from signals, however, it
|
||||
does use a signal to get a list of all available data shredders. Your plugin
|
||||
should listen for this signal and return the subclass of ``pretix.base.shredder.BaseDataShredder``
|
||||
that we'll provide in this plugin:
|
||||
|
||||
.. sourcecode:: python
|
||||
|
||||
from django.dispatch import receiver
|
||||
|
||||
from pretix.base.signals import register_data_shredders
|
||||
|
||||
|
||||
@receiver(register_data_shredders, dispatch_uid="custom_data_shredders")
|
||||
def register_shredder(sender, **kwargs):
|
||||
return [
|
||||
PluginDataShredder,
|
||||
]
|
||||
|
||||
The shredder class
|
||||
------------------
|
||||
|
||||
.. class:: pretix.base.shredder.BaseDataShredder
|
||||
|
||||
The central object of each invoice renderer is the subclass of ``BaseInvoiceRenderer``.
|
||||
|
||||
.. py:attribute:: BaseInvoiceRenderer.event
|
||||
|
||||
The default constructor sets this property to the event we are currently
|
||||
working for.
|
||||
|
||||
.. autoattribute:: identifier
|
||||
|
||||
This is an abstract attribute, you **must** override this!
|
||||
|
||||
.. autoattribute:: verbose_name
|
||||
|
||||
This is an abstract attribute, you **must** override this!
|
||||
|
||||
.. autoattribute:: description
|
||||
|
||||
This is an abstract attribute, you **must** override this!
|
||||
|
||||
.. automethod:: generate_files
|
||||
|
||||
.. automethod:: shred_data
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
For example, the core data shredder responsible for removing invoice address information including their history
|
||||
looks like this:
|
||||
|
||||
.. sourcecode:: python
|
||||
|
||||
class InvoiceAddressShredder(BaseDataShredder):
|
||||
verbose_name = _('Invoice addresses')
|
||||
identifier = 'invoice_addresses'
|
||||
description = _('This will remove all invoice addresses from orders, '
|
||||
'as well as logged changes to them.')
|
||||
|
||||
def generate_files(self) -> List[Tuple[str, str, str]]:
|
||||
yield 'invoice-addresses.json', 'application/json', json.dumps({
|
||||
ia.order.code: InvoiceAdddressSerializer(ia).data
|
||||
for ia in InvoiceAddress.objects.filter(order__event=self.event)
|
||||
}, indent=4)
|
||||
|
||||
@transaction.atomic
|
||||
def shred_data(self):
|
||||
InvoiceAddress.objects.filter(order__event=self.event).delete()
|
||||
|
||||
for le in self.event.logentry_set.filter(action_type="pretix.event.order.modified"):
|
||||
d = le.parsed_data
|
||||
if 'invoice_data' in d and not isinstance(d['invoice_data'], bool):
|
||||
for field in d['invoice_data']:
|
||||
if d['invoice_data'][field]:
|
||||
d['invoice_data'][field] = '█'
|
||||
le.data = json.dumps(d)
|
||||
le.shredded = True
|
||||
le.save(update_fields=['data', 'shredded'])
|
||||
|
||||
@@ -58,8 +58,6 @@ The output class
|
||||
|
||||
.. autoattribute:: is_enabled
|
||||
|
||||
.. autoattribute:: multi_download_enabled
|
||||
|
||||
.. autoattribute:: settings_form_fields
|
||||
|
||||
.. automethod:: settings_content_render
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
Concepts and Terminology
|
||||
========================
|
||||
Implementation concepts
|
||||
=======================
|
||||
|
||||
Basic terminology
|
||||
-----------------
|
||||
|
||||
The components
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
The project pretix is split into several components. The main components are:
|
||||
The project pretix is split into several components. The main three of them are:
|
||||
|
||||
**base**
|
||||
This is the foundation below all other components. It is primarily
|
||||
responsible for the data structures and database communication. It also hosts
|
||||
several utilities which are used by multiple other components and important parts of
|
||||
the business logic.
|
||||
several utilities which are used by multiple other components.
|
||||
|
||||
**control**
|
||||
This is the web-based backend software which allows organizers to
|
||||
@@ -18,13 +20,7 @@ The project pretix is split into several components. The main components are:
|
||||
|
||||
**presale**
|
||||
This is the ticket-shop itself, containing all of the parts visible to the
|
||||
end user. Also called "frontend" in parts of this documentation.
|
||||
|
||||
**api**
|
||||
A RESTful API exposed to integrate with third-party software.
|
||||
|
||||
**plugins**
|
||||
A set of pretix plugins that ship bundled with pretix.
|
||||
end user.
|
||||
|
||||
Users and events
|
||||
^^^^^^^^^^^^^^^^
|
||||
@@ -59,13 +55,12 @@ If an item is assigned to multiple quotas, it can only be bought if *all of them
|
||||
If multiple items are assigned to the same quota, the quota will be counted as sold out as soon as the
|
||||
*sum* of the two items exceeds the quota limit.
|
||||
|
||||
The availability of a quota is currently calculated by subtracting the following numbers from the quota
|
||||
The availability of a quota is currently calculated by substracting the following numbers from the quota
|
||||
limit:
|
||||
|
||||
* The number of orders placed for an item that are either already paid or within their granted payment period
|
||||
* The number of non-expired items currently in the shopping cart of users
|
||||
* The number of vouchers defined as "quota blocking" (see blow)
|
||||
* The number of people on the waiting list
|
||||
|
||||
The quota system tries very hard to be as friendly as possible to your event attendees while still making sure
|
||||
your limit is never exceeded. For example, when the payment period of an order expires without the order being
|
||||
@@ -82,12 +77,6 @@ Orders
|
||||
^^^^^^
|
||||
|
||||
If a customer completes the checkout process, an **Order** will be created containing all the entered information.
|
||||
An order can be in one of currently four states that are listed in the diagram below:
|
||||
An order can be in one of currently five states that are listed in the diagram below:
|
||||
|
||||
.. image:: /images/order_states.png
|
||||
|
||||
There are additional "fake" states that are displayed like states but not represented as states in the system:
|
||||
|
||||
* An order is considered **canceled (with paid fee)** if it is in **paid** status but does not include any non-cancelled positions.
|
||||
|
||||
* An order is considered **requiring approval** if it is in **pending** status with the ``require_approval`` attribute set to ``True``.
|
||||
|
||||
@@ -77,6 +77,6 @@ Attribution
|
||||
-----------
|
||||
|
||||
This Code of Conduct is adapted from the `Contributor Covenant`_, version 1.4,
|
||||
available at https://www.contributor-covenant.org/version/1/4/
|
||||
available at http://contributor-covenant.org/version/1/4/
|
||||
|
||||
.. _Contributor Covenant: https://www.contributor-covenant.org
|
||||
.. _Contributor Covenant: http://contributor-covenant.org
|
||||
|
||||
@@ -9,8 +9,7 @@ constructive and friendly feedback on your changes.
|
||||
First of all, you'll need pretix running locally on your machine. Head over to :ref:`devsetup` to learn how to do this.
|
||||
If you run into any problems on your way, please do not hesitate to ask us anytime!
|
||||
|
||||
Please note that we bound ourselves to a :ref:`coc` that applies to all communication around the project. You can be
|
||||
assured that we will not tolerate any form of harassment.
|
||||
Please note that we have a :ref:`coc` in place that applies to all communication around the project.
|
||||
|
||||
Sending a patch
|
||||
---------------
|
||||
@@ -19,9 +18,8 @@ If you improved pretix in any way, we'd be very happy if you contribute it
|
||||
back to the main code base! The easiest way to do so is to `create a pull request`_
|
||||
on our `GitHub repository`_.
|
||||
|
||||
We recommend that you create a feature branch for every issue you work on so the changes can
|
||||
be reviewed individually.
|
||||
Please use the test suite to check whether your changes break any existing features and run
|
||||
Before you do so, please `squash all your changes`_ into one single commit. Please
|
||||
use the test suite to check whether your changes break any existing features and run
|
||||
the code style checks to confirm you are consistent with pretix's coding style. You'll
|
||||
find instructions on this in the :ref:`checksandtests` section of the development setup guide.
|
||||
|
||||
@@ -36,3 +34,4 @@ Again: If you get stuck, do not hesitate to contact any of us, or Raphael person
|
||||
|
||||
.. _create a pull request: https://help.github.com/articles/creating-a-pull-request/
|
||||
.. _GitHub repository: https://github.com/pretix/pretix
|
||||
.. _squash all your changes: https://davidwalsh.name/squash-commits-git
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Contributing to pretix
|
||||
======================
|
||||
Contribution guide
|
||||
==================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
@@ -1,33 +1,39 @@
|
||||
Coding style and quality
|
||||
========================
|
||||
Coding style
|
||||
============
|
||||
|
||||
* Basically, we want all python code to follow the `PEP 8`_ standard. There are a few exceptions where
|
||||
we see things differently or just aren't that strict. The ``setup.cfg`` file in the project's source
|
||||
folder contains definitions that allow `flake8`_ to check for violations automatically. See :ref:`checksandtests`
|
||||
for more information. Use four spaces for indentation.
|
||||
Python code
|
||||
-----------
|
||||
|
||||
* We sort our imports by a certain schema, but you don't have to do this by hand. Again, ``setup.cfg`` contains
|
||||
some definitions that allow the command ``isort -rc <directory>`` to automatically sort the imports in your source
|
||||
files.
|
||||
* Basically: Follow `PEP 8`_.
|
||||
|
||||
* For templates and models, please take a look at the `Django Coding Style`_. We like Django's `class-based views`_ and
|
||||
kindly ask you to use them where appropriate.
|
||||
Use `flake8`_ to check for conformance problems. The project includes a setup.cfg file
|
||||
with a default configuration for flake8 that excludes migrations and other non-relevant
|
||||
code parts. It also silences a few checks, e.g. ``N802`` (function names should be lowercase)
|
||||
and increases the maximum line length to more than 79 characters. **However** you should
|
||||
still name all your functions lowercase [#f1]_ and keep your lines short when possible.
|
||||
|
||||
* Please remember to always mark all strings ever displayed to any user for `translation`_.
|
||||
* Our build server will reject all code violating other flake8 checks than the following:
|
||||
|
||||
* We expect all new code to come with proper tests. When writing new tests, please write them using `pytest-style`_
|
||||
test functions and raw ``assert`` statements. Use `fixtures`_ to prevent repetitive code. Some old parts of pretix'
|
||||
test suite are in the style of Python's unit test module. If you extend those files, you might continue in this style,
|
||||
but please use pytest style for any new test files.
|
||||
* E123: closing bracket does not match indentation of opening bracket’s line
|
||||
* F403: ``from module import *`` used; unable to detect undefined names
|
||||
* F401: module imported but unused
|
||||
* N802: function names should be lowercase
|
||||
|
||||
* Please keep the first line of your commit messages short. When referencing an issue, please phrase it like
|
||||
``Fix #123 -- Problems with order creation`` or ``Refs #123 -- Fix this part of that bug``.
|
||||
So please make sure that you *always* follow all other rules and break these rules *only when
|
||||
it makes sense*.
|
||||
|
||||
* Use ``isort -rc pretix`` in the source directory to order your imports.
|
||||
|
||||
* Indent your code with four spaces.
|
||||
|
||||
* For templates and models, follow the `Django Coding Style`_.
|
||||
|
||||
* Use Django's class-based views
|
||||
|
||||
* Always mark all strings ever displayed to any user for translation.
|
||||
|
||||
|
||||
.. _PEP 8: https://legacy.python.org/dev/peps/pep-0008/
|
||||
.. _PEP 8: http://legacy.python.org/dev/peps/pep-0008/
|
||||
.. _flake8: https://pypi.python.org/pypi/flake8
|
||||
.. _Django Coding Style: https://docs.djangoproject.com/en/dev/internals/contributing/writing-code/coding-style/
|
||||
.. _translation: https://docs.djangoproject.com/en/1.11/topics/i18n/translation/
|
||||
.. _class-based views: https://docs.djangoproject.com/en/1.11/topics/class-based-views/
|
||||
.. _pytest-style: https://docs.pytest.org/en/latest/assert.html
|
||||
.. _fixtures: https://docs.pytest.org/en/latest/fixture.html
|
||||
.. [#f1] But Python's very own ``unittest`` module forces us to use ``setUp`` as a method name...
|
||||
|
||||
@@ -14,7 +14,7 @@ Implementing a task
|
||||
A common pattern for implementing asynchronous tasks can be seen a lot in ``pretix.base.services``
|
||||
and looks like this::
|
||||
|
||||
from pretix.celery_app import app
|
||||
from pretix.celery import app
|
||||
|
||||
@app.task
|
||||
def my_task(argument1, argument2):
|
||||
|
||||
@@ -2,9 +2,6 @@ Sending Email
|
||||
=============
|
||||
|
||||
pretix allows event organizers to configure how they want to send emails to their users in multiple ways.
|
||||
Therefore, all emails should be sent through the following function.
|
||||
|
||||
If the email you send is related to an order, you should also take a look at the
|
||||
:py:meth:`~pretix.base.models.Order.send_mail` of the order model.
|
||||
Therefore, all emails should be sent through the following function:
|
||||
|
||||
.. autofunction:: pretix.base.services.mail.mail
|
||||
|
||||
@@ -6,18 +6,116 @@ One of pretix's major selling points is its multi-language capability. We make h
|
||||
way to translate *user-generated content*. In our case, we need to translate strings like product names
|
||||
or event descriptions, so we need event organizers to be able to fill in all fields in multiple languages.
|
||||
|
||||
For this purpose, we use ``django-i18nfield`` which started out as part of pretix and then got refactored into
|
||||
its own library. It has comprehensive documentation on how to work with its `strings`_, `database fields`_ and
|
||||
`forms`_.
|
||||
.. note:: Implementing object-level translation in a relational database is a task that requires some difficult
|
||||
trade-off. We decided for a design that is not elegant on the database level (as it violates the `1NF`_) and
|
||||
makes searching in the respective database fields very hard, but allows for a simple design on the ORM level
|
||||
and adds only minimal performance overhead.
|
||||
|
||||
All classes and functions introduced in this document are located in ``pretix.base.i18n`` if not stated otherwise.
|
||||
|
||||
Database storage
|
||||
----------------
|
||||
|
||||
pretix provides two custom model field types that allow you to work with localized strings: ``I18nCharField`` and
|
||||
``I18nTextField``. Both of them are stored in the database as a ``TextField`` internally, they only differ in the
|
||||
default form widget that is used by ``ModelForm``.
|
||||
|
||||
As pretix does not use these fields in places that need to be searched, the negative performance impact when searching
|
||||
and indexing these fields in negligible, as mentioned above. Lookups are currently not even implemented on these
|
||||
fields. In the database, the strings will be stored as a JSON-encoded mapping of language codes to strings.
|
||||
|
||||
Whenever you interact with those fields, you will either provide or receive an instance of the following class:
|
||||
|
||||
.. autoclass:: pretix.base.i18n.LazyI18nString
|
||||
:members: __init__, localize, __str__
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
The following examples are given to illustrate how you can work with ``LazyI18nString``.
|
||||
|
||||
.. testsetup:: *
|
||||
|
||||
from pretix.base.i18n import LazyI18nString, language
|
||||
|
||||
To create a LazyI18nString, we can cast a simple string:
|
||||
|
||||
.. doctest::
|
||||
|
||||
>>> naive = LazyI18nString('Naive untranslated string')
|
||||
>>> naive
|
||||
<LazyI18nString: 'Naive untranslated string'>
|
||||
|
||||
Or we can provide a dictionary with multiple translations:
|
||||
|
||||
.. doctest::
|
||||
|
||||
>>> translated = LazyI18nString({'en': 'English String', 'de': 'Deutscher String'})
|
||||
|
||||
We can use ``localize`` to get the string in a specific language:
|
||||
|
||||
.. doctest::
|
||||
|
||||
>>> translated.localize('de')
|
||||
'Deutscher String'
|
||||
|
||||
>>> translated.localize('en')
|
||||
'English String'
|
||||
|
||||
If we try a locale that does not exist for the string, we might get a it either in a similar locale or in the system's default language:
|
||||
|
||||
.. doctest::
|
||||
|
||||
>>> translated.localize('de-AT')
|
||||
'Deutscher String'
|
||||
|
||||
>>> translated.localize('zh')
|
||||
'English String'
|
||||
|
||||
>>> naive.localize('de')
|
||||
'Naive untranslated string'
|
||||
|
||||
If we cast a ``LazyI18nString`` to ``str``, ``localize`` will be called with the currently active language:
|
||||
|
||||
.. doctest::
|
||||
|
||||
>>> from django.utils import translation
|
||||
>>> str(translated)
|
||||
'English String'
|
||||
>>> translation.activate('de')
|
||||
>>> str(translated)
|
||||
'Deutscher String'
|
||||
|
||||
You can also use our handy context manager to set the locale temporarily:
|
||||
|
||||
.. doctest::
|
||||
|
||||
>>> translation.activate('en')
|
||||
>>> with language('de'):
|
||||
... str(translated)
|
||||
'Deutscher String'
|
||||
>>> str(translated)
|
||||
'English String'
|
||||
|
||||
Forms
|
||||
-----
|
||||
|
||||
For backwards-compatibility with older parts of pretix' code base and older plugins, ``pretix.base.forms`` still
|
||||
contains a number of forms that are equivalent in name and usage to their counterparts in ``i18nfield.forms`` with
|
||||
the difference that they take an ``event`` keyword argument and then set the ``locales`` argument based on
|
||||
``event.settings.get('locales')``.
|
||||
We provide i18n-aware versions of the respective form fields and widgets: ``I18nFormField`` with the ``I18nTextInput``
|
||||
and ``I18nTextarea`` widgets. They transparently allow you to use ``LazyI18nString`` values in forms and render text
|
||||
inputs for multiple languages.
|
||||
|
||||
.. autoclass:: pretix.base.i18n.I18nFormField
|
||||
|
||||
To easily limit the displayed languages to the languages relevant to an event, there is a custom ``ModelForm`` subclass
|
||||
that deals with this for you:
|
||||
|
||||
.. autoclass:: pretix.base.forms.I18nModelForm
|
||||
|
||||
There are equivalents for ``BaseModelFormSet`` and ``BaseInlineFormSet``:
|
||||
|
||||
.. autoclass:: pretix.base.forms.I18nFormSet
|
||||
|
||||
.. autoclass:: pretix.base.forms.I18nInlineFormSet
|
||||
|
||||
Useful utilities
|
||||
----------------
|
||||
@@ -37,6 +135,4 @@ action that causes the mail to be sent.
|
||||
|
||||
.. _translation features: https://docs.djangoproject.com/en/1.9/topics/i18n/translation/
|
||||
.. _GNU gettext: https://www.gnu.org/software/gettext/
|
||||
.. _strings: https://django-i18nfield.readthedocs.io/en/latest/strings.html
|
||||
.. _database fields: https://django-i18nfield.readthedocs.io/en/latest/quickstart.html
|
||||
.. _forms: https://django-i18nfield.readthedocs.io/en/latest/forms.html
|
||||
.. _1NF: https://en.wikipedia.org/wiki/First_normal_form
|
||||
|
||||
@@ -16,5 +16,4 @@ Contents:
|
||||
settings
|
||||
background
|
||||
email
|
||||
permissions
|
||||
logging
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
Logging and notifications
|
||||
=========================
|
||||
Logging
|
||||
=======
|
||||
|
||||
As pretix is handling monetary transactions, we are very careful to make it possible to review all changes
|
||||
in the system that lead to the current state.
|
||||
|
||||
.. _`logging`:
|
||||
|
||||
Logging changes
|
||||
---------------
|
||||
|
||||
@@ -21,7 +19,7 @@ To actually log an action, you can just call the ``log_action`` method on your o
|
||||
order.log_action('pretix.event.order.canceled', user=user, data={})
|
||||
|
||||
The positional ``action`` argument should represent the type of action and should be globally unique, we
|
||||
recommend to prefix it with your package name, e.g. ``paypal.payment.rejected``. The ``user`` argument is
|
||||
recomment do prefix it with your packagename, e.g. ``paypal.payment.rejected``. The ``user`` argument is
|
||||
optional and may contain the user who performed the action. The optional ``data`` argument can contain
|
||||
additional information about this action.
|
||||
|
||||
@@ -83,61 +81,6 @@ implementation could look like::
|
||||
if logentry.action_type in plains:
|
||||
return plains[logentry.action_type]
|
||||
|
||||
Sending notifications
|
||||
---------------------
|
||||
|
||||
If you think that the logged information might be important or urgent enough to send out a notification to interested
|
||||
organizers. In this case, you should listen for the :py:attr:`pretix.base.signals.register_notification_types` signal
|
||||
to register a notification type::
|
||||
|
||||
@receiver(register_notification_types)
|
||||
def register_my_notification_types(sender, **kwargs):
|
||||
return [MyNotificationType(sender)]
|
||||
|
||||
Note that this event is different than other events send out by pretix: ``sender`` may be an event or ``None``. The
|
||||
latter case is required to let the user define global notification preferences for all events.
|
||||
|
||||
You also need to implement a custom class that specifies how notifications should be handled for your notification type.
|
||||
You should subclass the base ``NotificationType`` class and implement all its members:
|
||||
|
||||
.. autoclass:: pretix.base.notifications.NotificationType
|
||||
:members: action_type, verbose_name, required_permission, build_notification
|
||||
|
||||
A simple implementation could look like this::
|
||||
|
||||
class MyNotificationType(NotificationType):
|
||||
required_permission = "can_view_orders"
|
||||
action_type = "pretix.event.order.paid"
|
||||
verbose_name = _("Order has been paid")
|
||||
|
||||
def build_notification(self, logentry: LogEntry):
|
||||
order = logentry.content_object
|
||||
|
||||
order_url = build_absolute_uri(
|
||||
'control:event.order',
|
||||
kwargs={
|
||||
'organizer': logentry.event.organizer.slug,
|
||||
'event': logentry.event.slug,
|
||||
'code': order.code
|
||||
}
|
||||
)
|
||||
|
||||
n = Notification(
|
||||
event=logentry.event,
|
||||
title=_('Order {code} has been marked as paid').format(code=order.code),
|
||||
url=order_url
|
||||
)
|
||||
n.add_attribute(_('Order code'), order.code)
|
||||
n.add_action(_('View order details'), order_url)
|
||||
return n
|
||||
|
||||
As you can see, the relevant code is in the ``build_notification`` method that is supposed to create a ``Notification``
|
||||
method that has a title, description, URL, attributes, and actions. The full definition of ``Notification`` is the
|
||||
following:
|
||||
|
||||
.. autoclass:: pretix.base.notifications.Notification
|
||||
:members: add_action, add_attribute
|
||||
|
||||
|
||||
Logging technical information
|
||||
-----------------------------
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
.. highlight:: python
|
||||
:linenothreshold: 5
|
||||
|
||||
.. spelling:: answ contrib
|
||||
|
||||
Data model
|
||||
==========
|
||||
|
||||
@@ -22,30 +20,18 @@ Organizers and events
|
||||
.. autoclass:: pretix.base.models.Organizer
|
||||
:members:
|
||||
|
||||
.. autoclass:: pretix.base.models.Event
|
||||
:members: get_date_from_display, get_time_from_display, get_date_to_display, get_date_range_display, presale_has_ended, presale_is_running, cache, lock, get_plugins, get_mail_backend, payment_term_last, get_payment_providers, get_invoice_renderers, invoice_renderer, settings
|
||||
|
||||
.. autoclass:: pretix.base.models.SubEvent
|
||||
:members: get_date_from_display, get_time_from_display, get_date_to_display, get_date_range_display, presale_has_ended, presale_is_running
|
||||
|
||||
.. autoclass:: pretix.base.models.Team
|
||||
.. autoclass:: pretix.base.models.OrganizerPermission
|
||||
:members:
|
||||
|
||||
.. autoclass:: pretix.base.models.TeamAPIToken
|
||||
.. autoclass:: pretix.base.models.Event
|
||||
:members:
|
||||
|
||||
.. autoclass:: pretix.base.models.EventPermission
|
||||
:members:
|
||||
|
||||
.. autoclass:: pretix.base.models.RequiredAction
|
||||
:members:
|
||||
|
||||
.. autoclass:: pretix.base.models.EventMetaProperty
|
||||
:members:
|
||||
|
||||
.. autoclass:: pretix.base.models.EventMetaValue
|
||||
:members:
|
||||
|
||||
.. autoclass:: pretix.base.models.SubEventMetaValue
|
||||
:members:
|
||||
|
||||
|
||||
Items
|
||||
-----
|
||||
@@ -59,15 +45,6 @@ Items
|
||||
.. autoclass:: pretix.base.models.ItemVariation
|
||||
:members:
|
||||
|
||||
.. autoclass:: pretix.base.models.SubEventItem
|
||||
:members:
|
||||
|
||||
.. autoclass:: pretix.base.models.SubEventItemVariation
|
||||
:members:
|
||||
|
||||
.. autoclass:: pretix.base.models.ItemAddOn
|
||||
:members:
|
||||
|
||||
.. autoclass:: pretix.base.models.Question
|
||||
:members:
|
||||
|
||||
@@ -86,20 +63,11 @@ Carts and Orders
|
||||
.. autoclass:: pretix.base.models.OrderPosition
|
||||
:members:
|
||||
|
||||
.. autoclass:: pretix.base.models.OrderFee
|
||||
:members:
|
||||
|
||||
.. autoclass:: pretix.base.models.OrderPayment
|
||||
:members:
|
||||
|
||||
.. autoclass:: pretix.base.models.OrderRefund
|
||||
:members:
|
||||
|
||||
.. autoclass:: pretix.base.models.CartPosition
|
||||
:members:
|
||||
|
||||
.. autoclass:: pretix.base.models.QuestionAnswer
|
||||
:members:
|
||||
:members:
|
||||
|
||||
.. autoclass:: pretix.base.models.Checkin
|
||||
:members:
|
||||
@@ -124,3 +92,5 @@ Vouchers
|
||||
|
||||
.. autoclass:: pretix.base.models.Voucher
|
||||
:members:
|
||||
|
||||
.. _cleanerversion: https://github.com/swisscom/cleanerversion
|
||||
|
||||
@@ -1,194 +0,0 @@
|
||||
Permissions
|
||||
===========
|
||||
|
||||
pretix uses a fine-grained permission system to control who is allowed to control what parts of the system.
|
||||
The central concept here is the concept of *Teams*. You can read more on `configuring teams and permissions <user-teams>`_
|
||||
and the :class:`pretix.base.models.Team` model in the respective parts of the documentation. The basic digest is:
|
||||
An organizer account can have any number of teams, and any number of users can be part of a team. A team can be
|
||||
assigned a set of permissions and connected to some or all of the events of the organizer.
|
||||
|
||||
A second way to access pretix is via the REST API, which allows authentication via tokens that are bound to a team,
|
||||
but not to a user. You can read more at :class:`pretix.base.models.TeamAPIToken`. This page will show you how to
|
||||
work with permissions in plugins and within the pretix code base.
|
||||
|
||||
Requiring permissions for a view
|
||||
--------------------------------
|
||||
|
||||
pretix provides a number of useful mixins and decorators that allow you to specify that a user needs a certain
|
||||
permission level to access a view::
|
||||
|
||||
from pretix.control.permissions import (
|
||||
OrganizerPermissionRequiredMixin, organizer_permission_required
|
||||
)
|
||||
|
||||
|
||||
class MyOrgaView(OrganizerPermissionRequiredMixin, View):
|
||||
permission = 'can_change_organizer_settings'
|
||||
# Only users with the permission ``can_change_organizer_settings`` on
|
||||
# this organizer can access this
|
||||
|
||||
|
||||
class MyOtherOrgaView(OrganizerPermissionRequiredMixin, View):
|
||||
permission = None
|
||||
# Only users with *any* permission on this organizer can access this
|
||||
|
||||
|
||||
@organizer_permission_required('can_change_organizer_settings')
|
||||
def my_orga_view(request, organizer, **kwargs):
|
||||
# Only users with the permission ``can_change_organizer_settings`` on
|
||||
# this organizer can access this
|
||||
|
||||
|
||||
@organizer_permission_required()
|
||||
def my_other_orga_view(request, organizer, **kwargs):
|
||||
# Only users with *any* permission on this organizer can access this
|
||||
|
||||
|
||||
Of course, the same is available on event level::
|
||||
|
||||
from pretix.control.permissions import (
|
||||
EventPermissionRequiredMixin, event_permission_required
|
||||
)
|
||||
|
||||
|
||||
class MyEventView(EventPermissionRequiredMixin, View):
|
||||
permission = 'can_change_event_settings'
|
||||
# Only users with the permission ``can_change_event_settings`` on
|
||||
# this event can access this
|
||||
|
||||
|
||||
class MyOtherEventView(EventPermissionRequiredMixin, View):
|
||||
permission = None
|
||||
# Only users with *any* permission on this event can access this
|
||||
|
||||
|
||||
@event_permission_required('can_change_event_settings')
|
||||
def my_event_view(request, organizer, **kwargs):
|
||||
# Only users with the permission ``can_change_event_settings`` on
|
||||
# this event can access this
|
||||
|
||||
|
||||
@event_permission_required()
|
||||
def my_other_event_view(request, organizer, **kwargs):
|
||||
# Only users with *any* permission on this event can access this
|
||||
|
||||
You can also require that this view is only accessible by system administrators with an active "admin session"
|
||||
(see below for what this means)::
|
||||
|
||||
from pretix.control.permissions import (
|
||||
AdministratorPermissionRequiredMixin, administrator_permission_required
|
||||
)
|
||||
|
||||
|
||||
class MyGlobalView(AdministratorPermissionRequiredMixin, View):
|
||||
# ...
|
||||
|
||||
|
||||
@administrator_permission_required
|
||||
def my_global_view(request, organizer, **kwargs):
|
||||
# ...
|
||||
|
||||
In rare cases it might also be useful to expose a feature only to people who have a staff account but do not
|
||||
necessarily have an active admin session::
|
||||
|
||||
from pretix.control.permissions import (
|
||||
StaffMemberRequiredMixin, staff_member_required
|
||||
)
|
||||
|
||||
|
||||
class MyGlobalView(StaffMemberRequiredMixin, View):
|
||||
# ...
|
||||
|
||||
|
||||
@staff_member_required
|
||||
def my_global_view(request, organizer, **kwargs):
|
||||
# ...
|
||||
|
||||
|
||||
|
||||
Requiring permissions in the REST API
|
||||
-------------------------------------
|
||||
|
||||
When creating your own ``viewset`` using Django REST framework, you just need to set the ``permission`` attribute
|
||||
and pretix will check it automatically for you::
|
||||
|
||||
class MyModelViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
permission = 'can_view_orders'
|
||||
|
||||
Checking permission in code
|
||||
---------------------------
|
||||
|
||||
If you need to work with permissions manually, there are a couple of useful helper methods on the :class:`pretix.base.models.Event`,
|
||||
:class:`pretix.base.models.User` and :class:`pretix.base.models.TeamAPIToken` classes. Here's a quick overview.
|
||||
|
||||
Return all users that are in any team that is connected to this event::
|
||||
|
||||
>>> event.get_users_with_any_permission()
|
||||
<QuerySet: …>
|
||||
|
||||
Return all users that are in a team with a specific permission for this event::
|
||||
|
||||
>>> event.get_users_with_permission('can_change_event_settings')
|
||||
<QuerySet: …>
|
||||
|
||||
Determine if a user has a certain permission for a specific event::
|
||||
|
||||
>>> user.has_event_permission(organizer, event, 'can_change_event_settings', request=request)
|
||||
True
|
||||
|
||||
Determine if a user has any permission for a specific event::
|
||||
|
||||
>>> user.has_event_permission(organizer, event, request=request)
|
||||
True
|
||||
|
||||
In the two previous commands, the ``request`` argument is optional, but required to support staff sessions (see below).
|
||||
|
||||
The same method exists for organizer-level permissions::
|
||||
|
||||
>>> user.has_organizer_permission(organizer, 'can_change_event_settings', request=request)
|
||||
True
|
||||
|
||||
Sometimes, it might be more useful to get the set of permissions at once::
|
||||
|
||||
>>> user.get_event_permission_set(organizer, event)
|
||||
{'can_change_event_settings', 'can_view_orders', 'can_change_orders'}
|
||||
|
||||
>>> user.get_organizer_permission_set(organizer, event)
|
||||
{'can_change_organizer_settings', 'can_create_events'}
|
||||
|
||||
Within a view on the ``/control`` subpath, the results of these two methods are already available in the
|
||||
``request.eventpermset`` and ``request.orgapermset`` properties. This makes it convenient to query them in templates::
|
||||
|
||||
{% if "can_change_orders" in request.eventpermset %}
|
||||
…
|
||||
{% endif %}
|
||||
|
||||
You can also do the reverse to get any events a user has access to::
|
||||
|
||||
>>> user.get_events_with_permission('can_change_event_settings', request=request)
|
||||
<QuerySet: …>
|
||||
|
||||
>>> user.get_events_with_any_permission(request=request)
|
||||
<QuerySet: …>
|
||||
|
||||
Most of these methods work identically on :class:`pretix.base.models.TeamAPIToken`.
|
||||
|
||||
Staff sessions
|
||||
--------------
|
||||
|
||||
.. versionchanged:: 1.14
|
||||
|
||||
In 1.14, the ``User.is_superuser`` attribute has been deprecated and statically set to return ``False``. Staff
|
||||
sessions have been newly introduced.
|
||||
|
||||
System administrators of a pretix instance are identified by the ``is_staff`` attribute on the user model. By default,
|
||||
the regular permission rules apply for users with ``is_staff = True``. The only difference is that such users can
|
||||
temporarily turn on "staff mode" via a button in the user interface that grants them **all permissions** as long as
|
||||
staff mode is active. You can check if a user is in staff mode using their session key:
|
||||
|
||||
>>> user.has_active_staff_session(request.session.session_key)
|
||||
False
|
||||
|
||||
Staff mode has a hard time limit and during staff mode, a middleware will log all requests made by that user. Later,
|
||||
the user is able to also save a message to comment on what they did in their administrative session. This feature is
|
||||
intended to help compliance with data protection rules as imposed e.g. by GDPR.
|
||||
@@ -2,10 +2,7 @@ Settings storage
|
||||
================
|
||||
|
||||
pretix is highly configurable and therefore needs to store a lot of per-event and per-organizer settings.
|
||||
For this purpose, we use `django-hierarkey`_ which started out as part of pretix and then got refactored into
|
||||
its own library. It has a comprehensive `documentation`_ which you should read if you work with settings in pretix.
|
||||
|
||||
The settings are stored in the database and accessed through a ``HierarkeyProxy`` instance. You can obtain
|
||||
Those settings are stored in the database and accessed through a ``SettingsProxy`` instance. You can obtain
|
||||
such an instance from any event or organizer model instance by just accessing ``event.settings`` or
|
||||
``organizer.settings``, respectively.
|
||||
|
||||
@@ -20,10 +17,12 @@ includes serializers for serializing the following types:
|
||||
|
||||
In code, we recommend to always use the ``.get()`` method on the settings object to access a value, but for
|
||||
convenience in templates you can also access settings values at ``settings[name]`` and ``settings.name``.
|
||||
See the hierarkey `documentation`_ for more information.
|
||||
|
||||
.. autoclass:: pretix.base.settings.SettingsProxy
|
||||
:members: get, set, delete, freeze
|
||||
|
||||
To avoid naming conflicts, plugins are requested to prefix all settings they use with the name of the plugin
|
||||
or something unique, e.g. ``payment_paypal_api_key``. To reduce redundant typing of this prefix, we provide
|
||||
or something unique, e.g. ``payment.paypal.api_key``. To reduce redundant typing of this prefix, we provide
|
||||
another helper class:
|
||||
|
||||
.. autoclass:: pretix.base.settings.SettingsSandbox
|
||||
@@ -34,10 +33,10 @@ you will just be passed a sandbox object with a prefix generated from your provi
|
||||
Forms
|
||||
-----
|
||||
|
||||
Hierarkey also provides a base class for forms that allow the modification of settings. pretix contains a
|
||||
subclass that also adds support for internationalized fields:
|
||||
We also provide a base class for forms that allow the modification of settings:
|
||||
|
||||
.. autoclass:: pretix.base.forms.SettingsForm
|
||||
:members: save
|
||||
|
||||
You can simply use it like this::
|
||||
|
||||
@@ -52,17 +51,3 @@ You can simply use it like this::
|
||||
help_text=_("The number of days after placing an order the user has to pay to "
|
||||
"preserve his reservation."),
|
||||
)
|
||||
|
||||
Defaults in plugins
|
||||
-------------------
|
||||
|
||||
Plugins can add custom hardcoded defaults in the following way::
|
||||
|
||||
from pretix.base.settings import settings_hierarkey
|
||||
|
||||
settings_hierarkey.add_default('key', 'value', type)
|
||||
|
||||
Make sure that you include this code in a module that is imported at app loading time.
|
||||
|
||||
.. _django-hierarkey: https://github.com/raphaelm/django-hierarkey
|
||||
.. _documentation: https://django-hierarkey.readthedocs.io/en/latest/
|
||||
|
||||
@@ -67,7 +67,7 @@ available as ``plugins:sendmail:send``.
|
||||
Generating a URL for the frontend is a complicated task, because you need to know whether the event's
|
||||
organizer uses a custom URL or not and then generate the URL with a different domain and different
|
||||
arguments based on this information. pretix provides some helpers to make this easier. The first helper
|
||||
is a python method that emulates a behavior similar to ``reverse``:
|
||||
is a python method that emulates a behaviour similar to ``reverse``:
|
||||
|
||||
.. autofunction:: pretix.multidomain.urlreverse.eventreverse
|
||||
|
||||
@@ -82,5 +82,5 @@ Implementation details
|
||||
----------------------
|
||||
|
||||
There are some other caveats when using a design like this, e.g. you have to care about cookie domains
|
||||
and referrer verification yourself. If you want to see how we built this, look into the ``pretix/multidomain/``
|
||||
and referer verification yourself. If you want to see how we built this, look into the ``pretix/multidomain/``
|
||||
sub-tree.
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
Developer documentation
|
||||
=======================
|
||||
|
||||
Contents:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
concepts
|
||||
setup
|
||||
structure
|
||||
contribution/index
|
||||
implementation/index
|
||||
translation/index
|
||||
api/index
|
||||
structure
|
||||
|
||||
.. TODO::
|
||||
Document settings objects, ItemVariation objects, form fields.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user