forked from CGM_Public/pretix_original
Compare commits
15 Commits
ci-postgre
...
organizer-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ecf81bdfe | ||
|
|
e395834811 | ||
|
|
86a32d7856 | ||
|
|
47e8549f19 | ||
|
|
47b84c06b0 | ||
|
|
204bc84e85 | ||
|
|
0487d5803b | ||
|
|
a94c89ba4f | ||
|
|
2045009e2e | ||
|
|
9269a485a6 | ||
|
|
166f50fcb0 | ||
|
|
a3358bae6b | ||
|
|
a3164a94b7 | ||
|
|
f56df892e3 | ||
|
|
093a0db182 |
@@ -75,6 +75,14 @@ FORMAT_MODULE_PATH = [
|
||||
'pretix.helpers.formats',
|
||||
]
|
||||
|
||||
CORE_MODULES = {
|
||||
"pretix.base",
|
||||
"pretix.presale",
|
||||
"pretix.control",
|
||||
"pretix.plugins.checkinlists",
|
||||
"pretix.plugins.reports",
|
||||
}
|
||||
|
||||
ALL_LANGUAGES = [
|
||||
('en', _('English')),
|
||||
('de', _('German')),
|
||||
|
||||
164
src/pretix/base/logentrytypes.py
Normal file
164
src/pretix/base/logentrytypes.py
Normal file
@@ -0,0 +1,164 @@
|
||||
from collections import defaultdict
|
||||
|
||||
from django.urls import reverse
|
||||
from django.utils.html import escape
|
||||
from django.utils.translation import gettext_lazy as _, pgettext_lazy
|
||||
|
||||
from pretix.base.signals import PluginRegistry
|
||||
|
||||
|
||||
def make_link(a_map, wrapper, is_active=True, event=None, plugin_name=None):
|
||||
if a_map:
|
||||
if is_active:
|
||||
a_map['val'] = '<a href="{href}">{val}</a>'.format_map(a_map)
|
||||
elif event and plugin_name:
|
||||
a_map['val'] = (
|
||||
'<i>{val}</i> <a href="{plugin_href}">'
|
||||
'<span data-toggle="tooltip" title="{errmes}" class="fa fa-warning fa-fw"></span></a>'
|
||||
).format_map({
|
||||
**a_map,
|
||||
"errmes": _("The relevant plugin is currently not active. To activate it, click here to go to the plugin settings."),
|
||||
"plugin_href": reverse('control:event.settings.plugins', kwargs={
|
||||
'organizer': event.organizer.slug,
|
||||
'event': event.slug,
|
||||
}) + '#plugin_' + plugin_name,
|
||||
})
|
||||
else:
|
||||
a_map['val'] = '<i>{val}</i> <span data-toggle="tooltip" title="{errmes}" class="fa fa-warning fa-fw"></span>'.format_map({
|
||||
**a_map,
|
||||
"errmes": _("The relevant plugin is currently not active."),
|
||||
})
|
||||
return wrapper.format_map(a_map)
|
||||
|
||||
|
||||
class LogEntryTypeRegistry(PluginRegistry):
|
||||
def new_from_dict(self, data):
|
||||
def reg(clz):
|
||||
for action_type, plain in data.items():
|
||||
self.register(clz(action_type=action_type, plain=plain))
|
||||
return reg
|
||||
|
||||
|
||||
log_entry_types = LogEntryTypeRegistry({'action_type': lambda o: getattr(o, 'action_type')})
|
||||
|
||||
|
||||
class LogEntryType:
|
||||
def __init__(self, action_type=None, plain=None):
|
||||
assert self.__module__ != LogEntryType.__module__ # must not instantiate base classes, only derived ones
|
||||
if action_type:
|
||||
self.action_type = action_type
|
||||
if plain:
|
||||
self.plain = plain
|
||||
|
||||
def display(self, logentry):
|
||||
if hasattr(self, 'plain'):
|
||||
plain = str(self.plain)
|
||||
if '{' in plain:
|
||||
data = defaultdict(lambda: '?', logentry.parsed_data)
|
||||
return plain.format_map(data)
|
||||
else:
|
||||
return plain
|
||||
|
||||
def get_object_link_info(self, logentry) -> dict:
|
||||
pass
|
||||
|
||||
def get_object_link(self, logentry):
|
||||
a_map = self.get_object_link_info(logentry)
|
||||
return make_link(a_map, self.object_link_wrapper)
|
||||
|
||||
object_link_wrapper = '{val}'
|
||||
|
||||
def shred_pii(self, logentry):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class EventLogEntryType(LogEntryType):
|
||||
def get_object_link_info(self, logentry) -> dict:
|
||||
if hasattr(self, 'object_link_viewname') and hasattr(self, 'object_link_argname') and logentry.content_object:
|
||||
return {
|
||||
'href': reverse(self.object_link_viewname, kwargs={
|
||||
'event': logentry.event.slug,
|
||||
'organizer': logentry.event.organizer.slug,
|
||||
self.object_link_argname: self.object_link_argvalue(logentry.content_object),
|
||||
}),
|
||||
'val': escape(self.object_link_display_name(logentry.content_object)),
|
||||
}
|
||||
|
||||
def object_link_argvalue(self, content_object):
|
||||
return content_object.id
|
||||
|
||||
def object_link_display_name(self, content_object):
|
||||
return str(content_object)
|
||||
|
||||
|
||||
class OrderLogEntryType(EventLogEntryType):
|
||||
object_link_wrapper = _('Order {val}')
|
||||
object_link_viewname = 'control:event.order'
|
||||
object_link_argname = 'code'
|
||||
|
||||
def object_link_argvalue(self, order):
|
||||
return order.code
|
||||
|
||||
def object_link_display_name(self, order):
|
||||
return order.code
|
||||
|
||||
|
||||
class VoucherLogEntryType(EventLogEntryType):
|
||||
object_link_wrapper = _('Voucher {val}…')
|
||||
object_link_viewname = 'control:event.voucher'
|
||||
object_link_argname = 'voucher'
|
||||
|
||||
def object_link_display_name(self, order):
|
||||
return order.code[:6]
|
||||
|
||||
|
||||
class ItemLogEntryType(EventLogEntryType):
|
||||
object_link_wrapper = _('Product {val}')
|
||||
object_link_viewname = 'control:event.item'
|
||||
object_link_argname = 'item'
|
||||
|
||||
|
||||
class SubEventLogEntryType(EventLogEntryType):
|
||||
object_link_wrapper = pgettext_lazy('subevent', 'Date {val}')
|
||||
object_link_viewname = 'control:event.subevent'
|
||||
object_link_argname = 'subevent'
|
||||
|
||||
|
||||
class QuotaLogEntryType(EventLogEntryType):
|
||||
object_link_wrapper = _('Quota {val}')
|
||||
object_link_viewname = 'control:event.items.quotas.show'
|
||||
object_link_argname = 'quota'
|
||||
|
||||
|
||||
class DiscountLogEntryType(EventLogEntryType):
|
||||
object_link_wrapper = _('Discount {val}')
|
||||
object_link_viewname = 'control:event.items.discounts.edit'
|
||||
object_link_argname = 'discount'
|
||||
|
||||
|
||||
class ItemCategoryLogEntryType(EventLogEntryType):
|
||||
object_link_wrapper = _('Category {val}')
|
||||
object_link_viewname = 'control:event.items.categories.edit'
|
||||
object_link_argname = 'category'
|
||||
|
||||
|
||||
class QuestionLogEntryType(EventLogEntryType):
|
||||
object_link_wrapper = _('Question {val}')
|
||||
object_link_viewname = 'control:event.items.questions.show'
|
||||
object_link_argname = 'question'
|
||||
|
||||
|
||||
class TaxRuleLogEntryType(EventLogEntryType):
|
||||
object_link_wrapper = _('Tax rule {val}')
|
||||
object_link_viewname = 'control:event.settings.tax.edit'
|
||||
object_link_argname = 'rule'
|
||||
|
||||
|
||||
class NoOpShredderMixin:
|
||||
def shred_pii(self, logentry):
|
||||
pass
|
||||
|
||||
|
||||
class ClearDataShredderMixin:
|
||||
def shred_pii(self, logentry):
|
||||
logentry.data = None
|
||||
@@ -742,8 +742,8 @@ class Event(EventMixin, LoggedModel):
|
||||
Returns the names of the plugins activated for this event as a list.
|
||||
"""
|
||||
if self.plugins is None:
|
||||
return []
|
||||
return self.plugins.split(",")
|
||||
return self.organizer.get_plugins()
|
||||
return self.plugins.split(",") + self.organizer.get_plugins()
|
||||
|
||||
def get_cache(self):
|
||||
"""
|
||||
|
||||
@@ -33,16 +33,17 @@
|
||||
# License for the specific language governing permissions and limitations under the License.
|
||||
|
||||
import json
|
||||
import logging
|
||||
|
||||
from django.contrib.contenttypes.fields import GenericForeignKey
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.db import models
|
||||
from django.urls import reverse
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.html import escape
|
||||
from django.utils.translation import gettext_lazy as _, pgettext_lazy
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from pretix.base.signals import logentry_object_link
|
||||
from pretix.base.logentrytypes import log_entry_types, make_link
|
||||
from pretix.base.signals import is_app_active, logentry_object_link
|
||||
|
||||
|
||||
class VisibleOnlyManager(models.Manager):
|
||||
@@ -92,6 +93,10 @@ class LogEntry(models.Model):
|
||||
indexes = [models.Index(fields=["datetime", "id"])]
|
||||
|
||||
def display(self):
|
||||
log_entry_type, meta = log_entry_types.find(action_type=self.action_type)
|
||||
if log_entry_type:
|
||||
return log_entry_type.display(self)
|
||||
|
||||
from ..signals import logentry_display
|
||||
|
||||
for receiver, response in logentry_display.send(self.event, logentry=self):
|
||||
@@ -126,10 +131,18 @@ class LogEntry(models.Model):
|
||||
@cached_property
|
||||
def display_object(self):
|
||||
from . import (
|
||||
Discount, Event, Item, ItemCategory, Order, Question, Quota,
|
||||
SubEvent, TaxRule, Voucher,
|
||||
Discount, Event, Item, Order, Question, Quota, SubEvent, Voucher,
|
||||
)
|
||||
|
||||
log_entry_type, meta = log_entry_types.find(action_type=self.action_type)
|
||||
if log_entry_type:
|
||||
link_info = log_entry_type.get_object_link_info(self)
|
||||
if is_app_active(self.event, meta['plugin']):
|
||||
return make_link(link_info, log_entry_type.object_link_wrapper)
|
||||
else:
|
||||
return make_link(link_info, log_entry_type.object_link_wrapper, is_active=False,
|
||||
event=self.event, plugin_name=meta['plugin'] and getattr(meta['plugin'], 'name'))
|
||||
|
||||
try:
|
||||
if self.content_type.model_class() is Event:
|
||||
return ''
|
||||
@@ -137,110 +150,15 @@ class LogEntry(models.Model):
|
||||
co = self.content_object
|
||||
except:
|
||||
return ''
|
||||
a_map = None
|
||||
a_text = None
|
||||
|
||||
if isinstance(co, Order):
|
||||
a_text = _('Order {val}')
|
||||
a_map = {
|
||||
'href': reverse('control:event.order', kwargs={
|
||||
'event': self.event.slug,
|
||||
'organizer': self.event.organizer.slug,
|
||||
'code': co.code
|
||||
}),
|
||||
'val': escape(co.code),
|
||||
}
|
||||
elif isinstance(co, Voucher):
|
||||
a_text = _('Voucher {val}…')
|
||||
a_map = {
|
||||
'href': reverse('control:event.voucher', kwargs={
|
||||
'event': self.event.slug,
|
||||
'organizer': self.event.organizer.slug,
|
||||
'voucher': co.id
|
||||
}),
|
||||
'val': escape(co.code[:6]),
|
||||
}
|
||||
elif isinstance(co, Item):
|
||||
a_text = _('Product {val}')
|
||||
a_map = {
|
||||
'href': reverse('control:event.item', kwargs={
|
||||
'event': self.event.slug,
|
||||
'organizer': self.event.organizer.slug,
|
||||
'item': co.id
|
||||
}),
|
||||
'val': escape(co.name),
|
||||
}
|
||||
elif isinstance(co, SubEvent):
|
||||
a_text = pgettext_lazy('subevent', 'Date {val}')
|
||||
a_map = {
|
||||
'href': reverse('control:event.subevent', kwargs={
|
||||
'event': self.event.slug,
|
||||
'organizer': self.event.organizer.slug,
|
||||
'subevent': co.id
|
||||
}),
|
||||
'val': escape(str(co))
|
||||
}
|
||||
elif isinstance(co, Quota):
|
||||
a_text = _('Quota {val}')
|
||||
a_map = {
|
||||
'href': reverse('control:event.items.quotas.show', kwargs={
|
||||
'event': self.event.slug,
|
||||
'organizer': self.event.organizer.slug,
|
||||
'quota': co.id
|
||||
}),
|
||||
'val': escape(co.name),
|
||||
}
|
||||
elif isinstance(co, Discount):
|
||||
a_text = _('Discount {val}')
|
||||
a_map = {
|
||||
'href': reverse('control:event.items.discounts.edit', kwargs={
|
||||
'event': self.event.slug,
|
||||
'organizer': self.event.organizer.slug,
|
||||
'discount': co.id
|
||||
}),
|
||||
'val': escape(co.internal_name),
|
||||
}
|
||||
elif isinstance(co, ItemCategory):
|
||||
a_text = _('Category {val}')
|
||||
a_map = {
|
||||
'href': reverse('control:event.items.categories.edit', kwargs={
|
||||
'event': self.event.slug,
|
||||
'organizer': self.event.organizer.slug,
|
||||
'category': co.id
|
||||
}),
|
||||
'val': escape(co.name),
|
||||
}
|
||||
elif isinstance(co, Question):
|
||||
a_text = _('Question {val}')
|
||||
a_map = {
|
||||
'href': reverse('control:event.items.questions.show', kwargs={
|
||||
'event': self.event.slug,
|
||||
'organizer': self.event.organizer.slug,
|
||||
'question': co.id
|
||||
}),
|
||||
'val': escape(co.question),
|
||||
}
|
||||
elif isinstance(co, TaxRule):
|
||||
a_text = _('Tax rule {val}')
|
||||
a_map = {
|
||||
'href': reverse('control:event.settings.tax.edit', kwargs={
|
||||
'event': self.event.slug,
|
||||
'organizer': self.event.organizer.slug,
|
||||
'rule': co.id
|
||||
}),
|
||||
'val': escape(co.name),
|
||||
}
|
||||
for receiver, response in logentry_object_link.send(self.event, logentry=self):
|
||||
if response:
|
||||
return response
|
||||
|
||||
if a_text and a_map:
|
||||
a_map['val'] = '<a href="{href}">{val}</a>'.format_map(a_map)
|
||||
return a_text.format_map(a_map)
|
||||
elif a_text:
|
||||
return a_text
|
||||
else:
|
||||
for receiver, response in logentry_object_link.send(self.event, logentry=self):
|
||||
if response:
|
||||
return response
|
||||
return ''
|
||||
if isinstance(co, (Order, Voucher, Item, SubEvent, Quota, Discount, Question)):
|
||||
logging.warning("LogEntryType missing or ill-defined: %s", self.action_type)
|
||||
|
||||
return ''
|
||||
|
||||
@cached_property
|
||||
def parsed_data(self):
|
||||
|
||||
@@ -2835,6 +2835,14 @@ class OrderPosition(AbstractPosition):
|
||||
(self.order.event.settings.change_allow_user_addons and ItemAddOn.objects.filter(base_item_id__in=[op.item_id for op in positions]).exists())
|
||||
)
|
||||
|
||||
@property
|
||||
def full_code(self):
|
||||
"""
|
||||
A ticket code which is unique among all events of a single organizer,
|
||||
built by concatenating the event slug and the order code.
|
||||
"""
|
||||
return '{order}-{position}'.format(order=self.order.full_code, position=self.positionid)
|
||||
|
||||
|
||||
class Transaction(models.Model):
|
||||
"""
|
||||
|
||||
@@ -91,6 +91,10 @@ class Organizer(LoggedModel):
|
||||
verbose_name=_("Short form"),
|
||||
unique=True
|
||||
)
|
||||
plugins = models.TextField(
|
||||
null=True, blank=True,
|
||||
verbose_name=_("Plugins"),
|
||||
)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Organizer")
|
||||
@@ -119,6 +123,14 @@ class Organizer(LoggedModel):
|
||||
"""
|
||||
self.settings.cookie_consent = True
|
||||
|
||||
def get_plugins(self):
|
||||
"""
|
||||
Returns the names of the plugins activated for this organizer as a list.
|
||||
"""
|
||||
if self.plugins is None:
|
||||
return []
|
||||
return self.plugins.split(",")
|
||||
|
||||
def get_cache(self):
|
||||
"""
|
||||
Returns an :py:class:`ObjectRelatedCache` object. This behaves equivalent to
|
||||
|
||||
@@ -52,49 +52,71 @@ def _populate_app_cache():
|
||||
app_cache[ac.name] = ac
|
||||
|
||||
|
||||
class EventPluginSignal(django.dispatch.Signal):
|
||||
def get_defining_app(o):
|
||||
# If sentry packed this in a wrapper, unpack that
|
||||
if "sentry" in o.__module__:
|
||||
o = o.__wrapped__
|
||||
|
||||
# Find the Django application this belongs to
|
||||
searchpath = o.__module__
|
||||
|
||||
# Core modules are always active
|
||||
if any(searchpath.startswith(cm) for cm in settings.CORE_MODULES):
|
||||
return 'CORE'
|
||||
|
||||
if not app_cache:
|
||||
_populate_app_cache()
|
||||
|
||||
while True:
|
||||
app = app_cache.get(searchpath)
|
||||
if "." not in searchpath or app:
|
||||
break
|
||||
searchpath, _ = searchpath.rsplit(".", 1)
|
||||
return app
|
||||
|
||||
|
||||
def is_app_active(sender, app):
|
||||
if app == 'CORE':
|
||||
return True
|
||||
|
||||
excluded = settings.PRETIX_PLUGINS_EXCLUDE
|
||||
if sender and app and app.name in sender.get_plugins() and app.name not in excluded:
|
||||
if not hasattr(app, 'compatibility_errors') or not app.compatibility_errors:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def is_receiver_active(sender, receiver):
|
||||
if sender is None:
|
||||
# Send to all events!
|
||||
return True
|
||||
|
||||
app = get_defining_app(receiver)
|
||||
|
||||
return is_app_active(sender, app)
|
||||
|
||||
|
||||
def is_plugin_host(sender):
|
||||
return hasattr(sender, 'get_plugins')
|
||||
|
||||
|
||||
class PluginSignal(django.dispatch.Signal):
|
||||
"""
|
||||
This is an extension to Django's built-in signals which differs in a way that it sends
|
||||
out it's events only to receivers which belong to plugins that are enabled for the given
|
||||
Event.
|
||||
"""
|
||||
|
||||
def _is_active(self, sender, receiver):
|
||||
if sender is None:
|
||||
# Send to all events!
|
||||
return True
|
||||
|
||||
# If sentry packed this in a wrapper, unpack that
|
||||
if "sentry" in receiver.__module__:
|
||||
receiver = receiver.__wrapped__
|
||||
|
||||
# Find the Django application this belongs to
|
||||
searchpath = receiver.__module__
|
||||
core_module = any([searchpath.startswith(cm) for cm in settings.CORE_MODULES])
|
||||
app = None
|
||||
if not core_module:
|
||||
while True:
|
||||
app = app_cache.get(searchpath)
|
||||
if "." not in searchpath or app:
|
||||
break
|
||||
searchpath, _ = searchpath.rsplit(".", 1)
|
||||
|
||||
# Only fire receivers from active plugins and core modules
|
||||
excluded = settings.PRETIX_PLUGINS_EXCLUDE
|
||||
if core_module or (sender and app and app.name in sender.get_plugins() and app.name not in excluded):
|
||||
if not hasattr(app, 'compatibility_errors') or not app.compatibility_errors:
|
||||
return True
|
||||
return False
|
||||
|
||||
def send(self, sender: Event, **named) -> List[Tuple[Callable, Any]]:
|
||||
def send(self, sender, **named) -> List[Tuple[Callable, Any]]:
|
||||
"""
|
||||
Send signal from sender to all connected receivers that belong to
|
||||
plugins enabled for the given Event.
|
||||
|
||||
sender is required to be an instance of ``pretix.base.models.Event``.
|
||||
sender is required to be a plugin host (an object with a `get_plugins` method),
|
||||
for example a ``pretix.base.models.Event``.
|
||||
"""
|
||||
if sender and not isinstance(sender, Event):
|
||||
raise ValueError("Sender needs to be an event.")
|
||||
if sender and not is_plugin_host(sender):
|
||||
raise ValueError("Sender needs to be a plugin host.")
|
||||
|
||||
responses = []
|
||||
if not self.receivers or self.sender_receivers_cache.get(sender) is NO_RECEIVERS:
|
||||
@@ -104,21 +126,22 @@ class EventPluginSignal(django.dispatch.Signal):
|
||||
_populate_app_cache()
|
||||
|
||||
for receiver in self._sorted_receivers(sender):
|
||||
if self._is_active(sender, receiver):
|
||||
if is_receiver_active(sender, receiver):
|
||||
response = receiver(signal=self, sender=sender, **named)
|
||||
responses.append((receiver, response))
|
||||
return responses
|
||||
|
||||
def send_chained(self, sender: Event, chain_kwarg_name, **named) -> List[Tuple[Callable, Any]]:
|
||||
def send_chained(self, sender, chain_kwarg_name, **named) -> List[Tuple[Callable, Any]]:
|
||||
"""
|
||||
Send signal from sender to all connected receivers. The return value of the first receiver
|
||||
will be used as the keyword argument specified by ``chain_kwarg_name`` in the input to the
|
||||
second receiver and so on. The return value of the last receiver is returned by this method.
|
||||
|
||||
sender is required to be an instance of ``pretix.base.models.Event``.
|
||||
sender is required to be a plugin host (an object with a `get_plugins` method),
|
||||
for example a ``pretix.base.models.Event``.
|
||||
"""
|
||||
if sender and not isinstance(sender, Event):
|
||||
raise ValueError("Sender needs to be an event.")
|
||||
if sender and not is_plugin_host(sender):
|
||||
raise ValueError("Sender needs to be a plugin host.")
|
||||
|
||||
response = named.get(chain_kwarg_name)
|
||||
if not self.receivers or self.sender_receivers_cache.get(sender) is NO_RECEIVERS:
|
||||
@@ -128,21 +151,22 @@ class EventPluginSignal(django.dispatch.Signal):
|
||||
_populate_app_cache()
|
||||
|
||||
for receiver in self._sorted_receivers(sender):
|
||||
if self._is_active(sender, receiver):
|
||||
if is_receiver_active(sender, receiver):
|
||||
named[chain_kwarg_name] = response
|
||||
response = receiver(signal=self, sender=sender, **named)
|
||||
return response
|
||||
|
||||
def send_robust(self, sender: Event, **named) -> List[Tuple[Callable, Any]]:
|
||||
def send_robust(self, sender, **named) -> List[Tuple[Callable, Any]]:
|
||||
"""
|
||||
Send signal from sender to all connected receivers. If a receiver raises an exception
|
||||
instead of returning a value, the exception is included as the result instead of
|
||||
stopping the response chain at the offending receiver.
|
||||
|
||||
sender is required to be an instance of ``pretix.base.models.Event``.
|
||||
sender is required to be a plugin host (an object with a `get_plugins` method),
|
||||
for example a ``pretix.base.models.Event``.
|
||||
"""
|
||||
if sender and not isinstance(sender, Event):
|
||||
raise ValueError("Sender needs to be an event.")
|
||||
if sender and not is_plugin_host(sender):
|
||||
raise ValueError("Sender needs to be a plugin host.")
|
||||
|
||||
responses = []
|
||||
if (
|
||||
@@ -155,7 +179,7 @@ class EventPluginSignal(django.dispatch.Signal):
|
||||
_populate_app_cache()
|
||||
|
||||
for receiver in self._sorted_receivers(sender):
|
||||
if self._is_active(sender, receiver):
|
||||
if is_receiver_active(sender, receiver):
|
||||
try:
|
||||
response = receiver(signal=self, sender=sender, **named)
|
||||
except Exception as err:
|
||||
@@ -177,6 +201,14 @@ class EventPluginSignal(django.dispatch.Signal):
|
||||
return sorted_list
|
||||
|
||||
|
||||
class OrganizerPluginSignal(PluginSignal):
|
||||
pass
|
||||
|
||||
|
||||
class EventPluginSignal(PluginSignal):
|
||||
pass
|
||||
|
||||
|
||||
class GlobalSignal(django.dispatch.Signal):
|
||||
def send_chained(self, sender: Event, chain_kwarg_name, **named) -> List[Tuple[Callable, Any]]:
|
||||
"""
|
||||
@@ -202,6 +234,37 @@ class DeprecatedSignal(django.dispatch.Signal):
|
||||
super().connect(receiver, sender=None, weak=True, dispatch_uid=None)
|
||||
|
||||
|
||||
class Registry:
|
||||
def __init__(self, keys):
|
||||
self.registered_items = list()
|
||||
self.keys = keys
|
||||
self.by_key = {key: {} for key in self.keys.keys()}
|
||||
|
||||
def register(self, *objs):
|
||||
for obj in objs:
|
||||
meta = {k: accessor(obj) for k, accessor in self.keys.items()}
|
||||
tup = (obj, meta)
|
||||
for key, accessor in self.keys.items():
|
||||
self.by_key[key][accessor(obj)] = tup
|
||||
self.registered_items.append(tup)
|
||||
|
||||
def new(self, *args, **kwargs):
|
||||
def reg(clz):
|
||||
obj = clz(*args, **kwargs)
|
||||
self.register(obj)
|
||||
return clz
|
||||
return reg
|
||||
|
||||
def find(self, **kwargs):
|
||||
(key, value), = kwargs.items()
|
||||
return self.by_key.get(key).get(value, (None, None))
|
||||
|
||||
|
||||
class PluginRegistry(Registry):
|
||||
def __init__(self, keys):
|
||||
super().__init__({"plugin": lambda o: get_defining_app(o), **keys})
|
||||
|
||||
|
||||
event_live_issues = EventPluginSignal()
|
||||
"""
|
||||
This signal is sent out to determine whether an event can be taken live. If you want to
|
||||
|
||||
@@ -47,11 +47,19 @@ from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import gettext_lazy as _, pgettext_lazy
|
||||
from i18nfield.strings import LazyI18nString
|
||||
|
||||
from pretix.base.logentrytypes import (
|
||||
DiscountLogEntryType, EventLogEntryType, ItemCategoryLogEntryType,
|
||||
ItemLogEntryType, LogEntryType, OrderLogEntryType, QuestionLogEntryType,
|
||||
QuotaLogEntryType, TaxRuleLogEntryType, VoucherLogEntryType,
|
||||
log_entry_types,
|
||||
)
|
||||
from pretix.base.models import (
|
||||
Checkin, CheckinList, Event, ItemVariation, LogEntry, OrderPosition,
|
||||
TaxRule,
|
||||
)
|
||||
from pretix.base.signals import logentry_display, orderposition_blocked_display
|
||||
from pretix.base.signals import (
|
||||
app_cache, logentry_display, orderposition_blocked_display,
|
||||
)
|
||||
from pretix.base.templatetags.money import money_filter
|
||||
|
||||
OVERVIEW_BANLIST = [
|
||||
@@ -328,278 +336,6 @@ def _display_checkin(event, logentry):
|
||||
|
||||
@receiver(signal=logentry_display, dispatch_uid="pretixcontrol_logentry_display")
|
||||
def pretixcontrol_logentry_display(sender: Event, logentry: LogEntry, **kwargs):
|
||||
plains = {
|
||||
'pretix.object.cloned': _('This object has been created by cloning.'),
|
||||
'pretix.organizer.changed': _('The organizer has been changed.'),
|
||||
'pretix.organizer.settings': _('The organizer settings have been changed.'),
|
||||
'pretix.organizer.footerlinks.changed': _('The footer links have been changed.'),
|
||||
'pretix.organizer.export.schedule.added': _('A scheduled export has been added.'),
|
||||
'pretix.organizer.export.schedule.changed': _('A scheduled export has been changed.'),
|
||||
'pretix.organizer.export.schedule.deleted': _('A scheduled export has been deleted.'),
|
||||
'pretix.organizer.export.schedule.executed': _('A scheduled export has been executed.'),
|
||||
'pretix.organizer.export.schedule.failed': _('A scheduled export has failed: {reason}.'),
|
||||
'pretix.giftcards.acceptance.added': _('Gift card acceptance for another organizer has been added.'),
|
||||
'pretix.giftcards.acceptance.removed': _('Gift card acceptance for another organizer has been removed.'),
|
||||
'pretix.giftcards.acceptance.acceptor.invited': _('A new gift card acceptor has been invited.'),
|
||||
'pretix.giftcards.acceptance.acceptor.removed': _('A gift card acceptor has been removed.'),
|
||||
'pretix.giftcards.acceptance.issuer.removed': _('A gift card issuer has been removed or declined.'),
|
||||
'pretix.giftcards.acceptance.issuer.accepted': _('A new gift card issuer has been accepted.'),
|
||||
'pretix.webhook.created': _('The webhook has been created.'),
|
||||
'pretix.webhook.changed': _('The webhook has been changed.'),
|
||||
'pretix.webhook.retries.expedited': _('The webhook call retry jobs have been manually expedited.'),
|
||||
'pretix.webhook.retries.dropped': _('The webhook call retry jobs have been dropped.'),
|
||||
'pretix.ssoprovider.created': _('The SSO provider has been created.'),
|
||||
'pretix.ssoprovider.changed': _('The SSO provider has been changed.'),
|
||||
'pretix.ssoprovider.deleted': _('The SSO provider has been deleted.'),
|
||||
'pretix.ssoclient.created': _('The SSO client has been created.'),
|
||||
'pretix.ssoclient.changed': _('The SSO client has been changed.'),
|
||||
'pretix.ssoclient.deleted': _('The SSO client has been deleted.'),
|
||||
'pretix.membershiptype.created': _('The membership type has been created.'),
|
||||
'pretix.membershiptype.changed': _('The membership type has been changed.'),
|
||||
'pretix.membershiptype.deleted': _('The membership type has been deleted.'),
|
||||
'pretix.saleschannel.created': _('The sales channel has been created.'),
|
||||
'pretix.saleschannel.changed': _('The sales channel has been changed.'),
|
||||
'pretix.saleschannel.deleted': _('The sales channel has been deleted.'),
|
||||
'pretix.customer.created': _('The account has been created.'),
|
||||
'pretix.customer.changed': _('The account has been changed.'),
|
||||
'pretix.customer.membership.created': _('A membership for this account has been added.'),
|
||||
'pretix.customer.membership.changed': _('A membership of this account has been changed.'),
|
||||
'pretix.customer.membership.deleted': _('A membership of this account has been deleted.'),
|
||||
'pretix.customer.anonymized': _('The account has been disabled and anonymized.'),
|
||||
'pretix.customer.password.resetrequested': _('A new password has been requested.'),
|
||||
'pretix.customer.password.set': _('A new password has been set.'),
|
||||
'pretix.reusable_medium.created': _('The reusable medium has been created.'),
|
||||
'pretix.reusable_medium.created.auto': _('The reusable medium has been created automatically.'),
|
||||
'pretix.reusable_medium.changed': _('The reusable medium has been changed.'),
|
||||
'pretix.reusable_medium.linked_orderposition.changed': _('The medium has been connected to a new ticket.'),
|
||||
'pretix.reusable_medium.linked_giftcard.changed': _('The medium has been connected to a new gift card.'),
|
||||
'pretix.email.error': _('Sending of an email has failed.'),
|
||||
'pretix.event.comment': _('The event\'s internal comment has been updated.'),
|
||||
'pretix.event.canceled': _('The event has been canceled.'),
|
||||
'pretix.event.deleted': _('An event has been deleted.'),
|
||||
'pretix.event.shredder.started': _('A removal process for personal data has been started.'),
|
||||
'pretix.event.shredder.completed': _('A removal process for personal data has been completed.'),
|
||||
'pretix.event.order.modified': _('The order details have been changed.'),
|
||||
'pretix.event.order.unpaid': _('The order has been marked as unpaid.'),
|
||||
'pretix.event.order.secret.changed': _('The order\'s secret has been changed.'),
|
||||
'pretix.event.order.expirychanged': _('The order\'s expiry date has been changed.'),
|
||||
'pretix.event.order.valid_if_pending.set': _('The order has been set to be usable before it is paid.'),
|
||||
'pretix.event.order.valid_if_pending.unset': _('The order has been set to require payment before use.'),
|
||||
'pretix.event.order.expired': _('The order has been marked as expired.'),
|
||||
'pretix.event.order.paid': _('The order has been marked as paid.'),
|
||||
'pretix.event.order.cancellationrequest.deleted': _('The cancellation request has been deleted.'),
|
||||
'pretix.event.order.refunded': _('The order has been refunded.'),
|
||||
'pretix.event.order.reactivated': _('The order has been reactivated.'),
|
||||
'pretix.event.order.deleted': _('The test mode order {code} has been deleted.'),
|
||||
'pretix.event.order.placed': _('The order has been created.'),
|
||||
'pretix.event.order.placed.require_approval': _('The order requires approval before it can continue to be processed.'),
|
||||
'pretix.event.order.approved': _('The order has been approved.'),
|
||||
'pretix.event.order.denied': _('The order has been denied (comment: "{comment}").'),
|
||||
'pretix.event.order.contact.changed': _('The email address has been changed from "{old_email}" '
|
||||
'to "{new_email}".'),
|
||||
'pretix.event.order.contact.confirmed': _('The email address has been confirmed to be working (the user clicked on a link '
|
||||
'in the email for the first time).'),
|
||||
'pretix.event.order.phone.changed': _('The phone number has been changed from "{old_phone}" '
|
||||
'to "{new_phone}".'),
|
||||
'pretix.event.order.customer.changed': _('The customer account has been changed.'),
|
||||
'pretix.event.order.locale.changed': _('The order locale has been changed.'),
|
||||
'pretix.event.order.invoice.generated': _('The invoice has been generated.'),
|
||||
'pretix.event.order.invoice.regenerated': _('The invoice has been regenerated.'),
|
||||
'pretix.event.order.invoice.reissued': _('The invoice has been reissued.'),
|
||||
'pretix.event.order.comment': _('The order\'s internal comment has been updated.'),
|
||||
'pretix.event.order.custom_followup_at': _('The order\'s follow-up date has been updated.'),
|
||||
'pretix.event.order.checkin_attention': _('The order\'s flag to require attention at check-in has been '
|
||||
'toggled.'),
|
||||
'pretix.event.order.checkin_text': _('The order\'s check-in text has been changed.'),
|
||||
'pretix.event.order.pretix.event.order.valid_if_pending': _('The order\'s flag to be considered valid even if '
|
||||
'unpaid has been toggled.'),
|
||||
'pretix.event.order.payment.changed': _('A new payment {local_id} has been started instead of the previous one.'),
|
||||
'pretix.event.order.email.sent': _('An unidentified type email has been sent.'),
|
||||
'pretix.event.order.email.error': _('Sending of an email has failed.'),
|
||||
'pretix.event.order.email.attachments.skipped': _('The email has been sent without attached tickets since they '
|
||||
'would have been too large to be likely to arrive.'),
|
||||
'pretix.event.order.email.custom_sent': _('A custom email has been sent.'),
|
||||
'pretix.event.order.position.email.custom_sent': _('A custom email has been sent to an attendee.'),
|
||||
'pretix.event.order.email.download_reminder_sent': _('An email has been sent with a reminder that the ticket '
|
||||
'is available for download.'),
|
||||
'pretix.event.order.email.expire_warning_sent': _('An email has been sent with a warning that the order is about '
|
||||
'to expire.'),
|
||||
'pretix.event.order.email.order_canceled': _('An email has been sent to notify the user that the order has been canceled.'),
|
||||
'pretix.event.order.email.event_canceled': _('An email has been sent to notify the user that the event has '
|
||||
'been canceled.'),
|
||||
'pretix.event.order.email.order_changed': _('An email has been sent to notify the user that the order has been changed.'),
|
||||
'pretix.event.order.email.order_free': _('An email has been sent to notify the user that the order has been received.'),
|
||||
'pretix.event.order.email.order_paid': _('An email has been sent to notify the user that payment has been received.'),
|
||||
'pretix.event.order.email.order_denied': _('An email has been sent to notify the user that the order has been denied.'),
|
||||
'pretix.event.order.email.order_approved': _('An email has been sent to notify the user that the order has '
|
||||
'been approved.'),
|
||||
'pretix.event.order.email.order_placed': _('An email has been sent to notify the user that the order has been received and requires payment.'),
|
||||
'pretix.event.order.email.order_placed_require_approval': _('An email has been sent to notify the user that '
|
||||
'the order has been received and requires '
|
||||
'approval.'),
|
||||
'pretix.event.order.email.resend': _('An email with a link to the order detail page has been resent to the user.'),
|
||||
'pretix.event.order.email.payment_failed': _('An email has been sent to notify the user that the payment failed.'),
|
||||
'pretix.event.order.payment.confirmed': _('Payment {local_id} has been confirmed.'),
|
||||
'pretix.event.order.payment.canceled': _('Payment {local_id} has been canceled.'),
|
||||
'pretix.event.order.payment.canceled.failed': _('Canceling payment {local_id} has failed.'),
|
||||
'pretix.event.order.payment.started': _('Payment {local_id} has been started.'),
|
||||
'pretix.event.order.payment.failed': _('Payment {local_id} has failed.'),
|
||||
'pretix.event.order.quotaexceeded': _('The order could not be marked as paid: {message}'),
|
||||
'pretix.event.order.overpaid': _('The order has been overpaid.'),
|
||||
'pretix.event.order.refund.created': _('Refund {local_id} has been created.'),
|
||||
'pretix.event.order.refund.created.externally': _('Refund {local_id} has been created by an external entity.'),
|
||||
'pretix.event.order.refund.requested': _('The customer requested you to issue a refund.'),
|
||||
'pretix.event.order.refund.done': _('Refund {local_id} has been completed.'),
|
||||
'pretix.event.order.refund.canceled': _('Refund {local_id} has been canceled.'),
|
||||
'pretix.event.order.refund.failed': _('Refund {local_id} has failed.'),
|
||||
'pretix.event.export.schedule.added': _('A scheduled export has been added.'),
|
||||
'pretix.event.export.schedule.changed': _('A scheduled export has been changed.'),
|
||||
'pretix.event.export.schedule.deleted': _('A scheduled export has been deleted.'),
|
||||
'pretix.event.export.schedule.executed': _('A scheduled export has been executed.'),
|
||||
'pretix.event.export.schedule.failed': _('A scheduled export has failed: {reason}.'),
|
||||
'pretix.control.auth.user.created': _('The user has been created.'),
|
||||
'pretix.control.auth.user.new_source': _('A first login using {agent_type} on {os_type} from {country} has '
|
||||
'been detected.'),
|
||||
'pretix.user.settings.2fa.enabled': _('Two-factor authentication has been enabled.'),
|
||||
'pretix.user.settings.2fa.disabled': _('Two-factor authentication has been disabled.'),
|
||||
'pretix.user.settings.2fa.regenemergency': _('Your two-factor emergency codes have been regenerated.'),
|
||||
'pretix.user.settings.2fa.emergency': _('A two-factor emergency code has been generated.'),
|
||||
'pretix.user.settings.2fa.device.added': _('A new two-factor authentication device "{name}" has been added to '
|
||||
'your account.'),
|
||||
'pretix.user.settings.2fa.device.deleted': _('The two-factor authentication device "{name}" has been removed '
|
||||
'from your account.'),
|
||||
'pretix.user.settings.notifications.enabled': _('Notifications have been enabled.'),
|
||||
'pretix.user.settings.notifications.disabled': _('Notifications have been disabled.'),
|
||||
'pretix.user.settings.notifications.changed': _('Your notification settings have been changed.'),
|
||||
'pretix.user.anonymized': _('This user has been anonymized.'),
|
||||
'pretix.user.oauth.authorized': _('The application "{application_name}" has been authorized to access your '
|
||||
'account.'),
|
||||
'pretix.control.auth.user.forgot_password.mail_sent': _('Password reset mail sent.'),
|
||||
'pretix.control.auth.user.forgot_password.recovered': _('The password has been reset.'),
|
||||
'pretix.control.auth.user.forgot_password.denied.repeated': _('A repeated password reset has been denied, as '
|
||||
'the last request was less than 24 hours ago.'),
|
||||
'pretix.organizer.deleted': _('The organizer "{name}" has been deleted.'),
|
||||
'pretix.voucher.added': _('The voucher has been created.'),
|
||||
'pretix.voucher.sent': _('The voucher has been sent to {recipient}.'),
|
||||
'pretix.voucher.added.waitinglist': _('The voucher has been created and sent to a person on the waiting list.'),
|
||||
'pretix.voucher.expired.waitinglist': _('The voucher has been set to expire because the recipient removed themselves from the waiting list.'),
|
||||
'pretix.voucher.changed': _('The voucher has been changed.'),
|
||||
'pretix.voucher.deleted': _('The voucher has been deleted.'),
|
||||
'pretix.voucher.redeemed': _('The voucher has been redeemed in order {order_code}.'),
|
||||
'pretix.event.item.added': _('The product has been created.'),
|
||||
'pretix.event.item.changed': _('The product has been changed.'),
|
||||
'pretix.event.item.reordered': _('The product has been reordered.'),
|
||||
'pretix.event.item.deleted': _('The product has been deleted.'),
|
||||
'pretix.event.item.variation.added': _('The variation "{value}" has been created.'),
|
||||
'pretix.event.item.variation.deleted': _('The variation "{value}" has been deleted.'),
|
||||
'pretix.event.item.variation.changed': _('The variation "{value}" has been changed.'),
|
||||
'pretix.event.item.addons.added': _('An add-on has been added to this product.'),
|
||||
'pretix.event.item.addons.removed': _('An add-on has been removed from this product.'),
|
||||
'pretix.event.item.addons.changed': _('An add-on has been changed on this product.'),
|
||||
'pretix.event.item.bundles.added': _('A bundled item has been added to this product.'),
|
||||
'pretix.event.item.bundles.removed': _('A bundled item has been removed from this product.'),
|
||||
'pretix.event.item.bundles.changed': _('A bundled item has been changed on this product.'),
|
||||
'pretix.event.item_meta_property.added': _('A meta property has been added to this event.'),
|
||||
'pretix.event.item_meta_property.deleted': _('A meta property has been removed from this event.'),
|
||||
'pretix.event.item_meta_property.changed': _('A meta property has been changed on this event.'),
|
||||
'pretix.event.quota.added': _('The quota has been added.'),
|
||||
'pretix.event.quota.deleted': _('The quota has been deleted.'),
|
||||
'pretix.event.quota.changed': _('The quota has been changed.'),
|
||||
'pretix.event.quota.closed': _('The quota has closed.'),
|
||||
'pretix.event.quota.opened': _('The quota has been re-opened.'),
|
||||
'pretix.event.category.added': _('The category has been added.'),
|
||||
'pretix.event.category.deleted': _('The category has been deleted.'),
|
||||
'pretix.event.category.changed': _('The category has been changed.'),
|
||||
'pretix.event.category.reordered': _('The category has been reordered.'),
|
||||
'pretix.event.question.added': _('The question has been added.'),
|
||||
'pretix.event.question.deleted': _('The question has been deleted.'),
|
||||
'pretix.event.question.changed': _('The question has been changed.'),
|
||||
'pretix.event.question.reordered': _('The question has been reordered.'),
|
||||
'pretix.event.discount.added': _('The discount has been added.'),
|
||||
'pretix.event.discount.deleted': _('The discount has been deleted.'),
|
||||
'pretix.event.discount.changed': _('The discount has been changed.'),
|
||||
'pretix.event.taxrule.added': _('The tax rule has been added.'),
|
||||
'pretix.event.taxrule.deleted': _('The tax rule has been deleted.'),
|
||||
'pretix.event.taxrule.changed': _('The tax rule has been changed.'),
|
||||
'pretix.event.checkinlist.added': _('The check-in list has been added.'),
|
||||
'pretix.event.checkinlist.deleted': _('The check-in list has been deleted.'),
|
||||
'pretix.event.checkinlists.deleted': _('The check-in list has been deleted.'), # backwards compatibility
|
||||
'pretix.event.checkinlist.changed': _('The check-in list has been changed.'),
|
||||
'pretix.event.settings': _('The event settings have been changed.'),
|
||||
'pretix.event.tickets.settings': _('The ticket download settings have been changed.'),
|
||||
'pretix.event.plugins.enabled': _('A plugin has been enabled.'),
|
||||
'pretix.event.plugins.disabled': _('A plugin has been disabled.'),
|
||||
'pretix.event.live.activated': _('The shop has been taken live.'),
|
||||
'pretix.event.live.deactivated': _('The shop has been taken offline.'),
|
||||
'pretix.event.testmode.activated': _('The shop has been taken into test mode.'),
|
||||
'pretix.event.testmode.deactivated': _('The test mode has been disabled.'),
|
||||
'pretix.event.added': _('The event has been created.'),
|
||||
'pretix.event.changed': _('The event details have been changed.'),
|
||||
'pretix.event.footerlinks.changed': _('The footer links have been changed.'),
|
||||
'pretix.event.question.option.added': _('An answer option has been added to the question.'),
|
||||
'pretix.event.question.option.deleted': _('An answer option has been removed from the question.'),
|
||||
'pretix.event.question.option.changed': _('An answer option has been changed.'),
|
||||
'pretix.event.permissions.added': _('A user has been added to the event team.'),
|
||||
'pretix.event.permissions.invited': _('A user has been invited to the event team.'),
|
||||
'pretix.event.permissions.changed': _('A user\'s permissions have been changed.'),
|
||||
'pretix.event.permissions.deleted': _('A user has been removed from the event team.'),
|
||||
'pretix.waitinglist.voucher': _('A voucher has been sent to a person on the waiting list.'), # legacy
|
||||
'pretix.event.orders.waitinglist.voucher_assigned': _('A voucher has been sent to a person on the waiting list.'),
|
||||
'pretix.event.orders.waitinglist.deleted': _('An entry has been removed from the waiting list.'),
|
||||
'pretix.event.order.waitinglist.transferred': _('An entry has been transferred to another waiting list.'), # legacy
|
||||
'pretix.event.orders.waitinglist.changed': _('An entry has been changed on the waiting list.'),
|
||||
'pretix.event.orders.waitinglist.added': _('An entry has been added to the waiting list.'),
|
||||
'pretix.team.created': _('The team has been created.'),
|
||||
'pretix.team.changed': _('The team settings have been changed.'),
|
||||
'pretix.team.deleted': _('The team has been deleted.'),
|
||||
'pretix.gate.created': _('The gate has been created.'),
|
||||
'pretix.gate.changed': _('The gate has been changed.'),
|
||||
'pretix.gate.deleted': _('The gate has been deleted.'),
|
||||
'pretix.subevent.deleted': pgettext_lazy('subevent', 'The event date has been deleted.'),
|
||||
'pretix.subevent.canceled': pgettext_lazy('subevent', 'The event date has been canceled.'),
|
||||
'pretix.subevent.changed': pgettext_lazy('subevent', 'The event date has been changed.'),
|
||||
'pretix.subevent.added': pgettext_lazy('subevent', 'The event date has been created.'),
|
||||
'pretix.subevent.quota.added': pgettext_lazy('subevent', 'A quota has been added to the event date.'),
|
||||
'pretix.subevent.quota.changed': pgettext_lazy('subevent', 'A quota has been changed on the event date.'),
|
||||
'pretix.subevent.quota.deleted': pgettext_lazy('subevent', 'A quota has been removed from the event date.'),
|
||||
'pretix.device.created': _('The device has been created.'),
|
||||
'pretix.device.changed': _('The device has been changed.'),
|
||||
'pretix.device.revoked': _('Access of the device has been revoked.'),
|
||||
'pretix.device.initialized': _('The device has been initialized.'),
|
||||
'pretix.device.keyroll': _('The access token of the device has been regenerated.'),
|
||||
'pretix.device.updated': _('The device has notified the server of an hardware or software update.'),
|
||||
'pretix.giftcards.created': _('The gift card has been created.'),
|
||||
'pretix.giftcards.modified': _('The gift card has been changed.'),
|
||||
'pretix.giftcards.transaction.manual': _('A manual transaction has been performed.'),
|
||||
}
|
||||
|
||||
data = json.loads(logentry.data)
|
||||
|
||||
if logentry.action_type.startswith('pretix.event.item.variation'):
|
||||
if 'value' not in data:
|
||||
# Backwards compatibility
|
||||
var = ItemVariation.objects.filter(id=data['id']).first()
|
||||
if var:
|
||||
data['value'] = str(var.value)
|
||||
else:
|
||||
data['value'] = '?'
|
||||
else:
|
||||
data['value'] = LazyI18nString(data['value'])
|
||||
|
||||
if logentry.action_type == "pretix.voucher.redeemed":
|
||||
data = defaultdict(lambda: '?', data)
|
||||
url = reverse('control:event.order', kwargs={
|
||||
'event': logentry.event.slug,
|
||||
'organizer': logentry.event.organizer.slug,
|
||||
'code': data['order_code']
|
||||
})
|
||||
return mark_safe(plains[logentry.action_type].format(
|
||||
order_code='<a href="{}">{}</a>'.format(url, data['order_code']),
|
||||
))
|
||||
|
||||
if logentry.action_type in plains:
|
||||
data = defaultdict(lambda: '?', data)
|
||||
return plains[logentry.action_type].format_map(data)
|
||||
|
||||
if logentry.action_type.startswith('pretix.event.order.changed'):
|
||||
return _display_order_changed(sender, logentry)
|
||||
@@ -623,91 +359,22 @@ def pretixcontrol_logentry_display(sender: Event, logentry: LogEntry, **kwargs):
|
||||
return _('The order has been canceled.')
|
||||
|
||||
if logentry.action_type in ('pretix.control.views.checkin.reverted', 'pretix.event.checkin.reverted'):
|
||||
if 'list' in data:
|
||||
if 'list' in logentry.parsed_data:
|
||||
try:
|
||||
checkin_list = sender.checkin_lists.get(pk=data.get('list')).name
|
||||
checkin_list = sender.checkin_lists.get(pk=logentry.parsed_data.get('list')).name
|
||||
except CheckinList.DoesNotExist:
|
||||
checkin_list = _("(unknown)")
|
||||
else:
|
||||
checkin_list = _("(unknown)")
|
||||
|
||||
return _('The check-in of position #{posid} on list "{list}" has been reverted.').format(
|
||||
posid=data.get('positionid'),
|
||||
posid=logentry.parsed_data.get('positionid'),
|
||||
list=checkin_list,
|
||||
)
|
||||
|
||||
if sender and logentry.action_type.startswith('pretix.event.checkin'):
|
||||
return _display_checkin(sender, logentry)
|
||||
|
||||
if logentry.action_type == 'pretix.control.views.checkin':
|
||||
# deprecated
|
||||
dt = dateutil.parser.parse(data.get('datetime'))
|
||||
tz = sender.timezone
|
||||
dt_formatted = date_format(dt.astimezone(tz), "SHORT_DATETIME_FORMAT")
|
||||
if 'list' in data:
|
||||
try:
|
||||
checkin_list = sender.checkin_lists.get(pk=data.get('list')).name
|
||||
except CheckinList.DoesNotExist:
|
||||
checkin_list = _("(unknown)")
|
||||
else:
|
||||
checkin_list = _("(unknown)")
|
||||
|
||||
if data.get('first'):
|
||||
return _('Position #{posid} has been checked in manually at {datetime} on list "{list}".').format(
|
||||
posid=data.get('positionid'),
|
||||
datetime=dt_formatted,
|
||||
list=checkin_list,
|
||||
)
|
||||
return _('Position #{posid} has been checked in again at {datetime} on list "{list}".').format(
|
||||
posid=data.get('positionid'),
|
||||
datetime=dt_formatted,
|
||||
list=checkin_list
|
||||
)
|
||||
|
||||
if logentry.action_type == 'pretix.team.member.added':
|
||||
return _('{user} has been added to the team.').format(user=data.get('email'))
|
||||
|
||||
if logentry.action_type == 'pretix.team.member.removed':
|
||||
return _('{user} has been removed from the team.').format(user=data.get('email'))
|
||||
|
||||
if logentry.action_type == 'pretix.team.member.joined':
|
||||
return _('{user} has joined the team using the invite sent to {email}.').format(
|
||||
user=data.get('email'), email=data.get('invite_email')
|
||||
)
|
||||
|
||||
if logentry.action_type == 'pretix.team.invite.created':
|
||||
return _('{user} has been invited to the team.').format(user=data.get('email'))
|
||||
|
||||
if logentry.action_type == 'pretix.team.invite.resent':
|
||||
return _('Invite for {user} has been resent.').format(user=data.get('email'))
|
||||
|
||||
if logentry.action_type == 'pretix.team.invite.deleted':
|
||||
return _('The invite for {user} has been revoked.').format(user=data.get('email'))
|
||||
|
||||
if logentry.action_type == 'pretix.team.token.created':
|
||||
return _('The token "{name}" has been created.').format(name=data.get('name'))
|
||||
|
||||
if logentry.action_type == 'pretix.team.token.deleted':
|
||||
return _('The token "{name}" has been revoked.').format(name=data.get('name'))
|
||||
|
||||
if logentry.action_type == 'pretix.user.settings.changed':
|
||||
text = str(_('Your account settings have been changed.'))
|
||||
if 'email' in data:
|
||||
text = text + ' ' + str(_('Your email address has been changed to {email}.').format(email=data['email']))
|
||||
if 'new_pw' in data:
|
||||
text = text + ' ' + str(_('Your password has been changed.'))
|
||||
if data.get('is_active') is True:
|
||||
text = text + ' ' + str(_('Your account has been enabled.'))
|
||||
elif data.get('is_active') is False:
|
||||
text = text + ' ' + str(_('Your account has been disabled.'))
|
||||
return text
|
||||
|
||||
if logentry.action_type == 'pretix.control.auth.user.impersonated':
|
||||
return str(_('You impersonated {}.')).format(data['other_email'])
|
||||
|
||||
if logentry.action_type == 'pretix.control.auth.user.impersonate_stopped':
|
||||
return str(_('You stopped impersonating {}.')).format(data['other_email'])
|
||||
|
||||
|
||||
@receiver(signal=orderposition_blocked_display, dispatch_uid="pretixcontrol_orderposition_blocked_display")
|
||||
def pretixcontrol_orderposition_blocked_display(sender: Event, orderposition, block_name, **kwargs):
|
||||
@@ -715,3 +382,459 @@ def pretixcontrol_orderposition_blocked_display(sender: Event, orderposition, bl
|
||||
return _('Blocked manually')
|
||||
elif block_name.startswith('api:'):
|
||||
return _('Blocked because of an API integration')
|
||||
|
||||
|
||||
@log_entry_types.new_from_dict({
|
||||
'pretix.event.order.modified': _('The order details have been changed.'),
|
||||
'pretix.event.order.unpaid': _('The order has been marked as unpaid.'),
|
||||
'pretix.event.order.secret.changed': _('The order\'s secret has been changed.'),
|
||||
'pretix.event.order.expirychanged': _('The order\'s expiry date has been changed.'),
|
||||
'pretix.event.order.valid_if_pending.set': _('The order has been set to be usable before it is paid.'),
|
||||
'pretix.event.order.valid_if_pending.unset': _('The order has been set to require payment before use.'),
|
||||
'pretix.event.order.expired': _('The order has been marked as expired.'),
|
||||
'pretix.event.order.paid': _('The order has been marked as paid.'),
|
||||
'pretix.event.order.cancellationrequest.deleted': _('The cancellation request has been deleted.'),
|
||||
'pretix.event.order.refunded': _('The order has been refunded.'),
|
||||
'pretix.event.order.reactivated': _('The order has been reactivated.'),
|
||||
'pretix.event.order.deleted': _('The test mode order {code} has been deleted.'),
|
||||
'pretix.event.order.placed': _('The order has been created.'),
|
||||
'pretix.event.order.placed.require_approval': _(
|
||||
'The order requires approval before it can continue to be processed.'),
|
||||
'pretix.event.order.approved': _('The order has been approved.'),
|
||||
'pretix.event.order.denied': _('The order has been denied (comment: "{comment}").'),
|
||||
'pretix.event.order.contact.changed': _('The email address has been changed from "{old_email}" '
|
||||
'to "{new_email}".'),
|
||||
'pretix.event.order.contact.confirmed': _(
|
||||
'The email address has been confirmed to be working (the user clicked on a link '
|
||||
'in the email for the first time).'),
|
||||
'pretix.event.order.phone.changed': _('The phone number has been changed from "{old_phone}" '
|
||||
'to "{new_phone}".'),
|
||||
'pretix.event.order.customer.changed': _('The customer account has been changed.'),
|
||||
'pretix.event.order.locale.changed': _('The order locale has been changed.'),
|
||||
'pretix.event.order.invoice.generated': _('The invoice has been generated.'),
|
||||
'pretix.event.order.invoice.regenerated': _('The invoice has been regenerated.'),
|
||||
'pretix.event.order.invoice.reissued': _('The invoice has been reissued.'),
|
||||
'pretix.event.order.comment': _('The order\'s internal comment has been updated.'),
|
||||
'pretix.event.order.custom_followup_at': _('The order\'s follow-up date has been updated.'),
|
||||
'pretix.event.order.checkin_attention': _('The order\'s flag to require attention at check-in has been '
|
||||
'toggled.'),
|
||||
'pretix.event.order.checkin_text': _('The order\'s check-in text has been changed.'),
|
||||
'pretix.event.order.pretix.event.order.valid_if_pending': _('The order\'s flag to be considered valid even if '
|
||||
'unpaid has been toggled.'),
|
||||
'pretix.event.order.payment.changed': _('A new payment {local_id} has been started instead of the previous one.'),
|
||||
'pretix.event.order.email.sent': _('An unidentified type email has been sent.'),
|
||||
'pretix.event.order.email.error': _('Sending of an email has failed.'),
|
||||
'pretix.event.order.email.attachments.skipped': _('The email has been sent without attached tickets since they '
|
||||
'would have been too large to be likely to arrive.'),
|
||||
'pretix.event.order.email.custom_sent': _('A custom email has been sent.'),
|
||||
'pretix.event.order.position.email.custom_sent': _('A custom email has been sent to an attendee.'),
|
||||
'pretix.event.order.email.download_reminder_sent': _('An email has been sent with a reminder that the ticket '
|
||||
'is available for download.'),
|
||||
'pretix.event.order.email.expire_warning_sent': _('An email has been sent with a warning that the order is about '
|
||||
'to expire.'),
|
||||
'pretix.event.order.email.order_canceled': _(
|
||||
'An email has been sent to notify the user that the order has been canceled.'),
|
||||
'pretix.event.order.email.event_canceled': _('An email has been sent to notify the user that the event has '
|
||||
'been canceled.'),
|
||||
'pretix.event.order.email.order_changed': _(
|
||||
'An email has been sent to notify the user that the order has been changed.'),
|
||||
'pretix.event.order.email.order_free': _(
|
||||
'An email has been sent to notify the user that the order has been received.'),
|
||||
'pretix.event.order.email.order_paid': _(
|
||||
'An email has been sent to notify the user that payment has been received.'),
|
||||
'pretix.event.order.email.order_denied': _(
|
||||
'An email has been sent to notify the user that the order has been denied.'),
|
||||
'pretix.event.order.email.order_approved': _('An email has been sent to notify the user that the order has '
|
||||
'been approved.'),
|
||||
'pretix.event.order.email.order_placed': _(
|
||||
'An email has been sent to notify the user that the order has been received and requires payment.'),
|
||||
'pretix.event.order.email.order_placed_require_approval': _('An email has been sent to notify the user that '
|
||||
'the order has been received and requires '
|
||||
'approval.'),
|
||||
'pretix.event.order.email.resend': _('An email with a link to the order detail page has been resent to the user.'),
|
||||
'pretix.event.order.email.payment_failed': _('An email has been sent to notify the user that the payment failed.'),
|
||||
})
|
||||
class CoreOrderLogEntryType(OrderLogEntryType):
|
||||
pass
|
||||
|
||||
|
||||
@log_entry_types.new_from_dict({
|
||||
'pretix.voucher.added': _('The voucher has been created.'),
|
||||
'pretix.voucher.sent': _('The voucher has been sent to {recipient}.'),
|
||||
'pretix.voucher.added.waitinglist': _('The voucher has been created and sent to a person on the waiting list.'),
|
||||
'pretix.voucher.expired.waitinglist': _(
|
||||
'The voucher has been set to expire because the recipient removed themselves from the waiting list.'),
|
||||
'pretix.voucher.changed': _('The voucher has been changed.'),
|
||||
'pretix.voucher.deleted': _('The voucher has been deleted.'),
|
||||
})
|
||||
class CoreVoucherLogEntryType(VoucherLogEntryType):
|
||||
pass
|
||||
|
||||
|
||||
@log_entry_types.new()
|
||||
class VoucherRedeemedLogEntryType(VoucherLogEntryType):
|
||||
action_type = 'pretix.voucher.redeemed'
|
||||
plain = _('The voucher has been redeemed in order {order_code}.')
|
||||
|
||||
def display(self, logentry):
|
||||
data = json.loads(logentry.data)
|
||||
data = defaultdict(lambda: '?', data)
|
||||
url = reverse('control:event.order', kwargs={
|
||||
'event': logentry.event.slug,
|
||||
'organizer': logentry.event.organizer.slug,
|
||||
'code': data['order_code']
|
||||
})
|
||||
return mark_safe(self.plain.format(
|
||||
order_code='<a href="{}">{}</a>'.format(url, data['order_code']),
|
||||
))
|
||||
|
||||
|
||||
@log_entry_types.new_from_dict({
|
||||
'pretix.event.category.added': _('The category has been added.'),
|
||||
'pretix.event.category.deleted': _('The category has been deleted.'),
|
||||
'pretix.event.category.changed': _('The category has been changed.'),
|
||||
'pretix.event.category.reordered': _('The category has been reordered.'),
|
||||
})
|
||||
class CoreItemCategoryLogEntryType(ItemCategoryLogEntryType):
|
||||
pass
|
||||
|
||||
|
||||
@log_entry_types.new_from_dict({
|
||||
'pretix.event.taxrule.added': _('The tax rule has been added.'),
|
||||
'pretix.event.taxrule.deleted': _('The tax rule has been deleted.'),
|
||||
'pretix.event.taxrule.changed': _('The tax rule has been changed.'),
|
||||
})
|
||||
class CoreTaxRuleLogEntryType(TaxRuleLogEntryType):
|
||||
pass
|
||||
|
||||
|
||||
class TeamMembershipLogEntryType(LogEntryType):
|
||||
def display(self, logentry):
|
||||
return self.plain.format(user=logentry.parsed_data.get('email'))
|
||||
|
||||
|
||||
@log_entry_types.new_from_dict({
|
||||
'pretix.team.member.added': _('{user} has been added to the team.'),
|
||||
'pretix.team.member.removed': _('{user} has been removed from the team.'),
|
||||
'pretix.team.invite.created': _('{user} has been invited to the team.'),
|
||||
'pretix.team.invite.resent': _('Invite for {user} has been resent.'),
|
||||
})
|
||||
class CoreTeamMembershipLogEntryType(TeamMembershipLogEntryType):
|
||||
pass
|
||||
|
||||
|
||||
@log_entry_types.new()
|
||||
class TeamMemberJoinedLogEntryType(LogEntryType):
|
||||
action_type = 'pretix.team.member.joined'
|
||||
|
||||
def display(self, logentry):
|
||||
return _('{user} has joined the team using the invite sent to {email}.').format(
|
||||
user=logentry.parsed_data.get('email'), email=logentry.parsed_data.get('invite_email')
|
||||
)
|
||||
|
||||
|
||||
@log_entry_types.new()
|
||||
class UserSettingsChangedLogEntryType(LogEntryType):
|
||||
action_type = 'pretix.user.settings.changed'
|
||||
|
||||
def display(self, logentry):
|
||||
text = str(_('Your account settings have been changed.'))
|
||||
if 'email' in logentry.parsed_data:
|
||||
text = text + ' ' + str(
|
||||
_('Your email address has been changed to {email}.').format(email=logentry.parsed_data['email']))
|
||||
if 'new_pw' in logentry.parsed_data:
|
||||
text = text + ' ' + str(_('Your password has been changed.'))
|
||||
if logentry.parsed_data.get('is_active') is True:
|
||||
text = text + ' ' + str(_('Your account has been enabled.'))
|
||||
elif logentry.parsed_data.get('is_active') is False:
|
||||
text = text + ' ' + str(_('Your account has been disabled.'))
|
||||
return text
|
||||
|
||||
|
||||
class UserImpersonatedLogEntryType(LogEntryType):
|
||||
def display(self, logentry):
|
||||
return self.plain.format(logentry.parsed_data['other_email'])
|
||||
|
||||
|
||||
@log_entry_types.new_from_dict({
|
||||
'pretix.control.auth.user.impersonated': _('You impersonated {}.'),
|
||||
'pretix.control.auth.user.impersonate_stopped': _('You stopped impersonating {}.'),
|
||||
})
|
||||
class CoreUserImpersonatedLogEntryType(UserImpersonatedLogEntryType):
|
||||
pass
|
||||
|
||||
|
||||
@log_entry_types.new_from_dict({
|
||||
'pretix.object.cloned': _('This object has been created by cloning.'),
|
||||
'pretix.organizer.changed': _('The organizer has been changed.'),
|
||||
'pretix.organizer.settings': _('The organizer settings have been changed.'),
|
||||
'pretix.organizer.footerlinks.changed': _('The footer links have been changed.'),
|
||||
'pretix.organizer.export.schedule.added': _('A scheduled export has been added.'),
|
||||
'pretix.organizer.export.schedule.changed': _('A scheduled export has been changed.'),
|
||||
'pretix.organizer.export.schedule.deleted': _('A scheduled export has been deleted.'),
|
||||
'pretix.organizer.export.schedule.executed': _('A scheduled export has been executed.'),
|
||||
'pretix.organizer.export.schedule.failed': _('A scheduled export has failed: {reason}.'),
|
||||
'pretix.giftcards.acceptance.added': _('Gift card acceptance for another organizer has been added.'),
|
||||
'pretix.giftcards.acceptance.removed': _('Gift card acceptance for another organizer has been removed.'),
|
||||
'pretix.giftcards.acceptance.acceptor.invited': _('A new gift card acceptor has been invited.'),
|
||||
'pretix.giftcards.acceptance.acceptor.removed': _('A gift card acceptor has been removed.'),
|
||||
'pretix.giftcards.acceptance.issuer.removed': _('A gift card issuer has been removed or declined.'),
|
||||
'pretix.giftcards.acceptance.issuer.accepted': _('A new gift card issuer has been accepted.'),
|
||||
'pretix.webhook.created': _('The webhook has been created.'),
|
||||
'pretix.webhook.changed': _('The webhook has been changed.'),
|
||||
'pretix.webhook.retries.expedited': _('The webhook call retry jobs have been manually expedited.'),
|
||||
'pretix.webhook.retries.dropped': _('The webhook call retry jobs have been dropped.'),
|
||||
'pretix.ssoprovider.created': _('The SSO provider has been created.'),
|
||||
'pretix.ssoprovider.changed': _('The SSO provider has been changed.'),
|
||||
'pretix.ssoprovider.deleted': _('The SSO provider has been deleted.'),
|
||||
'pretix.ssoclient.created': _('The SSO client has been created.'),
|
||||
'pretix.ssoclient.changed': _('The SSO client has been changed.'),
|
||||
'pretix.ssoclient.deleted': _('The SSO client has been deleted.'),
|
||||
'pretix.membershiptype.created': _('The membership type has been created.'),
|
||||
'pretix.membershiptype.changed': _('The membership type has been changed.'),
|
||||
'pretix.membershiptype.deleted': _('The membership type has been deleted.'),
|
||||
'pretix.saleschannel.created': _('The sales channel has been created.'),
|
||||
'pretix.saleschannel.changed': _('The sales channel has been changed.'),
|
||||
'pretix.saleschannel.deleted': _('The sales channel has been deleted.'),
|
||||
'pretix.customer.created': _('The account has been created.'),
|
||||
'pretix.customer.changed': _('The account has been changed.'),
|
||||
'pretix.customer.membership.created': _('A membership for this account has been added.'),
|
||||
'pretix.customer.membership.changed': _('A membership of this account has been changed.'),
|
||||
'pretix.customer.membership.deleted': _('A membership of this account has been deleted.'),
|
||||
'pretix.customer.anonymized': _('The account has been disabled and anonymized.'),
|
||||
'pretix.customer.password.resetrequested': _('A new password has been requested.'),
|
||||
'pretix.customer.password.set': _('A new password has been set.'),
|
||||
'pretix.reusable_medium.created': _('The reusable medium has been created.'),
|
||||
'pretix.reusable_medium.created.auto': _('The reusable medium has been created automatically.'),
|
||||
'pretix.reusable_medium.changed': _('The reusable medium has been changed.'),
|
||||
'pretix.reusable_medium.linked_orderposition.changed': _('The medium has been connected to a new ticket.'),
|
||||
'pretix.reusable_medium.linked_giftcard.changed': _('The medium has been connected to a new gift card.'),
|
||||
'pretix.email.error': _('Sending of an email has failed.'),
|
||||
'pretix.event.comment': _('The event\'s internal comment has been updated.'),
|
||||
'pretix.event.canceled': _('The event has been canceled.'),
|
||||
'pretix.event.deleted': _('An event has been deleted.'),
|
||||
'pretix.event.shredder.started': _('A removal process for personal data has been started.'),
|
||||
'pretix.event.shredder.completed': _('A removal process for personal data has been completed.'),
|
||||
'pretix.event.export.schedule.added': _('A scheduled export has been added.'),
|
||||
'pretix.event.export.schedule.changed': _('A scheduled export has been changed.'),
|
||||
'pretix.event.export.schedule.deleted': _('A scheduled export has been deleted.'),
|
||||
'pretix.event.export.schedule.executed': _('A scheduled export has been executed.'),
|
||||
'pretix.event.export.schedule.failed': _('A scheduled export has failed: {reason}.'),
|
||||
'pretix.control.auth.user.created': _('The user has been created.'),
|
||||
'pretix.control.auth.user.new_source': _('A first login using {agent_type} on {os_type} from {country} has '
|
||||
'been detected.'),
|
||||
'pretix.user.settings.2fa.enabled': _('Two-factor authentication has been enabled.'),
|
||||
'pretix.user.settings.2fa.disabled': _('Two-factor authentication has been disabled.'),
|
||||
'pretix.user.settings.2fa.regenemergency': _('Your two-factor emergency codes have been regenerated.'),
|
||||
'pretix.user.settings.2fa.emergency': _('A two-factor emergency code has been generated.'),
|
||||
'pretix.user.settings.2fa.device.added': _('A new two-factor authentication device "{name}" has been added to '
|
||||
'your account.'),
|
||||
'pretix.user.settings.2fa.device.deleted': _('The two-factor authentication device "{name}" has been removed '
|
||||
'from your account.'),
|
||||
'pretix.user.settings.notifications.enabled': _('Notifications have been enabled.'),
|
||||
'pretix.user.settings.notifications.disabled': _('Notifications have been disabled.'),
|
||||
'pretix.user.settings.notifications.changed': _('Your notification settings have been changed.'),
|
||||
'pretix.user.anonymized': _('This user has been anonymized.'),
|
||||
'pretix.user.oauth.authorized': _('The application "{application_name}" has been authorized to access your '
|
||||
'account.'),
|
||||
'pretix.control.auth.user.forgot_password.mail_sent': _('Password reset mail sent.'),
|
||||
'pretix.control.auth.user.forgot_password.recovered': _('The password has been reset.'),
|
||||
'pretix.control.auth.user.forgot_password.denied.repeated': _('A repeated password reset has been denied, as '
|
||||
'the last request was less than 24 hours ago.'),
|
||||
'pretix.organizer.deleted': _('The organizer "{name}" has been deleted.'),
|
||||
'pretix.waitinglist.voucher': _('A voucher has been sent to a person on the waiting list.'), # legacy
|
||||
'pretix.event.orders.waitinglist.voucher_assigned': _('A voucher has been sent to a person on the waiting list.'),
|
||||
'pretix.event.orders.waitinglist.deleted': _('An entry has been removed from the waiting list.'),
|
||||
'pretix.event.order.waitinglist.transferred': _('An entry has been transferred to another waiting list.'), # legacy
|
||||
'pretix.event.orders.waitinglist.changed': _('An entry has been changed on the waiting list.'),
|
||||
'pretix.event.orders.waitinglist.added': _('An entry has been added to the waiting list.'),
|
||||
'pretix.team.created': _('The team has been created.'),
|
||||
'pretix.team.changed': _('The team settings have been changed.'),
|
||||
'pretix.team.deleted': _('The team has been deleted.'),
|
||||
'pretix.gate.created': _('The gate has been created.'),
|
||||
'pretix.gate.changed': _('The gate has been changed.'),
|
||||
'pretix.gate.deleted': _('The gate has been deleted.'),
|
||||
'pretix.subevent.deleted': pgettext_lazy('subevent', 'The event date has been deleted.'),
|
||||
'pretix.subevent.canceled': pgettext_lazy('subevent', 'The event date has been canceled.'),
|
||||
'pretix.subevent.changed': pgettext_lazy('subevent', 'The event date has been changed.'),
|
||||
'pretix.subevent.added': pgettext_lazy('subevent', 'The event date has been created.'),
|
||||
'pretix.subevent.quota.added': pgettext_lazy('subevent', 'A quota has been added to the event date.'),
|
||||
'pretix.subevent.quota.changed': pgettext_lazy('subevent', 'A quota has been changed on the event date.'),
|
||||
'pretix.subevent.quota.deleted': pgettext_lazy('subevent', 'A quota has been removed from the event date.'),
|
||||
'pretix.device.created': _('The device has been created.'),
|
||||
'pretix.device.changed': _('The device has been changed.'),
|
||||
'pretix.device.revoked': _('Access of the device has been revoked.'),
|
||||
'pretix.device.initialized': _('The device has been initialized.'),
|
||||
'pretix.device.keyroll': _('The access token of the device has been regenerated.'),
|
||||
'pretix.device.updated': _('The device has notified the server of an hardware or software update.'),
|
||||
'pretix.giftcards.created': _('The gift card has been created.'),
|
||||
'pretix.giftcards.modified': _('The gift card has been changed.'),
|
||||
'pretix.giftcards.transaction.manual': _('A manual transaction has been performed.'),
|
||||
'pretix.team.token.created': _('The token "{name}" has been created.'),
|
||||
'pretix.team.token.deleted': _('The token "{name}" has been revoked.'),
|
||||
})
|
||||
class CoreLogEntryType(LogEntryType):
|
||||
pass
|
||||
|
||||
|
||||
@log_entry_types.new_from_dict({
|
||||
'pretix.event.item_meta_property.added': _('A meta property has been added to this event.'),
|
||||
'pretix.event.item_meta_property.deleted': _('A meta property has been removed from this event.'),
|
||||
'pretix.event.item_meta_property.changed': _('A meta property has been changed on this event.'),
|
||||
'pretix.event.checkinlist.added': _('The check-in list has been added.'),
|
||||
'pretix.event.checkinlist.deleted': _('The check-in list has been deleted.'),
|
||||
'pretix.event.checkinlists.deleted': _('The check-in list has been deleted.'), # backwards compatibility
|
||||
'pretix.event.checkinlist.changed': _('The check-in list has been changed.'),
|
||||
'pretix.event.settings': _('The event settings have been changed.'),
|
||||
'pretix.event.tickets.settings': _('The ticket download settings have been changed.'),
|
||||
'pretix.event.live.activated': _('The shop has been taken live.'),
|
||||
'pretix.event.live.deactivated': _('The shop has been taken offline.'),
|
||||
'pretix.event.testmode.activated': _('The shop has been taken into test mode.'),
|
||||
'pretix.event.testmode.deactivated': _('The test mode has been disabled.'),
|
||||
'pretix.event.added': _('The event has been created.'),
|
||||
'pretix.event.changed': _('The event details have been changed.'),
|
||||
'pretix.event.footerlinks.changed': _('The footer links have been changed.'),
|
||||
'pretix.event.question.option.added': _('An answer option has been added to the question.'),
|
||||
'pretix.event.question.option.deleted': _('An answer option has been removed from the question.'),
|
||||
'pretix.event.question.option.changed': _('An answer option has been changed.'),
|
||||
'pretix.event.permissions.added': _('A user has been added to the event team.'),
|
||||
'pretix.event.permissions.invited': _('A user has been invited to the event team.'),
|
||||
'pretix.event.permissions.changed': _('A user\'s permissions have been changed.'),
|
||||
'pretix.event.permissions.deleted': _('A user has been removed from the event team.'),
|
||||
})
|
||||
class CoreEventLogEntryType(EventLogEntryType):
|
||||
pass
|
||||
|
||||
|
||||
@log_entry_types.new_from_dict({
|
||||
'pretix.event.plugins.enabled': _('The plugin has been enabled.'),
|
||||
'pretix.event.plugins.disabled': _('The plugin has been disabled.'),
|
||||
})
|
||||
class EventPluginStateLogEntryType(EventLogEntryType):
|
||||
object_link_wrapper = _('Plugin {val}')
|
||||
|
||||
def get_object_link_info(self, logentry) -> dict:
|
||||
if 'plugin' in logentry.parsed_data:
|
||||
app = app_cache.get(logentry.parsed_data['plugin'])
|
||||
if app and hasattr(app, 'PretixPluginMeta'):
|
||||
return {
|
||||
'href': reverse('control:event.settings.plugins', kwargs={
|
||||
'organizer': logentry.event.organizer.slug,
|
||||
'event': logentry.event.slug,
|
||||
}) + '#plugin_' + logentry.parsed_data['plugin'],
|
||||
'val': app.PretixPluginMeta.name
|
||||
}
|
||||
|
||||
|
||||
@log_entry_types.new_from_dict({
|
||||
'pretix.event.item.added': _('The product has been created.'),
|
||||
'pretix.event.item.changed': _('The product has been changed.'),
|
||||
'pretix.event.item.reordered': _('The product has been reordered.'),
|
||||
'pretix.event.item.deleted': _('The product has been deleted.'),
|
||||
'pretix.event.item.addons.added': _('An add-on has been added to this product.'),
|
||||
'pretix.event.item.addons.removed': _('An add-on has been removed from this product.'),
|
||||
'pretix.event.item.addons.changed': _('An add-on has been changed on this product.'),
|
||||
'pretix.event.item.bundles.added': _('A bundled item has been added to this product.'),
|
||||
'pretix.event.item.bundles.removed': _('A bundled item has been removed from this product.'),
|
||||
'pretix.event.item.bundles.changed': _('A bundled item has been changed on this product.'),
|
||||
})
|
||||
class CoreItemLogEntryType(ItemLogEntryType):
|
||||
pass
|
||||
|
||||
|
||||
@log_entry_types.new_from_dict({
|
||||
'pretix.event.item.variation.added': _('The variation "{value}" has been created.'),
|
||||
'pretix.event.item.variation.deleted': _('The variation "{value}" has been deleted.'),
|
||||
'pretix.event.item.variation.changed': _('The variation "{value}" has been changed.'),
|
||||
})
|
||||
class VariationLogEntryType(ItemLogEntryType):
|
||||
def display(self, logentry):
|
||||
if 'value' not in logentry.parsed_data:
|
||||
# Backwards compatibility
|
||||
var = ItemVariation.objects.filter(id=logentry.parsed_data['id']).first()
|
||||
if var:
|
||||
logentry.parsed_data['value'] = str(var.value)
|
||||
else:
|
||||
logentry.parsed_data['value'] = '?'
|
||||
else:
|
||||
logentry.parsed_data['value'] = LazyI18nString(logentry.parsed_data['value'])
|
||||
return super().display(logentry)
|
||||
|
||||
|
||||
@log_entry_types.new_from_dict({
|
||||
'pretix.event.order.payment.confirmed': _('Payment {local_id} has been confirmed.'),
|
||||
'pretix.event.order.payment.canceled': _('Payment {local_id} has been canceled.'),
|
||||
'pretix.event.order.payment.canceled.failed': _('Canceling payment {local_id} has failed.'),
|
||||
'pretix.event.order.payment.started': _('Payment {local_id} has been started.'),
|
||||
'pretix.event.order.payment.failed': _('Payment {local_id} has failed.'),
|
||||
'pretix.event.order.quotaexceeded': _('The order could not be marked as paid: {message}'),
|
||||
'pretix.event.order.overpaid': _('The order has been overpaid.'),
|
||||
'pretix.event.order.refund.created': _('Refund {local_id} has been created.'),
|
||||
'pretix.event.order.refund.created.externally': _('Refund {local_id} has been created by an external entity.'),
|
||||
'pretix.event.order.refund.requested': _('The customer requested you to issue a refund.'),
|
||||
'pretix.event.order.refund.done': _('Refund {local_id} has been completed.'),
|
||||
'pretix.event.order.refund.canceled': _('Refund {local_id} has been canceled.'),
|
||||
'pretix.event.order.refund.failed': _('Refund {local_id} has failed.'),
|
||||
})
|
||||
class CoreOrderPaymentLogEntryType(OrderLogEntryType):
|
||||
pass
|
||||
|
||||
|
||||
@log_entry_types.new_from_dict({
|
||||
'pretix.event.quota.added': _('The quota has been added.'),
|
||||
'pretix.event.quota.deleted': _('The quota has been deleted.'),
|
||||
'pretix.event.quota.changed': _('The quota has been changed.'),
|
||||
'pretix.event.quota.closed': _('The quota has closed.'),
|
||||
'pretix.event.quota.opened': _('The quota has been re-opened.'),
|
||||
})
|
||||
class CoreQuotaLogEntryType(QuotaLogEntryType):
|
||||
pass
|
||||
|
||||
|
||||
@log_entry_types.new_from_dict({
|
||||
'pretix.event.question.added': _('The question has been added.'),
|
||||
'pretix.event.question.deleted': _('The question has been deleted.'),
|
||||
'pretix.event.question.changed': _('The question has been changed.'),
|
||||
'pretix.event.question.reordered': _('The question has been reordered.'),
|
||||
})
|
||||
class CoreQuestionLogEntryType(QuestionLogEntryType):
|
||||
pass
|
||||
|
||||
|
||||
@log_entry_types.new_from_dict({
|
||||
'pretix.event.discount.added': _('The discount has been added.'),
|
||||
'pretix.event.discount.deleted': _('The discount has been deleted.'),
|
||||
'pretix.event.discount.changed': _('The discount has been changed.'),
|
||||
})
|
||||
class CoreDiscountLogEntryType(DiscountLogEntryType):
|
||||
pass
|
||||
|
||||
|
||||
@log_entry_types.new()
|
||||
class LegacyCheckinLogEntryType(OrderLogEntryType):
|
||||
action_type = 'pretix.control.views.checkin'
|
||||
|
||||
def display(self, logentry):
|
||||
# deprecated
|
||||
dt = dateutil.parser.parse(logentry.parsed_data.get('datetime'))
|
||||
tz = logentry.event.timezone
|
||||
dt_formatted = date_format(dt.astimezone(tz), "SHORT_DATETIME_FORMAT")
|
||||
if 'list' in logentry.parsed_data:
|
||||
try:
|
||||
checkin_list = logentry.event.checkin_lists.get(pk=logentry.parsed_data.get('list')).name
|
||||
except CheckinList.DoesNotExist:
|
||||
checkin_list = _("(unknown)")
|
||||
else:
|
||||
checkin_list = _("(unknown)")
|
||||
|
||||
if logentry.parsed_data.get('first'):
|
||||
return _('Position #{posid} has been checked in manually at {datetime} on list "{list}".').format(
|
||||
posid=logentry.parsed_data.get('positionid'),
|
||||
datetime=dt_formatted,
|
||||
list=checkin_list,
|
||||
)
|
||||
return _('Position #{posid} has been checked in again at {datetime} on list "{list}".').format(
|
||||
posid=logentry.parsed_data.get('positionid'),
|
||||
datetime=dt_formatted,
|
||||
list=checkin_list
|
||||
)
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
from django.dispatch import Signal
|
||||
|
||||
from pretix.base.signals import DeprecatedSignal, EventPluginSignal
|
||||
from pretix.base.signals import DeprecatedSignal, EventPluginSignal, OrganizerPluginSignal
|
||||
|
||||
html_page_start = Signal()
|
||||
"""
|
||||
@@ -221,7 +221,7 @@ Deprecated signal, no longer works. We just keep the definition so old plugins d
|
||||
break the installation.
|
||||
"""
|
||||
|
||||
nav_organizer = Signal()
|
||||
nav_organizer = OrganizerPluginSignal()
|
||||
"""
|
||||
Arguments: 'organizer', 'request'
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<legend>{{ catlabel }}</legend>
|
||||
<div class="plugin-list">
|
||||
{% for plugin in plist %}
|
||||
<div class="plugin-container {% if plugin.featured %}featured-plugin{% endif %}">
|
||||
<div class="plugin-container {% if plugin.featured %}featured-plugin{% endif %}" id="plugin_{{ plugin.module }}">
|
||||
{% if plugin.featured %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
|
||||
@@ -26,13 +26,12 @@ from collections import defaultdict
|
||||
from django.dispatch import receiver
|
||||
from django.template.loader import get_template
|
||||
from django.urls import resolve, reverse
|
||||
from django.utils.html import escape
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from pretix.base.logentrytypes import EventLogEntryType, log_entry_types
|
||||
from pretix.base.models import Event, Order
|
||||
from pretix.base.signals import (
|
||||
event_copy_data, item_copy_data, logentry_display, logentry_object_link,
|
||||
register_data_exporters,
|
||||
event_copy_data, item_copy_data, register_data_exporters,
|
||||
)
|
||||
from pretix.control.signals import (
|
||||
item_forms, nav_event, order_info, order_position_buttons,
|
||||
@@ -173,35 +172,13 @@ def control_order_info(sender: Event, request, order: Order, **kwargs):
|
||||
return template.render(ctx, request=request)
|
||||
|
||||
|
||||
@receiver(signal=logentry_display, dispatch_uid="badges_logentry_display")
|
||||
def badges_logentry_display(sender, logentry, **kwargs):
|
||||
if not logentry.action_type.startswith('pretix.plugins.badges'):
|
||||
return
|
||||
|
||||
plains = {
|
||||
'pretix.plugins.badges.layout.added': _('Badge layout created.'),
|
||||
'pretix.plugins.badges.layout.deleted': _('Badge layout deleted.'),
|
||||
'pretix.plugins.badges.layout.changed': _('Badge layout changed.'),
|
||||
}
|
||||
|
||||
if logentry.action_type in plains:
|
||||
return plains[logentry.action_type]
|
||||
|
||||
|
||||
@receiver(signal=logentry_object_link, dispatch_uid="badges_logentry_object_link")
|
||||
def badges_logentry_object_link(sender, logentry, **kwargs):
|
||||
if not logentry.action_type.startswith('pretix.plugins.badges.layout') or not isinstance(logentry.content_object,
|
||||
BadgeLayout):
|
||||
return
|
||||
|
||||
a_text = _('Badge layout {val}')
|
||||
a_map = {
|
||||
'href': reverse('plugins:badges:edit', kwargs={
|
||||
'event': sender.slug,
|
||||
'organizer': sender.organizer.slug,
|
||||
'layout': logentry.content_object.id
|
||||
}),
|
||||
'val': escape(logentry.content_object.name),
|
||||
}
|
||||
a_map['val'] = '<a href="{href}">{val}</a>'.format_map(a_map)
|
||||
return a_text.format_map(a_map)
|
||||
@log_entry_types.new_from_dict({
|
||||
'pretix.plugins.badges.layout.added': _('Badge layout created.'),
|
||||
'pretix.plugins.badges.layout.deleted': _('Badge layout deleted.'),
|
||||
'pretix.plugins.badges.layout.changed': _('Badge layout changed.'),
|
||||
})
|
||||
class BadgeLogEntryType(EventLogEntryType):
|
||||
object_type = BadgeLayout
|
||||
object_link_wrapper = _('Badge layout {val}')
|
||||
object_link_viewname = 'plugins:badges:edit'
|
||||
object_link_argname = 'layout'
|
||||
|
||||
@@ -25,9 +25,12 @@ from django.urls import resolve, reverse
|
||||
from django.utils.translation import gettext_lazy as _, gettext_noop
|
||||
from i18nfield.strings import LazyI18nString
|
||||
|
||||
from pretix.base.signals import logentry_display, register_payment_providers
|
||||
from pretix.base.signals import register_payment_providers
|
||||
from pretix.control.signals import html_head, nav_event, nav_organizer
|
||||
|
||||
from ...base.logentrytypes import (
|
||||
ClearDataShredderMixin, OrderLogEntryType, log_entry_types,
|
||||
)
|
||||
from ...base.settings import settings_hierarkey
|
||||
from .payment import BankTransfer
|
||||
|
||||
@@ -117,13 +120,10 @@ def html_head_presale(sender, request=None, **kwargs):
|
||||
return ""
|
||||
|
||||
|
||||
@receiver(signal=logentry_display)
|
||||
def pretixcontrol_logentry_display(sender, logentry, **kwargs):
|
||||
plains = {
|
||||
'pretix.plugins.banktransfer.order.email.invoice': _('The invoice was sent to the designated email address.'),
|
||||
}
|
||||
if logentry.action_type in plains:
|
||||
return plains[logentry.action_type]
|
||||
@log_entry_types.new()
|
||||
class BanktransferOrderEmailInvoiceLogEntryType(OrderLogEntryType, ClearDataShredderMixin):
|
||||
action_type = 'pretix.plugins.banktransfer.order.email.invoice'
|
||||
plain = _('The invoice was sent to the designated email address.')
|
||||
|
||||
|
||||
settings_hierarkey.add_default(
|
||||
|
||||
@@ -22,17 +22,10 @@
|
||||
|
||||
from django.dispatch import receiver
|
||||
|
||||
from pretix.base.signals import logentry_display, register_payment_providers
|
||||
from pretix.base.signals import register_payment_providers
|
||||
|
||||
|
||||
@receiver(register_payment_providers, dispatch_uid="payment_paypal")
|
||||
def register_payment_provider(sender, **kwargs):
|
||||
from .payment import Paypal
|
||||
return Paypal
|
||||
|
||||
|
||||
@receiver(signal=logentry_display, dispatch_uid="paypal_logentry_display")
|
||||
def pretixcontrol_logentry_display(sender, logentry, **kwargs):
|
||||
from pretix.plugins.paypal2.signals import pretixcontrol_logentry_display
|
||||
|
||||
return pretixcontrol_logentry_display(sender, logentry, **kwargs)
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
import json
|
||||
from collections import OrderedDict
|
||||
|
||||
from django import forms
|
||||
@@ -32,10 +31,11 @@ from django.utils.crypto import get_random_string
|
||||
from django.utils.translation import gettext_lazy as _, pgettext_lazy
|
||||
|
||||
from pretix.base.forms import SecretKeySettingsField
|
||||
from pretix.base.logentrytypes import EventLogEntryType, log_entry_types
|
||||
from pretix.base.middleware import _merge_csp, _parse_csp, _render_csp
|
||||
from pretix.base.settings import settings_hierarkey
|
||||
from pretix.base.signals import (
|
||||
logentry_display, register_global_settings, register_payment_providers,
|
||||
register_global_settings, register_payment_providers,
|
||||
)
|
||||
from pretix.plugins.paypal2.payment import PaypalMethod
|
||||
from pretix.presale.signals import html_head, process_response
|
||||
@@ -47,33 +47,32 @@ def register_payment_provider(sender, **kwargs):
|
||||
return [PaypalSettingsHolder, PaypalWallet, PaypalAPM]
|
||||
|
||||
|
||||
@receiver(signal=logentry_display, dispatch_uid="paypal2_logentry_display")
|
||||
def pretixcontrol_logentry_display(sender, logentry, **kwargs):
|
||||
if logentry.action_type != 'pretix.plugins.paypal.event':
|
||||
return
|
||||
@log_entry_types.new()
|
||||
class PaypalEventLogEntryType(EventLogEntryType):
|
||||
action_type = 'pretix.plugins.paypal.event'
|
||||
|
||||
data = json.loads(logentry.data)
|
||||
event_type = data.get('event_type')
|
||||
text = None
|
||||
plains = {
|
||||
'PAYMENT.SALE.COMPLETED': _('Payment completed.'),
|
||||
'PAYMENT.SALE.DENIED': _('Payment denied.'),
|
||||
'PAYMENT.SALE.REFUNDED': _('Payment refunded.'),
|
||||
'PAYMENT.SALE.REVERSED': _('Payment reversed.'),
|
||||
'PAYMENT.SALE.PENDING': _('Payment pending.'),
|
||||
'CHECKOUT.ORDER.APPROVED': pgettext_lazy('paypal', 'Order approved.'),
|
||||
'CHECKOUT.ORDER.COMPLETED': pgettext_lazy('paypal', 'Order completed.'),
|
||||
'PAYMENT.CAPTURE.COMPLETED': pgettext_lazy('paypal', 'Capture completed.'),
|
||||
'PAYMENT.CAPTURE.PENDING': pgettext_lazy('paypal', 'Capture pending.'),
|
||||
}
|
||||
def display(self, logentry):
|
||||
event_type = logentry.parsed_data.get('event_type')
|
||||
text = None
|
||||
plains = {
|
||||
'PAYMENT.SALE.COMPLETED': _('Payment completed.'),
|
||||
'PAYMENT.SALE.DENIED': _('Payment denied.'),
|
||||
'PAYMENT.SALE.REFUNDED': _('Payment refunded.'),
|
||||
'PAYMENT.SALE.REVERSED': _('Payment reversed.'),
|
||||
'PAYMENT.SALE.PENDING': _('Payment pending.'),
|
||||
'CHECKOUT.ORDER.APPROVED': pgettext_lazy('paypal', 'Order approved.'),
|
||||
'CHECKOUT.ORDER.COMPLETED': pgettext_lazy('paypal', 'Order completed.'),
|
||||
'PAYMENT.CAPTURE.COMPLETED': pgettext_lazy('paypal', 'Capture completed.'),
|
||||
'PAYMENT.CAPTURE.PENDING': pgettext_lazy('paypal', 'Capture pending.'),
|
||||
}
|
||||
|
||||
if event_type in plains:
|
||||
text = plains[event_type]
|
||||
else:
|
||||
text = event_type
|
||||
if event_type in plains:
|
||||
text = plains[event_type]
|
||||
else:
|
||||
text = event_type
|
||||
|
||||
if text:
|
||||
return _('PayPal reported an event: {}').format(text)
|
||||
if text:
|
||||
return _('PayPal reported an event: {}').format(text)
|
||||
|
||||
|
||||
@receiver(register_global_settings, dispatch_uid='paypal2_global_settings')
|
||||
|
||||
@@ -46,13 +46,16 @@ from django.utils.timezone import now
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django_scopes import scope, scopes_disabled
|
||||
|
||||
from pretix.base.logentrytypes import (
|
||||
EventLogEntryType, OrderLogEntryType, log_entry_types,
|
||||
)
|
||||
from pretix.base.models import SubEvent
|
||||
from pretix.base.signals import (
|
||||
EventPluginSignal, event_copy_data, logentry_display, periodic_task,
|
||||
EventPluginSignal, event_copy_data, periodic_task,
|
||||
)
|
||||
from pretix.control.signals import nav_event
|
||||
from pretix.helpers import OF_SELF
|
||||
from pretix.plugins.sendmail.models import ScheduledMail
|
||||
from pretix.plugins.sendmail.models import Rule, ScheduledMail
|
||||
from pretix.plugins.sendmail.views import OrderSendView, WaitinglistSendView
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -116,21 +119,28 @@ def control_nav_import(sender, request=None, **kwargs):
|
||||
]
|
||||
|
||||
|
||||
@receiver(signal=logentry_display)
|
||||
def pretixcontrol_logentry_display(sender, logentry, **kwargs):
|
||||
plains = {
|
||||
'pretix.plugins.sendmail.sent': _('Mass email was sent to customers or attendees.'),
|
||||
'pretix.plugins.sendmail.sent.waitinglist': _('Mass email was sent to waiting list entries.'),
|
||||
'pretix.plugins.sendmail.order.email.sent': _('The order received a mass email.'),
|
||||
'pretix.plugins.sendmail.order.email.sent.attendee': _('A ticket holder of this order received a mass email.'),
|
||||
'pretix.plugins.sendmail.rule.added': _('An email rule was created'),
|
||||
'pretix.plugins.sendmail.rule.changed': _('An email rule was updated'),
|
||||
'pretix.plugins.sendmail.rule.order.email.sent': _('A scheduled email was sent to the order'),
|
||||
'pretix.plugins.sendmail.rule.order.position.email.sent': _('A scheduled email was sent to a ticket holder'),
|
||||
'pretix.plugins.sendmail.rule.deleted': _('An email rule was deleted'),
|
||||
}
|
||||
if logentry.action_type in plains:
|
||||
return plains[logentry.action_type]
|
||||
@log_entry_types.new('pretix.plugins.sendmail.sent', _('Mass email was sent to customers or attendees.'))
|
||||
@log_entry_types.new('pretix.plugins.sendmail.sent.waitinglist', _('Mass email was sent to waiting list entries.'))
|
||||
class SendmailPluginLogEntryType(EventLogEntryType):
|
||||
pass
|
||||
|
||||
|
||||
@log_entry_types.new('pretix.plugins.sendmail.order.email.sent', _('The order received a mass email.'))
|
||||
@log_entry_types.new('pretix.plugins.sendmail.order.email.sent.attendee', _('A ticket holder of this order received a mass email.'))
|
||||
class SendmailPluginOrderLogEntryType(OrderLogEntryType):
|
||||
pass
|
||||
|
||||
|
||||
@log_entry_types.new('pretix.plugins.sendmail.rule.added', _('An email rule was created'))
|
||||
@log_entry_types.new('pretix.plugins.sendmail.rule.changed', _('An email rule was updated'))
|
||||
@log_entry_types.new('pretix.plugins.sendmail.rule.order.email.sent', _('A scheduled email was sent to the order'))
|
||||
@log_entry_types.new('pretix.plugins.sendmail.rule.order.position.email.sent', _('A scheduled email was sent to a ticket holder'))
|
||||
@log_entry_types.new('pretix.plugins.sendmail.rule.deleted', _('An email rule was deleted'))
|
||||
class SendmailPluginRuleLogEntryType(EventLogEntryType):
|
||||
object_type = Rule
|
||||
object_link_wrapper = _('Mail rule {val}')
|
||||
object_link_viewname = 'plugins:sendmail:rule.update'
|
||||
object_link_argname = 'rule'
|
||||
|
||||
|
||||
@receiver(periodic_task)
|
||||
|
||||
@@ -24,11 +24,11 @@ import json
|
||||
|
||||
from django.dispatch import receiver
|
||||
from django.template.loader import get_template
|
||||
from django.urls import reverse
|
||||
from django.utils.html import escape
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from pretix.base.logentrytypes import EventLogEntryType
|
||||
from pretix.base.models import Event, SalesChannel
|
||||
from pretix.base.models.log import log_entry_types
|
||||
from pretix.base.signals import ( # NOQA: legacy import
|
||||
EventPluginSignal, event_copy_data, item_copy_data, layout_text_variables,
|
||||
logentry_display, logentry_object_link, register_data_exporters,
|
||||
@@ -134,38 +134,16 @@ def pdf_event_copy_data_receiver(sender, other, item_map, question_map, **kwargs
|
||||
return layout_map
|
||||
|
||||
|
||||
@receiver(signal=logentry_display, dispatch_uid="pretix_ticketoutputpdf_logentry_display")
|
||||
def pdf_logentry_display(sender, logentry, **kwargs):
|
||||
if not logentry.action_type.startswith('pretix.plugins.ticketoutputpdf'):
|
||||
return
|
||||
|
||||
plains = {
|
||||
'pretix.plugins.ticketoutputpdf.layout.added': _('Ticket layout created.'),
|
||||
'pretix.plugins.ticketoutputpdf.layout.deleted': _('Ticket layout deleted.'),
|
||||
'pretix.plugins.ticketoutputpdf.layout.changed': _('Ticket layout changed.'),
|
||||
}
|
||||
|
||||
if logentry.action_type in plains:
|
||||
return plains[logentry.action_type]
|
||||
|
||||
|
||||
@receiver(signal=logentry_object_link, dispatch_uid="pretix_ticketoutputpdf_logentry_object_link")
|
||||
def pdf_logentry_object_link(sender, logentry, **kwargs):
|
||||
if not logentry.action_type.startswith('pretix.plugins.ticketoutputpdf.layout') or not isinstance(
|
||||
logentry.content_object, TicketLayout):
|
||||
return
|
||||
|
||||
a_text = _('Ticket layout {val}')
|
||||
a_map = {
|
||||
'href': reverse('plugins:ticketoutputpdf:edit', kwargs={
|
||||
'event': sender.slug,
|
||||
'organizer': sender.organizer.slug,
|
||||
'layout': logentry.content_object.id
|
||||
}),
|
||||
'val': escape(logentry.content_object.name),
|
||||
}
|
||||
a_map['val'] = '<a href="{href}">{val}</a>'.format_map(a_map)
|
||||
return a_text.format_map(a_map)
|
||||
@log_entry_types.new_from_dict({
|
||||
'pretix.plugins.ticketoutputpdf.layout.added': _('Ticket layout created.'),
|
||||
'pretix.plugins.ticketoutputpdf.layout.deleted': _('Ticket layout deleted.'),
|
||||
'pretix.plugins.ticketoutputpdf.layout.changed': _('Ticket layout changed.'),
|
||||
})
|
||||
class PdfTicketLayoutLogEntryType(EventLogEntryType):
|
||||
object_type = TicketLayout
|
||||
object_link_wrapper = _('Ticket layout {val}')
|
||||
object_link_viewname = 'plugins:ticketoutputpdf:edit'
|
||||
object_link_argname = 'layout'
|
||||
|
||||
|
||||
def _ticket_layouts_for_item(request, item):
|
||||
|
||||
@@ -427,14 +427,6 @@ REST_FRAMEWORK = {
|
||||
}
|
||||
|
||||
|
||||
CORE_MODULES = {
|
||||
"pretix.base",
|
||||
"pretix.presale",
|
||||
"pretix.control",
|
||||
"pretix.plugins.checkinlists",
|
||||
"pretix.plugins.reports",
|
||||
}
|
||||
|
||||
MIDDLEWARE = [
|
||||
'pretix.helpers.logs.RequestIdMiddleware',
|
||||
'pretix.api.middleware.IdempotencyMiddleware',
|
||||
|
||||
@@ -552,6 +552,16 @@ var form_handlers = function (el) {
|
||||
language: $("body").attr("data-select2-locale"),
|
||||
});
|
||||
|
||||
el.find('[data-model-select2=json_script]').each(function() {
|
||||
const selectedValue = this.value;
|
||||
this.replaceChildren();
|
||||
$(this).select2({
|
||||
theme: "bootstrap",
|
||||
language: $("body").attr("data-select2-locale"),
|
||||
data: JSON.parse($(this.getAttribute('data-select2-src')).text()),
|
||||
}).val(selectedValue).trigger('change');
|
||||
});
|
||||
|
||||
el.find('input[data-typeahead-url]').each(function () {
|
||||
var $inp = $(this);
|
||||
if ($inp.data("ttTypeahead") || $inp.hasClass("tt-hint")) {
|
||||
|
||||
Reference in New Issue
Block a user