Upgrade to Django 3.2 (#2056)

This commit is contained in:
Raphael Michel
2021-05-07 12:00:30 +02:00
committed by GitHub
parent 0a7a3537eb
commit 403b8191e4
120 changed files with 1994 additions and 1555 deletions

View File

@@ -19,15 +19,3 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from django.apps import AppConfig
class PretixApiConfig(AppConfig):
name = 'pretix.api'
label = 'pretixapi'
def ready(self):
from . import signals, webhooks # noqa
default_app_config = 'pretix.api.PretixApiConfig'

30
src/pretix/api/apps.py Normal file
View File

@@ -0,0 +1,30 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from django.apps import AppConfig
class PretixApiConfig(AppConfig):
name = 'pretix.api'
label = 'pretixapi'
def ready(self):
from . import signals, webhooks # noqa

View File

@@ -89,7 +89,7 @@ class IdempotencyMiddleware:
call.response_body = json.dumps(resp.data)
else:
call.response_body = repr(resp).encode()
call.response_headers = json.dumps(resp._headers)
call.response_headers = json.dumps(resp.headers._store)
call.locked = None
call.save(update_fields=['locked', 'response_code', 'response_headers',
'response_body'])

View File

@@ -19,6 +19,7 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
import os
from datetime import timedelta
from django.core.files import File
@@ -125,9 +126,10 @@ class CartPositionCreateSerializer(I18nAwareModelSerializer):
if isinstance(answ_data['answer'], File):
an = answ_data.pop('answer')
answ = cp.answers.create(**answ_data, answer='')
answ.file.save(an.name, an, save=False)
answ.file.save(os.path.basename(an.name), an, save=False)
answ.answer = 'file://' + answ.file.name
answ.save()
an.close()
else:
answ = cp.answers.create(**answ_data)
answ.options.add(*options)

View File

@@ -21,6 +21,7 @@
#
import json
import logging
import os
from collections import Counter, defaultdict
from decimal import Decimal
@@ -467,7 +468,7 @@ class OrderPositionSerializer(I18nAwareModelSerializer):
if isinstance(answ_data['answer'], File):
an = answ_data.pop('answer')
a = instance.answers.create(**answ_data, answer='')
a.file.save(an.name, an, save=False)
a.file.save(os.path.basename(an.name), an, save=False)
a.answer = 'file://' + a.file.name
a.save()
else:
@@ -1274,7 +1275,7 @@ class OrderCreateSerializer(I18nAwareModelSerializer):
if isinstance(answ_data['answer'], File):
an = answ_data.pop('answer')
answ = pos.answers.create(**answ_data, answer='')
answ.file.save(an.name, an, save=False)
answ.file.save(os.path.basename(an.name), an, save=False)
answ.answer = 'file://' + answ.file.name
answ.save()
else:

View File

@@ -29,9 +29,7 @@ from pretix.api.models import ApiCall, WebHookCall
from pretix.base.signals import periodic_task
from pretix.helpers.periodic import minimum_interval
register_webhook_events = Signal(
providing_args=[]
)
register_webhook_events = Signal()
"""
This signal is sent out to get all known webhook events. Receivers should return an
instance of a subclass of pretix.api.webhooks.WebhookEvent or a list of such

View File

@@ -35,7 +35,7 @@
import importlib
from django.apps import apps
from django.conf.urls import include, url
from django.conf.urls import include, re_path
from rest_framework import routers
from pretix.api.views import cart
@@ -109,30 +109,30 @@ for app in apps.get_app_configs():
importlib.import_module(app.name + '.urls')
urlpatterns = [
url(r'^', include(router.urls)),
url(r'^organizers/(?P<organizer>[^/]+)/', include(orga_router.urls)),
url(r'^organizers/(?P<organizer>[^/]+)/settings/$', organizer.OrganizerSettingsView.as_view(),
name="organizer.settings"),
url(r'^organizers/(?P<organizer>[^/]+)/giftcards/(?P<giftcard>[^/]+)/', include(giftcard_router.urls)),
url(r'^organizers/(?P<organizer>[^/]+)/events/(?P<event>[^/]+)/settings/$', event.EventSettingsView.as_view(),
name="event.settings"),
url(r'^organizers/(?P<organizer>[^/]+)/events/(?P<event>[^/]+)/', include(event_router.urls)),
url(r'^organizers/(?P<organizer>[^/]+)/teams/(?P<team>[^/]+)/', include(team_router.urls)),
url(r'^organizers/(?P<organizer>[^/]+)/events/(?P<event>[^/]+)/items/(?P<item>[^/]+)/', include(item_router.urls)),
url(r'^organizers/(?P<organizer>[^/]+)/events/(?P<event>[^/]+)/questions/(?P<question>[^/]+)/',
include(question_router.urls)),
url(r'^organizers/(?P<organizer>[^/]+)/events/(?P<event>[^/]+)/checkinlists/(?P<list>[^/]+)/',
include(checkinlist_router.urls)),
url(r'^organizers/(?P<organizer>[^/]+)/events/(?P<event>[^/]+)/orders/(?P<order>[^/]+)/', include(order_router.urls)),
url(r"^oauth/authorize$", oauth.AuthorizationView.as_view(), name="authorize"),
url(r"^oauth/token$", oauth.TokenView.as_view(), name="token"),
url(r"^oauth/revoke_token$", oauth.RevokeTokenView.as_view(), name="revoke-token"),
url(r"^device/initialize$", device.InitializeView.as_view(), name="device.initialize"),
url(r"^device/update$", device.UpdateView.as_view(), name="device.update"),
url(r"^device/roll$", device.RollKeyView.as_view(), name="device.roll"),
url(r"^device/revoke$", device.RevokeKeyView.as_view(), name="device.revoke"),
url(r"^device/eventselection$", device.EventSelectionView.as_view(), name="device.eventselection"),
url(r"^upload$", upload.UploadView.as_view(), name="upload"),
url(r"^me$", user.MeView.as_view(), name="user.me"),
url(r"^version$", version.VersionView.as_view(), name="version"),
re_path(r'^', include(router.urls)),
re_path(r'^organizers/(?P<organizer>[^/]+)/', include(orga_router.urls)),
re_path(r'^organizers/(?P<organizer>[^/]+)/settings/$', organizer.OrganizerSettingsView.as_view(),
name="organizer.settings"),
re_path(r'^organizers/(?P<organizer>[^/]+)/giftcards/(?P<giftcard>[^/]+)/', include(giftcard_router.urls)),
re_path(r'^organizers/(?P<organizer>[^/]+)/events/(?P<event>[^/]+)/settings/$', event.EventSettingsView.as_view(),
name="event.settings"),
re_path(r'^organizers/(?P<organizer>[^/]+)/events/(?P<event>[^/]+)/', include(event_router.urls)),
re_path(r'^organizers/(?P<organizer>[^/]+)/teams/(?P<team>[^/]+)/', include(team_router.urls)),
re_path(r'^organizers/(?P<organizer>[^/]+)/events/(?P<event>[^/]+)/items/(?P<item>[^/]+)/', include(item_router.urls)),
re_path(r'^organizers/(?P<organizer>[^/]+)/events/(?P<event>[^/]+)/questions/(?P<question>[^/]+)/',
include(question_router.urls)),
re_path(r'^organizers/(?P<organizer>[^/]+)/events/(?P<event>[^/]+)/checkinlists/(?P<list>[^/]+)/',
include(checkinlist_router.urls)),
re_path(r'^organizers/(?P<organizer>[^/]+)/events/(?P<event>[^/]+)/orders/(?P<order>[^/]+)/', include(order_router.urls)),
re_path(r"^oauth/authorize$", oauth.AuthorizationView.as_view(), name="authorize"),
re_path(r"^oauth/token$", oauth.TokenView.as_view(), name="token"),
re_path(r"^oauth/revoke_token$", oauth.RevokeTokenView.as_view(), name="revoke-token"),
re_path(r"^device/initialize$", device.InitializeView.as_view(), name="device.initialize"),
re_path(r"^device/update$", device.UpdateView.as_view(), name="device.update"),
re_path(r"^device/roll$", device.RollKeyView.as_view(), name="device.roll"),
re_path(r"^device/revoke$", device.RevokeKeyView.as_view(), name="device.revoke"),
re_path(r"^device/eventselection$", device.EventSelectionView.as_view(), name="device.eventselection"),
re_path(r"^upload$", upload.UploadView.as_view(), name="upload"),
re_path(r"^me$", user.MeView.as_view(), name="user.me"),
re_path(r"^version$", version.VersionView.as_view(), name="version"),
]

View File

@@ -22,7 +22,7 @@
import django_filters
from django.core.exceptions import ValidationError
from django.db.models import (
Count, Exists, F, Max, OuterRef, Prefetch, Q, Subquery,
Count, Exists, F, Max, OrderBy, OuterRef, Prefetch, Q, Subquery,
)
from django.db.models.functions import Coalesce
from django.http import Http404
@@ -48,7 +48,6 @@ from pretix.base.models import (
from pretix.base.services.checkin import (
CheckInError, RequiredQuestionsError, SQLLogic, perform_checkin,
)
from pretix.helpers.database import FixedOrderBy
with scopes_disabled():
class CheckinListFilter(FilterSet):
@@ -239,10 +238,10 @@ class CheckinListPositionViewSet(viewsets.ReadOnlyModelViewSet):
'display_name': Coalesce('attendee_name_cached', 'addon_to__attendee_name_cached')
},
'last_checked_in': {
'_order': FixedOrderBy(F('last_checked_in'), nulls_first=True),
'_order': OrderBy(F('last_checked_in'), nulls_first=True),
},
'-last_checked_in': {
'_order': FixedOrderBy(F('last_checked_in'), nulls_last=True, descending=True),
'_order': OrderBy(F('last_checked_in'), nulls_last=True, descending=True),
},
}

View File

@@ -19,48 +19,3 @@
# 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/>.
#
# This file is based on an earlier version of pretix which was released under the Apache License 2.0. The full text of
# the Apache License 2.0 can be obtained at <http://www.apache.org/licenses/LICENSE-2.0>.
#
# This file may have since been changed and any changes are released under the terms of AGPLv3 as described above. A
# full history of changes and contributors is available at <https://github.com/pretix/pretix>.
#
# This file contains Apache-licensed contributions copyrighted by: Tobias Kunze
#
# Unless required by applicable law or agreed to in writing, software distributed under the Apache License 2.0 is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under the License.
from django.apps import AppConfig
class PretixBaseConfig(AppConfig):
name = 'pretix.base'
label = 'pretixbase'
def ready(self):
from . import exporter # NOQA
from . import payment # NOQA
from . import exporters # NOQA
from . import invoice # NOQA
from . import notifications # NOQA
from . import email # NOQA
from .services import auth, checkin, export, mail, tickets, cart, orderimport, orders, invoices, cleanup, update_check, quotas, notifications, vouchers # NOQA
from django.conf import settings
try:
from .celery_app import app as celery_app # NOQA
except ImportError:
pass
if hasattr(settings, 'RAVEN_CONFIG'):
from ..sentry import initialize
initialize()
default_app_config = 'pretix.base.PretixBaseConfig'
try:
import pretix.celery_app as celery # NOQA
except ImportError:
pass

65
src/pretix/base/apps.py Normal file
View File

@@ -0,0 +1,65 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
# This file is based on an earlier version of pretix which was released under the Apache License 2.0. The full text of
# the Apache License 2.0 can be obtained at <http://www.apache.org/licenses/LICENSE-2.0>.
#
# This file may have since been changed and any changes are released under the terms of AGPLv3 as described above. A
# full history of changes and contributors is available at <https://github.com/pretix/pretix>.
#
# This file contains Apache-licensed contributions copyrighted by: Tobias Kunze
#
# Unless required by applicable law or agreed to in writing, software distributed under the Apache License 2.0 is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under the License.
from django.apps import AppConfig
class PretixBaseConfig(AppConfig):
name = 'pretix.base'
label = 'pretixbase'
def ready(self):
from . import exporter # NOQA
from . import payment # NOQA
from . import exporters # NOQA
from . import invoice # NOQA
from . import notifications # NOQA
from . import email # NOQA
from .services import auth, checkin, export, mail, tickets, cart, orderimport, orders, invoices, cleanup, update_check, quotas, notifications, vouchers # NOQA
from django.conf import settings
try:
from .celery_app import app as celery_app # NOQA
except ImportError:
pass
if hasattr(settings, 'RAVEN_CONFIG'):
from ..sentry import initialize
initialize()
try:
import pretix.celery_app as celery # NOQA
except ImportError:
pass

View File

@@ -107,10 +107,11 @@ ALLOWED_LANGUAGES = dict(settings.LANGUAGES)
def get_babel_locale():
babel_locale = 'en'
# Babel, and therefore django-phonenumberfield, do not support our custom locales such das de_Informal
if localedata.exists(translation.get_language()):
babel_locale = translation.get_language()
elif localedata.exists(translation.get_language()[:2]):
babel_locale = translation.get_language()[:2]
if translation.get_language():
if localedata.exists(translation.get_language()):
babel_locale = translation.get_language()
elif localedata.exists(translation.get_language()[:2]):
babel_locale = translation.get_language()[:2]
return babel_locale

View File

@@ -75,7 +75,7 @@ class Migration(migrations.Migration):
('date', models.DateTimeField(blank=True, null=True)),
('filename', models.CharField(max_length=255)),
('type', models.CharField(max_length=255)),
('file', models.FileField(blank=True, null=True, upload_to=pretix.base.models.base.cachedfile_name)),
('file', models.FileField(blank=True, null=True, upload_to=pretix.base.models.base._cachedfile_name)),
],
),
migrations.CreateModel(

View File

@@ -32,7 +32,7 @@ class Migration(migrations.Migration):
('date', models.DateTimeField(blank=True, null=True)),
('filename', models.CharField(max_length=255)),
('type', models.CharField(max_length=255)),
('file', models.FileField(blank=True, null=True, upload_to=pretix.base.models.base.cachedfile_name)),
('file', models.FileField(blank=True, null=True, upload_to=pretix.base.models.base._cachedfile_name)),
],
),
migrations.CreateModel(

View File

@@ -1,8 +1,8 @@
# Generated by Django 2.1 on 2018-10-17 00:24
import jsonfallback.fields
from django.core.exceptions import ImproperlyConfigured
from django.db import migrations
from django.db import migrations, models
from django_mysql.checks import mysql_connections
from django_mysql.utils import connection_is_mariadb
@@ -77,19 +77,19 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='cartposition',
name='attendee_name_parts',
field=jsonfallback.fields.FallbackJSONField(null=False, default=dict),
field=models.JSONField(null=False, default=dict),
preserve_default=False,
),
migrations.AddField(
model_name='orderposition',
name='attendee_name_parts',
field=jsonfallback.fields.FallbackJSONField(null=False, default=dict),
field=models.JSONField(null=False, default=dict),
preserve_default=False,
),
migrations.AddField(
model_name='invoiceaddress',
name='name_parts',
field=jsonfallback.fields.FallbackJSONField(default=dict),
field=models.JSONField(default=dict),
preserve_default=False,
),
migrations.RunPython(set_attendee_name_parts, migrations.RunPython.noop)

View File

@@ -1,7 +1,6 @@
# Generated by Django 2.1.1 on 2018-11-21 12:24
import django.db.models.deletion
import jsonfallback.fields
from django.db import migrations, models
import pretix.base.models.fields

View File

@@ -2,7 +2,6 @@
import django.db.models.deletion
import django.db.models.manager
import jsonfallback.fields
from django.db import migrations, models

View File

@@ -1,7 +1,6 @@
# Generated by Django 2.1 on 2019-01-12 15:12
import django.db.models.deletion
import jsonfallback.fields
from django.db import migrations, models
import pretix.base.models.fields

View File

@@ -1,7 +1,6 @@
# Generated by Django 2.1.5 on 2019-01-29 13:37
import django.db.models.deletion
import jsonfallback.fields
from django.db import migrations, models
import pretix.base.models.fields

View File

@@ -1,7 +1,6 @@
# Generated by Django 2.1.5 on 2019-02-01 15:27
import django.db.models.deletion
import jsonfallback.fields
from django.db import migrations, models
import pretix.base.models.fields
@@ -17,6 +16,6 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='item',
name='generate_tickets',
field=models.NullBooleanField(verbose_name='Allow ticket download'),
field=models.BooleanField(verbose_name='Allow ticket download', null=True, blank=True),
),
]

View File

@@ -3,7 +3,6 @@
from decimal import Decimal
import django.db.models.deletion
import jsonfallback.fields
from django.conf import settings
from django.core.cache import cache
from django.db import migrations, models
@@ -71,7 +70,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='item',
name='generate_tickets',
field=models.NullBooleanField(verbose_name='Allow ticket download'),
field=models.BooleanField(verbose_name='Allow ticket download', null=True, blank=True),
),
migrations.AddField(
model_name='invoiceline',
@@ -190,7 +189,7 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='cartposition',
name='attendee_name_parts',
field=jsonfallback.fields.FallbackJSONField(default=dict),
field=models.JSONField(default=dict),
),
migrations.AlterField(
model_name='cartposition',
@@ -210,7 +209,7 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='invoiceaddress',
name='name_parts',
field=jsonfallback.fields.FallbackJSONField(default=dict),
field=models.JSONField(default=dict),
),
migrations.AlterField(
model_name='item',
@@ -225,7 +224,7 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='orderposition',
name='attendee_name_parts',
field=jsonfallback.fields.FallbackJSONField(default=dict),
field=models.JSONField(default=dict),
),
migrations.AlterField(
model_name='orderposition',
@@ -338,7 +337,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='item',
name='show_quota_left',
field=models.NullBooleanField(),
field=models.BooleanField(null=True, blank=True),
),
migrations.RenameField(
model_name='question',

View File

@@ -1,7 +1,6 @@
# Generated by Django 2.1 on 2019-02-08 14:32
import django.db.models.deletion
import jsonfallback.fields
from django.db import migrations, models
import pretix.base.models.fields

View File

@@ -1,7 +1,6 @@
# Generated by Django 2.1.5 on 2019-02-19 12:45
import django.db.models.deletion
import jsonfallback.fields
from django.db import migrations, models
import pretix.base.models.fields

View File

@@ -1,7 +1,6 @@
# Generated by Django 2.1.5 on 2019-02-19 09:49
import django.db.models.deletion
import jsonfallback.fields
from django.db import migrations, models
import pretix.base.models.fields

View File

@@ -1,7 +1,6 @@
# Generated by Django 2.1.5 on 2019-03-12 09:42
import django.db.models.deletion
import jsonfallback.fields
from django.db import migrations, models
import pretix.base.models.fields

View File

@@ -1,7 +1,6 @@
# Generated by Django 2.1.7 on 2019-03-16 10:14
import django.db.models.deletion
import jsonfallback.fields
from django.db import migrations, models
import pretix.base.models.fields

View File

@@ -3,7 +3,6 @@
from decimal import Decimal
import django.db.models.deletion
import jsonfallback.fields
from django.db import migrations, models
import pretix.base.models.fields

View File

@@ -1,7 +1,6 @@
# Generated by Django 2.1.5 on 2019-04-02 07:22
import django.db.models.deletion
import jsonfallback.fields
from django.db import migrations, models
import pretix.base.models.fields

View File

@@ -1,7 +1,6 @@
# Generated by Django 2.2 on 2019-04-23 08:39
import django.db.models.deletion
import jsonfallback.fields
from django.db import migrations, models
import pretix.base.models.fields

View File

@@ -1,7 +1,6 @@
# Generated by Django 2.2 on 2019-05-09 06:54
import django.db.models.deletion
import jsonfallback.fields
from django.db import migrations, models
import pretix.base.models.fields

View File

@@ -1,7 +1,6 @@
# Generated by Django 2.2 on 2019-05-09 07:36
import django.db.models.deletion
import jsonfallback.fields
from django.db import migrations, models
import pretix.base.models.fields
@@ -17,7 +16,7 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='cartposition',
name='attendee_name_parts',
field=jsonfallback.fields.FallbackJSONField(default=dict),
field=models.JSONField(default=dict),
),
migrations.AlterField(
model_name='cartposition',
@@ -37,7 +36,7 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='invoiceaddress',
name='name_parts',
field=jsonfallback.fields.FallbackJSONField(default=dict),
field=models.JSONField(default=dict),
),
migrations.AlterField(
model_name='item',
@@ -52,7 +51,7 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='orderposition',
name='attendee_name_parts',
field=jsonfallback.fields.FallbackJSONField(default=dict),
field=models.JSONField(default=dict),
),
migrations.AlterField(
model_name='orderposition',

View File

@@ -13,6 +13,6 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='item',
name='show_quota_left',
field=models.NullBooleanField(),
field=models.BooleanField(null=True, blank=True),
),
]

View File

@@ -2,7 +2,6 @@
import django.db.models.deletion
import django_countries.fields
import jsonfallback.fields
from django.db import migrations, models
import pretix.helpers.countries
@@ -43,7 +42,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='checkinlist',
name='rules',
field=jsonfallback.fields.FallbackJSONField(default=dict),
field=models.JSONField(default=dict),
),
migrations.AlterUniqueTogether(
name='checkin',

View File

@@ -16,7 +16,7 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='cachedfile',
name='file',
field=models.FileField(max_length=255, null=True, upload_to=pretix.base.models.base.cachedfile_name),
field=models.FileField(max_length=255, null=True, upload_to=pretix.base.models.base._cachedfile_name),
),
migrations.AlterField(
model_name='cartposition',

View File

@@ -1,6 +1,6 @@
# Generated by Django 3.0.10 on 2021-03-01 15:10
import jsonfallback.fields
import phonenumber_field.modelfields
from django.db import migrations, models
@@ -20,7 +20,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='waitinglistentry',
name='name_parts',
field=jsonfallback.fields.FallbackJSONField(default=dict),
field=models.JSONField(default=dict),
),
migrations.AddField(
model_name='waitinglistentry',

View File

@@ -1,7 +1,6 @@
# Generated by Django 3.0.13 on 2021-04-06 07:25
import django.db.models.deletion
import jsonfallback.fields
from django.db import migrations, models
import pretix.base.models.base
@@ -28,7 +27,7 @@ class Migration(migrations.Migration):
('email', models.EmailField(db_index=True, max_length=190, null=True)),
('password', models.CharField(max_length=128)),
('name_cached', models.CharField(max_length=255)),
('name_parts', jsonfallback.fields.FallbackJSONField(default=dict)),
('name_parts', models.JSONField(default=dict)),
('is_active', models.BooleanField(default=True)),
('is_verified', models.BooleanField(default=True)),
('last_login', models.DateTimeField(blank=True, null=True)),

View File

@@ -2,7 +2,6 @@
import django.db.models.deletion
import i18nfield.fields
import jsonfallback.fields
from django.db import migrations, models
import pretix.base.models.base
@@ -61,7 +60,7 @@ class Migration(migrations.Migration):
('id', models.BigAutoField(primary_key=True, serialize=False)),
('date_start', models.DateTimeField()),
('date_end', models.DateTimeField()),
('attendee_name_parts', jsonfallback.fields.FallbackJSONField(default=dict, null=True)),
('attendee_name_parts', models.JSONField(default=dict, null=True)),
('customer', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='memberships', to='pretixbase.Customer')),
('granted_in', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='granted_memberships', to='pretixbase.OrderPosition', null=True)),
('membership_type', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='memberships', to='pretixbase.MembershipType')),

View File

@@ -36,7 +36,13 @@ from pretix.helpers.json import CustomJSONEncoder
def cachedfile_name(instance, filename: str) -> str:
secret = get_random_string(length=12)
return 'cachedfiles/%s.%s.%s' % (instance.id, secret, filename.split('.')[-1])
return '%s.%s.%s' % (instance.id, secret, filename.split('.')[-1])
def _cachedfile_name(instance, filename: str) -> str:
# This was previously combined with cachedfile_name in one function, but a security patch for Django introduced
# additional file name validation in May 2021, and this was the best way to fix it without breaking plugins.
return 'cachedfiles/' + cachedfile_name(instance, filename)
class CachedFile(models.Model):
@@ -48,7 +54,7 @@ class CachedFile(models.Model):
date = models.DateTimeField(null=True, blank=True)
filename = models.CharField(max_length=255)
type = models.CharField(max_length=255)
file = models.FileField(null=True, blank=True, upload_to=cachedfile_name, max_length=255)
file = models.FileField(null=True, blank=True, upload_to=_cachedfile_name, max_length=255)
web_download = models.BooleanField(default=True) # allow web download, True for backwards compatibility in plugins
session_key = models.TextField(null=True, blank=True) # only allow download in this session

View File

@@ -39,7 +39,6 @@ from django.db.models import Exists, F, Max, OuterRef, Q, Subquery
from django.utils.timezone import now
from django.utils.translation import gettext_lazy as _, pgettext_lazy
from django_scopes import ScopedManager, scopes_disabled
from jsonfallback.fields import FallbackJSONField
from pretix.base.models import LoggedModel
from pretix.base.models.fields import MultiStringField
@@ -82,7 +81,7 @@ class CheckinList(LoggedModel):
'any of the selected sales channels. This option can be useful when tickets sold at the box office '
'are not checked again before entry and should be considered validated directly upon purchase.')
)
rules = FallbackJSONField(default=dict, blank=True)
rules = models.JSONField(default=dict, blank=True)
objects = ScopedManager(organizer='event__organizer')

View File

@@ -27,7 +27,6 @@ from django.db import models
from django.utils.crypto import get_random_string, salted_hmac
from django.utils.translation import gettext_lazy as _
from django_scopes import ScopedManager, scopes_disabled
from jsonfallback.fields import FallbackJSONField
from pretix.base.banlist import banned
from pretix.base.models.base import LoggedModel
@@ -45,7 +44,7 @@ class Customer(LoggedModel):
email = models.EmailField(db_index=True, null=True, blank=False, verbose_name=_('E-mail'), max_length=190)
password = models.CharField(verbose_name=_('Password'), max_length=128)
name_cached = models.CharField(max_length=255, verbose_name=_('Full name'), blank=True)
name_parts = FallbackJSONField(default=dict)
name_parts = models.JSONField(default=dict)
is_active = models.BooleanField(default=True, verbose_name=_('Account active'))
is_verified = models.BooleanField(default=True, verbose_name=_('Verified email address'))
last_login = models.DateTimeField(verbose_name=_('Last login'), blank=True, null=True)
@@ -60,6 +59,10 @@ class Customer(LoggedModel):
class Meta:
unique_together = [['organizer', 'email']]
ordering = ('email',)
def get_email_field_name(self):
return 'email'
def save(self, **kwargs):
if self.email:

View File

@@ -1270,7 +1270,8 @@ class SubEvent(EventMixin, LoggedModel):
).order_by().values('subevent').annotate(items=GroupConcat('item_id', delimiter=',')).values('items'),
output_field=models.TextField(),
),
Value('')
Value(''),
output_field=models.TextField()
),
disabled_vars=Coalesce(
Subquery(
@@ -1280,7 +1281,8 @@ class SubEvent(EventMixin, LoggedModel):
).order_by().values('subevent').annotate(items=GroupConcat('variation_id', delimiter=',')).values('items'),
output_field=models.TextField(),
),
Value('')
Value(''),
output_field=models.TextField()
)
)

View File

@@ -401,7 +401,7 @@ class Item(LoggedModel):
),
default=False
)
generate_tickets = models.NullBooleanField(
generate_tickets = models.BooleanField(
verbose_name=_("Generate tickets"),
blank=True, null=True,
)
@@ -410,7 +410,7 @@ class Item(LoggedModel):
help_text=_("This will only work if waiting lists are enabled for this event."),
default=True
)
show_quota_left = models.NullBooleanField(
show_quota_left = models.BooleanField(
verbose_name=_("Show number of tickets left"),
help_text=_("Publicly show how many tickets are still available."),
blank=True, null=True,

View File

@@ -27,7 +27,6 @@ from django.utils.timezone import now
from django.utils.translation import gettext_lazy as _
from django_scopes import ScopedManager, scopes_disabled
from i18nfield.fields import I18nCharField
from jsonfallback.fields import FallbackJSONField
from pretix.base.models import Customer
from pretix.base.models.base import LoggedModel
@@ -59,6 +58,9 @@ class MembershipType(LoggedModel):
null=True, blank=True,
)
class Meta:
ordering = ('id',)
def __str__(self):
return str(self.name)
@@ -87,7 +89,7 @@ class MembershipQuerySet(models.QuerySet):
c=Count('*')
).values('c')
),
Value('0')
Value(0),
)
)
@@ -135,7 +137,7 @@ class Membership(models.Model):
date_end = models.DateTimeField(
verbose_name=_('End date')
)
attendee_name_parts = FallbackJSONField(default=dict, null=True)
attendee_name_parts = models.JSONField(default=dict, null=True)
objects = MembershipQuerySetManager()

View File

@@ -65,7 +65,6 @@ from django.utils.translation import gettext_lazy as _, pgettext_lazy
from django_countries.fields import Country
from django_scopes import ScopedManager, scopes_disabled
from i18nfield.strings import LazyI18nString
from jsonfallback.fields import FallbackJSONField
from phonenumber_field.modelfields import PhoneNumberField
from phonenumber_field.phonenumber import PhoneNumber
from phonenumbers import NumberParseException
@@ -378,12 +377,12 @@ class Order(LockModel, LoggedModel):
refund_sum=refund_sum_sq,
)
qs = qs.annotate(
computed_payment_refund_sum=Coalesce(payment_sum_sq, 0) - Coalesce(refund_sum_sq, 0),
computed_payment_refund_sum=Coalesce(payment_sum_sq, Decimal('0.00')) - Coalesce(refund_sum_sq, Decimal('0.00')),
)
qs = qs.annotate(
pending_sum_t=F('total') - Coalesce(payment_sum_sq, 0) + Coalesce(refund_sum_sq, 0),
pending_sum_rc=-1 * Coalesce(payment_sum_sq, 0) + Coalesce(refund_sum_sq, 0),
pending_sum_t=F('total') - Coalesce(payment_sum_sq, Decimal('0.00')) + Coalesce(refund_sum_sq, Decimal('0.00')),
pending_sum_rc=-1 * Coalesce(payment_sum_sq, Decimal('0.00')) + Coalesce(refund_sum_sq, Decimal('0.00')),
)
if refunds:
qs = qs.annotate(
@@ -394,23 +393,23 @@ class Order(LockModel, LoggedModel):
qs = qs.annotate(
is_overpaid=Case(
When(~Q(status=Order.STATUS_CANCELED) & Q(pending_sum_t__lt=-1e-8),
then=Value('1')),
then=Value(1)),
When(Q(status=Order.STATUS_CANCELED) & Q(pending_sum_rc__lt=-1e-8),
then=Value('1')),
default=Value('0'),
then=Value(1)),
default=Value(0),
output_field=models.IntegerField()
),
is_pending_with_full_payment=Case(
When(Q(status__in=(Order.STATUS_EXPIRED, Order.STATUS_PENDING)) & Q(pending_sum_t__lte=1e-8)
& Q(require_approval=False),
then=Value('1')),
default=Value('0'),
then=Value(1)),
default=Value(0),
output_field=models.IntegerField()
),
is_underpaid=Case(
When(Q(status=Order.STATUS_PAID) & Q(pending_sum_t__gt=1e-8),
then=Value('1')),
default=Value('0'),
then=Value(1)),
default=Value(0),
output_field=models.IntegerField()
)
)
@@ -1190,7 +1189,7 @@ class AbstractPosition(models.Model):
blank=True, null=True,
help_text=_("Empty, if this product is not an admission ticket")
)
attendee_name_parts = FallbackJSONField(
attendee_name_parts = models.JSONField(
blank=True, default=dict
)
attendee_email = models.EmailField(
@@ -2313,7 +2312,7 @@ class InvoiceAddress(models.Model):
is_business = models.BooleanField(default=False, verbose_name=_('Business customer'))
company = models.CharField(max_length=255, blank=True, verbose_name=_('Company name'))
name_cached = models.CharField(max_length=255, verbose_name=_('Full name'), blank=True)
name_parts = FallbackJSONField(default=dict)
name_parts = models.JSONField(default=dict)
street = models.TextField(verbose_name=_('Address'), blank=False)
zipcode = models.CharField(max_length=30, verbose_name=_('ZIP code'), blank=False)
city = models.CharField(max_length=255, verbose_name=_('City'), blank=False)

View File

@@ -26,7 +26,6 @@ from django.db import models, transaction
from django.utils.timezone import now
from django.utils.translation import gettext_lazy as _, pgettext_lazy
from django_scopes import ScopedManager
from jsonfallback.fields import FallbackJSONField
from phonenumber_field.modelfields import PhoneNumberField
from pretix.base.email import get_email_context
@@ -66,7 +65,7 @@ class WaitingListEntry(LoggedModel):
verbose_name=_("Name"),
blank=True, null=True,
)
name_parts = FallbackJSONField(
name_parts = models.JSONField(
blank=True, default=dict
)
email = models.EmailField(

View File

@@ -31,7 +31,7 @@
# Unless required by applicable law or agreed to in writing, software distributed under the Apache License 2.0 is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under the License.
import os
from datetime import datetime, timedelta
from functools import partial, reduce
@@ -545,7 +545,7 @@ def _save_answers(op, answers, given_answers):
qa = answers[q]
else:
qa = op.answers.create(question=q, answer=str(a))
qa.file.save(a.name, a, save=False)
qa.file.save(os.path.basename(a.name), a, save=False)
qa.answer = 'file://' + qa.file.name
qa.save()
written = True

View File

@@ -198,9 +198,7 @@ class DeprecatedSignal(django.dispatch.Signal):
super().connect(receiver, sender=None, weak=True, dispatch_uid=None)
event_live_issues = EventPluginSignal(
providing_args=[]
)
event_live_issues = EventPluginSignal()
"""
This signal is sent out to determine whether an event can be taken live. If you want to
prevent the event from going live, return a string that will be displayed to the user
@@ -210,9 +208,7 @@ As with all event-plugin signals, the ``sender`` keyword argument will contain t
"""
register_payment_providers = EventPluginSignal(
providing_args=[]
)
register_payment_providers = EventPluginSignal()
"""
This signal is sent out to get all known payment providers. Receivers should return a
subclass of pretix.base.payment.BasePaymentProvider or a list of these
@@ -220,9 +216,7 @@ subclass of pretix.base.payment.BasePaymentProvider or a list of these
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""
register_mail_placeholders = EventPluginSignal(
providing_args=[]
)
register_mail_placeholders = EventPluginSignal()
"""
This signal is sent out to get all known email text placeholders. Receivers should return
an instance of a subclass of pretix.base.email.BaseMailTextPlaceholder or a list of these.
@@ -230,9 +224,7 @@ an instance of a subclass of pretix.base.email.BaseMailTextPlaceholder or a list
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""
register_html_mail_renderers = EventPluginSignal(
providing_args=[]
)
register_html_mail_renderers = EventPluginSignal()
"""
This signal is sent out to get all known HTML email renderers. Receivers should return a
subclass of pretix.base.email.BaseHTMLMailRenderer or a list of these
@@ -240,9 +232,7 @@ subclass of pretix.base.email.BaseHTMLMailRenderer or a list of these
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""
register_invoice_renderers = EventPluginSignal(
providing_args=[]
)
register_invoice_renderers = EventPluginSignal()
"""
This signal is sent out to get all known invoice renderers. Receivers should return a
subclass of pretix.base.invoice.BaseInvoiceRenderer or a list of these
@@ -250,9 +240,7 @@ subclass of pretix.base.invoice.BaseInvoiceRenderer or a list of these
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""
register_ticket_secret_generators = EventPluginSignal(
providing_args=[]
)
register_ticket_secret_generators = EventPluginSignal()
"""
This signal is sent out to get all known ticket secret generators. Receivers should return a
subclass of ``pretix.base.secrets.BaseTicketSecretGenerator`` or a list of these
@@ -260,9 +248,7 @@ subclass of ``pretix.base.secrets.BaseTicketSecretGenerator`` or a list of these
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""
register_data_shredders = EventPluginSignal(
providing_args=[]
)
register_data_shredders = EventPluginSignal()
"""
This signal is sent out to get all known data shredders. Receivers should return a
subclass of pretix.base.shredder.BaseDataShredder or a list of these
@@ -270,9 +256,7 @@ subclass of pretix.base.shredder.BaseDataShredder or a list of these
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""
register_ticket_outputs = EventPluginSignal(
providing_args=[]
)
register_ticket_outputs = EventPluginSignal()
"""
This signal is sent out to get all known ticket outputs. Receivers should return a
subclass of pretix.base.ticketoutput.BaseTicketOutput
@@ -280,9 +264,7 @@ subclass of pretix.base.ticketoutput.BaseTicketOutput
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""
register_notification_types = EventPluginSignal(
providing_args=[]
)
register_notification_types = EventPluginSignal()
"""
This signal is sent out to get all known notification types. Receivers should return an
instance of a subclass of pretix.base.notifications.NotificationType or a list of such
@@ -293,18 +275,14 @@ however for this signal, the ``sender`` **may also be None** to allow creating t
notification settings!
"""
register_sales_channels = django.dispatch.Signal(
providing_args=[]
)
register_sales_channels = django.dispatch.Signal()
"""
This signal is sent out to get all known sales channels types. Receivers should return an
instance of a subclass of ``pretix.base.channels.SalesChannel`` or a list of such
instances.
"""
register_data_exporters = EventPluginSignal(
providing_args=[]
)
register_data_exporters = EventPluginSignal()
"""
This signal is sent out to get all known data exporters. Receivers should return a
subclass of pretix.base.exporter.BaseExporter
@@ -312,10 +290,10 @@ subclass of pretix.base.exporter.BaseExporter
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""
register_multievent_data_exporters = django.dispatch.Signal(
providing_args=["event"]
)
register_multievent_data_exporters = django.dispatch.Signal()
"""
Arguments: ``event``
This signal is sent out to get all known data exporters, which support exporting data for
multiple events. Receivers should return a subclass of pretix.base.exporter.BaseExporter
@@ -323,10 +301,11 @@ The ``sender`` keyword argument will contain an organizer.
"""
validate_order = EventPluginSignal(
providing_args=["payment_provider", "positions", "email", "locale", "invoice_address",
"meta_info", "customer"]
)
"""
Arguments: ``payment_provider``, ``positions``, ``email``, ``locale``, ``invoice_address``,
``meta_info``, ``customer``
This signal is sent out when the user tries to confirm the order, before we actually create
the order. It allows you to inspect the cart positions. Your return value will be ignored,
but you can raise an OrderError with an appropriate exception message if you like to block
@@ -335,10 +314,10 @@ the order. We strongly discourage making changes to the order here.
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""
validate_cart = EventPluginSignal(
providing_args=["positions"]
)
validate_cart = EventPluginSignal()
"""
Arguments: ``positions``
This signal is sent out before the user starts checkout. It includes an iterable
with the current CartPosition objects.
The response of receivers will be ignored, but you can raise a CartError with an
@@ -347,10 +326,10 @@ appropriate exception message.
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""
validate_cart_addons = EventPluginSignal(
providing_args=["addons", "base_position", "iao"]
)
validate_cart_addons = EventPluginSignal()
"""
Arguments: ``addons``, ``base_position``, ``iao``
This signal is sent when a user tries to select a combination of addons. In contrast to
``validate_cart``, this is executed before the cart is actually modified. You are passed
an argument ``addons`` containing a dict of ``(item, variation or None) → count`` tuples as well
@@ -362,10 +341,10 @@ appropriate exception message.
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""
order_placed = EventPluginSignal(
providing_args=["order"]
)
order_placed = EventPluginSignal()
"""
Arguments: ``order``
This signal is sent out every time an order is placed. The order object is given
as the first argument. This signal is *not* sent out if an order is created through
splitting an existing order, so you can not expect to see all orders by listening
@@ -374,10 +353,10 @@ to this signal.
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""
order_paid = EventPluginSignal(
providing_args=["order"]
)
order_paid = EventPluginSignal()
"""
Arguments: ``order``
This signal is sent out every time an order is paid. The order object is given
as the first argument. This signal is *not* sent out if an order is marked as paid
because an already-paid order has been split.
@@ -385,80 +364,80 @@ because an already-paid order has been split.
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""
order_canceled = EventPluginSignal(
providing_args=["order"]
)
order_canceled = EventPluginSignal()
"""
Arguments: ``order``
This signal is sent out every time an order is canceled. The order object is given
as the first argument.
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""
order_reactivated = EventPluginSignal(
providing_args=["order"]
)
order_reactivated = EventPluginSignal()
"""
Arguments: ``order``
This signal is sent out every time a canceled order is reactivated. The order object is given
as the first argument.
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""
order_expired = EventPluginSignal(
providing_args=["order"]
)
order_expired = EventPluginSignal()
"""
Arguments: ``order``
This signal is sent out every time an order is marked as expired. The order object is given
as the first argument.
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""
order_modified = EventPluginSignal(
providing_args=["order"]
)
order_modified = EventPluginSignal()
"""
Arguments: ``order``
This signal is sent out every time an order's information is modified. The order object is given
as the first argument.
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""
order_changed = EventPluginSignal(
providing_args=["order"]
)
order_changed = EventPluginSignal()
"""
Arguments: ``order``
This signal is sent out every time an order's content is changed. The order object is given
as the first argument.
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""
order_approved = EventPluginSignal(
providing_args=["order"]
)
order_approved = EventPluginSignal()
"""
Arguments: ``order``
This signal is sent out every time an order is being approved. The order object is given
as the first argument.
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""
order_denied = EventPluginSignal(
providing_args=["order"]
)
order_denied = EventPluginSignal()
"""
Arguments: ``order``
This signal is sent out every time an order is being denied. The order object is given
as the first argument.
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""
order_gracefully_delete = EventPluginSignal(
providing_args=["order"]
)
order_gracefully_delete = EventPluginSignal()
"""
Arguments: ``order``
This signal is sent out every time a test-mode order is being deleted. The order object
is given as the first argument.
@@ -469,10 +448,10 @@ the deletion of the order.
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""
checkin_created = EventPluginSignal(
providing_args=["checkin"],
)
checkin_created = EventPluginSignal()
"""
Arguments: ``checkin``
This signal is sent out every time a check-in is created (i.e. an order position is marked as
checked in). It is not send if the position was already checked in and is force-checked-in a second time.
The check-in object is given as the first argument
@@ -480,10 +459,10 @@ The check-in object is given as the first argument
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""
logentry_display = EventPluginSignal(
providing_args=["logentry"]
)
logentry_display = EventPluginSignal()
"""
Arguments: ``logentry``
To display an instance of the ``LogEntry`` model to a human user,
``pretix.base.signals.logentry_display`` will be sent out with a ``logentry`` argument.
@@ -493,10 +472,10 @@ to the user. The receivers are expected to return plain text.
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""
logentry_object_link = EventPluginSignal(
providing_args=["logentry"]
)
logentry_object_link = EventPluginSignal()
"""
Arguments: ``logentry``
To display the relationship of an instance of the ``LogEntry`` model to another model
to a human user, ``pretix.base.signals.logentry_object_link`` will be sent out with a
``logentry`` argument.
@@ -521,10 +500,10 @@ Make sure that any user content in the HTML code you return is properly escaped!
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""
requiredaction_display = EventPluginSignal(
providing_args=["action", "request"]
)
requiredaction_display = EventPluginSignal()
"""
Arguments: ``action``, ``request``
To display an instance of the ``RequiredAction`` model to a human user,
``pretix.base.signals.requiredaction_display`` will be sent out with a ``action`` argument.
You will also get the current ``request`` in a different argument.
@@ -535,10 +514,10 @@ to the user. The receivers are expected to return HTML code.
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""
event_copy_data = EventPluginSignal(
providing_args=["other", "tax_map", "category_map", "item_map", "question_map", "variation_map", "checkin_list_map"]
)
event_copy_data = EventPluginSignal()
"""
Arguments: "other", ``tax_map``, ``category_map``, ``item_map``, ``question_map``, ``variation_map``, ``checkin_list_map``
This signal is sent out when a new event is created as a clone of an existing event, i.e.
the settings from the older event are copied to the newer one. You can listen to this
signal to copy data or configuration stored within your plugin's models as well.
@@ -553,10 +532,10 @@ keyword argument will contain the event to **copy from**. The keyword arguments
in the new event of the respective types.
"""
item_copy_data = EventPluginSignal(
providing_args=["source", "target"]
)
item_copy_data = EventPluginSignal()
"""
Arguments: ``source``, ``target``
This signal is sent out when a new product is created as a clone of an existing product, i.e.
the settings from the older product are copied to the newer one. You can listen to this
signal to copy data or configuration stored within your plugin's models as well.
@@ -580,10 +559,10 @@ All plugins that are installed may send fields for the global settings form, as
an OrderedDict of (setting name, form field).
"""
order_fee_calculation = EventPluginSignal(
providing_args=['positions', 'invoice_address', 'meta_info', 'total', 'gift_cards']
)
order_fee_calculation = EventPluginSignal()
"""
Arguments: ``positions``, ``invoice_address``, ``meta_info``, ``total``, ``gift_cards``
This signals allows you to add fees to an order while it is being created. You are expected to
return a list of ``OrderFee`` objects that are not yet saved to the database
(because there is no order yet).
@@ -596,10 +575,10 @@ keyword argument will contain the total cart sum without any fees. You should no
the gift cards in use.
"""
order_fee_type_name = EventPluginSignal(
providing_args=['request', 'fee']
)
order_fee_type_name = EventPluginSignal()
"""
Arguments: ``request``, ``fee``
This signals allows you to return a human-readable description for a fee type based on the ``fee_type``
and ``internal_type`` attributes of the ``OrderFee`` model that you get as keyword arguments. You are
expected to return a string or None, if you don't know about this fee.
@@ -607,20 +586,20 @@ expected to return a string or None, if you don't know about this fee.
As with all plugin signals, the ``sender`` keyword argument will contain the event.
"""
allow_ticket_download = EventPluginSignal(
providing_args=['order']
)
allow_ticket_download = EventPluginSignal()
"""
Arguments: ``order``
This signal is sent out to check if tickets for an order can be downloaded. If any receiver returns false,
a download will not be offered.
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""
email_filter = EventPluginSignal(
providing_args=['message', 'order', 'user']
)
email_filter = EventPluginSignal()
"""
Arguments: ``message``, ``order``, ``user``
This signal allows you to implement a middleware-style filter on all outgoing emails. You are expected to
return a (possibly modified) copy of the message object passed to you.
@@ -632,10 +611,10 @@ If the email is associated with a specific user, e.g. a notification email, the
well, otherwise it will be ``None``.
"""
global_email_filter = GlobalSignal(
providing_args=['message', 'order', 'user', 'customer', 'organizer']
)
global_email_filter = GlobalSignal()
"""
Arguments: ``message``, ``order``, ``user``, ``customer``, ``organizer``
This signal allows you to implement a middleware-style filter on all outgoing emails. You are expected to
return a (possibly modified) copy of the message object passed to you.
@@ -700,10 +679,10 @@ a ``subevent`` argument which might be none and you are expected to return a lis
"""
quota_availability = EventPluginSignal(
providing_args=['quota', 'result', 'count_waitinglist']
)
quota_availability = EventPluginSignal()
"""
Arguments: ``quota``, ``result``, ``count_waitinglist``
This signal allows you to modify the availability of a quota. You are passed the ``quota`` and an
``availability`` result calculated by pretix code or other plugins. ``availability`` is a tuple
with the first entry being one of the ``Quota.AVAILABILITY_*`` constants and the second entry being
@@ -716,25 +695,23 @@ system really bad.** Also, keep in mind that your response is subject to caching
quotas might be used for display (not for actual order processing).
"""
order_split = EventPluginSignal(
providing_args=["original", "split_order"]
)
order_split = EventPluginSignal()
"""
Arguments: ``original``, ``split_order``
This signal is sent out when an order is split into two orders and allows you to copy related models
to the new order. You will be passed the old order as ``original`` and the new order as ``split_order``.
"""
invoice_line_text = EventPluginSignal(
providing_args=["position"]
)
invoice_line_text = EventPluginSignal()
"""
Arguments: ``position``
This signal is sent out when an invoice is built for an order. You can return additional text that
should be shown on the invoice for the given ``position``.
"""
order_import_columns = EventPluginSignal(
providing_args=[]
)
order_import_columns = EventPluginSignal()
"""
This signal is sent out if the user performs an import of orders from an external source. You can use this
to define additional columns that can be read during import. You are expected to return a list of instances of
@@ -743,10 +720,10 @@ to define additional columns that can be read during import. You are expected to
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""
validate_event_settings = EventPluginSignal(
providing_args=["settings_dict"]
)
validate_event_settings = EventPluginSignal()
"""
Arguments: ``settings_dict``
This signal is sent out if the user performs an update of event settings through the API or web interface.
You are passed a ``settings_dict`` dictionary with the new state of the event settings object and are expected
to raise a ``django.core.exceptions.ValidationError`` if the new state is not valid.
@@ -757,9 +734,7 @@ serializer field instead.
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""
api_event_settings_fields = EventPluginSignal(
providing_args=[]
)
api_event_settings_fields = EventPluginSignal()
"""
This signal is sent out to collect serializable settings fields for the API. You are expected to
return a dictionary mapping names of attributes in the settings store to DRF serializer field instances.

View File

@@ -187,9 +187,9 @@ def markdown_compile_email(source):
class SnippetExtension(markdown.extensions.Extension):
def extendMarkdown(self, md, *args, **kwargs):
del md.parser.blockprocessors['olist']
del md.parser.blockprocessors['ulist']
del md.parser.blockprocessors['quote']
md.parser.blockprocessors.deregister('olist')
md.parser.blockprocessors.deregister('ulist')
md.parser.blockprocessors.deregister('quote')
def markdown_compile(source, snippet=False):

View File

@@ -19,29 +19,3 @@
# 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/>.
#
# This file is based on an earlier version of pretix which was released under the Apache License 2.0. The full text of
# the Apache License 2.0 can be obtained at <http://www.apache.org/licenses/LICENSE-2.0>.
#
# This file may have since been changed and any changes are released under the terms of AGPLv3 as described above. A
# full history of changes and contributors is available at <https://github.com/pretix/pretix>.
#
# This file contains Apache-licensed contributions copyrighted by: Tobias Kunze
#
# Unless required by applicable law or agreed to in writing, software distributed under the Apache License 2.0 is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under the License.
from django.apps import AppConfig
class PretixControlConfig(AppConfig):
name = 'pretix.control'
label = 'pretixcontrol'
def ready(self):
from .views import dashboards # noqa
from . import logdisplay # noqa
default_app_config = 'pretix.control.PretixControlConfig'

View File

@@ -0,0 +1,44 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
# This file is based on an earlier version of pretix which was released under the Apache License 2.0. The full text of
# the Apache License 2.0 can be obtained at <http://www.apache.org/licenses/LICENSE-2.0>.
#
# This file may have since been changed and any changes are released under the terms of AGPLv3 as described above. A
# full history of changes and contributors is available at <https://github.com/pretix/pretix>.
#
# This file contains Apache-licensed contributions copyrighted by: Tobias Kunze
#
# Unless required by applicable law or agreed to in writing, software distributed under the Apache License 2.0 is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under the License.
from django.apps import AppConfig
class PretixControlConfig(AppConfig):
name = 'pretix.control'
label = 'pretixcontrol'
def ready(self):
from .views import dashboards # noqa
from . import logdisplay # noqa

View File

@@ -40,7 +40,7 @@ from django import forms
from django.apps import apps
from django.conf import settings
from django.db.models import (
Count, Exists, F, Max, Model, OuterRef, Q, QuerySet,
Count, Exists, F, Max, Model, OrderBy, OuterRef, Q, QuerySet,
)
from django.db.models.functions import Coalesce, ExtractWeekDay
from django.urls import reverse, reverse_lazy
@@ -62,7 +62,7 @@ from pretix.base.signals import register_payment_providers
from pretix.control.forms.widgets import Select2
from pretix.control.signals import order_search_filter_q
from pretix.helpers.countries import CachedCountries
from pretix.helpers.database import FixedOrderBy, rolledback_transaction
from pretix.helpers.database import rolledback_transaction
from pretix.helpers.dicts import move_to_end
from pretix.helpers.i18n import i18ncomp
@@ -1270,10 +1270,10 @@ class CheckInFilterForm(FilterForm):
'-code': ('-order__code', '-item__name'),
'email': ('order__email', 'item__name'),
'-email': ('-order__email', '-item__name'),
'status': (FixedOrderBy(F('last_entry'), nulls_first=True, descending=True), 'order__code'),
'-status': (FixedOrderBy(F('last_entry'), nulls_last=True), '-order__code'),
'timestamp': (FixedOrderBy(F('last_entry'), nulls_first=True), 'order__code'),
'-timestamp': (FixedOrderBy(F('last_entry'), nulls_last=True, descending=True), '-order__code'),
'status': (OrderBy(F('last_entry'), nulls_first=True, descending=True), 'order__code'),
'-status': (OrderBy(F('last_entry'), nulls_last=True), '-order__code'),
'timestamp': (OrderBy(F('last_entry'), nulls_first=True), 'order__code'),
'-timestamp': (OrderBy(F('last_entry'), nulls_last=True, descending=True), '-order__code'),
'item': ('item__name', 'variation__value', 'order__code'),
'-item': ('-item__name', '-variation__value', '-order__code'),
'seat': ('seat__sorting_rank', 'seat__guid'),

View File

@@ -36,9 +36,7 @@ from django.dispatch import Signal
from pretix.base.signals import DeprecatedSignal, EventPluginSignal
html_page_start = Signal(
providing_args=[]
)
html_page_start = Signal()
"""
This signal allows you to put code in the beginning of the main page for every
page in the backend. You are expected to return HTML.
@@ -46,10 +44,10 @@ page in the backend. You are expected to return HTML.
The ``sender`` keyword argument will contain the request.
"""
html_head = EventPluginSignal(
providing_args=["request"]
)
html_head = EventPluginSignal()
"""
Arguments: ``request``
This signal allows you to put code inside the HTML ``<head>`` tag
of every page in the backend. You will get the request as the keyword argument
``request`` and are expected to return plain HTML.
@@ -57,10 +55,10 @@ of every page in the backend. You will get the request as the keyword argument
As with all plugin signals, the ``sender`` keyword argument will contain the event.
"""
nav_event = EventPluginSignal(
providing_args=["request"]
)
nav_event = EventPluginSignal()
"""
Arguments: ``request``
This signal allows you to add additional views to the admin panel
navigation. You will get the request as a keyword argument ``request``.
Receivers are expected to return a list of dictionaries. The dictionaries
@@ -82,10 +80,10 @@ in pretix.
As with all plugin signals, the ``sender`` keyword argument will contain the event.
"""
nav_topbar = Signal(
providing_args=["request"]
)
nav_topbar = Signal()
"""
Arguments: ``request``
This signal allows you to add additional views to the top navigation bar.
You will get the request as a keyword argument ``request``.
Receivers are expected to return a list of dictionaries. The dictionaries
@@ -101,10 +99,10 @@ This is no ``EventPluginSignal``, so you do not get the event in the ``sender``
and you may get the signal regardless of whether your plugin is active.
"""
nav_global = Signal(
providing_args=["request"]
)
nav_global = Signal()
"""
Arguments: ``request``
This signal allows you to add additional views to the navigation bar when no event is
selected. You will get the request as a keyword argument ``request``.
Receivers are expected to return a list of dictionaries. The dictionaries
@@ -126,10 +124,10 @@ This is no ``EventPluginSignal``, so you do not get the event in the ``sender``
and you may get the signal regardless of whether your plugin is active.
"""
event_dashboard_top = EventPluginSignal(
providing_args=['request']
)
event_dashboard_top = EventPluginSignal()
"""
Arguments: 'request'
This signal is sent out to include custom HTML in the top part of the the event dashboard.
Receivers should return HTML.
@@ -137,9 +135,7 @@ As with all plugin signals, the ``sender`` keyword argument will contain the eve
An additional keyword argument ``subevent`` *can* contain a sub-event.
"""
event_dashboard_widgets = EventPluginSignal(
providing_args=[]
)
event_dashboard_widgets = EventPluginSignal()
"""
This signal is sent out to include widgets in the event dashboard. Receivers
should return a list of dictionaries, where each dictionary can have the keys:
@@ -154,10 +150,10 @@ As with all plugin signals, the ``sender`` keyword argument will contain the eve
An additional keyword argument ``subevent`` *can* contain a sub-event.
"""
user_dashboard_widgets = Signal(
providing_args=['user']
)
user_dashboard_widgets = Signal()
"""
Arguments: 'user'
This signal is sent out to include widgets in the personal user dashboard. Receivers
should return a list of dictionaries, where each dictionary can have the keys:
@@ -170,20 +166,20 @@ should return a list of dictionaries, where each dictionary can have the keys:
This is a regular django signal (no pretix event signal).
"""
voucher_form_html = EventPluginSignal(
providing_args=['form']
)
voucher_form_html = EventPluginSignal()
"""
Arguments: 'form'
This signal allows you to add additional HTML to the form that is used for modifying vouchers.
You receive the form object in the ``form`` keyword argument.
As with all plugin signals, the ``sender`` keyword argument will contain the event.
"""
voucher_form_class = EventPluginSignal(
providing_args=['cls']
)
voucher_form_class = EventPluginSignal()
"""
Arguments: ``cls``
This signal allows you to replace the form class that is used for modifying vouchers.
You will receive the default form class (or the class set by a previous plugin) in the
``cls`` argument so that you can inherit from it.
@@ -196,10 +192,10 @@ for every batch persisted to the database.
As with all plugin signals, the ``sender`` keyword argument will contain the event.
"""
voucher_form_validation = EventPluginSignal(
providing_args=['form']
)
voucher_form_validation = EventPluginSignal()
"""
Arguments: 'form'
This signal allows you to add additional validation to the form that is used for
creating and modifying vouchers. You will receive the form instance in the ``form``
argument and the current data state in the ``data`` argument.
@@ -207,28 +203,28 @@ argument and the current data state in the ``data`` argument.
As with all plugin signals, the ``sender`` keyword argument will contain the event.
"""
quota_detail_html = EventPluginSignal(
providing_args=['quota']
)
quota_detail_html = EventPluginSignal()
"""
Arguments: 'quota'
This signal allows you to append HTML to a Quota's detail view. You receive the
quota as argument in the ``quota`` keyword argument.
As with all plugin signals, the ``sender`` keyword argument will contain the event.
"""
organizer_edit_tabs = DeprecatedSignal(
providing_args=['organizer', 'request']
)
organizer_edit_tabs = DeprecatedSignal()
"""
Arguments: 'organizer', 'request'
Deprecated signal, no longer works. We just keep the definition so old plugins don't
break the installation.
"""
nav_organizer = Signal(
providing_args=['organizer', 'request']
)
nav_organizer = Signal()
"""
Arguments: 'organizer', 'request'
This signal is sent out to include tab links on the detail page of an organizer.
Receivers are expected to return a list of dictionaries. The dictionaries
should contain at least the keys ``label`` and ``url``. You should also return
@@ -249,30 +245,30 @@ This is a regular django signal (no pretix event signal). Receivers will be pass
the keyword arguments ``organizer`` and ``request``.
"""
order_info = EventPluginSignal(
providing_args=["order", "request"]
)
order_info = EventPluginSignal()
"""
Arguments: ``order``, ``request``
This signal is sent out to display additional information on the order detail page
As with all plugin signals, the ``sender`` keyword argument will contain the event.
Additionally, the argument ``order`` and ``request`` are available.
"""
order_position_buttons = EventPluginSignal(
providing_args=["order", "position", "request"]
)
order_position_buttons = EventPluginSignal()
"""
Arguments: ``order``, ``position``, ``request``
This signal is sent out to display additional buttons for a single position of an order.
As with all plugin signals, the ``sender`` keyword argument will contain the event.
Additionally, the argument ``order`` and ``request`` are available.
"""
nav_event_settings = EventPluginSignal(
providing_args=['request']
)
nav_event_settings = EventPluginSignal()
"""
Arguments: 'request'
This signal is sent out to include tab links on the settings page of an event.
Receivers are expected to return a list of dictionaries. The dictionaries
should contain at least the keys ``label`` and ``url``. You should also return
@@ -287,10 +283,10 @@ As with all plugin signals, the ``sender`` keyword argument will contain the eve
A second keyword argument ``request`` will contain the request object.
"""
event_settings_widget = EventPluginSignal(
providing_args=['request']
)
event_settings_widget = EventPluginSignal()
"""
Arguments: 'request'
This signal is sent out to include template snippets on the settings page of an event
that allows generating a pretix Widget code.
@@ -298,10 +294,10 @@ As with all plugin signals, the ``sender`` keyword argument will contain the eve
A second keyword argument ``request`` will contain the request object.
"""
item_forms = EventPluginSignal(
providing_args=['request', 'item']
)
item_forms = EventPluginSignal()
"""
Arguments: 'request', 'item'
This signal allows you to return additional forms that should be rendered on the product
modification page. You are passed ``request`` and ``item`` arguments and are expected to return
an instance of a form class that you bind yourself when appropriate. Your form will be executed
@@ -311,10 +307,10 @@ styles. It is advisable to set a prefix for your form to avoid clashes with othe
As with all plugin signals, the ``sender`` keyword argument will contain the event.
"""
item_formsets = EventPluginSignal(
providing_args=['request', 'item']
)
item_formsets = EventPluginSignal()
"""
Arguments: 'request', 'item'
This signal allows you to return additional formsets that should be rendered on the product
modification page. You are passed ``request`` and ``item`` arguments and are expected to return
an instance of a formset class that you bind yourself when appropriate. Your formset will be
@@ -329,10 +325,10 @@ will be passed a ``formset`` variable with your formset.
As with all plugin signals, the ``sender`` keyword argument will contain the event.
"""
subevent_forms = EventPluginSignal(
providing_args=['request', 'subevent', 'copy_from']
)
subevent_forms = EventPluginSignal()
"""
Arguments: 'request', 'subevent', 'copy_from'
This signal allows you to return additional forms that should be rendered on the subevent creation
or modification page. You are passed ``request`` and ``subevent`` arguments and are expected to return
an instance of a form class that you bind yourself when appropriate. Your form will be executed
@@ -346,17 +342,17 @@ creation, ``copy_from`` can be a subevent that is being copied from.
As with all plugin signals, the ``sender`` keyword argument will contain the event.
"""
oauth_application_registered = Signal(
providing_args=["user", "application"]
)
oauth_application_registered = Signal()
"""
Arguments: ``user``, ``application``
This signal will be called whenever a user registers a new OAuth application.
"""
order_search_filter_q = Signal(
providing_args=["query"]
)
order_search_filter_q = Signal()
"""
Arguments: ``query``
This signal will be called whenever a free-text order search is performed. You are expected to return one
Q object that will be OR-ed with existing search queries. As order search exists on a global level as well,
this is not an Event signal and will be called even if your plugin is not active. ``sender`` will contain the
@@ -364,10 +360,10 @@ event if the search is performed within an event, and ``None`` otherwise. The se
``query``.
"""
order_search_forms = EventPluginSignal(
providing_args=['request']
)
order_search_forms = EventPluginSignal()
"""
Arguments: 'request'
This signal allows you to return additional forms that should be rendered in the advanced order search.
You are passed ``request`` argument and are expected to return an instance of a form class that you bind
yourself when appropriate. Your form will be executed as part of the standard validation and rendering

View File

@@ -33,7 +33,7 @@
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under the License.
from django.conf.urls import include, url
from django.conf.urls import include, re_path
from django.views.generic.base import RedirectView
from pretix.control.views import (
@@ -43,334 +43,334 @@ from pretix.control.views import (
)
urlpatterns = [
url(r'^logout$', auth.logout, name='auth.logout'),
url(r'^login$', auth.login, name='auth.login'),
url(r'^login/2fa$', auth.Login2FAView.as_view(), name='auth.login.2fa'),
url(r'^register$', auth.register, name='auth.register'),
url(r'^invite/(?P<token>[a-zA-Z0-9]+)$', auth.invite, name='auth.invite'),
url(r'^forgot$', auth.Forgot.as_view(), name='auth.forgot'),
url(r'^forgot/recover$', auth.Recover.as_view(), name='auth.forgot.recover'),
url(r'^$', dashboards.user_index, name='index'),
url(r'^widgets.json$', dashboards.user_index_widgets_lazy, name='index.widgets'),
url(r'^global/settings/$', global_settings.GlobalSettingsView.as_view(), name='global.settings'),
url(r'^global/update/$', global_settings.UpdateCheckView.as_view(), name='global.update'),
url(r'^global/license/$', global_settings.LicenseCheckView.as_view(), name='global.license'),
url(r'^global/message/$', global_settings.MessageView.as_view(), name='global.message'),
url(r'^logdetail/$', global_settings.LogDetailView.as_view(), name='global.logdetail'),
url(r'^logdetail/payment/$', global_settings.PaymentDetailView.as_view(), name='global.paymentdetail'),
url(r'^logdetail/refund/$', global_settings.RefundDetailView.as_view(), name='global.refunddetail'),
url(r'^geocode/$', geo.GeoCodeView.as_view(), name='global.geocode'),
url(r'^reauth/$', user.ReauthView.as_view(), name='user.reauth'),
url(r'^sudo/$', user.StartStaffSession.as_view(), name='user.sudo'),
url(r'^sudo/stop/$', user.StopStaffSession.as_view(), name='user.sudo.stop'),
url(r'^sudo/(?P<id>\d+)/$', user.EditStaffSession.as_view(), name='user.sudo.edit'),
url(r'^sudo/sessions/$', user.StaffSessionList.as_view(), name='user.sudo.list'),
url(r'^users/$', users.UserListView.as_view(), name='users'),
url(r'^users/select2$', typeahead.users_select2, name='users.select2'),
url(r'^users/add$', users.UserCreateView.as_view(), name='users.add'),
url(r'^users/impersonate/stop', users.UserImpersonateStopView.as_view(), name='users.impersonate.stop'),
url(r'^users/(?P<id>\d+)/$', users.UserEditView.as_view(), name='users.edit'),
url(r'^users/(?P<id>\d+)/reset$', users.UserResetView.as_view(), name='users.reset'),
url(r'^users/(?P<id>\d+)/impersonate', users.UserImpersonateView.as_view(), name='users.impersonate'),
url(r'^users/(?P<id>\d+)/anonymize', users.UserAnonymizeView.as_view(), name='users.anonymize'),
url(r'^pdf/editor/webfonts.css', pdf.FontsCSSView.as_view(), name='pdf.css'),
url(r'^settings/?$', user.UserSettings.as_view(), name='user.settings'),
url(r'^settings/history/$', user.UserHistoryView.as_view(), name='user.settings.history'),
url(r'^settings/notifications/$', user.UserNotificationsEditView.as_view(), name='user.settings.notifications'),
url(r'^settings/notifications/off/(?P<id>\d+)/(?P<token>[^/]+)/$', user.UserNotificationsDisableView.as_view(),
name='user.settings.notifications.off'),
url(r'^settings/oauth/authorized/$', oauth.AuthorizationListView.as_view(),
name='user.settings.oauth.list'),
url(r'^settings/oauth/authorized/(?P<pk>\d+)/revoke$', oauth.AuthorizationRevokeView.as_view(),
name='user.settings.oauth.revoke'),
url(r'^settings/oauth/apps/$', oauth.OAuthApplicationListView.as_view(),
name='user.settings.oauth.apps'),
url(r'^settings/oauth/apps/add$', oauth.OAuthApplicationRegistrationView.as_view(),
name='user.settings.oauth.apps.register'),
url(r'^settings/oauth/apps/(?P<pk>\d+)/$', oauth.OAuthApplicationUpdateView.as_view(),
name='user.settings.oauth.app'),
url(r'^settings/oauth/apps/(?P<pk>\d+)/disable$', oauth.OAuthApplicationDeleteView.as_view(),
name='user.settings.oauth.app.disable'),
url(r'^settings/oauth/apps/(?P<pk>\d+)/roll$', oauth.OAuthApplicationRollView.as_view(),
name='user.settings.oauth.app.roll'),
url(r'^settings/2fa/$', user.User2FAMainView.as_view(), name='user.settings.2fa'),
url(r'^settings/2fa/add$', user.User2FADeviceAddView.as_view(), name='user.settings.2fa.add'),
url(r'^settings/2fa/enable', user.User2FAEnableView.as_view(), name='user.settings.2fa.enable'),
url(r'^settings/2fa/disable', user.User2FADisableView.as_view(), name='user.settings.2fa.disable'),
url(r'^settings/2fa/regenemergency', user.User2FARegenerateEmergencyView.as_view(),
name='user.settings.2fa.regenemergency'),
url(r'^settings/2fa/totp/(?P<device>[0-9]+)/confirm', user.User2FADeviceConfirmTOTPView.as_view(),
name='user.settings.2fa.confirm.totp'),
url(r'^settings/2fa/webauthn/(?P<device>[0-9]+)/confirm', user.User2FADeviceConfirmWebAuthnView.as_view(),
name='user.settings.2fa.confirm.webauthn'),
url(r'^settings/2fa/(?P<devicetype>[^/]+)/(?P<device>[0-9]+)/delete', user.User2FADeviceDeleteView.as_view(),
name='user.settings.2fa.delete'),
url(r'^organizers/$', organizer.OrganizerList.as_view(), name='organizers'),
url(r'^organizers/add$', organizer.OrganizerCreate.as_view(), name='organizers.add'),
url(r'^organizers/select2$', typeahead.organizer_select2, name='organizers.select2'),
url(r'^organizer/(?P<organizer>[^/]+)/$', organizer.OrganizerDetail.as_view(), name='organizer'),
url(r'^organizer/(?P<organizer>[^/]+)/edit$', organizer.OrganizerUpdate.as_view(), name='organizer.edit'),
url(r'^organizer/(?P<organizer>[^/]+)/settings/email$',
organizer.OrganizerMailSettings.as_view(), name='organizer.settings.mail'),
url(r'^organizer/(?P<organizer>[^/]+)/settings/email/preview$',
organizer.MailSettingsPreview.as_view(), name='organizer.settings.mail.preview'),
url(r'^organizer/(?P<organizer>[^/]+)/delete$', organizer.OrganizerDelete.as_view(), name='organizer.delete'),
url(r'^organizer/(?P<organizer>[^/]+)/settings/display$', organizer.OrganizerDisplaySettings.as_view(),
name='organizer.display'),
url(r'^organizer/(?P<organizer>[^/]+)/properties$', organizer.EventMetaPropertyListView.as_view(), name='organizer.properties'),
url(r'^organizer/(?P<organizer>[^/]+)/property/add$', organizer.EventMetaPropertyCreateView.as_view(),
name='organizer.property.add'),
url(r'^organizer/(?P<organizer>[^/]+)/property/(?P<property>[^/]+)/edit$', organizer.EventMetaPropertyUpdateView.as_view(),
name='organizer.property.edit'),
url(r'^organizer/(?P<organizer>[^/]+)/property/(?P<property>[^/]+)/delete$', organizer.EventMetaPropertyDeleteView.as_view(),
name='organizer.property.delete'),
url(r'^organizer/(?P<organizer>[^/]+)/membershiptypes$', organizer.MembershipTypeListView.as_view(), name='organizer.membershiptypes'),
url(r'^organizer/(?P<organizer>[^/]+)/membershiptype/add$', organizer.MembershipTypeCreateView.as_view(),
name='organizer.membershiptype.add'),
url(r'^organizer/(?P<organizer>[^/]+)/membershiptype/(?P<type>[^/]+)/edit$', organizer.MembershipTypeUpdateView.as_view(),
name='organizer.membershiptype.edit'),
url(r'^organizer/(?P<organizer>[^/]+)/membershiptype/(?P<type>[^/]+)/delete$', organizer.MembershipTypeDeleteView.as_view(),
name='organizer.membershiptype.delete'),
url(r'^organizer/(?P<organizer>[^/]+)/customers$', organizer.CustomerListView.as_view(), name='organizer.customers'),
url(r'^organizer/(?P<organizer>[^/]+)/customers/select2$', typeahead.customer_select2, name='organizer.customers.select2'),
url(r'^organizer/(?P<organizer>[^/]+)/customer/(?P<customer>[^/]+)/$',
organizer.CustomerDetailView.as_view(), name='organizer.customer'),
url(r'^organizer/(?P<organizer>[^/]+)/customer/(?P<customer>[^/]+)/edit$',
organizer.CustomerUpdateView.as_view(), name='organizer.customer.edit'),
url(r'^organizer/(?P<organizer>[^/]+)/customer/(?P<customer>[^/]+)/membership/add$',
organizer.MembershipCreateView.as_view(), name='organizer.customer.membership.add'),
url(r'^organizer/(?P<organizer>[^/]+)/customer/(?P<customer>[^/]+)/membership/(?P<id>[^/]+)/edit$',
organizer.MembershipUpdateView.as_view(), name='organizer.customer.membership.edit'),
url(r'^organizer/(?P<organizer>[^/]+)/customer/(?P<customer>[^/]+)/anonymize$',
organizer.CustomerAnonymizeView.as_view(), name='organizer.customer.anonymize'),
url(r'^organizer/(?P<organizer>[^/]+)/giftcards$', organizer.GiftCardListView.as_view(), name='organizer.giftcards'),
url(r'^organizer/(?P<organizer>[^/]+)/giftcard/add$', organizer.GiftCardCreateView.as_view(), name='organizer.giftcard.add'),
url(r'^organizer/(?P<organizer>[^/]+)/giftcard/(?P<giftcard>[^/]+)/$', organizer.GiftCardDetailView.as_view(), name='organizer.giftcard'),
url(r'^organizer/(?P<organizer>[^/]+)/giftcard/(?P<giftcard>[^/]+)/edit$', organizer.GiftCardUpdateView.as_view(),
name='organizer.giftcard.edit'),
url(r'^organizer/(?P<organizer>[^/]+)/webhooks$', organizer.WebHookListView.as_view(), name='organizer.webhooks'),
url(r'^organizer/(?P<organizer>[^/]+)/webhook/add$', organizer.WebHookCreateView.as_view(),
name='organizer.webhook.add'),
url(r'^organizer/(?P<organizer>[^/]+)/webhook/(?P<webhook>[^/]+)/edit$', organizer.WebHookUpdateView.as_view(),
name='organizer.webhook.edit'),
url(r'^organizer/(?P<organizer>[^/]+)/webhook/(?P<webhook>[^/]+)/logs$', organizer.WebHookLogsView.as_view(),
name='organizer.webhook.logs'),
url(r'^organizer/(?P<organizer>[^/]+)/devices$', organizer.DeviceListView.as_view(), name='organizer.devices'),
url(r'^organizer/(?P<organizer>[^/]+)/device/add$', organizer.DeviceCreateView.as_view(),
name='organizer.device.add'),
url(r'^organizer/(?P<organizer>[^/]+)/device/(?P<device>[^/]+)/edit$', organizer.DeviceUpdateView.as_view(),
name='organizer.device.edit'),
url(r'^organizer/(?P<organizer>[^/]+)/device/(?P<device>[^/]+)/connect$', organizer.DeviceConnectView.as_view(),
name='organizer.device.connect'),
url(r'^organizer/(?P<organizer>[^/]+)/device/(?P<device>[^/]+)/revoke$', organizer.DeviceRevokeView.as_view(),
name='organizer.device.revoke'),
url(r'^organizer/(?P<organizer>[^/]+)/device/(?P<device>[^/]+)/logs$', organizer.DeviceLogView.as_view(),
name='organizer.device.logs'),
url(r'^organizer/(?P<organizer>[^/]+)/gates$', organizer.GateListView.as_view(), name='organizer.gates'),
url(r'^organizer/(?P<organizer>[^/]+)/gate/add$', organizer.GateCreateView.as_view(), name='organizer.gate.add'),
url(r'^organizer/(?P<organizer>[^/]+)/gate/(?P<gate>[^/]+)/edit$', organizer.GateUpdateView.as_view(),
name='organizer.gate.edit'),
url(r'^organizer/(?P<organizer>[^/]+)/gate/(?P<gate>[^/]+)/delete$', organizer.GateDeleteView.as_view(),
name='organizer.gate.delete'),
url(r'^organizer/(?P<organizer>[^/]+)/teams$', organizer.TeamListView.as_view(), name='organizer.teams'),
url(r'^organizer/(?P<organizer>[^/]+)/team/add$', organizer.TeamCreateView.as_view(), name='organizer.team.add'),
url(r'^organizer/(?P<organizer>[^/]+)/team/(?P<team>[^/]+)/$', organizer.TeamMemberView.as_view(),
name='organizer.team'),
url(r'^organizer/(?P<organizer>[^/]+)/team/(?P<team>[^/]+)/edit$', organizer.TeamUpdateView.as_view(),
name='organizer.team.edit'),
url(r'^organizer/(?P<organizer>[^/]+)/team/(?P<team>[^/]+)/delete$', organizer.TeamDeleteView.as_view(),
name='organizer.team.delete'),
url(r'^organizer/(?P<organizer>[^/]+)/slugrng', main.SlugRNG.as_view(), name='events.add.slugrng'),
url(r'^organizer/(?P<organizer>[^/]+)/logs', organizer.LogView.as_view(), name='organizer.log'),
url(r'^organizer/(?P<organizer>[^/]+)/export/$', organizer.ExportView.as_view(), name='organizer.export'),
url(r'^organizer/(?P<organizer>[^/]+)/export/do$', organizer.ExportDoView.as_view(), name='organizer.export.do'),
url(r'^nav/typeahead/$', typeahead.nav_context_list, name='nav.typeahead'),
url(r'^events/$', main.EventList.as_view(), name='events'),
url(r'^events/add$', main.EventWizard.as_view(), name='events.add'),
url(r'^events/typeahead/$', typeahead.event_list, name='events.typeahead'),
url(r'^events/typeahead/meta/$', typeahead.meta_values, name='events.meta.typeahead'),
url(r'^search/orders/$', search.OrderSearch.as_view(), name='search.orders'),
url(r'^event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/', include([
url(r'^$', dashboards.event_index, name='event.index'),
url(r'^widgets.json$', dashboards.event_index_widgets_lazy, name='event.index.widgets'),
url(r'^live/$', event.EventLive.as_view(), name='event.live'),
url(r'^logs/$', event.EventLog.as_view(), name='event.log'),
url(r'^delete/$', event.EventDelete.as_view(), name='event.delete'),
url(r'^requiredactions/$', event.EventActions.as_view(), name='event.requiredactions'),
url(r'^requiredactions/(?P<id>\d+)/discard$', event.EventActionDiscard.as_view(),
name='event.requiredaction.discard'),
url(r'^comment/$', event.EventComment.as_view(),
name='event.comment'),
url(r'^quickstart/$', event.QuickSetupView.as_view(), name='event.quick'),
url(r'^settings/$', event.EventUpdate.as_view(), name='event.settings'),
url(r'^settings/plugins$', event.EventPlugins.as_view(), name='event.settings.plugins'),
url(r'^settings/payment/(?P<provider>[^/]+)$', event.PaymentProviderSettings.as_view(),
name='event.settings.payment.provider'),
url(r'^settings/payment$', event.PaymentSettings.as_view(), name='event.settings.payment'),
url(r'^settings/tickets$', event.TicketSettings.as_view(), name='event.settings.tickets'),
url(r'^settings/tickets/preview/(?P<output>[^/]+)$', event.TicketSettingsPreview.as_view(),
name='event.settings.tickets.preview'),
url(r'^settings/email$', event.MailSettings.as_view(), name='event.settings.mail'),
url(r'^settings/email/preview$', event.MailSettingsPreview.as_view(), name='event.settings.mail.preview'),
url(r'^settings/email/layoutpreview$', event.MailSettingsRendererPreview.as_view(),
name='event.settings.mail.preview.layout'),
url(r'^settings/cancel', event.CancelSettings.as_view(), name='event.settings.cancel'),
url(r'^settings/invoice$', event.InvoiceSettings.as_view(), name='event.settings.invoice'),
url(r'^settings/invoice/preview$', event.InvoicePreview.as_view(), name='event.settings.invoice.preview'),
url(r'^settings/display', event.DisplaySettings.as_view(), name='event.settings.display'),
url(r'^settings/tax/$', event.TaxList.as_view(), name='event.settings.tax'),
url(r'^settings/tax/(?P<rule>\d+)/$', event.TaxUpdate.as_view(), name='event.settings.tax.edit'),
url(r'^settings/tax/add$', event.TaxCreate.as_view(), name='event.settings.tax.add'),
url(r'^settings/tax/(?P<rule>\d+)/delete$', event.TaxDelete.as_view(), name='event.settings.tax.delete'),
url(r'^settings/widget$', event.WidgetSettings.as_view(), name='event.settings.widget'),
url(r'^pdf/editor/webfonts.css', pdf.FontsCSSView.as_view(), name='pdf.css'),
url(r'^pdf/editor/(?P<filename>[^/]+).pdf$', pdf.PdfView.as_view(), name='pdf.background'),
url(r'^subevents/$', subevents.SubEventList.as_view(), name='event.subevents'),
url(r'^subevents/select2$', typeahead.subevent_select2, name='event.subevents.select2'),
url(r'^subevents/(?P<subevent>\d+)/$', subevents.SubEventUpdate.as_view(), name='event.subevent'),
url(r'^subevents/(?P<subevent>\d+)/delete$', subevents.SubEventDelete.as_view(),
name='event.subevent.delete'),
url(r'^subevents/add$', subevents.SubEventCreate.as_view(), name='event.subevents.add'),
url(r'^subevents/bulk_add$', subevents.SubEventBulkCreate.as_view(), name='event.subevents.bulk'),
url(r'^subevents/bulk_action$', subevents.SubEventBulkAction.as_view(), name='event.subevents.bulkaction'),
url(r'^subevents/bulk_edit$', subevents.SubEventBulkEdit.as_view(), name='event.subevents.bulkedit'),
url(r'^items/$', item.ItemList.as_view(), name='event.items'),
url(r'^items/add$', item.ItemCreate.as_view(), name='event.items.add'),
url(r'^items/(?P<item>\d+)/$', item.ItemUpdateGeneral.as_view(), name='event.item'),
url(r'^items/(?P<item>\d+)/up$', item.item_move_up, name='event.items.up'),
url(r'^items/(?P<item>\d+)/down$', item.item_move_down, name='event.items.down'),
url(r'^items/(?P<item>\d+)/delete$', item.ItemDelete.as_view(), name='event.items.delete'),
url(r'^items/typeahead/meta/$', typeahead.item_meta_values, name='event.items.meta.typeahead'),
url(r'^items/select2$', typeahead.items_select2, name='event.items.select2'),
url(r'^items/select2/variation$', typeahead.variations_select2, name='event.items.variations.select2'),
url(r'^categories/$', item.CategoryList.as_view(), name='event.items.categories'),
url(r'^categories/select2$', typeahead.category_select2, name='event.items.categories.select2'),
url(r'^categories/(?P<category>\d+)/delete$', item.CategoryDelete.as_view(),
name='event.items.categories.delete'),
url(r'^categories/(?P<category>\d+)/up$', item.category_move_up, name='event.items.categories.up'),
url(r'^categories/(?P<category>\d+)/down$', item.category_move_down,
name='event.items.categories.down'),
url(r'^categories/(?P<category>\d+)/$', item.CategoryUpdate.as_view(),
name='event.items.categories.edit'),
url(r'^categories/add$', item.CategoryCreate.as_view(), name='event.items.categories.add'),
url(r'^questions/$', item.QuestionList.as_view(), name='event.items.questions'),
url(r'^questions/reorder$', item.reorder_questions, name='event.items.questions.reorder'),
url(r'^questions/(?P<question>\d+)/delete$', item.QuestionDelete.as_view(),
name='event.items.questions.delete'),
url(r'^questions/(?P<question>\d+)/$', item.QuestionView.as_view(),
name='event.items.questions.show'),
url(r'^questions/(?P<question>\d+)/change$', item.QuestionUpdate.as_view(),
name='event.items.questions.edit'),
url(r'^questions/add$', item.QuestionCreate.as_view(), name='event.items.questions.add'),
url(r'^quotas/$', item.QuotaList.as_view(), name='event.items.quotas'),
url(r'^quotas/(?P<quota>\d+)/$', item.QuotaView.as_view(), name='event.items.quotas.show'),
url(r'^quotas/select$', typeahead.quotas_select2, name='event.items.quotas.select2'),
url(r'^quotas/(?P<quota>\d+)/change$', item.QuotaUpdate.as_view(), name='event.items.quotas.edit'),
url(r'^quotas/(?P<quota>\d+)/delete$', item.QuotaDelete.as_view(),
name='event.items.quotas.delete'),
url(r'^quotas/add$', item.QuotaCreate.as_view(), name='event.items.quotas.add'),
url(r'^vouchers/$', vouchers.VoucherList.as_view(), name='event.vouchers'),
url(r'^vouchers/tags/$', vouchers.VoucherTags.as_view(), name='event.vouchers.tags'),
url(r'^vouchers/rng$', vouchers.VoucherRNG.as_view(), name='event.vouchers.rng'),
url(r'^vouchers/item_select$', typeahead.itemvarquota_select2, name='event.vouchers.itemselect2'),
url(r'^vouchers/(?P<voucher>\d+)/$', vouchers.VoucherUpdate.as_view(), name='event.voucher'),
url(r'^vouchers/(?P<voucher>\d+)/delete$', vouchers.VoucherDelete.as_view(),
name='event.voucher.delete'),
url(r'^vouchers/add$', vouchers.VoucherCreate.as_view(), name='event.vouchers.add'),
url(r'^vouchers/go$', vouchers.VoucherGo.as_view(), name='event.vouchers.go'),
url(r'^vouchers/bulk_add$', vouchers.VoucherBulkCreate.as_view(), name='event.vouchers.bulk'),
url(r'^vouchers/bulk_action$', vouchers.VoucherBulkAction.as_view(), name='event.vouchers.bulkaction'),
url(r'^orders/(?P<code>[0-9A-Z]+)/transition$', orders.OrderTransition.as_view(),
name='event.order.transition'),
url(r'^orders/(?P<code>[0-9A-Z]+)/resend$', orders.OrderResendLink.as_view(),
name='event.order.resendlink'),
url(r'^orders/(?P<code>[0-9A-Z]+)/(?P<position>\d+)/resend$', orders.OrderResendLink.as_view(),
name='event.order.resendlink'),
url(r'^orders/(?P<code>[0-9A-Z]+)/invoice$', orders.OrderInvoiceCreate.as_view(),
name='event.order.geninvoice'),
url(r'^orders/(?P<code>[0-9A-Z]+)/invoices/(?P<id>\d+)/regenerate$', orders.OrderInvoiceRegenerate.as_view(),
name='event.order.regeninvoice'),
url(r'^orders/(?P<code>[0-9A-Z]+)/invoices/(?P<id>\d+)/reissue$', orders.OrderInvoiceReissue.as_view(),
name='event.order.reissueinvoice'),
url(r'^orders/(?P<code>[0-9A-Z]+)/download/(?P<position>\d+)/(?P<output>[^/]+)/$',
orders.OrderDownload.as_view(),
name='event.order.download.ticket'),
url(r'^orders/(?P<code>[0-9A-Z]+)/answer/(?P<answer>[^/]+)/$',
orders.AnswerDownload.as_view(),
name='event.order.download.answer'),
url(r'^orders/(?P<code>[0-9A-Z]+)/checkvatid', orders.OrderCheckVATID.as_view(),
name='event.order.checkvatid'),
url(r'^orders/(?P<code>[0-9A-Z]+)/extend$', orders.OrderExtend.as_view(),
name='event.order.extend'),
url(r'^orders/(?P<code>[0-9A-Z]+)/reactivate$', orders.OrderReactivate.as_view(),
name='event.order.reactivate'),
url(r'^orders/(?P<code>[0-9A-Z]+)/contact$', orders.OrderContactChange.as_view(),
name='event.order.contact'),
url(r'^orders/(?P<code>[0-9A-Z]+)/locale', orders.OrderLocaleChange.as_view(),
name='event.order.locale'),
url(r'^orders/(?P<code>[0-9A-Z]+)/comment$', orders.OrderComment.as_view(),
name='event.order.comment'),
url(r'^orders/(?P<code>[0-9A-Z]+)/change$', orders.OrderChange.as_view(),
name='event.order.change'),
url(r'^orders/(?P<code>[0-9A-Z]+)/approve', orders.OrderApprove.as_view(),
name='event.order.approve'),
url(r'^orders/(?P<code>[0-9A-Z]+)/deny$', orders.OrderDeny.as_view(),
name='event.order.deny'),
url(r'^orders/(?P<code>[0-9A-Z]+)/delete$', orders.OrderDelete.as_view(),
name='event.order.delete'),
url(r'^orders/(?P<code>[0-9A-Z]+)/info', orders.OrderModifyInformation.as_view(),
name='event.order.info'),
url(r'^orders/(?P<code>[0-9A-Z]+)/sendmail$', orders.OrderSendMail.as_view(),
name='event.order.sendmail'),
url(r'^orders/(?P<code>[0-9A-Z]+)/(?P<position>[0-9A-Z]+)/sendmail$', orders.OrderPositionSendMail.as_view(),
name='event.order.position.sendmail'),
url(r'^orders/(?P<code>[0-9A-Z]+)/mail_history$', orders.OrderEmailHistory.as_view(),
name='event.order.mail_history'),
url(r'^orders/(?P<code>[0-9A-Z]+)/payments/(?P<payment>\d+)/cancel$', orders.OrderPaymentCancel.as_view(),
name='event.order.payments.cancel'),
url(r'^orders/(?P<code>[0-9A-Z]+)/payments/(?P<payment>\d+)/confirm$', orders.OrderPaymentConfirm.as_view(),
name='event.order.payments.confirm'),
url(r'^orders/(?P<code>[0-9A-Z]+)/refund$', orders.OrderRefundView.as_view(),
name='event.order.refunds.start'),
url(r'^orders/(?P<code>[0-9A-Z]+)/refunds/(?P<refund>\d+)/cancel$', orders.OrderRefundCancel.as_view(),
name='event.order.refunds.cancel'),
url(r'^orders/(?P<code>[0-9A-Z]+)/refunds/(?P<refund>\d+)/process$', orders.OrderRefundProcess.as_view(),
name='event.order.refunds.process'),
url(r'^orders/(?P<code>[0-9A-Z]+)/refunds/(?P<refund>\d+)/done$', orders.OrderRefundDone.as_view(),
name='event.order.refunds.done'),
url(r'^orders/(?P<code>[0-9A-Z]+)/cancellationrequests/(?P<req>\d+)/delete$',
orders.OrderCancellationRequestDelete.as_view(),
name='event.order.cancellationrequests.delete'),
url(r'^orders/(?P<code>[0-9A-Z]+)/$', orders.OrderDetail.as_view(), name='event.order'),
url(r'^invoice/(?P<invoice>[^/]+)$', orders.InvoiceDownload.as_view(),
name='event.invoice.download'),
url(r'^orders/overview/$', orders.OverView.as_view(), name='event.orders.overview'),
url(r'^orders/import/$', orderimport.ImportView.as_view(), name='event.orders.import'),
url(r'^orders/import/(?P<file>[^/]+)/$', orderimport.ProcessView.as_view(), name='event.orders.import.process'),
url(r'^orders/export/$', orders.ExportView.as_view(), name='event.orders.export'),
url(r'^orders/export/do$', orders.ExportDoView.as_view(), name='event.orders.export.do'),
url(r'^orders/refunds/$', orders.RefundList.as_view(), name='event.orders.refunds'),
url(r'^orders/go$', orders.OrderGo.as_view(), name='event.orders.go'),
url(r'^orders/$', orders.OrderList.as_view(), name='event.orders'),
url(r'^orders/search$', orders.OrderSearch.as_view(), name='event.orders.search'),
url(r'^dangerzone/$', event.DangerZone.as_view(), name='event.dangerzone'),
url(r'^cancel/$', orders.EventCancel.as_view(), name='event.cancel'),
url(r'^shredder/$', shredder.StartShredView.as_view(), name='event.shredder.start'),
url(r'^shredder/export$', shredder.ShredExportView.as_view(), name='event.shredder.export'),
url(r'^shredder/download/(?P<file>[^/]+)/$', shredder.ShredDownloadView.as_view(), name='event.shredder.download'),
url(r'^shredder/shred', shredder.ShredDoView.as_view(), name='event.shredder.shred'),
url(r'^waitinglist/$', waitinglist.WaitingListView.as_view(), name='event.orders.waitinglist'),
url(r'^waitinglist/auto_assign$', waitinglist.AutoAssign.as_view(), name='event.orders.waitinglist.auto'),
url(r'^waitinglist/(?P<entry>\d+)/delete$', waitinglist.EntryDelete.as_view(),
name='event.orders.waitinglist.delete'),
url(r'^checkinlists/$', checkin.CheckinListList.as_view(), name='event.orders.checkinlists'),
url(r'^checkinlists/add$', checkin.CheckinListCreate.as_view(), name='event.orders.checkinlists.add'),
url(r'^checkinlists/select2$', typeahead.checkinlist_select2, name='event.orders.checkinlists.select2'),
url(r'^checkinlists/(?P<list>\d+)/$', checkin.CheckInListShow.as_view(), name='event.orders.checkinlists.show'),
url(r'^checkinlists/(?P<list>\d+)/change$', checkin.CheckinListUpdate.as_view(),
name='event.orders.checkinlists.edit'),
url(r'^checkinlists/(?P<list>\d+)/delete$', checkin.CheckinListDelete.as_view(),
name='event.orders.checkinlists.delete'),
re_path(r'^logout$', auth.logout, name='auth.logout'),
re_path(r'^login$', auth.login, name='auth.login'),
re_path(r'^login/2fa$', auth.Login2FAView.as_view(), name='auth.login.2fa'),
re_path(r'^register$', auth.register, name='auth.register'),
re_path(r'^invite/(?P<token>[a-zA-Z0-9]+)$', auth.invite, name='auth.invite'),
re_path(r'^forgot$', auth.Forgot.as_view(), name='auth.forgot'),
re_path(r'^forgot/recover$', auth.Recover.as_view(), name='auth.forgot.recover'),
re_path(r'^$', dashboards.user_index, name='index'),
re_path(r'^widgets.json$', dashboards.user_index_widgets_lazy, name='index.widgets'),
re_path(r'^global/settings/$', global_settings.GlobalSettingsView.as_view(), name='global.settings'),
re_path(r'^global/update/$', global_settings.UpdateCheckView.as_view(), name='global.update'),
re_path(r'^global/license/$', global_settings.LicenseCheckView.as_view(), name='global.license'),
re_path(r'^global/message/$', global_settings.MessageView.as_view(), name='global.message'),
re_path(r'^logdetail/$', global_settings.LogDetailView.as_view(), name='global.logdetail'),
re_path(r'^logdetail/payment/$', global_settings.PaymentDetailView.as_view(), name='global.paymentdetail'),
re_path(r'^logdetail/refund/$', global_settings.RefundDetailView.as_view(), name='global.refunddetail'),
re_path(r'^geocode/$', geo.GeoCodeView.as_view(), name='global.geocode'),
re_path(r'^reauth/$', user.ReauthView.as_view(), name='user.reauth'),
re_path(r'^sudo/$', user.StartStaffSession.as_view(), name='user.sudo'),
re_path(r'^sudo/stop/$', user.StopStaffSession.as_view(), name='user.sudo.stop'),
re_path(r'^sudo/(?P<id>\d+)/$', user.EditStaffSession.as_view(), name='user.sudo.edit'),
re_path(r'^sudo/sessions/$', user.StaffSessionList.as_view(), name='user.sudo.list'),
re_path(r'^users/$', users.UserListView.as_view(), name='users'),
re_path(r'^users/select2$', typeahead.users_select2, name='users.select2'),
re_path(r'^users/add$', users.UserCreateView.as_view(), name='users.add'),
re_path(r'^users/impersonate/stop', users.UserImpersonateStopView.as_view(), name='users.impersonate.stop'),
re_path(r'^users/(?P<id>\d+)/$', users.UserEditView.as_view(), name='users.edit'),
re_path(r'^users/(?P<id>\d+)/reset$', users.UserResetView.as_view(), name='users.reset'),
re_path(r'^users/(?P<id>\d+)/impersonate', users.UserImpersonateView.as_view(), name='users.impersonate'),
re_path(r'^users/(?P<id>\d+)/anonymize', users.UserAnonymizeView.as_view(), name='users.anonymize'),
re_path(r'^pdf/editor/webfonts.css', pdf.FontsCSSView.as_view(), name='pdf.css'),
re_path(r'^settings/?$', user.UserSettings.as_view(), name='user.settings'),
re_path(r'^settings/history/$', user.UserHistoryView.as_view(), name='user.settings.history'),
re_path(r'^settings/notifications/$', user.UserNotificationsEditView.as_view(), name='user.settings.notifications'),
re_path(r'^settings/notifications/off/(?P<id>\d+)/(?P<token>[^/]+)/$', user.UserNotificationsDisableView.as_view(),
name='user.settings.notifications.off'),
re_path(r'^settings/oauth/authorized/$', oauth.AuthorizationListView.as_view(),
name='user.settings.oauth.list'),
re_path(r'^settings/oauth/authorized/(?P<pk>\d+)/revoke$', oauth.AuthorizationRevokeView.as_view(),
name='user.settings.oauth.revoke'),
re_path(r'^settings/oauth/apps/$', oauth.OAuthApplicationListView.as_view(),
name='user.settings.oauth.apps'),
re_path(r'^settings/oauth/apps/add$', oauth.OAuthApplicationRegistrationView.as_view(),
name='user.settings.oauth.apps.register'),
re_path(r'^settings/oauth/apps/(?P<pk>\d+)/$', oauth.OAuthApplicationUpdateView.as_view(),
name='user.settings.oauth.app'),
re_path(r'^settings/oauth/apps/(?P<pk>\d+)/disable$', oauth.OAuthApplicationDeleteView.as_view(),
name='user.settings.oauth.app.disable'),
re_path(r'^settings/oauth/apps/(?P<pk>\d+)/roll$', oauth.OAuthApplicationRollView.as_view(),
name='user.settings.oauth.app.roll'),
re_path(r'^settings/2fa/$', user.User2FAMainView.as_view(), name='user.settings.2fa'),
re_path(r'^settings/2fa/add$', user.User2FADeviceAddView.as_view(), name='user.settings.2fa.add'),
re_path(r'^settings/2fa/enable', user.User2FAEnableView.as_view(), name='user.settings.2fa.enable'),
re_path(r'^settings/2fa/disable', user.User2FADisableView.as_view(), name='user.settings.2fa.disable'),
re_path(r'^settings/2fa/regenemergency', user.User2FARegenerateEmergencyView.as_view(),
name='user.settings.2fa.regenemergency'),
re_path(r'^settings/2fa/totp/(?P<device>[0-9]+)/confirm', user.User2FADeviceConfirmTOTPView.as_view(),
name='user.settings.2fa.confirm.totp'),
re_path(r'^settings/2fa/webauthn/(?P<device>[0-9]+)/confirm', user.User2FADeviceConfirmWebAuthnView.as_view(),
name='user.settings.2fa.confirm.webauthn'),
re_path(r'^settings/2fa/(?P<devicetype>[^/]+)/(?P<device>[0-9]+)/delete', user.User2FADeviceDeleteView.as_view(),
name='user.settings.2fa.delete'),
re_path(r'^organizers/$', organizer.OrganizerList.as_view(), name='organizers'),
re_path(r'^organizers/add$', organizer.OrganizerCreate.as_view(), name='organizers.add'),
re_path(r'^organizers/select2$', typeahead.organizer_select2, name='organizers.select2'),
re_path(r'^organizer/(?P<organizer>[^/]+)/$', organizer.OrganizerDetail.as_view(), name='organizer'),
re_path(r'^organizer/(?P<organizer>[^/]+)/edit$', organizer.OrganizerUpdate.as_view(), name='organizer.edit'),
re_path(r'^organizer/(?P<organizer>[^/]+)/settings/email$',
organizer.OrganizerMailSettings.as_view(), name='organizer.settings.mail'),
re_path(r'^organizer/(?P<organizer>[^/]+)/settings/email/preview$',
organizer.MailSettingsPreview.as_view(), name='organizer.settings.mail.preview'),
re_path(r'^organizer/(?P<organizer>[^/]+)/delete$', organizer.OrganizerDelete.as_view(), name='organizer.delete'),
re_path(r'^organizer/(?P<organizer>[^/]+)/settings/display$', organizer.OrganizerDisplaySettings.as_view(),
name='organizer.display'),
re_path(r'^organizer/(?P<organizer>[^/]+)/properties$', organizer.EventMetaPropertyListView.as_view(), name='organizer.properties'),
re_path(r'^organizer/(?P<organizer>[^/]+)/property/add$', organizer.EventMetaPropertyCreateView.as_view(),
name='organizer.property.add'),
re_path(r'^organizer/(?P<organizer>[^/]+)/property/(?P<property>[^/]+)/edit$', organizer.EventMetaPropertyUpdateView.as_view(),
name='organizer.property.edit'),
re_path(r'^organizer/(?P<organizer>[^/]+)/property/(?P<property>[^/]+)/delete$', organizer.EventMetaPropertyDeleteView.as_view(),
name='organizer.property.delete'),
re_path(r'^organizer/(?P<organizer>[^/]+)/membershiptypes$', organizer.MembershipTypeListView.as_view(), name='organizer.membershiptypes'),
re_path(r'^organizer/(?P<organizer>[^/]+)/membershiptype/add$', organizer.MembershipTypeCreateView.as_view(),
name='organizer.membershiptype.add'),
re_path(r'^organizer/(?P<organizer>[^/]+)/membershiptype/(?P<type>[^/]+)/edit$', organizer.MembershipTypeUpdateView.as_view(),
name='organizer.membershiptype.edit'),
re_path(r'^organizer/(?P<organizer>[^/]+)/membershiptype/(?P<type>[^/]+)/delete$', organizer.MembershipTypeDeleteView.as_view(),
name='organizer.membershiptype.delete'),
re_path(r'^organizer/(?P<organizer>[^/]+)/customers$', organizer.CustomerListView.as_view(), name='organizer.customers'),
re_path(r'^organizer/(?P<organizer>[^/]+)/customers/select2$', typeahead.customer_select2, name='organizer.customers.select2'),
re_path(r'^organizer/(?P<organizer>[^/]+)/customer/(?P<customer>[^/]+)/$',
organizer.CustomerDetailView.as_view(), name='organizer.customer'),
re_path(r'^organizer/(?P<organizer>[^/]+)/customer/(?P<customer>[^/]+)/edit$',
organizer.CustomerUpdateView.as_view(), name='organizer.customer.edit'),
re_path(r'^organizer/(?P<organizer>[^/]+)/customer/(?P<customer>[^/]+)/membership/add$',
organizer.MembershipCreateView.as_view(), name='organizer.customer.membership.add'),
re_path(r'^organizer/(?P<organizer>[^/]+)/customer/(?P<customer>[^/]+)/membership/(?P<id>[^/]+)/edit$',
organizer.MembershipUpdateView.as_view(), name='organizer.customer.membership.edit'),
re_path(r'^organizer/(?P<organizer>[^/]+)/customer/(?P<customer>[^/]+)/anonymize$',
organizer.CustomerAnonymizeView.as_view(), name='organizer.customer.anonymize'),
re_path(r'^organizer/(?P<organizer>[^/]+)/giftcards$', organizer.GiftCardListView.as_view(), name='organizer.giftcards'),
re_path(r'^organizer/(?P<organizer>[^/]+)/giftcard/add$', organizer.GiftCardCreateView.as_view(), name='organizer.giftcard.add'),
re_path(r'^organizer/(?P<organizer>[^/]+)/giftcard/(?P<giftcard>[^/]+)/$', organizer.GiftCardDetailView.as_view(), name='organizer.giftcard'),
re_path(r'^organizer/(?P<organizer>[^/]+)/giftcard/(?P<giftcard>[^/]+)/edit$', organizer.GiftCardUpdateView.as_view(),
name='organizer.giftcard.edit'),
re_path(r'^organizer/(?P<organizer>[^/]+)/webhooks$', organizer.WebHookListView.as_view(), name='organizer.webhooks'),
re_path(r'^organizer/(?P<organizer>[^/]+)/webhook/add$', organizer.WebHookCreateView.as_view(),
name='organizer.webhook.add'),
re_path(r'^organizer/(?P<organizer>[^/]+)/webhook/(?P<webhook>[^/]+)/edit$', organizer.WebHookUpdateView.as_view(),
name='organizer.webhook.edit'),
re_path(r'^organizer/(?P<organizer>[^/]+)/webhook/(?P<webhook>[^/]+)/logs$', organizer.WebHookLogsView.as_view(),
name='organizer.webhook.logs'),
re_path(r'^organizer/(?P<organizer>[^/]+)/devices$', organizer.DeviceListView.as_view(), name='organizer.devices'),
re_path(r'^organizer/(?P<organizer>[^/]+)/device/add$', organizer.DeviceCreateView.as_view(),
name='organizer.device.add'),
re_path(r'^organizer/(?P<organizer>[^/]+)/device/(?P<device>[^/]+)/edit$', organizer.DeviceUpdateView.as_view(),
name='organizer.device.edit'),
re_path(r'^organizer/(?P<organizer>[^/]+)/device/(?P<device>[^/]+)/connect$', organizer.DeviceConnectView.as_view(),
name='organizer.device.connect'),
re_path(r'^organizer/(?P<organizer>[^/]+)/device/(?P<device>[^/]+)/revoke$', organizer.DeviceRevokeView.as_view(),
name='organizer.device.revoke'),
re_path(r'^organizer/(?P<organizer>[^/]+)/device/(?P<device>[^/]+)/logs$', organizer.DeviceLogView.as_view(),
name='organizer.device.logs'),
re_path(r'^organizer/(?P<organizer>[^/]+)/gates$', organizer.GateListView.as_view(), name='organizer.gates'),
re_path(r'^organizer/(?P<organizer>[^/]+)/gate/add$', organizer.GateCreateView.as_view(), name='organizer.gate.add'),
re_path(r'^organizer/(?P<organizer>[^/]+)/gate/(?P<gate>[^/]+)/edit$', organizer.GateUpdateView.as_view(),
name='organizer.gate.edit'),
re_path(r'^organizer/(?P<organizer>[^/]+)/gate/(?P<gate>[^/]+)/delete$', organizer.GateDeleteView.as_view(),
name='organizer.gate.delete'),
re_path(r'^organizer/(?P<organizer>[^/]+)/teams$', organizer.TeamListView.as_view(), name='organizer.teams'),
re_path(r'^organizer/(?P<organizer>[^/]+)/team/add$', organizer.TeamCreateView.as_view(), name='organizer.team.add'),
re_path(r'^organizer/(?P<organizer>[^/]+)/team/(?P<team>[^/]+)/$', organizer.TeamMemberView.as_view(),
name='organizer.team'),
re_path(r'^organizer/(?P<organizer>[^/]+)/team/(?P<team>[^/]+)/edit$', organizer.TeamUpdateView.as_view(),
name='organizer.team.edit'),
re_path(r'^organizer/(?P<organizer>[^/]+)/team/(?P<team>[^/]+)/delete$', organizer.TeamDeleteView.as_view(),
name='organizer.team.delete'),
re_path(r'^organizer/(?P<organizer>[^/]+)/slugrng', main.SlugRNG.as_view(), name='events.add.slugrng'),
re_path(r'^organizer/(?P<organizer>[^/]+)/logs', organizer.LogView.as_view(), name='organizer.log'),
re_path(r'^organizer/(?P<organizer>[^/]+)/export/$', organizer.ExportView.as_view(), name='organizer.export'),
re_path(r'^organizer/(?P<organizer>[^/]+)/export/do$', organizer.ExportDoView.as_view(), name='organizer.export.do'),
re_path(r'^nav/typeahead/$', typeahead.nav_context_list, name='nav.typeahead'),
re_path(r'^events/$', main.EventList.as_view(), name='events'),
re_path(r'^events/add$', main.EventWizard.as_view(), name='events.add'),
re_path(r'^events/typeahead/$', typeahead.event_list, name='events.typeahead'),
re_path(r'^events/typeahead/meta/$', typeahead.meta_values, name='events.meta.typeahead'),
re_path(r'^search/orders/$', search.OrderSearch.as_view(), name='search.orders'),
re_path(r'^event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/', include([
re_path(r'^$', dashboards.event_index, name='event.index'),
re_path(r'^widgets.json$', dashboards.event_index_widgets_lazy, name='event.index.widgets'),
re_path(r'^live/$', event.EventLive.as_view(), name='event.live'),
re_path(r'^logs/$', event.EventLog.as_view(), name='event.log'),
re_path(r'^delete/$', event.EventDelete.as_view(), name='event.delete'),
re_path(r'^requiredactions/$', event.EventActions.as_view(), name='event.requiredactions'),
re_path(r'^requiredactions/(?P<id>\d+)/discard$', event.EventActionDiscard.as_view(),
name='event.requiredaction.discard'),
re_path(r'^comment/$', event.EventComment.as_view(),
name='event.comment'),
re_path(r'^quickstart/$', event.QuickSetupView.as_view(), name='event.quick'),
re_path(r'^settings/$', event.EventUpdate.as_view(), name='event.settings'),
re_path(r'^settings/plugins$', event.EventPlugins.as_view(), name='event.settings.plugins'),
re_path(r'^settings/payment/(?P<provider>[^/]+)$', event.PaymentProviderSettings.as_view(),
name='event.settings.payment.provider'),
re_path(r'^settings/payment$', event.PaymentSettings.as_view(), name='event.settings.payment'),
re_path(r'^settings/tickets$', event.TicketSettings.as_view(), name='event.settings.tickets'),
re_path(r'^settings/tickets/preview/(?P<output>[^/]+)$', event.TicketSettingsPreview.as_view(),
name='event.settings.tickets.preview'),
re_path(r'^settings/email$', event.MailSettings.as_view(), name='event.settings.mail'),
re_path(r'^settings/email/preview$', event.MailSettingsPreview.as_view(), name='event.settings.mail.preview'),
re_path(r'^settings/email/layoutpreview$', event.MailSettingsRendererPreview.as_view(),
name='event.settings.mail.preview.layout'),
re_path(r'^settings/cancel', event.CancelSettings.as_view(), name='event.settings.cancel'),
re_path(r'^settings/invoice$', event.InvoiceSettings.as_view(), name='event.settings.invoice'),
re_path(r'^settings/invoice/preview$', event.InvoicePreview.as_view(), name='event.settings.invoice.preview'),
re_path(r'^settings/display', event.DisplaySettings.as_view(), name='event.settings.display'),
re_path(r'^settings/tax/$', event.TaxList.as_view(), name='event.settings.tax'),
re_path(r'^settings/tax/(?P<rule>\d+)/$', event.TaxUpdate.as_view(), name='event.settings.tax.edit'),
re_path(r'^settings/tax/add$', event.TaxCreate.as_view(), name='event.settings.tax.add'),
re_path(r'^settings/tax/(?P<rule>\d+)/delete$', event.TaxDelete.as_view(), name='event.settings.tax.delete'),
re_path(r'^settings/widget$', event.WidgetSettings.as_view(), name='event.settings.widget'),
re_path(r'^pdf/editor/webfonts.css', pdf.FontsCSSView.as_view(), name='pdf.css'),
re_path(r'^pdf/editor/(?P<filename>[^/]+).pdf$', pdf.PdfView.as_view(), name='pdf.background'),
re_path(r'^subevents/$', subevents.SubEventList.as_view(), name='event.subevents'),
re_path(r'^subevents/select2$', typeahead.subevent_select2, name='event.subevents.select2'),
re_path(r'^subevents/(?P<subevent>\d+)/$', subevents.SubEventUpdate.as_view(), name='event.subevent'),
re_path(r'^subevents/(?P<subevent>\d+)/delete$', subevents.SubEventDelete.as_view(),
name='event.subevent.delete'),
re_path(r'^subevents/add$', subevents.SubEventCreate.as_view(), name='event.subevents.add'),
re_path(r'^subevents/bulk_add$', subevents.SubEventBulkCreate.as_view(), name='event.subevents.bulk'),
re_path(r'^subevents/bulk_action$', subevents.SubEventBulkAction.as_view(), name='event.subevents.bulkaction'),
re_path(r'^subevents/bulk_edit$', subevents.SubEventBulkEdit.as_view(), name='event.subevents.bulkedit'),
re_path(r'^items/$', item.ItemList.as_view(), name='event.items'),
re_path(r'^items/add$', item.ItemCreate.as_view(), name='event.items.add'),
re_path(r'^items/(?P<item>\d+)/$', item.ItemUpdateGeneral.as_view(), name='event.item'),
re_path(r'^items/(?P<item>\d+)/up$', item.item_move_up, name='event.items.up'),
re_path(r'^items/(?P<item>\d+)/down$', item.item_move_down, name='event.items.down'),
re_path(r'^items/(?P<item>\d+)/delete$', item.ItemDelete.as_view(), name='event.items.delete'),
re_path(r'^items/typeahead/meta/$', typeahead.item_meta_values, name='event.items.meta.typeahead'),
re_path(r'^items/select2$', typeahead.items_select2, name='event.items.select2'),
re_path(r'^items/select2/variation$', typeahead.variations_select2, name='event.items.variations.select2'),
re_path(r'^categories/$', item.CategoryList.as_view(), name='event.items.categories'),
re_path(r'^categories/select2$', typeahead.category_select2, name='event.items.categories.select2'),
re_path(r'^categories/(?P<category>\d+)/delete$', item.CategoryDelete.as_view(),
name='event.items.categories.delete'),
re_path(r'^categories/(?P<category>\d+)/up$', item.category_move_up, name='event.items.categories.up'),
re_path(r'^categories/(?P<category>\d+)/down$', item.category_move_down,
name='event.items.categories.down'),
re_path(r'^categories/(?P<category>\d+)/$', item.CategoryUpdate.as_view(),
name='event.items.categories.edit'),
re_path(r'^categories/add$', item.CategoryCreate.as_view(), name='event.items.categories.add'),
re_path(r'^questions/$', item.QuestionList.as_view(), name='event.items.questions'),
re_path(r'^questions/reorder$', item.reorder_questions, name='event.items.questions.reorder'),
re_path(r'^questions/(?P<question>\d+)/delete$', item.QuestionDelete.as_view(),
name='event.items.questions.delete'),
re_path(r'^questions/(?P<question>\d+)/$', item.QuestionView.as_view(),
name='event.items.questions.show'),
re_path(r'^questions/(?P<question>\d+)/change$', item.QuestionUpdate.as_view(),
name='event.items.questions.edit'),
re_path(r'^questions/add$', item.QuestionCreate.as_view(), name='event.items.questions.add'),
re_path(r'^quotas/$', item.QuotaList.as_view(), name='event.items.quotas'),
re_path(r'^quotas/(?P<quota>\d+)/$', item.QuotaView.as_view(), name='event.items.quotas.show'),
re_path(r'^quotas/select$', typeahead.quotas_select2, name='event.items.quotas.select2'),
re_path(r'^quotas/(?P<quota>\d+)/change$', item.QuotaUpdate.as_view(), name='event.items.quotas.edit'),
re_path(r'^quotas/(?P<quota>\d+)/delete$', item.QuotaDelete.as_view(),
name='event.items.quotas.delete'),
re_path(r'^quotas/add$', item.QuotaCreate.as_view(), name='event.items.quotas.add'),
re_path(r'^vouchers/$', vouchers.VoucherList.as_view(), name='event.vouchers'),
re_path(r'^vouchers/tags/$', vouchers.VoucherTags.as_view(), name='event.vouchers.tags'),
re_path(r'^vouchers/rng$', vouchers.VoucherRNG.as_view(), name='event.vouchers.rng'),
re_path(r'^vouchers/item_select$', typeahead.itemvarquota_select2, name='event.vouchers.itemselect2'),
re_path(r'^vouchers/(?P<voucher>\d+)/$', vouchers.VoucherUpdate.as_view(), name='event.voucher'),
re_path(r'^vouchers/(?P<voucher>\d+)/delete$', vouchers.VoucherDelete.as_view(),
name='event.voucher.delete'),
re_path(r'^vouchers/add$', vouchers.VoucherCreate.as_view(), name='event.vouchers.add'),
re_path(r'^vouchers/go$', vouchers.VoucherGo.as_view(), name='event.vouchers.go'),
re_path(r'^vouchers/bulk_add$', vouchers.VoucherBulkCreate.as_view(), name='event.vouchers.bulk'),
re_path(r'^vouchers/bulk_action$', vouchers.VoucherBulkAction.as_view(), name='event.vouchers.bulkaction'),
re_path(r'^orders/(?P<code>[0-9A-Z]+)/transition$', orders.OrderTransition.as_view(),
name='event.order.transition'),
re_path(r'^orders/(?P<code>[0-9A-Z]+)/resend$', orders.OrderResendLink.as_view(),
name='event.order.resendlink'),
re_path(r'^orders/(?P<code>[0-9A-Z]+)/(?P<position>\d+)/resend$', orders.OrderResendLink.as_view(),
name='event.order.resendlink'),
re_path(r'^orders/(?P<code>[0-9A-Z]+)/invoice$', orders.OrderInvoiceCreate.as_view(),
name='event.order.geninvoice'),
re_path(r'^orders/(?P<code>[0-9A-Z]+)/invoices/(?P<id>\d+)/regenerate$', orders.OrderInvoiceRegenerate.as_view(),
name='event.order.regeninvoice'),
re_path(r'^orders/(?P<code>[0-9A-Z]+)/invoices/(?P<id>\d+)/reissue$', orders.OrderInvoiceReissue.as_view(),
name='event.order.reissueinvoice'),
re_path(r'^orders/(?P<code>[0-9A-Z]+)/download/(?P<position>\d+)/(?P<output>[^/]+)/$',
orders.OrderDownload.as_view(),
name='event.order.download.ticket'),
re_path(r'^orders/(?P<code>[0-9A-Z]+)/answer/(?P<answer>[^/]+)/$',
orders.AnswerDownload.as_view(),
name='event.order.download.answer'),
re_path(r'^orders/(?P<code>[0-9A-Z]+)/checkvatid', orders.OrderCheckVATID.as_view(),
name='event.order.checkvatid'),
re_path(r'^orders/(?P<code>[0-9A-Z]+)/extend$', orders.OrderExtend.as_view(),
name='event.order.extend'),
re_path(r'^orders/(?P<code>[0-9A-Z]+)/reactivate$', orders.OrderReactivate.as_view(),
name='event.order.reactivate'),
re_path(r'^orders/(?P<code>[0-9A-Z]+)/contact$', orders.OrderContactChange.as_view(),
name='event.order.contact'),
re_path(r'^orders/(?P<code>[0-9A-Z]+)/locale', orders.OrderLocaleChange.as_view(),
name='event.order.locale'),
re_path(r'^orders/(?P<code>[0-9A-Z]+)/comment$', orders.OrderComment.as_view(),
name='event.order.comment'),
re_path(r'^orders/(?P<code>[0-9A-Z]+)/change$', orders.OrderChange.as_view(),
name='event.order.change'),
re_path(r'^orders/(?P<code>[0-9A-Z]+)/approve', orders.OrderApprove.as_view(),
name='event.order.approve'),
re_path(r'^orders/(?P<code>[0-9A-Z]+)/deny$', orders.OrderDeny.as_view(),
name='event.order.deny'),
re_path(r'^orders/(?P<code>[0-9A-Z]+)/delete$', orders.OrderDelete.as_view(),
name='event.order.delete'),
re_path(r'^orders/(?P<code>[0-9A-Z]+)/info', orders.OrderModifyInformation.as_view(),
name='event.order.info'),
re_path(r'^orders/(?P<code>[0-9A-Z]+)/sendmail$', orders.OrderSendMail.as_view(),
name='event.order.sendmail'),
re_path(r'^orders/(?P<code>[0-9A-Z]+)/(?P<position>[0-9A-Z]+)/sendmail$', orders.OrderPositionSendMail.as_view(),
name='event.order.position.sendmail'),
re_path(r'^orders/(?P<code>[0-9A-Z]+)/mail_history$', orders.OrderEmailHistory.as_view(),
name='event.order.mail_history'),
re_path(r'^orders/(?P<code>[0-9A-Z]+)/payments/(?P<payment>\d+)/cancel$', orders.OrderPaymentCancel.as_view(),
name='event.order.payments.cancel'),
re_path(r'^orders/(?P<code>[0-9A-Z]+)/payments/(?P<payment>\d+)/confirm$', orders.OrderPaymentConfirm.as_view(),
name='event.order.payments.confirm'),
re_path(r'^orders/(?P<code>[0-9A-Z]+)/refund$', orders.OrderRefundView.as_view(),
name='event.order.refunds.start'),
re_path(r'^orders/(?P<code>[0-9A-Z]+)/refunds/(?P<refund>\d+)/cancel$', orders.OrderRefundCancel.as_view(),
name='event.order.refunds.cancel'),
re_path(r'^orders/(?P<code>[0-9A-Z]+)/refunds/(?P<refund>\d+)/process$', orders.OrderRefundProcess.as_view(),
name='event.order.refunds.process'),
re_path(r'^orders/(?P<code>[0-9A-Z]+)/refunds/(?P<refund>\d+)/done$', orders.OrderRefundDone.as_view(),
name='event.order.refunds.done'),
re_path(r'^orders/(?P<code>[0-9A-Z]+)/cancellationrequests/(?P<req>\d+)/delete$',
orders.OrderCancellationRequestDelete.as_view(),
name='event.order.cancellationrequests.delete'),
re_path(r'^orders/(?P<code>[0-9A-Z]+)/$', orders.OrderDetail.as_view(), name='event.order'),
re_path(r'^invoice/(?P<invoice>[^/]+)$', orders.InvoiceDownload.as_view(),
name='event.invoice.download'),
re_path(r'^orders/overview/$', orders.OverView.as_view(), name='event.orders.overview'),
re_path(r'^orders/import/$', orderimport.ImportView.as_view(), name='event.orders.import'),
re_path(r'^orders/import/(?P<file>[^/]+)/$', orderimport.ProcessView.as_view(), name='event.orders.import.process'),
re_path(r'^orders/export/$', orders.ExportView.as_view(), name='event.orders.export'),
re_path(r'^orders/export/do$', orders.ExportDoView.as_view(), name='event.orders.export.do'),
re_path(r'^orders/refunds/$', orders.RefundList.as_view(), name='event.orders.refunds'),
re_path(r'^orders/go$', orders.OrderGo.as_view(), name='event.orders.go'),
re_path(r'^orders/$', orders.OrderList.as_view(), name='event.orders'),
re_path(r'^orders/search$', orders.OrderSearch.as_view(), name='event.orders.search'),
re_path(r'^dangerzone/$', event.DangerZone.as_view(), name='event.dangerzone'),
re_path(r'^cancel/$', orders.EventCancel.as_view(), name='event.cancel'),
re_path(r'^shredder/$', shredder.StartShredView.as_view(), name='event.shredder.start'),
re_path(r'^shredder/export$', shredder.ShredExportView.as_view(), name='event.shredder.export'),
re_path(r'^shredder/download/(?P<file>[^/]+)/$', shredder.ShredDownloadView.as_view(), name='event.shredder.download'),
re_path(r'^shredder/shred', shredder.ShredDoView.as_view(), name='event.shredder.shred'),
re_path(r'^waitinglist/$', waitinglist.WaitingListView.as_view(), name='event.orders.waitinglist'),
re_path(r'^waitinglist/auto_assign$', waitinglist.AutoAssign.as_view(), name='event.orders.waitinglist.auto'),
re_path(r'^waitinglist/(?P<entry>\d+)/delete$', waitinglist.EntryDelete.as_view(),
name='event.orders.waitinglist.delete'),
re_path(r'^checkinlists/$', checkin.CheckinListList.as_view(), name='event.orders.checkinlists'),
re_path(r'^checkinlists/add$', checkin.CheckinListCreate.as_view(), name='event.orders.checkinlists.add'),
re_path(r'^checkinlists/select2$', typeahead.checkinlist_select2, name='event.orders.checkinlists.select2'),
re_path(r'^checkinlists/(?P<list>\d+)/$', checkin.CheckInListShow.as_view(), name='event.orders.checkinlists.show'),
re_path(r'^checkinlists/(?P<list>\d+)/change$', checkin.CheckinListUpdate.as_view(),
name='event.orders.checkinlists.edit'),
re_path(r'^checkinlists/(?P<list>\d+)/delete$', checkin.CheckinListDelete.as_view(),
name='event.orders.checkinlists.delete'),
])),
url(r'^event/(?P<organizer>[^/]+)/$', RedirectView.as_view(pattern_name='control:organizer'), name='event.organizerredirect'),
re_path(r'^event/(?P<organizer>[^/]+)/$', RedirectView.as_view(pattern_name='control:organizer'), name='event.organizerredirect'),
]

View File

@@ -19,7 +19,7 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
import collections
import collections.abc
import warnings
from django.core.paginator import (
@@ -86,7 +86,7 @@ class PaginationMixin:
return ctx
class LargeResultSetPage(collections.Sequence):
class LargeResultSetPage(collections.abc.Sequence):
def __init__(self, object_list, number, paginator):
self.object_list = object_list

View File

@@ -19,14 +19,4 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from django.apps import AppConfig
from .database import * # noqa
class PretixHelpersConfig(AppConfig):
name = 'pretix.helpers'
label = 'pretixhelpers'
default_app_config = 'pretix.helpers.PretixHelpersConfig'

View File

@@ -0,0 +1,27 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from django.apps import AppConfig
class PretixHelpersConfig(AppConfig):
name = 'pretix.helpers'
label = 'pretixhelpers'

View File

@@ -23,7 +23,6 @@ import contextlib
from django.db import transaction
from django.db.models import Aggregate, Field, Lookup
from django.db.models.expressions import OrderBy
class DummyRollbackException(Exception):
@@ -59,28 +58,6 @@ def casual_reads():
yield
class FixedOrderBy(OrderBy):
# Workaround for https://code.djangoproject.com/ticket/28848
template = '%(expression)s %(ordering)s'
def as_sql(self, compiler, connection, template=None, **extra_context):
if not template:
if self.nulls_last:
template = '%s NULLS LAST' % self.template
elif self.nulls_first:
template = '%s NULLS FIRST' % self.template
connection.ops.check_expression_support(self)
expression_sql, params = compiler.compile(self.expression)
placeholders = {
'expression': expression_sql,
'ordering': 'DESC' if self.descending else 'ASC',
}
placeholders.update(extra_context)
template = template or self.template
params = params * template.count('%(expression)s')
return (template % placeholders).rstrip(), params
class GroupConcat(Aggregate):
function = 'group_concat'
template = '%(function)s(%(field)s, "%(separator)s")'

View File

@@ -21,6 +21,7 @@
#
import copy
from django.core.files import File
from django.db import models
@@ -37,7 +38,7 @@ def modelcopy(obj: models.Model, **kwargs):
n = obj.__class__(**kwargs)
for f in obj._meta.fields:
val = getattr(obj, f.name)
if isinstance(val, models.Model):
if isinstance(val, (models.Model, File)):
setattr(n, f.name, copy.copy(val))
else:
setattr(n, f.name, copy.deepcopy(val))

View File

@@ -0,0 +1,94 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
import copy
from django.db import NotSupportedError
from django.db.models import Expression, JSONField
def postgres_compile_json_path(key_transforms):
return "{" + ','.join(key_transforms) + "}"
def mysql_compile_json_path(key_transforms):
path = ['$']
for key_transform in key_transforms:
try:
num = int(key_transform)
path.append('[{}]'.format(num))
except ValueError: # non-integer
path.append('.')
path.append(key_transform)
return ''.join(path)
sqlite_compile_json_path = mysql_compile_json_path
class JSONExtract(Expression):
def __init__(self, expression, *path, output_field=JSONField(), **extra):
super().__init__(output_field=output_field)
self.path = path
self.source_expression = self._parse_expressions(expression)[0]
self.extra = extra
def resolve_expression(self, query=None, allow_joins=True, reuse=None, summarize=False, for_save=False):
c = self.copy()
c.is_summary = summarize
c.source_expression = c.source_expression.resolve_expression(query, allow_joins, reuse, summarize, for_save)
return c
def as_sql(self, compiler, connection, function=None, template=None, arg_joiner=None, **extra_context):
if '.postgresql' in connection.settings_dict['ENGINE']:
params = []
arg_sql, arg_params = compiler.compile(self.source_expression)
params.extend(arg_params)
json_path = postgres_compile_json_path(self.path)
params.append(json_path)
template = '{} #> %s'.format(arg_sql)
return template, params
elif '.mysql' in connection.settings_dict['ENGINE']:
params = []
arg_sql, arg_params = compiler.compile(self.source_expression)
params.extend(arg_params)
json_path = mysql_compile_json_path(self.path)
params.append(json_path)
template = 'JSON_EXTRACT({}, %s)'.format(arg_sql)
return template, params
elif '.sqlite' in connection.settings_dict['ENGINE']:
params = []
arg_sql, arg_params = compiler.compile(self.source_expression)
params.extend(arg_params)
json_path = sqlite_compile_json_path(self.path)
params.append(json_path)
template = 'json_extract({}, %s)'.format(arg_sql)
return template, params
else:
raise NotSupportedError(
'Functions on JSONFields are only supported on SQLite, PostgreSQL, and MySQL at the moment.'
)
def copy(self):
c = super().copy()
c.source_expression = copy.copy(self.source_expression)
c.extra = self.extra.copy()
return c

View File

@@ -32,19 +32,10 @@
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under the License.
from django.apps import AppConfig
from django.urls import URLPattern
from django.urls.resolvers import RegexPattern
class PretixMultidomainConfig(AppConfig):
name = 'pretix.multidomain'
label = 'pretixmultidomain'
default_app_config = 'pretix.multidomain.PretixMultidomainConfig'
def event_url(route, view, name=None, require_live=True):
if callable(view):
pattern = RegexPattern(route, name=name, is_endpoint=True)

View File

@@ -0,0 +1,40 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
# This file is based on an earlier version of pretix which was released under the Apache License 2.0. The full text of
# the Apache License 2.0 can be obtained at <http://www.apache.org/licenses/LICENSE-2.0>.
#
# This file may have since been changed and any changes are released under the terms of AGPLv3 as described above. A
# full history of changes and contributors is available at <https://github.com/pretix/pretix>.
#
# This file contains Apache-licensed contributions copyrighted by: Tobias Kunze
#
# Unless required by applicable law or agreed to in writing, software distributed under the Apache License 2.0 is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under the License.
from django.apps import AppConfig
class PretixMultidomainConfig(AppConfig):
name = 'pretix.multidomain'
label = 'pretixmultidomain'

View File

@@ -22,15 +22,15 @@
import importlib.util
from django.apps import apps
from django.conf.urls import include, url
from django.conf.urls import include, re_path
from pretix.multidomain.plugin_handler import plugin_event_urls
from pretix.presale.urls import event_patterns, locale_patterns
from pretix.urls import common_patterns
presale_patterns = [
url(r'', include((locale_patterns + [
url(r'', include(event_patterns)),
re_path(r'', include((locale_patterns + [
re_path(r'', include(event_patterns)),
], 'presale')))
]
@@ -42,11 +42,11 @@ for app in apps.get_app_configs():
if hasattr(urlmod, 'event_patterns'):
patterns = plugin_event_urls(urlmod.event_patterns, plugin=app.name)
raw_plugin_patterns.append(
url(r'', include((patterns, app.label)))
re_path(r'', include((patterns, app.label)))
)
plugin_patterns = [
url(r'', include((raw_plugin_patterns, 'plugins')))
re_path(r'', include((raw_plugin_patterns, 'plugins')))
]
# The presale namespace comes last, because it contains a wildcard catch

View File

@@ -35,7 +35,7 @@
import importlib.util
from django.apps import apps
from django.conf.urls import include, url
from django.conf.urls import include, re_path
from django.views.generic import TemplateView
from pretix.multidomain.plugin_handler import plugin_event_urls
@@ -45,10 +45,10 @@ from pretix.presale.urls import (
from pretix.urls import common_patterns
presale_patterns_main = [
url(r'', include((locale_patterns + [
url(r'^(?P<organizer>[^/]+)/', include(organizer_patterns)),
url(r'^(?P<organizer>[^/]+)/(?P<event>[^/]+)/', include(event_patterns)),
url(r'^$', TemplateView.as_view(template_name='pretixpresale/index.html'), name="index")
re_path(r'', include((locale_patterns + [
re_path(r'^(?P<organizer>[^/]+)/', include(organizer_patterns)),
re_path(r'^(?P<organizer>[^/]+)/(?P<event>[^/]+)/', include(event_patterns)),
re_path(r'^$', TemplateView.as_view(template_name='pretixpresale/index.html'), name="index")
], 'presale')))
]
@@ -62,18 +62,18 @@ for app in apps.get_app_configs():
single_plugin_patterns += urlmod.urlpatterns
if hasattr(urlmod, 'event_patterns'):
patterns = plugin_event_urls(urlmod.event_patterns, plugin=app.name)
single_plugin_patterns.append(url(r'^(?P<organizer>[^/]+)/(?P<event>[^/]+)/',
include(patterns)))
single_plugin_patterns.append(re_path(r'^(?P<organizer>[^/]+)/(?P<event>[^/]+)/',
include(patterns)))
if hasattr(urlmod, 'organizer_patterns'):
patterns = urlmod.organizer_patterns
single_plugin_patterns.append(url(r'^(?P<organizer>[^/]+)/',
include(patterns)))
single_plugin_patterns.append(re_path(r'^(?P<organizer>[^/]+)/',
include(patterns)))
raw_plugin_patterns.append(
url(r'', include((single_plugin_patterns, app.label)))
re_path(r'', include((single_plugin_patterns, app.label)))
)
plugin_patterns = [
url(r'', include((raw_plugin_patterns, 'plugins')))
re_path(r'', include((raw_plugin_patterns, 'plugins')))
]
# The presale namespace comes last, because it contains a wildcard catch

View File

@@ -22,7 +22,7 @@
import importlib.util
from django.apps import apps
from django.conf.urls import include, url
from django.conf.urls import include, re_path
from pretix.multidomain.plugin_handler import plugin_event_urls
from pretix.presale.urls import (
@@ -31,9 +31,9 @@ from pretix.presale.urls import (
from pretix.urls import common_patterns
presale_patterns = [
url(r'', include((locale_patterns + [
url(r'', include(organizer_patterns)),
url(r'^(?P<event>[^/]+)/', include(event_patterns)),
re_path(r'', include((locale_patterns + [
re_path(r'', include(organizer_patterns)),
re_path(r'^(?P<event>[^/]+)/', include(event_patterns)),
], 'presale')))
]
@@ -45,16 +45,16 @@ for app in apps.get_app_configs():
if hasattr(urlmod, 'event_patterns'):
patterns = plugin_event_urls(urlmod.event_patterns, plugin=app.name)
raw_plugin_patterns.append(
url(r'^(?P<event>[^/]+)/', include((patterns, app.label)))
re_path(r'^(?P<event>[^/]+)/', include((patterns, app.label)))
)
if hasattr(urlmod, 'organizer_patterns'):
patterns = urlmod.organizer_patterns
raw_plugin_patterns.append(
url(r'', include((patterns, app.label)))
re_path(r'', include((patterns, app.label)))
)
plugin_patterns = [
url(r'', include((raw_plugin_patterns, 'plugins')))
re_path(r'', include((raw_plugin_patterns, 'plugins')))
]
# The presale namespace comes last, because it contains a wildcard catch

View File

@@ -19,32 +19,3 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from django.apps import AppConfig
from django.utils.translation import gettext, gettext_lazy as _
from pretix import __version__ as version
class BadgesApp(AppConfig):
name = 'pretix.plugins.badges'
verbose_name = _("Badges")
class PretixPluginMeta:
name = _("Badges")
author = _("the pretix team")
version = version
category = "FEATURE"
description = _("This plugin allows you to generate badges or name tags for your attendees.")
def ready(self):
from . import signals # NOQA
def installed(self, event):
if not event.badge_layouts.exists():
event.badge_layouts.create(
name=gettext('Default'),
default=True,
)
default_app_config = 'pretix.plugins.badges.BadgesApp'

View File

@@ -0,0 +1,47 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from django.apps import AppConfig
from django.utils.translation import gettext, gettext_lazy as _
from pretix import __version__ as version
class BadgesApp(AppConfig):
name = 'pretix.plugins.badges'
verbose_name = _("Badges")
class PretixPluginMeta:
name = _("Badges")
author = _("the pretix team")
version = version
category = "FEATURE"
description = _("This plugin allows you to generate badges or name tags for your attendees.")
def ready(self):
from . import signals # NOQA
def installed(self, event):
if not event.badge_layouts.exists():
event.badge_layouts.create(
name=gettext('Default'),
default=True,
)

View File

@@ -41,7 +41,6 @@ from typing import Tuple
import dateutil.parser
from django import forms
from django.conf import settings
from django.contrib.staticfiles import finders
from django.core.files import File
from django.core.files.storage import default_storage
@@ -49,7 +48,6 @@ from django.db.models import Exists, OuterRef, Q
from django.db.models.functions import Coalesce
from django.utils.timezone import make_aware
from django.utils.translation import gettext as _, gettext_lazy
from jsonfallback.functions import JSONExtract
from reportlab.lib import pagesizes
from reportlab.lib.units import mm
from reportlab.pdfgen import canvas
@@ -60,6 +58,7 @@ from pretix.base.models import Order, OrderPosition
from pretix.base.pdf import Renderer
from pretix.base.services.orders import OrderError
from pretix.base.settings import PERSON_NAME_SCHEMES
from pretix.helpers.templatetags.jsonfield import JSONExtract
from pretix.plugins.badges.models import BadgeItem, BadgeLayout
@@ -297,7 +296,7 @@ class BadgeExporter(BaseExporter):
] + ([
('name:{}'.format(k), _('Attendee name: {part}').format(part=label))
for k, label, w in name_scheme['fields']
] if settings.JSON_FIELD_AVAILABLE and len(name_scheme['fields']) > 1 else []),
] if len(name_scheme['fields']) > 1 else []),
)),
]
)

View File

@@ -19,7 +19,7 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from django.conf.urls import url
from django.conf.urls import re_path
from pretix.api.urls import event_router
from pretix.plugins.badges.api import BadgeItemViewSet, BadgeLayoutViewSet
@@ -30,18 +30,18 @@ from .views import (
)
urlpatterns = [
url(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/badges/$',
LayoutListView.as_view(), name='index'),
url(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/badges/print$',
OrderPrintDo.as_view(), name='print'),
url(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/badges/add$',
LayoutCreate.as_view(), name='add'),
url(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/badges/(?P<layout>\d+)/default$',
LayoutSetDefault.as_view(), name='default'),
url(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/badges/(?P<layout>\d+)/delete$',
LayoutDelete.as_view(), name='delete'),
url(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/badges/(?P<layout>\d+)/editor',
LayoutEditorView.as_view(), name='edit'),
re_path(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/badges/$',
LayoutListView.as_view(), name='index'),
re_path(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/badges/print$',
OrderPrintDo.as_view(), name='print'),
re_path(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/badges/add$',
LayoutCreate.as_view(), name='add'),
re_path(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/badges/(?P<layout>\d+)/default$',
LayoutSetDefault.as_view(), name='default'),
re_path(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/badges/(?P<layout>\d+)/delete$',
LayoutDelete.as_view(), name='delete'),
re_path(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/badges/(?P<layout>\d+)/editor',
LayoutEditorView.as_view(), name='edit'),
]
event_router.register('badgelayouts', BadgeLayoutViewSet)
event_router.register('badgeitems', BadgeItemViewSet)

View File

@@ -19,38 +19,3 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from django.apps import AppConfig
from django.utils.functional import cached_property
from django.utils.translation import gettext_lazy as _
from pretix import __version__ as version
class BankTransferApp(AppConfig):
name = 'pretix.plugins.banktransfer'
verbose_name = _("Bank transfer")
class PretixPluginMeta:
name = _("Bank transfer")
author = _("the pretix team")
category = 'PAYMENT'
version = version
description = _("This plugin allows you to receive payments " +
"via bank transfer.")
def ready(self):
from . import signals # NOQA
from . import tasks # NOQA
from .templatetags import commadecimal, dotdecimal # NOQA
@cached_property
def compatibility_warnings(self):
errs = []
try:
import chardet # NOQA
except ImportError:
errs.append(_("Install the python package 'chardet' for better CSV import capabilities."))
return errs
default_app_config = 'pretix.plugins.banktransfer.BankTransferApp'

View File

@@ -0,0 +1,53 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from django.apps import AppConfig
from django.utils.functional import cached_property
from django.utils.translation import gettext_lazy as _
from pretix import __version__ as version
class BankTransferApp(AppConfig):
name = 'pretix.plugins.banktransfer'
verbose_name = _("Bank transfer")
class PretixPluginMeta:
name = _("Bank transfer")
author = _("the pretix team")
category = 'PAYMENT'
version = version
description = _("This plugin allows you to receive payments " +
"via bank transfer.")
def ready(self):
from . import signals # NOQA
from . import tasks # NOQA
from .templatetags import commadecimal, dotdecimal # NOQA
@cached_property
def compatibility_warnings(self):
errs = []
try:
import chardet # NOQA
except ImportError:
errs.append(_("Install the python package 'chardet' for better CSV import capabilities."))
return errs

View File

@@ -19,7 +19,7 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from django.conf.urls import url
from django.conf.urls import re_path
from pretix.api.urls import orga_router
from pretix.plugins.banktransfer.api import BankImportJobViewSet
@@ -27,38 +27,38 @@ from pretix.plugins.banktransfer.api import BankImportJobViewSet
from . import views
urlpatterns = [
url(r'^control/organizer/(?P<organizer>[^/]+)/banktransfer/import/',
views.OrganizerImportView.as_view(),
name='import'),
url(r'^control/organizer/(?P<organizer>[^/]+)/banktransfer/job/(?P<job>\d+)/',
views.OrganizerJobDetailView.as_view(), name='import.job'),
url(r'^control/organizer/(?P<organizer>[^/]+)/banktransfer/action/',
views.OrganizerActionView.as_view(), name='import.action'),
url(r'^control/organizer/(?P<organizer>[^/]+)/banktransfer/refunds/',
views.OrganizerRefundExportListView.as_view(), name='refunds.list'),
url(r'^control/organizer/(?P<organizer>[^/]+)/banktransfer/export/(?P<id>\d+)/$',
views.OrganizerDownloadRefundExportView.as_view(),
name='refunds.download'),
url(r'^control/organizer/(?P<organizer>[^/]+)/banktransfer/sepa-export/(?P<id>\d+)/$',
views.OrganizerSepaXMLExportView.as_view(),
name='refunds.sepa'),
re_path(r'^control/organizer/(?P<organizer>[^/]+)/banktransfer/import/',
views.OrganizerImportView.as_view(),
name='import'),
re_path(r'^control/organizer/(?P<organizer>[^/]+)/banktransfer/job/(?P<job>\d+)/',
views.OrganizerJobDetailView.as_view(), name='import.job'),
re_path(r'^control/organizer/(?P<organizer>[^/]+)/banktransfer/action/',
views.OrganizerActionView.as_view(), name='import.action'),
re_path(r'^control/organizer/(?P<organizer>[^/]+)/banktransfer/refunds/',
views.OrganizerRefundExportListView.as_view(), name='refunds.list'),
re_path(r'^control/organizer/(?P<organizer>[^/]+)/banktransfer/export/(?P<id>\d+)/$',
views.OrganizerDownloadRefundExportView.as_view(),
name='refunds.download'),
re_path(r'^control/organizer/(?P<organizer>[^/]+)/banktransfer/sepa-export/(?P<id>\d+)/$',
views.OrganizerSepaXMLExportView.as_view(),
name='refunds.sepa'),
url(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/banktransfer/import/',
views.EventImportView.as_view(),
name='import'),
url(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/banktransfer/job/(?P<job>\d+)/',
views.EventJobDetailView.as_view(), name='import.job'),
url(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/banktransfer/action/',
views.EventActionView.as_view(), name='import.action'),
url(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/banktransfer/refunds/',
views.EventRefundExportListView.as_view(),
name='refunds.list'),
url(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/banktransfer/export/(?P<id>\d+)/$',
views.EventDownloadRefundExportView.as_view(),
name='refunds.download'),
url(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/banktransfer/sepa-export/(?P<id>\d+)/$',
views.EventSepaXMLExportView.as_view(),
name='refunds.sepa'),
re_path(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/banktransfer/import/',
views.EventImportView.as_view(),
name='import'),
re_path(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/banktransfer/job/(?P<job>\d+)/',
views.EventJobDetailView.as_view(), name='import.job'),
re_path(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/banktransfer/action/',
views.EventActionView.as_view(), name='import.action'),
re_path(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/banktransfer/refunds/',
views.EventRefundExportListView.as_view(),
name='refunds.list'),
re_path(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/banktransfer/export/(?P<id>\d+)/$',
views.EventDownloadRefundExportView.as_view(),
name='refunds.download'),
re_path(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/banktransfer/sepa-export/(?P<id>\d+)/$',
views.EventSepaXMLExportView.as_view(),
name='refunds.sepa'),
]
orga_router.register('bankimportjobs', BankImportJobViewSet)

View File

@@ -31,36 +31,3 @@
# Unless required by applicable law or agreed to in writing, software distributed under the Apache License 2.0 is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under the License.
from django.apps import AppConfig
from django.utils.functional import cached_property
from django.utils.translation import gettext_lazy as _
from pretix import __version__ as version
class CheckinlistsApp(AppConfig):
name = 'pretix.plugins.checkinlists'
verbose_name = _("Check-in lists")
class PretixPluginMeta:
name = _("Check-in list exporter")
author = _("the pretix team")
version = version
visible = False
description = _("This plugin allows you to generate check-in lists for your conference.")
def ready(self):
from . import signals # NOQA
@cached_property
def compatibility_errors(self):
errs = []
try:
import reportlab # NOQA
except ImportError:
errs.append("Python package 'reportlab' is not installed.")
return errs
default_app_config = 'pretix.plugins.checkinlists.CheckinlistsApp'

View File

@@ -0,0 +1,63 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
# This file is based on an earlier version of pretix which was released under the Apache License 2.0. The full text of
# the Apache License 2.0 can be obtained at <http://www.apache.org/licenses/LICENSE-2.0>.
#
# This file may have since been changed and any changes are released under the terms of AGPLv3 as described above. A
# full history of changes and contributors is available at <https://github.com/pretix/pretix>.
#
# This file contains Apache-licensed contributions copyrighted by: Tobias Kunze
#
# Unless required by applicable law or agreed to in writing, software distributed under the Apache License 2.0 is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under the License.
from django.apps import AppConfig
from django.utils.functional import cached_property
from django.utils.translation import gettext_lazy as _
from pretix import __version__ as version
class CheckinlistsApp(AppConfig):
name = 'pretix.plugins.checkinlists'
verbose_name = _("Check-in lists")
class PretixPluginMeta:
name = _("Check-in list exporter")
author = _("the pretix team")
version = version
visible = False
description = _("This plugin allows you to generate check-in lists for your conference.")
def ready(self):
from . import signals # NOQA
@cached_property
def compatibility_errors(self):
errs = []
try:
import reportlab # NOQA
except ImportError:
errs.append("Python package 'reportlab' is not installed.")
return errs

View File

@@ -37,7 +37,6 @@ from datetime import datetime, time, timedelta
import dateutil.parser
from django import forms
from django.conf import settings
from django.db.models import (
Case, Exists, Max, OuterRef, Q, Subquery, Value, When,
)
@@ -46,7 +45,6 @@ from django.urls import reverse
from django.utils.formats import date_format
from django.utils.timezone import is_aware, make_aware
from django.utils.translation import gettext as _, gettext_lazy, pgettext
from jsonfallback.functions import JSONExtract
from pytz import UTC
from reportlab.lib.units import mm
from reportlab.platypus import Flowable, Paragraph, Spacer, Table, TableStyle
@@ -58,6 +56,7 @@ from pretix.base.models import (
from pretix.base.settings import PERSON_NAME_SCHEMES
from pretix.base.templatetags.money import money_filter
from pretix.control.forms.widgets import Select2
from pretix.helpers.templatetags.jsonfield import JSONExtract
from pretix.plugins.reports.exporters import ReportlabExportMixin
@@ -110,7 +109,7 @@ class CheckInListMixin(BaseExporter):
] + ([
('name:{}'.format(k), _('Attendee name: {part}').format(part=label))
for k, label, w in name_scheme['fields']
] if settings.JSON_FIELD_AVAILABLE and len(name_scheme['fields']) > 1 else []),
] if len(name_scheme['fields']) > 1 else []),
widget=forms.RadioSelect,
required=False
)),

View File

@@ -19,22 +19,3 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
from pretix import __version__ as version
class ManualPaymentApp(AppConfig):
name = 'pretix.plugins.manualpayment'
verbose_name = _("Manual payment")
class PretixPluginMeta:
name = _("Manual payment")
author = _("the pretix team")
version = version
category = 'PAYMENT'
description = _("This plugin adds a customizable payment method for manual processing.")
default_app_config = 'pretix.plugins.manualpayment.ManualPaymentApp'

View File

@@ -0,0 +1,37 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
from pretix import __version__ as version
class ManualPaymentApp(AppConfig):
name = 'pretix.plugins.manualpayment'
verbose_name = _("Manual payment")
class PretixPluginMeta:
name = _("Manual payment")
author = _("the pretix team")
version = version
category = 'PAYMENT'
description = _("This plugin adds a customizable payment method for manual processing.")

View File

@@ -31,36 +31,3 @@
# Unless required by applicable law or agreed to in writing, software distributed under the Apache License 2.0 is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under the License.
from django.apps import AppConfig
from django.utils.functional import cached_property
from django.utils.translation import gettext_lazy as _
from pretix import __version__ as version
class PaypalApp(AppConfig):
name = 'pretix.plugins.paypal'
verbose_name = _("PayPal")
class PretixPluginMeta:
name = _("PayPal")
author = _("the pretix team")
version = version
category = 'PAYMENT'
description = _("This plugin allows you to receive payments via PayPal")
def ready(self):
from . import signals # NOQA
@cached_property
def compatibility_errors(self):
errs = []
try:
import paypalrestsdk # NOQA
except ImportError:
errs.append("Python package 'paypalrestsdk' is not installed.")
return errs
default_app_config = 'pretix.plugins.paypal.PaypalApp'

View File

@@ -0,0 +1,63 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
# This file is based on an earlier version of pretix which was released under the Apache License 2.0. The full text of
# the Apache License 2.0 can be obtained at <http://www.apache.org/licenses/LICENSE-2.0>.
#
# This file may have since been changed and any changes are released under the terms of AGPLv3 as described above. A
# full history of changes and contributors is available at <https://github.com/pretix/pretix>.
#
# This file contains Apache-licensed contributions copyrighted by: Tobias Kunze
#
# Unless required by applicable law or agreed to in writing, software distributed under the Apache License 2.0 is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under the License.
from django.apps import AppConfig
from django.utils.functional import cached_property
from django.utils.translation import gettext_lazy as _
from pretix import __version__ as version
class PaypalApp(AppConfig):
name = 'pretix.plugins.paypal'
verbose_name = _("PayPal")
class PretixPluginMeta:
name = _("PayPal")
author = _("the pretix team")
version = version
category = 'PAYMENT'
description = _("This plugin allows you to receive payments via PayPal")
def ready(self):
from . import signals # NOQA
@cached_property
def compatibility_errors(self):
errs = []
try:
import paypalrestsdk # NOQA
except ImportError:
errs.append("Python package 'paypalrestsdk' is not installed.")
return errs

View File

@@ -19,7 +19,7 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from django.conf.urls import include, url
from django.conf.urls import include, re_path
from pretix.multidomain import event_url
@@ -28,22 +28,21 @@ from .views import (
)
event_patterns = [
url(r'^paypal/', include([
url(r'^abort/$', abort, name='abort'),
url(r'^return/$', success, name='return'),
url(r'^redirect/$', redirect_view, name='redirect'),
re_path(r'^paypal/', include([
re_path(r'^abort/$', abort, name='abort'),
re_path(r'^return/$', success, name='return'),
re_path(r'^redirect/$', redirect_view, name='redirect'),
url(r'w/(?P<cart_namespace>[a-zA-Z0-9]{16})/abort/', abort, name='abort'),
url(r'w/(?P<cart_namespace>[a-zA-Z0-9]{16})/return/', success, name='return'),
re_path(r'w/(?P<cart_namespace>[a-zA-Z0-9]{16})/abort/', abort, name='abort'),
re_path(r'w/(?P<cart_namespace>[a-zA-Z0-9]{16})/return/', success, name='return'),
event_url(r'^webhook/$', webhook, name='webhook', require_live=False),
])),
]
urlpatterns = [
url(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/paypal/disconnect/',
oauth_disconnect, name='oauth.disconnect'),
url(r'^_paypal/webhook/$', webhook, name='webhook'),
url(r'^_paypal/oauth_return/$', oauth_return, name='oauth.return'),
re_path(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/paypal/disconnect/',
oauth_disconnect, name='oauth.disconnect'),
re_path(r'^_paypal/webhook/$', webhook, name='webhook'),
re_path(r'^_paypal/oauth_return/$', oauth_return, name='oauth.return'),
]

View File

@@ -19,24 +19,3 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
from pretix import __version__ as version
class PretixdroidApp(AppConfig):
name = 'pretix.plugins.pretixdroid'
verbose_name = _("Old check-in device API")
class PretixPluginMeta:
name = _("Old check-in device API")
author = _("the pretix team")
version = version
visible = False
restricted = True
category = 'INTEGRATION'
description = _("This plugin allows you to use the pretixdroid and pretixdesk apps for your event.")
default_app_config = 'pretix.plugins.pretixdroid.PretixdroidApp'

View File

@@ -0,0 +1,39 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
from pretix import __version__ as version
class PretixdroidApp(AppConfig):
name = 'pretix.plugins.pretixdroid'
verbose_name = _("Old check-in device API")
class PretixPluginMeta:
name = _("Old check-in device API")
author = _("the pretix team")
version = version
visible = False
restricted = True
category = 'INTEGRATION'
description = _("This plugin allows you to use the pretixdroid and pretixdesk apps for your event.")

View File

@@ -31,36 +31,3 @@
# Unless required by applicable law or agreed to in writing, software distributed under the Apache License 2.0 is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under the License.
from django.apps import AppConfig
from django.utils.functional import cached_property
from django.utils.translation import gettext_lazy as _
from pretix import __version__ as version
class ReportsApp(AppConfig):
name = 'pretix.plugins.reports'
verbose_name = _("Report exporter")
class PretixPluginMeta:
name = _("Report exporter")
author = _("the pretix team")
version = version
category = 'FORMAT'
description = _("This plugin allows you to generate printable reports about your sales.")
def ready(self):
from . import signals # NOQA
@cached_property
def compatibility_errors(self):
errs = []
try:
import reportlab # NOQA
except ImportError:
errs.append("Python package 'reportlab' is not installed.")
return errs
default_app_config = 'pretix.plugins.reports.ReportsApp'

View File

@@ -0,0 +1,63 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
# This file is based on an earlier version of pretix which was released under the Apache License 2.0. The full text of
# the Apache License 2.0 can be obtained at <http://www.apache.org/licenses/LICENSE-2.0>.
#
# This file may have since been changed and any changes are released under the terms of AGPLv3 as described above. A
# full history of changes and contributors is available at <https://github.com/pretix/pretix>.
#
# This file contains Apache-licensed contributions copyrighted by: Tobias Kunze
#
# Unless required by applicable law or agreed to in writing, software distributed under the Apache License 2.0 is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under the License.
from django.apps import AppConfig
from django.utils.functional import cached_property
from django.utils.translation import gettext_lazy as _
from pretix import __version__ as version
class ReportsApp(AppConfig):
name = 'pretix.plugins.reports'
verbose_name = _("Report exporter")
class PretixPluginMeta:
name = _("Report exporter")
author = _("the pretix team")
version = version
category = 'FORMAT'
description = _("This plugin allows you to generate printable reports about your sales.")
def ready(self):
from . import signals # NOQA
@cached_property
def compatibility_errors(self):
errs = []
try:
import reportlab # NOQA
except ImportError:
errs.append("Python package 'reportlab' is not installed.")
return errs

View File

@@ -19,26 +19,3 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
from pretix import __version__ as version
class ReturnURLApp(AppConfig):
name = 'pretix.plugins.returnurl'
verbose_name = _("Redirection from order page")
class PretixPluginMeta:
name = _("Redirection from order page")
author = _("the pretix team")
version = version
category = 'API'
description = _("This plugin allows to link to payments and redirect back afterwards. This is useful in "
"combination with our API.")
def ready(self):
from . import signals # NOQA
default_app_config = 'pretix.plugins.returnurl.ReturnURLApp'

View File

@@ -0,0 +1,41 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
from pretix import __version__ as version
class ReturnURLApp(AppConfig):
name = 'pretix.plugins.returnurl'
verbose_name = _("Redirection from order page")
class PretixPluginMeta:
name = _("Redirection from order page")
author = _("the pretix team")
version = version
category = 'API'
description = _("This plugin allows to link to payments and redirect back afterwards. This is useful in "
"combination with our API.")
def ready(self):
from . import signals # NOQA

View File

@@ -19,11 +19,11 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from django.conf.urls import url
from django.conf.urls import re_path
from .views import ReturnSettings
urlpatterns = [
url(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/returnurl/settings$',
ReturnSettings.as_view(), name='settings'),
re_path(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/returnurl/settings$',
ReturnSettings.as_view(), name='settings'),
]

View File

@@ -19,27 +19,3 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
from pretix import __version__ as version
class SendMailApp(AppConfig):
name = 'pretix.plugins.sendmail'
verbose_name = _("Send out emails")
class PretixPluginMeta:
name = _("Send out emails")
author = _("the pretix team")
category = 'FEATURE'
version = version
description = _("This plugin allows you to send out emails " +
"to all your customers.")
def ready(self):
from . import signals # NOQA
from . import tasks # NOQA
default_app_config = 'pretix.plugins.sendmail.SendMailApp'

View File

@@ -0,0 +1,42 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
from pretix import __version__ as version
class SendMailApp(AppConfig):
name = 'pretix.plugins.sendmail'
verbose_name = _("Send out emails")
class PretixPluginMeta:
name = _("Send out emails")
author = _("the pretix team")
category = 'FEATURE'
version = version
description = _("This plugin allows you to send out emails " +
"to all your customers.")
def ready(self):
from . import signals # NOQA
from . import tasks # NOQA

View File

@@ -32,12 +32,12 @@
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under the License.
from django.conf.urls import url
from django.conf.urls import re_path
from . import views
urlpatterns = [
url(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/sendmail/$', views.SenderView.as_view(),
name='send'),
url(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/sendmail/history/', views.EmailHistoryView.as_view(), name='history')
re_path(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/sendmail/$', views.SenderView.as_view(),
name='send'),
re_path(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/sendmail/history/', views.EmailHistoryView.as_view(), name='history')
]

View File

@@ -19,25 +19,3 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
from pretix import __version__ as version
class StatisticsApp(AppConfig):
name = 'pretix.plugins.statistics'
verbose_name = _("Statistics")
class PretixPluginMeta:
name = _("Statistics")
author = _("the pretix team")
version = version
category = 'FEATURE'
description = _("This plugin shows you various statistics.")
def ready(self):
from . import signals # NOQA
default_app_config = 'pretix.plugins.statistics.StatisticsApp'

View File

@@ -0,0 +1,40 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
from pretix import __version__ as version
class StatisticsApp(AppConfig):
name = 'pretix.plugins.statistics'
verbose_name = _("Statistics")
class PretixPluginMeta:
name = _("Statistics")
author = _("the pretix team")
version = version
category = 'FEATURE'
description = _("This plugin shows you various statistics.")
def ready(self):
from . import signals # NOQA

View File

@@ -19,11 +19,11 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from django.conf.urls import url
from django.conf.urls import re_path
from . import views
urlpatterns = [
url(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/statistics/', views.IndexView.as_view(),
name='index'),
re_path(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/statistics/', views.IndexView.as_view(),
name='index'),
]

View File

@@ -19,36 +19,3 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from django.apps import AppConfig
from django.utils.functional import cached_property
from django.utils.translation import gettext_lazy as _
from pretix import __version__ as version
class StripeApp(AppConfig):
name = 'pretix.plugins.stripe'
verbose_name = _("Stripe")
class PretixPluginMeta:
name = _("Stripe")
author = _("the pretix team")
version = version
category = 'PAYMENT'
description = _("This plugin allows you to receive credit card payments " +
"via Stripe")
def ready(self):
from . import signals, tasks # NOQA
@cached_property
def compatibility_errors(self):
errs = []
try:
import stripe # NOQA
except ImportError:
errs.append("Python package 'stripe' is not installed.")
return errs
default_app_config = 'pretix.plugins.stripe.StripeApp'

View File

@@ -0,0 +1,51 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from django.apps import AppConfig
from django.utils.functional import cached_property
from django.utils.translation import gettext_lazy as _
from pretix import __version__ as version
class StripeApp(AppConfig):
name = 'pretix.plugins.stripe'
verbose_name = _("Stripe")
class PretixPluginMeta:
name = _("Stripe")
author = _("the pretix team")
version = version
category = 'PAYMENT'
description = _("This plugin allows you to receive credit card payments " +
"via Stripe")
def ready(self):
from . import signals, tasks # NOQA
@cached_property
def compatibility_errors(self):
errs = []
try:
import stripe # NOQA
except ImportError:
errs.append("Python package 'stripe' is not installed.")
return errs

View File

@@ -19,7 +19,7 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from django.conf.urls import include, url
from django.conf.urls import include, re_path
from pretix.multidomain import event_url
@@ -30,30 +30,30 @@ from .views import (
)
event_patterns = [
url(r'^stripe/', include([
re_path(r'^stripe/', include([
event_url(r'^webhook/$', webhook, name='webhook', require_live=False),
url(r'^redirect/$', redirect_view, name='redirect'),
url(r'^return/(?P<order>[^/]+)/(?P<hash>[^/]+)/(?P<payment>[0-9]+)/$', ReturnView.as_view(), name='return'),
url(r'^sca/(?P<order>[^/]+)/(?P<hash>[^/]+)/(?P<payment>[0-9]+)/$', ScaView.as_view(), name='sca'),
url(r'^sca/(?P<order>[^/]+)/(?P<hash>[^/]+)/(?P<payment>[0-9]+)/return/$',
ScaReturnView.as_view(), name='sca.return'),
re_path(r'^redirect/$', redirect_view, name='redirect'),
re_path(r'^return/(?P<order>[^/]+)/(?P<hash>[^/]+)/(?P<payment>[0-9]+)/$', ReturnView.as_view(), name='return'),
re_path(r'^sca/(?P<order>[^/]+)/(?P<hash>[^/]+)/(?P<payment>[0-9]+)/$', ScaView.as_view(), name='sca'),
re_path(r'^sca/(?P<order>[^/]+)/(?P<hash>[^/]+)/(?P<payment>[0-9]+)/return/$',
ScaReturnView.as_view(), name='sca.return'),
])),
url(r'^.well-known/apple-developer-merchantid-domain-association$',
applepay_association, name='applepay.association'),
re_path(r'^.well-known/apple-developer-merchantid-domain-association$',
applepay_association, name='applepay.association'),
]
organizer_patterns = [
url(r'^.well-known/apple-developer-merchantid-domain-association$',
applepay_association, name='applepay.association'),
re_path(r'^.well-known/apple-developer-merchantid-domain-association$',
applepay_association, name='applepay.association'),
]
urlpatterns = [
url(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/stripe/disconnect/',
oauth_disconnect, name='oauth.disconnect'),
url(r'^control/organizer/(?P<organizer>[^/]+)/stripeconnect/',
OrganizerSettingsFormView.as_view(), name='settings.connect'),
url(r'^_stripe/webhook/$', webhook, name='webhook'),
url(r'^_stripe/oauth_return/$', oauth_return, name='oauth.return'),
url(r'^.well-known/apple-developer-merchantid-domain-association$',
applepay_association, name='applepay.association'),
re_path(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/stripe/disconnect/',
oauth_disconnect, name='oauth.disconnect'),
re_path(r'^control/organizer/(?P<organizer>[^/]+)/stripeconnect/',
OrganizerSettingsFormView.as_view(), name='settings.connect'),
re_path(r'^_stripe/webhook/$', webhook, name='webhook'),
re_path(r'^_stripe/oauth_return/$', oauth_return, name='oauth.return'),
re_path(r'^.well-known/apple-developer-merchantid-domain-association$',
applepay_association, name='applepay.association'),
]

View File

@@ -31,36 +31,3 @@
# Unless required by applicable law or agreed to in writing, software distributed under the Apache License 2.0 is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under the License.
from django.apps import AppConfig
from django.utils.functional import cached_property
from django.utils.translation import gettext_lazy as _
from pretix import __version__ as version
class TicketOutputPdfApp(AppConfig):
name = 'pretix.plugins.ticketoutputpdf'
verbose_name = _("PDF ticket output")
class PretixPluginMeta:
name = _("PDF ticket output")
author = _("the pretix team")
version = version
category = 'FORMAT'
description = _("This plugin allows you to print out tickets as PDF files")
def ready(self):
from . import signals # NOQA
@cached_property
def compatibility_errors(self):
errs = []
try:
import reportlab # NOQA
except ImportError:
errs.append("Python package 'reportlab' is not installed.")
return errs
default_app_config = 'pretix.plugins.ticketoutputpdf.TicketOutputPdfApp'

View File

@@ -0,0 +1,63 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
# This file is based on an earlier version of pretix which was released under the Apache License 2.0. The full text of
# the Apache License 2.0 can be obtained at <http://www.apache.org/licenses/LICENSE-2.0>.
#
# This file may have since been changed and any changes are released under the terms of AGPLv3 as described above. A
# full history of changes and contributors is available at <https://github.com/pretix/pretix>.
#
# This file contains Apache-licensed contributions copyrighted by: Tobias Kunze
#
# Unless required by applicable law or agreed to in writing, software distributed under the Apache License 2.0 is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under the License.
from django.apps import AppConfig
from django.utils.functional import cached_property
from django.utils.translation import gettext_lazy as _
from pretix import __version__ as version
class TicketOutputPdfApp(AppConfig):
name = 'pretix.plugins.ticketoutputpdf'
verbose_name = _("PDF ticket output")
class PretixPluginMeta:
name = _("PDF ticket output")
author = _("the pretix team")
version = version
category = 'FORMAT'
description = _("This plugin allows you to print out tickets as PDF files")
def ready(self):
from . import signals # NOQA
@cached_property
def compatibility_errors(self):
errs = []
try:
import reportlab # NOQA
except ImportError:
errs.append("Python package 'reportlab' is not installed.")
return errs

View File

@@ -38,13 +38,11 @@ from io import BytesIO
import dateutil.parser
from django import forms
from django.conf import settings
from django.core.files.base import ContentFile
from django.db.models import Q
from django.db.models.functions import Coalesce
from django.utils.timezone import make_aware
from django.utils.translation import gettext as _, gettext_lazy
from jsonfallback.functions import JSONExtract
from PyPDF2.merger import PdfFileMerger
from pretix.base.exporter import BaseExporter
@@ -52,6 +50,7 @@ from pretix.base.i18n import language
from pretix.base.models import Event, Order, OrderPosition
from pretix.base.settings import PERSON_NAME_SCHEMES
from ...helpers.templatetags.jsonfield import JSONExtract
from .ticketoutput import PdfTicketOutput
@@ -94,7 +93,7 @@ class AllTicketsPDF(BaseExporter):
] + ([
('name:{}'.format(k), _('Attendee name: {part}').format(part=label))
for k, label, w in name_scheme['fields']
] if settings.JSON_FIELD_AVAILABLE and name_scheme and len(name_scheme['fields']) > 1 else []),
] if name_scheme and len(name_scheme['fields']) > 1 else []),
)),
]
)

View File

@@ -152,10 +152,10 @@ def pdf_logentry_object_link(sender, logentry, **kwargs):
return a_text.format_map(a_map)
override_layout = EventPluginSignal(
providing_args=["layout", "orderposition"]
)
override_layout = EventPluginSignal()
"""
Arguments: ``layout``, ``orderposition``
This signal allows you to forcefully override the ticket layout that is being used to create the ticket PDF. Use with
care, as this will render any specifically by the organizer selected templates useless.

View File

@@ -19,7 +19,7 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from django.conf.urls import url
from django.conf.urls import re_path
from pretix.api.urls import event_router
from pretix.plugins.ticketoutputpdf.api import (
@@ -31,18 +31,18 @@ from pretix.plugins.ticketoutputpdf.views import (
)
urlpatterns = [
url(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/pdfoutput/$',
LayoutListView.as_view(), name='index'),
url(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/pdfoutput/add$',
LayoutCreate.as_view(), name='add'),
url(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/pdfoutput/(?P<layout>\d+)/default$',
LayoutSetDefault.as_view(), name='default'),
url(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/pdfoutput/default$',
LayoutGetDefault.as_view(), name='getdefault'),
url(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/pdfoutput/(?P<layout>\d+)/delete$',
LayoutDelete.as_view(), name='delete'),
url(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/pdfoutput/(?P<layout>\d+)/editor',
LayoutEditorView.as_view(), name='edit'),
re_path(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/pdfoutput/$',
LayoutListView.as_view(), name='index'),
re_path(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/pdfoutput/add$',
LayoutCreate.as_view(), name='add'),
re_path(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/pdfoutput/(?P<layout>\d+)/default$',
LayoutSetDefault.as_view(), name='default'),
re_path(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/pdfoutput/default$',
LayoutGetDefault.as_view(), name='getdefault'),
re_path(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/pdfoutput/(?P<layout>\d+)/delete$',
LayoutDelete.as_view(), name='delete'),
re_path(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/pdfoutput/(?P<layout>\d+)/editor',
LayoutEditorView.as_view(), name='edit'),
]
event_router.register('ticketlayouts', TicketLayoutViewSet)
event_router.register('ticketlayoutitems', TicketLayoutItemViewSet)

View File

@@ -19,25 +19,3 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
from pretix import __version__ as version
class WebCheckinApp(AppConfig):
name = 'pretix.plugins.webcheckin'
verbose_name = _("Web-based check-in")
class PretixPluginMeta:
name = _("Web-based check-in")
author = _("the pretix team")
version = version
category = "FEATURE"
description = _("This plugin allows you to perform check-in actions in your browser.")
def ready(self):
from . import signals # NOQA
default_app_config = 'pretix.plugins.webcheckin.WebCheckinApp'

Some files were not shown because too many files have changed in this diff Show More