mirror of
https://github.com/pretix/pretix.git
synced 2026-08-21 12:36:26 +00:00
Document setting storage and mail sending
This commit is contained in:
@@ -0,0 +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:
|
||||||
|
|
||||||
|
.. autofunction:: pretix.base.services.mail.mail
|
||||||
@@ -11,6 +11,8 @@ Contents:
|
|||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
|
|
||||||
models
|
models
|
||||||
background
|
|
||||||
urlconfig
|
urlconfig
|
||||||
i18n
|
i18n
|
||||||
|
settings
|
||||||
|
background
|
||||||
|
email
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
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``.
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
* Built-in types: ``int``, ``float``, ``decimal.Decimal``, ``dict``, ``list``, ``bool``
|
||||||
|
* ``datetime.date``, ``datetime.datetime``, ``datetime.time``
|
||||||
|
* ``LazyI18nString``
|
||||||
|
* References to Django ``File`` objects that are already stored in a storage backend
|
||||||
|
* References to model instances
|
||||||
|
|
||||||
|
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``.
|
||||||
|
|
||||||
|
.. 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
|
||||||
|
another helper class:
|
||||||
|
|
||||||
|
.. autoclass:: pretix.base.settings.SettingsSandbox
|
||||||
|
|
||||||
|
When implementing e.g. a payment or export provider, you do not event need to create this sandbox yourself,
|
||||||
|
you will just be passed a sandbox object with a prefix generated from your provider name.
|
||||||
|
|
||||||
|
Forms
|
||||||
|
-----
|
||||||
|
|
||||||
|
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::
|
||||||
|
|
||||||
|
class EventSettingsForm(SettingsForm):
|
||||||
|
show_date_to = forms.BooleanField(
|
||||||
|
label=_("Show event end date"),
|
||||||
|
help_text=_("If disabled, only event's start date will be displayed to the public."),
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
payment_term_days = forms.IntegerField(
|
||||||
|
label=_('Payment term in days'),
|
||||||
|
help_text=_("The number of days after placing an order the user has to pay to "
|
||||||
|
"preserve his reservation."),
|
||||||
|
)
|
||||||
@@ -83,7 +83,12 @@ class I18nInlineFormSet(BaseInlineFormSet):
|
|||||||
|
|
||||||
class SettingsForm(forms.Form):
|
class SettingsForm(forms.Form):
|
||||||
"""
|
"""
|
||||||
This form is meant to be used for modifying Event- or OrganizerSettings
|
This form is meant to be used for modifying Event- or OrganizerSettings. It takes
|
||||||
|
care of loading the current values of the fields and saving the field inputs to the
|
||||||
|
settings storage. It also deals with setting the available languages for internationalized
|
||||||
|
fields.
|
||||||
|
|
||||||
|
:param obj: The event or organizer object which should be used for the settings storage
|
||||||
"""
|
"""
|
||||||
BOOL_CHOICES = (
|
BOOL_CHOICES = (
|
||||||
('False', _('disabled')),
|
('False', _('disabled')),
|
||||||
@@ -99,6 +104,9 @@ class SettingsForm(forms.Form):
|
|||||||
field.widget.enabled_langcodes = self.obj.settings.get('locales')
|
field.widget.enabled_langcodes = self.obj.settings.get('locales')
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
|
"""
|
||||||
|
Performs the save operation
|
||||||
|
"""
|
||||||
for name, field in self.fields.items():
|
for name, field in self.fields.items():
|
||||||
value = self.cleaned_data[name]
|
value = self.cleaned_data[name]
|
||||||
if isinstance(value, UploadedFile):
|
if isinstance(value, UploadedFile):
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import logging
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.mail import EmailMessage, get_connection
|
from django.core.mail import EmailMessage, get_connection
|
||||||
from django.template.loader import get_template
|
from django.template.loader import get_template
|
||||||
from django.utils import translation
|
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from typing import Any, Dict
|
from typing import Any, Dict
|
||||||
|
|
||||||
@@ -22,22 +21,26 @@ class TolerantDict(dict):
|
|||||||
def mail(email: str, subject: str, template: str,
|
def mail(email: str, subject: str, template: str,
|
||||||
context: Dict[str, Any]=None, event: Event=None, locale: str=None):
|
context: Dict[str, Any]=None, event: Event=None, locale: str=None):
|
||||||
"""
|
"""
|
||||||
Sends out an email to a user.
|
Sends out an email to a user. The mail will be sent synchronously or asynchronously depending on the installation.
|
||||||
|
|
||||||
:param email: The e-mail this should be sent to.
|
:param email: The e-mail address of the recipient.
|
||||||
:param subject: The e-mail subject. Should be localized.
|
|
||||||
:param template: The filename of a template to be used. It will
|
|
||||||
be rendered with the recipient's locale. Alternatively, you
|
|
||||||
can pass a LazyI18nString and ``context`` will be used
|
|
||||||
for a Python .format() call.
|
|
||||||
:param context: The context for rendering the template.
|
|
||||||
:param event: The event, used for determining the sender of the e-mail
|
|
||||||
:param locale: The locale used while rendering the template
|
|
||||||
|
|
||||||
:return: ``False`` on obvious failures, like the user having to e-mail
|
:param subject: The e-mail subject. Should be localized to the recipients's locale or a lazy object that will be
|
||||||
address, ``True`` otherwise. ``True`` does not necessarily mean that
|
localized by being casted to a string.
|
||||||
the email has been sent, just that it has been queued by the e-mail
|
|
||||||
backend.
|
:param template: The filename of a template to be used. It will be rendered with the locale given in the locale
|
||||||
|
argument and the context given in the next argument. Alternatively, you can pass a LazyI18nString and
|
||||||
|
``context`` will be used as the argument to a Python ``.format()`` call on the template.
|
||||||
|
|
||||||
|
:param context: The context for rendering the template (see ``template`` parameter).
|
||||||
|
|
||||||
|
:param event: The event this email is related to (optional). If set, this will be used to determine the sender,
|
||||||
|
a possible prefix for the subject and the SMTP server that should be used to send this email.
|
||||||
|
|
||||||
|
:param locale: The locale to be used while evaluating the subject and the template.
|
||||||
|
|
||||||
|
:return: ``False`` on obvious, immediate failures, ``True`` otherwise. ``True`` does not necessarily mean that
|
||||||
|
the email has been sent, just that it has been queued by the e-mail backend.
|
||||||
"""
|
"""
|
||||||
with language(locale):
|
with language(locale):
|
||||||
if isinstance(template, LazyI18nString):
|
if isinstance(template, LazyI18nString):
|
||||||
|
|||||||
+33
-11
@@ -213,7 +213,7 @@ class SettingsProxy:
|
|||||||
This objects allows convenient access to settings stored in the
|
This objects allows convenient access to settings stored in the
|
||||||
EventSettings/OrganizerSettings database model. It exposes all settings as
|
EventSettings/OrganizerSettings database model. It exposes all settings as
|
||||||
properties and it will do all the nasty inheritance and defaults stuff for
|
properties and it will do all the nasty inheritance and defaults stuff for
|
||||||
you. It will return None for non-existing properties.
|
you.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, obj: Model, parent: Optional[Model]=None, type=None):
|
def __init__(self, obj: Model, parent: Optional[Model]=None, type=None):
|
||||||
@@ -232,7 +232,11 @@ class SettingsProxy:
|
|||||||
def _flush(self) -> None:
|
def _flush(self) -> None:
|
||||||
self._cached_obj = None
|
self._cached_obj = None
|
||||||
|
|
||||||
def freeze(self):
|
def freeze(self) -> dict:
|
||||||
|
"""
|
||||||
|
Returns a dictionary of all settings set for this object, including
|
||||||
|
any default values of its parents or hardcoded in pretix.
|
||||||
|
"""
|
||||||
settings = {}
|
settings = {}
|
||||||
for key, v in DEFAULTS.items():
|
for key, v in DEFAULTS.items():
|
||||||
settings[key] = self._unserialize(v['default'], v['type'])
|
settings[key] = self._unserialize(v['default'], v['type'])
|
||||||
@@ -297,11 +301,17 @@ class SettingsProxy:
|
|||||||
|
|
||||||
raise TypeError('Unable to serialize %s into a setting.' % str(type(value)))
|
raise TypeError('Unable to serialize %s into a setting.' % str(type(value)))
|
||||||
|
|
||||||
def get(self, key: str, default: Any=None, as_type: type=None):
|
def get(self, key: str, default=None, as_type: type=None):
|
||||||
"""
|
"""
|
||||||
Get a setting specified by key 'key'. Normally, settings are strings, but
|
Get a setting specified by key ``key``. Normally, settings are strings, but
|
||||||
if you put non-strings into the settings object, you can request unserialization
|
if you put non-strings into the settings object, you can request unserialization
|
||||||
by specifying 'as_type'
|
by specifying ``as_type``. If the key does not have a harcdoded type in the pretix source,
|
||||||
|
omitting ``as_type`` always will get you a string.
|
||||||
|
|
||||||
|
If the setting with the specified name does not exist on this object, any parent object
|
||||||
|
will be queried (e.g. the organizer of an event). If still no value is found, a default
|
||||||
|
value hardcoded will be returned if one exists. If not, the value of the ``default`` argument
|
||||||
|
will be returned instead.
|
||||||
"""
|
"""
|
||||||
if as_type is None and key in DEFAULTS:
|
if as_type is None and key in DEFAULTS:
|
||||||
as_type = DEFAULTS[key]['type']
|
as_type = DEFAULTS[key]['type']
|
||||||
@@ -336,6 +346,9 @@ class SettingsProxy:
|
|||||||
self.set(key, value)
|
self.set(key, value)
|
||||||
|
|
||||||
def set(self, key: str, value: Any) -> None:
|
def set(self, key: str, value: Any) -> None:
|
||||||
|
"""
|
||||||
|
Stores a setting to the database of this object.
|
||||||
|
"""
|
||||||
if key in self._cache():
|
if key in self._cache():
|
||||||
s = self._cache()[key]
|
s = self._cache()[key]
|
||||||
else:
|
else:
|
||||||
@@ -347,9 +360,15 @@ class SettingsProxy:
|
|||||||
def __delattr__(self, key: str) -> None:
|
def __delattr__(self, key: str) -> None:
|
||||||
if key.startswith('_'):
|
if key.startswith('_'):
|
||||||
return super().__delattr__(key)
|
return super().__delattr__(key)
|
||||||
return self.__delitem__(key)
|
self.delete(key)
|
||||||
|
|
||||||
def __delitem__(self, key: str) -> None:
|
def __delitem__(self, key: str) -> None:
|
||||||
|
self.delete(key)
|
||||||
|
|
||||||
|
def delete(self, key: str) -> None:
|
||||||
|
"""
|
||||||
|
Deletes a setting from this object's storage.
|
||||||
|
"""
|
||||||
if key in self._cache():
|
if key in self._cache():
|
||||||
self._cache()[key].delete()
|
self._cache()[key].delete()
|
||||||
del self._cache()[key]
|
del self._cache()[key]
|
||||||
@@ -357,13 +376,16 @@ class SettingsProxy:
|
|||||||
|
|
||||||
class SettingsSandbox:
|
class SettingsSandbox:
|
||||||
"""
|
"""
|
||||||
Transparently proxied access to event settings, handling your domain-
|
Transparently proxied access to event settings, handling your prefixes for you.
|
||||||
prefixes for you.
|
|
||||||
|
:param typestr: The first part of the pretix, e.g. ``plugin``
|
||||||
|
:param key: The prefix, e.g. the name of your plugin
|
||||||
|
:param obj: The event or organizer that should be queried
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, type: str, key: str, event: Model):
|
def __init__(self, typestr: str, key: str, obj: Model):
|
||||||
self._event = event
|
self._event = obj
|
||||||
self._type = type
|
self._type = typestr
|
||||||
self._key = key
|
self._key = key
|
||||||
|
|
||||||
def _convert_key(self, key: str) -> str:
|
def _convert_key(self, key: str) -> str:
|
||||||
|
|||||||
Reference in New Issue
Block a user