Fixed minor documentation errors and mistakes (#151)

This commit is contained in:
Tobias Kunze
2016-07-14 20:01:38 +02:00
committed by Raphael Michel
parent f779b70deb
commit bfc721978d
41 changed files with 231 additions and 208 deletions

View File

@@ -4,7 +4,7 @@
Writing an exporter plugin
==========================
An is a method to export the product and order data in pretix for later use in another
An Exporter is a method to export the product and order data in pretix for later use in another
context.
In this document, we will walk through the creation of an exporter output plugin. This
@@ -18,7 +18,7 @@ Exporter registration
The exporter API does not make a lot of usage from signals, however, it does use a signal to get a list of
all available exporters. Your plugin should listen for this signal and return the subclass of
``pretix.base.exporter.BaseExporter``
that we'll soon create::
that we'll provide in this plugin::
from django.dispatch import receiver
@@ -36,8 +36,7 @@ The exporter class
.. class:: pretix.base.exporter.BaseExporter
The central object of each exporter is the subclass of ``BaseExporter`` we already mentioned above.
In this section, we will discuss it's interface in detail.
The central object of each exporter is the subclass of ``BaseExporter``.
.. py:attribute:: BaseExporter.event

View File

@@ -60,8 +60,8 @@ Dashboards
:members: event_dashboard_widgets, user_dashboard_widgets
Displaying of log entries
-------------------------
Display of log entries
----------------------
.. automodule:: pretix.base.signals
:members: logentry_display

View File

@@ -14,7 +14,7 @@ Provider registration
The payment provider API does not make a lot of usage from signals, however, it
does use a signal to get a list of all available payment providers. Your plugin
should listen for this signal and return the subclass of ``pretix.base.payment.BasePaymentProvider``
that we'll soon create::
that the plugin will provide::
from django.dispatch import receiver
@@ -32,8 +32,7 @@ The provider class
.. class:: pretix.base.payment.BasePaymentProvider
The central object of each payment provider is the subclass of ``BasePaymentProvider``
we already mentioned above. In this section, we will discuss it's interface in detail.
The central object of each payment provider is the subclass of ``BasePaymentProvider``.
.. py:attribute:: BasePaymentProvider.event
@@ -105,9 +104,9 @@ Additional views
For most simple payment providers it is more than sufficient to implement
some of the :py:class:`BasePaymentProvider` methods. However, in some cases
it is necessary to introduce additional views. One example is the PayPal
provider. It redirects the user to a paypal website in the
:py:meth:`BasePaymentProvider.checkout_prepare`` step of the checkout process
and provides PayPal with an URL to redirect back to. This URL points to a
provider. It redirects the user to a PayPal website in the
:py:meth:`BasePaymentProvider.checkout_prepare` step of the checkout process
and provides PayPal with a URL to redirect back to. This URL points to a
view which looks roughly like this::
@login_required
@@ -123,7 +122,7 @@ view which looks roughly like this::
try:
# Redirect back to the confirm page. We chose to save the
# event ID in the user's session. We could also put this
# information into an URL parameter.
# information into a URL parameter.
event = Event.objects.current.get(identity=request.session['payment_paypal_event'])
return redirect(reverse('presale:event.checkout.confirm', kwargs={
'event': event.slug,
@@ -136,6 +135,6 @@ view which looks roughly like this::
If you do not want to provide a view of your own, you could even let PayPal
redirect directly back to the confirm page and handle the query parameters
inside :py:meth:`BasePaymentProvider.checkout_is_valid_session``. However,
inside :py:meth:`BasePaymentProvider.checkout_is_valid_session`. However,
because some external providers (not PayPal) force you to have a *constant*
redirect URL, it might be necessary to define custom views.

View File

@@ -6,7 +6,7 @@ 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
in an own python package nstalled like any other python module. There are also some
in its own python package installed like any other python module. There are also some
official plugins inside the ``pretix/plugins/`` directory of your pretix installation.
The communication between pretix and the plugins happens mostly using Django's
@@ -16,13 +16,13 @@ on the next pages.
.. _`pluginsetup`:
To create a new plugin, create a new python package which must be a vaild `Django app`_
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.
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,
they do assume that you have prior knowledge about Django (e.g. it's view layer,
how it's ORM works, etc.).
they do assume that you have prior knowledge about Django (e.g. its view layer,
how its ORM works, etc.).
Plugin metadata
---------------
@@ -83,7 +83,7 @@ Plugin registration
Somehow, pretix needs to know that your plugin exists at all. For this purpose, we
make use of the `entry point`_ feature of setuptools. To register a plugin that lives
in a seperate python package, your ``setup.py`` sould contain something like this::
in a separate python package, your ``setup.py`` should contain something like this::
setup(
@@ -129,4 +129,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://pythonhosted.org/setuptools/setuptools.html#dynamic-discovery-of-services-and-plugins
.. _entry point: https://pythonhosted.org/setuptools/setuptools.html#dynamic-discovery-of-services-and-plugins

View File

@@ -17,7 +17,7 @@ Output registration
The ticket output API does not make a lot of usage from signals, however, it
does use a signal to get a list of all available ticket outputs. Your plugin
should listen for this signal and return the subclass of ``pretix.base.ticketoutput.BaseTicketOutput``
that we'll soon create::
that we'll provide in this plugin::
from django.dispatch import receiver
@@ -35,8 +35,7 @@ The output class
.. class:: pretix.base.ticketoutput.BaseTicketOutput
The central object of each ticket output is the subclass of ``BaseTicketOutput``
we already mentioned above. In this section, we will discuss it's interface in detail.
The central object of each ticket output is the subclass of ``BaseTicketOutput``.
.. py:attribute:: BaseTicketOutput.event

View File

@@ -19,7 +19,7 @@ The project pretix is split into several components. The main three of them are:
create and manage their events, items, orders and tickets.
**pretix.presale**
Pretixpresale is the ticket-shop itself, containing all the parts visible to the
Pretixpresale is the ticket-shop itself, containing all of the parts visible to the
end user.
Users and events
@@ -28,25 +28,24 @@ Users and events
Pretix is all about **events**, which are defined as something happening somewhere.
Every event is managed by the **organizer**, an abstract entity running the event.
Pretix has a concept of **users** that is used for all the people who have to log
in to the control panel to manage one or more events. No user is required to place an
order.
Pretix has a concept of **users** that is used for all people who have to log in to the
control panel to manage one or more events. No user is required to place an order.
Items and variations
^^^^^^^^^^^^^^^^^^^^
The purpose of pretix is to sell **items** (which belong to **events**) to **users**.
An **item** is a abstract thing, popular examples being event tickets or a piece of
The purpose of pretix is to sell **items** (which belong to **events**) to **users**.
An **item** is a abstract thing, popular examples being an event ticket or a piece of
merchandise, like 'T-shirt'. An **item** can have multiple **variations**. For example,
the **item** 'T-Shirt' could have the **variations** S', 'M' and 'L'.
the **item** 'T-Shirt' could have the **variations** 'S', 'M' and 'L'.
Questions
^^^^^^^^^
An item can be extended using **questions**. Questions enable items to be extended by
additional information which can be entered by the user. Examples of possible questions
include 'Name' or 'age'.
include 'name' or 'age'.
Restriction by number
"""""""""""""""""""""
@@ -59,17 +58,16 @@ special care in the implementation to never sell more tickets than allowed, even
* Every time a user places a item in the cart, a **cart position** is created, reducing the number of
available items in the pool by one. The position is valid for a fixed time (e.g. 30 minutes), but not
instantly deleted after those 30 minutes (we'll get to that).
* Every time a user places a binding order, the position object is replaced by an **order position** which behaves
much the same as the cart position. It reduces the number of available item and is valid for a fixed time, this
time for the configured payment term (e.g. 14 days).
* Every time a user places a binding order, the **cart position** object is replaced by an **order position**
object which behaves much the same as the cart position. It reduces the number of available items and is valid
for a fixed time, this time for the configured payment term (e.g. 14 days).
* If the order is being paid, the **order** becomes permanent.
* Once there are no available tickets left and user A wants to buy a ticket, he can do so, as long as
there are *expired* cart position in the system. In this case, user A gets a new cart position, so that there
are more cart position than available tickets and therefore have to remove one of the expired cart positions.
However, we do not choose one by random, but keep the surplus in a way that leads to the deletion
of the cart position f the user who tries *last* to use his cart position.
* The same goes for orders which are not paid within the specified timeframe. This policy allows the organizer to
sell as much items as possible. Moreover, it guarantees the users to get their items if they check out within the validity
* Once there are no available tickets left and user A wants to buy a ticket, they can do so, as long as
there are *expired* cart position in the system. In this case, user A gets a new cart position. Now there are
more cart positions than available tickets and therefore we have to remove one of the expired cart positions.
We will choose to delete the cart position of the user who tries *last* to use his cart position.
* The same goes for orders which are not paid within the configured time frame. This policy allows the organizer to
sell as many items as possible. Moreover, it guarantees the users to get their items if they check out within the validity
period of their positions and pay within the validity period of their orders. It does not guarantee them anything
any longer, but it tries to be *as tolerant as possible* to users who are paying after their payment
period or click checkout after the expiry of their position.

View File

@@ -20,11 +20,11 @@ on our `GitHub repository`_.
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' coding style. You'll
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.
We automatically run the tests and the code style check on every pull request on Travis CI and we wont
accept any pull requets without all tests passing. However, if you don't find out *why* they are not passing,
accept any pull requests without all tests passing. However, if you don't find out *why* they are not passing,
just send the pull request and tell us we'll be glad to help.
If you add a new feature, please include appropriate documentation into your patch. If you fix a bug,
@@ -34,4 +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
.. _squash all your changes: https://davidwalsh.name/squash-commits-git

View File

@@ -6,7 +6,7 @@ Python code
* Basically: Follow `PEP 8`_.
Use `flake8`_ to check for conformance problems. The project includes a setup.cfg
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

View File

@@ -2,7 +2,7 @@ Background tasks
================
pretix provides the ability to run all longer-running tasks like generating ticket files or sending emails
in a background thread instead of the webserver process. We use the well-established `Celery`_ project to
in a background thread instead of the web server process. We use the well-established `Celery`_ project to
implement this. However, as celery requires running a task queue like RabbitMQ and a result storage such as
Redis to work efficiently, we don't like to *depend* on celery being available to make small-scale installations
of pretix more straightforward. For this reason, the "background" in "background task" is always optional.
@@ -13,8 +13,8 @@ in the current installation.
Implementing a task
-------------------
A common pattern for implementing "optionally-asynchronous" tasks that can be seen a lot in ``pretix.base.services``
looks like this::
A common pattern for implementing "optionally-asynchronous" tasks can be seen a lot in ``pretix.base.services``
and looks like this::
def my_task(argument1, argument2):
# Important: All arguments and return values need to be serializable into JSON.
@@ -45,7 +45,7 @@ A usage example taken directly from the code is::
class OrderCancelDo(EventViewMixin, OrderDetailMixin, AsyncAction, View):
"""
A view that executes a task asynchronously. A POST request will kick of the
task into the background or run it in the foreground, if celery is not installed.
task into the background or run it in the foreground if celery is not installed.
In the former case, subsequent GET calls can be used to determinine the current
status of the task.
"""
@@ -93,4 +93,4 @@ AJAX sending of the form and display a loading indicator::
...
</form>
.. _Celery: http://www.celeryproject.org/
.. _Celery: http://www.celeryproject.org/

View File

@@ -1,7 +1,7 @@
Sending Email
=============
As pretix allows event organizers to configure how they want to sent emails to their users in multiple ways.
Therefore, all emails should be sent throught the following function:
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:
.. autofunction:: pretix.base.services.mail.mail
.. autofunction:: pretix.base.services.mail.mail

View File

@@ -1,11 +1,10 @@
Internationalization
====================
One of pretix' major selling points is it's multi-language capability. We make heavy use of Django's
One of pretix's major selling points is its multi-language capability. We make heavy use of Django's
`translation features`_ that are built upon `GNU gettext`_. However, Django does not provide a standard
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
at the same time.
or event descriptions, so we need event organizers to be able to fill in all fields in multiple languages.
.. 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
@@ -21,8 +20,8 @@ pretix provides two custom model field types that allow you to work with localiz
``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``.
Yes, we know that this has negative impact on performance when indexing or searching them, but as mentioned above,
within pretix this is not used in places that need to be searched. Lookups are currently not even implemented on these
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:
@@ -58,8 +57,8 @@ The ``i18n`` module contains a few more useful utilities, starting with simple l
numbers and dates, ``LazyDate`` and ``LazyNumber``. There also is a ``LazyLocaleException`` base class that provides
exceptions with gettext-localized exception messages.
Last, but definitely not least, we have the ``language`` context manager that allows you to execute a piece of code with
a different locale::
Last, but definitely not least, we have the ``language`` context manager (``pretix.base.i18n.language``) that allows
you to execute a piece of code with a different locale::
with language('de'):
render_mail_template()
@@ -69,4 +68,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/
.. _1NF: https://en.wikipedia.org/wiki/First_normal_form
.. _1NF: https://en.wikipedia.org/wiki/First_normal_form

View File

@@ -2,7 +2,7 @@ Implementation and Utilities
============================
This chapter describes the various inner workings that power pretix, most of them living in ``pretix.base``.
If you want to develop around pretix' core or advanced plugins, this aims to describe everything you absolutely
If you want to develop around pretix's core or advanced plugins, this aims to describe everything you absolutely
need to know.
Contents:

View File

@@ -3,7 +3,8 @@ Settings storage
pretix is highly configurable and therefore needs to store a lot of per-event and per-organizer settings.
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``.
such an instance from any event or organizer model instance by just accessing ``event.settings`` or
``organizer.settings``, respectively.
Any setting consists of a key and a value. By default, all settings are strings, but the settings system
includes serializers for serializing the following types:

View File

@@ -4,8 +4,8 @@ Working with URLs
=================
As soon as you write a plugin that provides a new view to the user (or if you want to
contribute to pretix itself), you need to understand how URLs work in pretix as it slightly
differs from the standard Django system.
contribute to pretix itself), you need to understand how URLs work in pretix as it differs
slightly from the standard Django system.
The reason for the complicated URL handling is that pretix supports custom subdomains for
single organizers. In this example we will use an event organizer with the slug ``bigorg``
@@ -24,10 +24,10 @@ URL routing
The hard part about implementing this URL routing in Django is that
``https://pretix.eu/bigorg/awesomecon/`` contains two parameters of nearly arbitrary content
and ``https://tickets.bigorg.com/awesomecon/`` contains only one. The only robust way to do
this is by having *seperate* URL configuration for those two cases. In pretix, we call the
former our ``maindomain`` config and the latter our ``subdomain`` config. For pretix' core
this is by having *separate* URL configuration for those two cases. In pretix, we call the
former our ``maindomain`` config and the latter our ``subdomain`` config. For pretix's core
modules we do some magic to avoid duplicate configuration, but for a fairly simple plugin with
only a handful of routes, we recommend just configuring the two URL sets seperately.
only a handful of routes, we recommend just configuring the two URL sets separately.
The file ``maindomain_urls.py`` inside your plugin package will be loaded and scanned for
URL configuration automatically and should be provided by any plugin that provides any view.
@@ -63,12 +63,12 @@ If you only provide URLs in the admin area, you do not need to provide a ``subdo
URL reversal
------------
pretix uses Django's URL namespacing feature. The URLs of pretix' core are available in the ``control``
pretix uses Django's URL namespacing feature. The URLs of pretix's core are available in the ``control``
and ``presale`` namespaces, there are only very few URLs in the root namespace. Your plugin's URLs will
be available in the ``plugins:<applabel>`` namespace, e.g. the form of the email sending plugin is
available as ``plugins:sendmail:send``.
Generating an URL for the frontend is a complicated task, because you need to know whether the event's
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 behaviour similar to ``reverse``:
@@ -87,4 +87,4 @@ Implementation details
There are some other caveats when using a design like this, e.g. you have to care about cookie domains
and referer verification yourself. If you want to see how we built this, look into the ``pretix/multidomain/``
sub-tree.
sub-tree.

View File

@@ -22,8 +22,8 @@ Your local python environment
-----------------------------
Please execute ``python -V`` or ``python3 -V`` to make sure you have Python 3.4
installed. Also make sure you have pip for Python 3 installed, you can execute
``pip3 -V`` to check. Then use Python 3.4's internal tools to create a virtual
(or newer) installed. Also make sure you have pip for Python 3 installed, you can
execute ``pip3 -V`` to check. Then use Python's internal tools to create a virtual
environment and activate it for your current session::
pyvenv env

View File

@@ -10,14 +10,14 @@ pretix/
This directory contains nearly all source code.
base/
This is the django app containing all the models and methods which are
This is the Django app containing all the models and methods which are
essential to all of pretix's features.
control/
This is the django app containing the front end for organizers.
This is the Django app containing the front end for organizers.
presale/
This is the django app containing the front end for users buying tickets.
This is the Django app containing the front end for users buying tickets.
helpers/
Helpers contain a very few modules providing workarounds for low-level flaws in