Compare commits

...

8 Commits

Author SHA1 Message Date
Raphael Michel
2fd81a2d20 Disable scopes for a management command 2019-06-17 10:46:10 +02:00
Raphael Michel
4271245a4a Disable scopes for get_Events_with_any_permission 2019-06-17 10:16:53 +02:00
Raphael Michel
b41139a143 Fix tests after rebase 2019-06-17 10:08:42 +02:00
Raphael Michel
a68b225529 Remove unused import 2019-06-17 10:04:54 +02:00
Raphael Michel
c12ba88ad8 Fix remaining tests 2019-06-17 10:04:54 +02:00
Raphael Michel
69a80f2540 Update tasks and cronjobs 2019-06-17 10:04:54 +02:00
Raphael Michel
867667cd12 Fix tests.api 2019-06-17 10:04:54 +02:00
Raphael Michel
5c06c41a5b Install django-scopes 2019-06-17 10:04:54 +02:00
130 changed files with 6253 additions and 4509 deletions

View File

@@ -1,4 +1,5 @@
from django.contrib.auth.models import AnonymousUser from django.contrib.auth.models import AnonymousUser
from django_scopes import scopes_disabled
from rest_framework import exceptions from rest_framework import exceptions
from rest_framework.authentication import TokenAuthentication from rest_framework.authentication import TokenAuthentication
@@ -12,7 +13,8 @@ class DeviceTokenAuthentication(TokenAuthentication):
def authenticate_credentials(self, key): def authenticate_credentials(self, key):
model = self.get_model() model = self.get_model()
try: try:
device = model.objects.select_related('organizer').get(api_token=key) with scopes_disabled():
device = model.objects.select_related('organizer').get(api_token=key)
except model.DoesNotExist: except model.DoesNotExist:
raise exceptions.AuthenticationFailed('Invalid token.') raise exceptions.AuthenticationFailed('Invalid token.')

View File

@@ -3,7 +3,7 @@ from rest_framework.permissions import SAFE_METHODS, BasePermission
from pretix.api.models import OAuthAccessToken from pretix.api.models import OAuthAccessToken
from pretix.base.models import Device, Event, User from pretix.base.models import Device, Event, User
from pretix.base.models.auth import SuperuserPermissionSet from pretix.base.models.auth import SuperuserPermissionSet
from pretix.base.models.organizer import Organizer, TeamAPIToken from pretix.base.models.organizer import TeamAPIToken
from pretix.helpers.security import ( from pretix.helpers.security import (
SessionInvalid, SessionReauthRequired, assert_session_valid, SessionInvalid, SessionReauthRequired, assert_session_valid,
) )
@@ -50,9 +50,6 @@ class EventPermission(BasePermission):
return False return False
elif 'organizer' in request.resolver_match.kwargs: elif 'organizer' in request.resolver_match.kwargs:
request.organizer = Organizer.objects.filter(
slug=request.resolver_match.kwargs['organizer'],
).first()
if not request.organizer or not perm_holder.has_organizer_permission(request.organizer, request=request): if not request.organizer or not perm_holder.has_organizer_permission(request.organizer, request=request):
return False return False
if isinstance(perm_holder, User) and perm_holder.has_active_staff_session(request.session.session_key): if isinstance(perm_holder, User) and perm_holder.has_active_staff_session(request.session.session_key):

View File

@@ -4,10 +4,13 @@ from hashlib import sha1
from django.conf import settings from django.conf import settings
from django.db import transaction from django.db import transaction
from django.http import HttpRequest, HttpResponse, JsonResponse from django.http import HttpRequest, HttpResponse, JsonResponse
from django.urls import resolve
from django.utils.timezone import now from django.utils.timezone import now
from django_scopes import scope
from rest_framework import status from rest_framework import status
from pretix.api.models import ApiCall from pretix.api.models import ApiCall
from pretix.base.models import Organizer
class IdempotencyMiddleware: class IdempotencyMiddleware:
@@ -89,3 +92,21 @@ class IdempotencyMiddleware:
for k, v in json.loads(call.response_headers).values(): for k, v in json.loads(call.response_headers).values():
r[k] = v r[k] = v
return r return r
class ApiScopeMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request: HttpRequest):
if not request.path.startswith('/api/'):
return self.get_response(request)
url = resolve(request.path_info)
if 'organizer' in url.kwargs:
request.organizer = Organizer.objects.filter(
slug=url.kwargs['organizer'],
).first()
with scope(organizer=getattr(request, 'organizer', None)):
return self.get_response(request)

View File

@@ -2,6 +2,7 @@ from datetime import timedelta
from django.dispatch import Signal, receiver from django.dispatch import Signal, receiver
from django.utils.timezone import now from django.utils.timezone import now
from django_scopes import scopes_disabled
from pretix.api.models import ApiCall, WebHookCall from pretix.api.models import ApiCall, WebHookCall
from pretix.base.signals import periodic_task from pretix.base.signals import periodic_task
@@ -17,10 +18,12 @@ instances.
@receiver(periodic_task) @receiver(periodic_task)
@scopes_disabled()
def cleanup_webhook_logs(sender, **kwargs): def cleanup_webhook_logs(sender, **kwargs):
WebHookCall.objects.filter(datetime__lte=now() - timedelta(days=30)).delete() WebHookCall.objects.filter(datetime__lte=now() - timedelta(days=30)).delete()
@receiver(periodic_task) @receiver(periodic_task)
@scopes_disabled()
def cleanup_api_logs(sender, **kwargs): def cleanup_api_logs(sender, **kwargs):
ApiCall.objects.filter(created__lte=now() - timedelta(hours=24)).delete() ApiCall.objects.filter(created__lte=now() - timedelta(hours=24)).delete()

View File

@@ -6,6 +6,7 @@ from django.shortcuts import get_object_or_404
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.timezone import now from django.utils.timezone import now
from django_filters.rest_framework import DjangoFilterBackend, FilterSet from django_filters.rest_framework import DjangoFilterBackend, FilterSet
from django_scopes import scopes_disabled
from rest_framework import viewsets from rest_framework import viewsets
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.fields import DateTimeField from rest_framework.fields import DateTimeField
@@ -24,11 +25,11 @@ from pretix.base.services.checkin import (
) )
from pretix.helpers.database import FixedOrderBy from pretix.helpers.database import FixedOrderBy
with scopes_disabled():
class CheckinListFilter(FilterSet): class CheckinListFilter(FilterSet):
class Meta: class Meta:
model = CheckinList model = CheckinList
fields = ['subevent'] fields = ['subevent']
class CheckinListViewSet(viewsets.ModelViewSet): class CheckinListViewSet(viewsets.ModelViewSet):
@@ -146,15 +147,16 @@ class CheckinListViewSet(viewsets.ModelViewSet):
return Response(response) return Response(response)
class CheckinOrderPositionFilter(OrderPositionFilter): with scopes_disabled():
class CheckinOrderPositionFilter(OrderPositionFilter):
def has_checkin_qs(self, queryset, name, value): def has_checkin_qs(self, queryset, name, value):
return queryset.filter(last_checked_in__isnull=not value) return queryset.filter(last_checked_in__isnull=not value)
class CheckinListPositionViewSet(viewsets.ReadOnlyModelViewSet): class CheckinListPositionViewSet(viewsets.ReadOnlyModelViewSet):
serializer_class = CheckinListOrderPositionSerializer serializer_class = CheckinListOrderPositionSerializer
queryset = OrderPosition.objects.none() queryset = OrderPosition.all.none()
filter_backends = (DjangoFilterBackend, RichOrderingFilter) filter_backends = (DjangoFilterBackend, RichOrderingFilter)
ordering = ('attendee_name_cached', 'positionid') ordering = ('attendee_name_cached', 'positionid')
ordering_fields = ( ordering_fields = (

View File

@@ -3,6 +3,7 @@ from django.db import transaction
from django.db.models import ProtectedError, Q from django.db.models import ProtectedError, Q
from django.utils.timezone import now from django.utils.timezone import now
from django_filters.rest_framework import DjangoFilterBackend, FilterSet from django_filters.rest_framework import DjangoFilterBackend, FilterSet
from django_scopes import scopes_disabled
from rest_framework import filters, viewsets from rest_framework import filters, viewsets
from rest_framework.exceptions import PermissionDenied from rest_framework.exceptions import PermissionDenied
@@ -18,51 +19,51 @@ from pretix.base.models import (
from pretix.base.models.event import SubEvent from pretix.base.models.event import SubEvent
from pretix.helpers.dicts import merge_dicts from pretix.helpers.dicts import merge_dicts
with scopes_disabled():
class EventFilter(FilterSet):
is_past = django_filters.rest_framework.BooleanFilter(method='is_past_qs')
is_future = django_filters.rest_framework.BooleanFilter(method='is_future_qs')
ends_after = django_filters.rest_framework.IsoDateTimeFilter(method='ends_after_qs')
class EventFilter(FilterSet): class Meta:
is_past = django_filters.rest_framework.BooleanFilter(method='is_past_qs') model = Event
is_future = django_filters.rest_framework.BooleanFilter(method='is_future_qs') fields = ['is_public', 'live', 'has_subevents']
ends_after = django_filters.rest_framework.IsoDateTimeFilter(method='ends_after_qs')
class Meta: def ends_after_qs(self, queryset, name, value):
model = Event expr = (
fields = ['is_public', 'live', 'has_subevents'] Q(has_subevents=False) &
Q(
def ends_after_qs(self, queryset, name, value): Q(Q(date_to__isnull=True) & Q(date_from__gte=value))
expr = ( | Q(Q(date_to__isnull=False) & Q(date_to__gte=value))
Q(has_subevents=False) & )
Q(
Q(Q(date_to__isnull=True) & Q(date_from__gte=value))
| Q(Q(date_to__isnull=False) & Q(date_to__gte=value))
) )
)
return queryset.filter(expr)
def is_past_qs(self, queryset, name, value):
expr = (
Q(has_subevents=False) &
Q(
Q(Q(date_to__isnull=True) & Q(date_from__lt=now()))
| Q(Q(date_to__isnull=False) & Q(date_to__lt=now()))
)
)
if value:
return queryset.filter(expr) return queryset.filter(expr)
else:
return queryset.exclude(expr)
def is_future_qs(self, queryset, name, value): def is_past_qs(self, queryset, name, value):
expr = ( expr = (
Q(has_subevents=False) & Q(has_subevents=False) &
Q( Q(
Q(Q(date_to__isnull=True) & Q(date_from__gte=now())) Q(Q(date_to__isnull=True) & Q(date_from__lt=now()))
| Q(Q(date_to__isnull=False) & Q(date_to__gte=now())) | Q(Q(date_to__isnull=False) & Q(date_to__lt=now()))
)
) )
) if value:
if value: return queryset.filter(expr)
return queryset.filter(expr) else:
else: return queryset.exclude(expr)
return queryset.exclude(expr)
def is_future_qs(self, queryset, name, value):
expr = (
Q(has_subevents=False) &
Q(
Q(Q(date_to__isnull=True) & Q(date_from__gte=now()))
| Q(Q(date_to__isnull=False) & Q(date_to__gte=now()))
)
)
if value:
return queryset.filter(expr)
else:
return queryset.exclude(expr)
class EventViewSet(viewsets.ModelViewSet): class EventViewSet(viewsets.ModelViewSet):
@@ -182,41 +183,42 @@ class CloneEventViewSet(viewsets.ModelViewSet):
) )
class SubEventFilter(FilterSet): with scopes_disabled():
is_past = django_filters.rest_framework.BooleanFilter(method='is_past_qs') class SubEventFilter(FilterSet):
is_future = django_filters.rest_framework.BooleanFilter(method='is_future_qs') is_past = django_filters.rest_framework.BooleanFilter(method='is_past_qs')
ends_after = django_filters.rest_framework.IsoDateTimeFilter(method='ends_after_qs') is_future = django_filters.rest_framework.BooleanFilter(method='is_future_qs')
ends_after = django_filters.rest_framework.IsoDateTimeFilter(method='ends_after_qs')
class Meta: class Meta:
model = SubEvent model = SubEvent
fields = ['active', 'event__live'] fields = ['active', 'event__live']
def ends_after_qs(self, queryset, name, value): def ends_after_qs(self, queryset, name, value):
expr = Q( expr = Q(
Q(Q(date_to__isnull=True) & Q(date_from__gte=value)) Q(Q(date_to__isnull=True) & Q(date_from__gte=value))
| Q(Q(date_to__isnull=False) & Q(date_to__gte=value)) | Q(Q(date_to__isnull=False) & Q(date_to__gte=value))
) )
return queryset.filter(expr)
def is_past_qs(self, queryset, name, value):
expr = Q(
Q(Q(date_to__isnull=True) & Q(date_from__lt=now()))
| Q(Q(date_to__isnull=False) & Q(date_to__lt=now()))
)
if value:
return queryset.filter(expr) return queryset.filter(expr)
else:
return queryset.exclude(expr)
def is_future_qs(self, queryset, name, value): def is_past_qs(self, queryset, name, value):
expr = Q( expr = Q(
Q(Q(date_to__isnull=True) & Q(date_from__gte=now())) Q(Q(date_to__isnull=True) & Q(date_from__lt=now()))
| Q(Q(date_to__isnull=False) & Q(date_to__gte=now())) | Q(Q(date_to__isnull=False) & Q(date_to__lt=now()))
) )
if value: if value:
return queryset.filter(expr) return queryset.filter(expr)
else: else:
return queryset.exclude(expr) return queryset.exclude(expr)
def is_future_qs(self, queryset, name, value):
expr = Q(
Q(Q(date_to__isnull=True) & Q(date_from__gte=now()))
| Q(Q(date_to__isnull=False) & Q(date_to__gte=now()))
)
if value:
return queryset.filter(expr)
else:
return queryset.exclude(expr)
class SubEventViewSet(ConditionalListView, viewsets.ModelViewSet): class SubEventViewSet(ConditionalListView, viewsets.ModelViewSet):

View File

@@ -3,6 +3,7 @@ from django.db.models import Q
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django_filters.rest_framework import DjangoFilterBackend, FilterSet from django_filters.rest_framework import DjangoFilterBackend, FilterSet
from django_scopes import scopes_disabled
from rest_framework import viewsets from rest_framework import viewsets
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.exceptions import PermissionDenied from rest_framework.exceptions import PermissionDenied
@@ -21,19 +22,19 @@ from pretix.base.models import (
) )
from pretix.helpers.dicts import merge_dicts from pretix.helpers.dicts import merge_dicts
with scopes_disabled():
class ItemFilter(FilterSet):
tax_rate = django_filters.CharFilter(method='tax_rate_qs')
class ItemFilter(FilterSet): def tax_rate_qs(self, queryset, name, value):
tax_rate = django_filters.CharFilter(method='tax_rate_qs') if value in ("0", "None", "0.00"):
return queryset.filter(Q(tax_rule__isnull=True) | Q(tax_rule__rate=0))
else:
return queryset.filter(tax_rule__rate=value)
def tax_rate_qs(self, queryset, name, value): class Meta:
if value in ("0", "None", "0.00"): model = Item
return queryset.filter(Q(tax_rule__isnull=True) | Q(tax_rule__rate=0)) fields = ['active', 'category', 'admission', 'tax_rate', 'free_price']
else:
return queryset.filter(tax_rule__rate=value)
class Meta:
model = Item
fields = ['active', 'category', 'admission', 'tax_rate', 'free_price']
class ItemViewSet(ConditionalListView, viewsets.ModelViewSet): class ItemViewSet(ConditionalListView, viewsets.ModelViewSet):
@@ -319,10 +320,11 @@ class ItemCategoryViewSet(ConditionalListView, viewsets.ModelViewSet):
super().perform_destroy(instance) super().perform_destroy(instance)
class QuestionFilter(FilterSet): with scopes_disabled():
class Meta: class QuestionFilter(FilterSet):
model = Question class Meta:
fields = ['ask_during_checkin', 'required', 'identifier'] model = Question
fields = ['ask_during_checkin', 'required', 'identifier']
class QuestionViewSet(ConditionalListView, viewsets.ModelViewSet): class QuestionViewSet(ConditionalListView, viewsets.ModelViewSet):
@@ -418,10 +420,11 @@ class QuestionOptionViewSet(viewsets.ModelViewSet):
super().perform_destroy(instance) super().perform_destroy(instance)
class QuotaFilter(FilterSet): with scopes_disabled():
class Meta: class QuotaFilter(FilterSet):
model = Quota class Meta:
fields = ['subevent'] model = Quota
fields = ['subevent']
class QuotaViewSet(ConditionalListView, viewsets.ModelViewSet): class QuotaViewSet(ConditionalListView, viewsets.ModelViewSet):

View File

@@ -11,6 +11,7 @@ from django.shortcuts import get_object_or_404
from django.utils.timezone import make_aware, now from django.utils.timezone import make_aware, now
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django_filters.rest_framework import DjangoFilterBackend, FilterSet from django_filters.rest_framework import DjangoFilterBackend, FilterSet
from django_scopes import scopes_disabled
from rest_framework import mixins, serializers, status, viewsets from rest_framework import mixins, serializers, status, viewsets
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.exceptions import ( from rest_framework.exceptions import (
@@ -50,17 +51,17 @@ from pretix.base.signals import (
) )
from pretix.base.templatetags.money import money_filter from pretix.base.templatetags.money import money_filter
with scopes_disabled():
class OrderFilter(FilterSet):
email = django_filters.CharFilter(field_name='email', lookup_expr='iexact')
code = django_filters.CharFilter(field_name='code', lookup_expr='iexact')
status = django_filters.CharFilter(field_name='status', lookup_expr='iexact')
modified_since = django_filters.IsoDateTimeFilter(field_name='last_modified', lookup_expr='gte')
created_since = django_filters.IsoDateTimeFilter(field_name='datetime', lookup_expr='gte')
class OrderFilter(FilterSet): class Meta:
email = django_filters.CharFilter(field_name='email', lookup_expr='iexact') model = Order
code = django_filters.CharFilter(field_name='code', lookup_expr='iexact') fields = ['code', 'status', 'email', 'locale', 'testmode', 'require_approval']
status = django_filters.CharFilter(field_name='status', lookup_expr='iexact')
modified_since = django_filters.IsoDateTimeFilter(field_name='last_modified', lookup_expr='gte')
created_since = django_filters.IsoDateTimeFilter(field_name='datetime', lookup_expr='gte')
class Meta:
model = Order
fields = ['code', 'status', 'email', 'locale', 'testmode', 'require_approval']
class OrderViewSet(viewsets.ModelViewSet): class OrderViewSet(viewsets.ModelViewSet):
@@ -531,48 +532,49 @@ class OrderViewSet(viewsets.ModelViewSet):
self.get_object().gracefully_delete(user=self.request.user if self.request.user.is_authenticated else None, auth=self.request.auth) self.get_object().gracefully_delete(user=self.request.user if self.request.user.is_authenticated else None, auth=self.request.auth)
class OrderPositionFilter(FilterSet): with scopes_disabled():
order = django_filters.CharFilter(field_name='order', lookup_expr='code__iexact') class OrderPositionFilter(FilterSet):
has_checkin = django_filters.rest_framework.BooleanFilter(method='has_checkin_qs') order = django_filters.CharFilter(field_name='order', lookup_expr='code__iexact')
attendee_name = django_filters.CharFilter(method='attendee_name_qs') has_checkin = django_filters.rest_framework.BooleanFilter(method='has_checkin_qs')
search = django_filters.CharFilter(method='search_qs') attendee_name = django_filters.CharFilter(method='attendee_name_qs')
search = django_filters.CharFilter(method='search_qs')
def search_qs(self, queryset, name, value): def search_qs(self, queryset, name, value):
return queryset.filter( return queryset.filter(
Q(secret__istartswith=value) Q(secret__istartswith=value)
| Q(attendee_name_cached__icontains=value) | Q(attendee_name_cached__icontains=value)
| Q(addon_to__attendee_name_cached__icontains=value) | Q(addon_to__attendee_name_cached__icontains=value)
| Q(attendee_email__icontains=value) | Q(attendee_email__icontains=value)
| Q(addon_to__attendee_email__icontains=value) | Q(addon_to__attendee_email__icontains=value)
| Q(order__code__istartswith=value) | Q(order__code__istartswith=value)
| Q(order__invoice_address__name_cached__icontains=value) | Q(order__invoice_address__name_cached__icontains=value)
| Q(order__email__icontains=value) | Q(order__email__icontains=value)
) )
def has_checkin_qs(self, queryset, name, value): def has_checkin_qs(self, queryset, name, value):
return queryset.filter(checkins__isnull=not value) return queryset.filter(checkins__isnull=not value)
def attendee_name_qs(self, queryset, name, value): def attendee_name_qs(self, queryset, name, value):
return queryset.filter(Q(attendee_name_cached__iexact=value) | Q(addon_to__attendee_name_cached__iexact=value)) return queryset.filter(Q(attendee_name_cached__iexact=value) | Q(addon_to__attendee_name_cached__iexact=value))
class Meta: class Meta:
model = OrderPosition model = OrderPosition
fields = { fields = {
'item': ['exact', 'in'], 'item': ['exact', 'in'],
'variation': ['exact', 'in'], 'variation': ['exact', 'in'],
'secret': ['exact'], 'secret': ['exact'],
'order__status': ['exact', 'in'], 'order__status': ['exact', 'in'],
'addon_to': ['exact', 'in'], 'addon_to': ['exact', 'in'],
'subevent': ['exact', 'in'], 'subevent': ['exact', 'in'],
'pseudonymization_id': ['exact'], 'pseudonymization_id': ['exact'],
'voucher__code': ['exact'], 'voucher__code': ['exact'],
'voucher': ['exact'], 'voucher': ['exact'],
} }
class OrderPositionViewSet(mixins.DestroyModelMixin, viewsets.ReadOnlyModelViewSet): class OrderPositionViewSet(mixins.DestroyModelMixin, viewsets.ReadOnlyModelViewSet):
serializer_class = OrderPositionSerializer serializer_class = OrderPositionSerializer
queryset = OrderPosition.objects.none() queryset = OrderPosition.all.none()
filter_backends = (DjangoFilterBackend, OrderingFilter) filter_backends = (DjangoFilterBackend, OrderingFilter)
ordering = ('order__datetime', 'positionid') ordering = ('order__datetime', 'positionid')
ordering_fields = ('order__code', 'order__datetime', 'positionid', 'attendee_name', 'order__status',) ordering_fields = ('order__code', 'order__datetime', 'positionid', 'attendee_name', 'order__status',)
@@ -960,22 +962,23 @@ class RefundViewSet(CreateModelMixin, viewsets.ReadOnlyModelViewSet):
serializer.save() serializer.save()
class InvoiceFilter(FilterSet): with scopes_disabled():
refers = django_filters.CharFilter(method='refers_qs') class InvoiceFilter(FilterSet):
number = django_filters.CharFilter(method='nr_qs') refers = django_filters.CharFilter(method='refers_qs')
order = django_filters.CharFilter(field_name='order', lookup_expr='code__iexact') number = django_filters.CharFilter(method='nr_qs')
order = django_filters.CharFilter(field_name='order', lookup_expr='code__iexact')
def refers_qs(self, queryset, name, value): def refers_qs(self, queryset, name, value):
return queryset.annotate( return queryset.annotate(
refers_nr=Concat('refers__prefix', 'refers__invoice_no') refers_nr=Concat('refers__prefix', 'refers__invoice_no')
).filter(refers_nr__iexact=value) ).filter(refers_nr__iexact=value)
def nr_qs(self, queryset, name, value): def nr_qs(self, queryset, name, value):
return queryset.filter(nr__iexact=value) return queryset.filter(nr__iexact=value)
class Meta: class Meta:
model = Invoice model = Invoice
fields = ['order', 'number', 'is_cancellation', 'refers', 'locale'] fields = ['order', 'number', 'is_cancellation', 'refers', 'locale']
class RetryException(APIException): class RetryException(APIException):

View File

@@ -6,6 +6,7 @@ from django.utils.timezone import now
from django_filters.rest_framework import ( from django_filters.rest_framework import (
BooleanFilter, DjangoFilterBackend, FilterSet, BooleanFilter, DjangoFilterBackend, FilterSet,
) )
from django_scopes import scopes_disabled
from rest_framework import status, viewsets from rest_framework import status, viewsets
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.exceptions import PermissionDenied from rest_framework.exceptions import PermissionDenied
@@ -15,22 +16,22 @@ from rest_framework.response import Response
from pretix.api.serializers.voucher import VoucherSerializer from pretix.api.serializers.voucher import VoucherSerializer
from pretix.base.models import Voucher from pretix.base.models import Voucher
with scopes_disabled():
class VoucherFilter(FilterSet):
active = BooleanFilter(method='filter_active')
class VoucherFilter(FilterSet): class Meta:
active = BooleanFilter(method='filter_active') model = Voucher
fields = ['code', 'max_usages', 'redeemed', 'block_quota', 'allow_ignore_quota',
'price_mode', 'value', 'item', 'variation', 'quota', 'tag', 'subevent']
class Meta: def filter_active(self, queryset, name, value):
model = Voucher if value:
fields = ['code', 'max_usages', 'redeemed', 'block_quota', 'allow_ignore_quota', return queryset.filter(Q(redeemed__lt=F('max_usages')) &
'price_mode', 'value', 'item', 'variation', 'quota', 'tag', 'subevent'] (Q(valid_until__isnull=True) | Q(valid_until__gt=now())))
else:
def filter_active(self, queryset, name, value): return queryset.filter(Q(redeemed__gte=F('max_usages')) |
if value: (Q(valid_until__isnull=False) & Q(valid_until__lte=now())))
return queryset.filter(Q(redeemed__lt=F('max_usages')) &
(Q(valid_until__isnull=True) | Q(valid_until__gt=now())))
else:
return queryset.filter(Q(redeemed__gte=F('max_usages')) |
(Q(valid_until__isnull=False) & Q(valid_until__lte=now())))
class VoucherViewSet(viewsets.ModelViewSet): class VoucherViewSet(viewsets.ModelViewSet):

View File

@@ -1,5 +1,6 @@
import django_filters import django_filters
from django_filters.rest_framework import DjangoFilterBackend, FilterSet from django_filters.rest_framework import DjangoFilterBackend, FilterSet
from django_scopes import scopes_disabled
from rest_framework import viewsets from rest_framework import viewsets
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.exceptions import PermissionDenied, ValidationError from rest_framework.exceptions import PermissionDenied, ValidationError
@@ -10,16 +11,16 @@ from pretix.api.serializers.waitinglist import WaitingListSerializer
from pretix.base.models import WaitingListEntry from pretix.base.models import WaitingListEntry
from pretix.base.models.waitinglist import WaitingListException from pretix.base.models.waitinglist import WaitingListException
with scopes_disabled():
class WaitingListFilter(FilterSet):
has_voucher = django_filters.rest_framework.BooleanFilter(method='has_voucher_qs')
class WaitingListFilter(FilterSet): def has_voucher_qs(self, queryset, name, value):
has_voucher = django_filters.rest_framework.BooleanFilter(method='has_voucher_qs') return queryset.filter(voucher__isnull=not value)
def has_voucher_qs(self, queryset, name, value): class Meta:
return queryset.filter(voucher__isnull=not value) model = WaitingListEntry
fields = ['item', 'variation', 'email', 'locale', 'has_voucher', 'subevent']
class Meta:
model = WaitingListEntry
fields = ['item', 'variation', 'email', 'locale', 'has_voucher', 'subevent']
class WaitingListViewSet(viewsets.ModelViewSet): class WaitingListViewSet(viewsets.ModelViewSet):

View File

@@ -8,6 +8,7 @@ from celery.exceptions import MaxRetriesExceededError
from django.db.models import Exists, OuterRef, Q from django.db.models import Exists, OuterRef, Q
from django.dispatch import receiver from django.dispatch import receiver
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django_scopes import scope, scopes_disabled
from requests import RequestException from requests import RequestException
from pretix.api.models import WebHook, WebHookCall, WebHookEventListener from pretix.api.models import WebHook, WebHookCall, WebHookEventListener
@@ -203,51 +204,52 @@ def notify_webhooks(logentry_id: int):
@app.task(base=ProfiledTask, bind=True, max_retries=9) @app.task(base=ProfiledTask, bind=True, max_retries=9)
def send_webhook(self, logentry_id: int, action_type: str, webhook_id: int): def send_webhook(self, logentry_id: int, action_type: str, webhook_id: int):
# 9 retries with 2**(2*x) timing is roughly 72 hours # 9 retries with 2**(2*x) timing is roughly 72 hours
logentry = LogEntry.all.get(id=logentry_id) with scopes_disabled():
webhook = WebHook.objects.get(id=webhook_id) webhook = WebHook.objects.get(id=webhook_id)
with scope(organizer=webhook.organizer):
logentry = LogEntry.all.get(id=logentry_id)
types = get_all_webhook_events()
event_type = types.get(action_type)
if not event_type or not webhook.enabled:
return # Ignore, e.g. plugin not installed
types = get_all_webhook_events() payload = event_type.build_payload(logentry)
event_type = types.get(action_type) t = time.time()
if not event_type or not webhook.enabled:
return # Ignore, e.g. plugin not installed
payload = event_type.build_payload(logentry)
t = time.time()
try:
try: try:
resp = requests.post( try:
webhook.target_url, resp = requests.post(
json=payload, webhook.target_url,
allow_redirects=False json=payload,
) allow_redirects=False
WebHookCall.objects.create( )
webhook=webhook, WebHookCall.objects.create(
action_type=logentry.action_type, webhook=webhook,
target_url=webhook.target_url, action_type=logentry.action_type,
is_retry=self.request.retries > 0, target_url=webhook.target_url,
execution_time=time.time() - t, is_retry=self.request.retries > 0,
return_code=resp.status_code, execution_time=time.time() - t,
payload=json.dumps(payload), return_code=resp.status_code,
response_body=resp.text[:1024 * 1024], payload=json.dumps(payload),
success=200 <= resp.status_code <= 299 response_body=resp.text[:1024 * 1024],
) success=200 <= resp.status_code <= 299
if resp.status_code == 410: )
webhook.enabled = False if resp.status_code == 410:
webhook.save() webhook.enabled = False
elif resp.status_code > 299: webhook.save()
elif resp.status_code > 299:
raise self.retry(countdown=2 ** (self.request.retries * 2))
except RequestException as e:
WebHookCall.objects.create(
webhook=webhook,
action_type=logentry.action_type,
target_url=webhook.target_url,
is_retry=self.request.retries > 0,
execution_time=time.time() - t,
return_code=0,
payload=json.dumps(payload),
response_body=str(e)[:1024 * 1024]
)
raise self.retry(countdown=2 ** (self.request.retries * 2)) raise self.retry(countdown=2 ** (self.request.retries * 2))
except RequestException as e: except MaxRetriesExceededError:
WebHookCall.objects.create( pass
webhook=webhook,
action_type=logentry.action_type,
target_url=webhook.target_url,
is_retry=self.request.retries > 0,
execution_time=time.time() - t,
return_code=0,
payload=json.dumps(payload),
response_body=str(e)[:1024 * 1024]
)
raise self.retry(countdown=2 ** (self.request.retries * 2))
except MaxRetriesExceededError:
pass

View File

@@ -12,6 +12,7 @@ from django.utils.crypto import get_random_string
from django.utils.timezone import now from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django_otp.models import Device from django_otp.models import Device
from django_scopes import scopes_disabled
from pretix.base.i18n import language from pretix.base.i18n import language
from pretix.helpers.urls import build_absolute_uri from pretix.helpers.urls import build_absolute_uri
@@ -283,6 +284,7 @@ class User(AbstractBaseUser, PermissionsMixin, LoggingMixin):
return True return True
return False return False
@scopes_disabled()
def get_events_with_any_permission(self, request=None): def get_events_with_any_permission(self, request=None):
""" """
Returns a queryset of events the user has any permissions to. Returns a queryset of events the user has any permissions to.
@@ -300,6 +302,7 @@ class User(AbstractBaseUser, PermissionsMixin, LoggingMixin):
| Q(id__in=self.teams.values_list('limit_events__id', flat=True)) | Q(id__in=self.teams.values_list('limit_events__id', flat=True))
) )
@scopes_disabled()
def get_events_with_permission(self, permission, request=None): def get_events_with_permission(self, permission, request=None):
""" """
Returns a queryset of events the user has a specific permissions to. Returns a queryset of events the user has a specific permissions to.

View File

@@ -3,6 +3,7 @@ from django.db.models import Case, Count, F, OuterRef, Q, Subquery, When
from django.db.models.functions import Coalesce from django.db.models.functions import Coalesce
from django.utils.timezone import now from django.utils.timezone import now
from django.utils.translation import pgettext_lazy, ugettext_lazy as _ from django.utils.translation import pgettext_lazy, ugettext_lazy as _
from django_scopes import ScopedManager
from pretix.base.models import LoggedModel from pretix.base.models import LoggedModel
@@ -20,6 +21,8 @@ class CheckinList(LoggedModel):
'order have not been paid. This only works with pretixdesk ' 'order have not been paid. This only works with pretixdesk '
'0.3.0 or newer or pretixdroid 1.9 or newer.')) '0.3.0 or newer or pretixdroid 1.9 or newer.'))
objects = ScopedManager(organizer='event__organizer')
class Meta: class Meta:
ordering = ('subevent__date_from', 'name') ordering = ('subevent__date_from', 'name')
@@ -167,6 +170,8 @@ class Checkin(models.Model):
'pretixbase.CheckinList', related_name='checkins', on_delete=models.PROTECT, 'pretixbase.CheckinList', related_name='checkins', on_delete=models.PROTECT,
) )
objects = ScopedManager(organizer='position__order__event__organizer')
class Meta: class Meta:
unique_together = (('list', 'position'),) unique_together = (('list', 'position'),)

View File

@@ -4,6 +4,7 @@ from django.db import models
from django.db.models import Max from django.db.models import Max
from django.utils.crypto import get_random_string from django.utils.crypto import get_random_string
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django_scopes import ScopedManager
from pretix.base.models import LoggedModel from pretix.base.models import LoggedModel
@@ -71,6 +72,8 @@ class Device(LoggedModel):
null=True, blank=True null=True, blank=True
) )
objects = ScopedManager(organizer='organizer')
class Meta: class Meta:
unique_together = (('organizer', 'device_id'),) unique_together = (('organizer', 'device_id'),)

View File

@@ -17,6 +17,7 @@ from django.utils.crypto import get_random_string
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.timezone import make_aware, now from django.utils.timezone import make_aware, now
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django_scopes import ScopedManager
from i18nfield.fields import I18nCharField, I18nTextField from i18nfield.fields import I18nCharField, I18nTextField
from pretix.base.models.base import LoggedModel from pretix.base.models.base import LoggedModel
@@ -336,6 +337,8 @@ class Event(EventMixin, LoggedModel):
default=False default=False
) )
objects = ScopedManager(organizer='organizer')
class Meta: class Meta:
verbose_name = _("Event") verbose_name = _("Event")
verbose_name_plural = _("Events") verbose_name_plural = _("Events")
@@ -875,6 +878,8 @@ class SubEvent(EventMixin, LoggedModel):
items = models.ManyToManyField('Item', through='SubEventItem') items = models.ManyToManyField('Item', through='SubEventItem')
variations = models.ManyToManyField('ItemVariation', through='SubEventItemVariation') variations = models.ManyToManyField('ItemVariation', through='SubEventItemVariation')
objects = ScopedManager(organizer='event__organizer')
class Meta: class Meta:
verbose_name = _("Date in event series") verbose_name = _("Date in event series")
verbose_name_plural = _("Dates in event series") verbose_name_plural = _("Dates in event series")

View File

@@ -9,6 +9,7 @@ from django.utils.crypto import get_random_string
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.translation import pgettext from django.utils.translation import pgettext
from django_countries.fields import CountryField from django_countries.fields import CountryField
from django_scopes import ScopedManager
def invoice_filename(instance, filename: str) -> str: def invoice_filename(instance, filename: str) -> str:
@@ -107,6 +108,8 @@ class Invoice(models.Model):
file = models.FileField(null=True, blank=True, upload_to=invoice_filename, max_length=255) file = models.FileField(null=True, blank=True, upload_to=invoice_filename, max_length=255)
internal_reference = models.TextField(blank=True) internal_reference = models.TextField(blank=True)
objects = ScopedManager(organizer='event__organizer')
@staticmethod @staticmethod
def _to_numeric_invoice_number(number): def _to_numeric_invoice_number(number):
return '{:05d}'.format(int(number)) return '{:05d}'.format(int(number))

View File

@@ -17,6 +17,7 @@ from django.utils.functional import cached_property
from django.utils.timezone import is_naive, make_aware, now from django.utils.timezone import is_naive, make_aware, now
from django.utils.translation import pgettext_lazy, ugettext_lazy as _ from django.utils.translation import pgettext_lazy, ugettext_lazy as _
from django_countries.fields import Country from django_countries.fields import Country
from django_scopes import ScopedManager
from i18nfield.fields import I18nCharField, I18nTextField from i18nfield.fields import I18nCharField, I18nTextField
from pretix.base.models import fields from pretix.base.models import fields
@@ -155,28 +156,41 @@ class SubEventItemVariation(models.Model):
self.subevent.event.cache.clear() self.subevent.event.cache.clear()
def filter_available(qs, channel='web', voucher=None, allow_addons=False):
q = (
# IMPORTANT: If this is updated, also update the ItemVariation query
# in models/event.py: EventMixin.annotated()
Q(active=True)
& Q(Q(available_from__isnull=True) | Q(available_from__lte=now()))
& Q(Q(available_until__isnull=True) | Q(available_until__gte=now()))
& Q(sales_channels__contains=channel) & Q(require_bundling=False)
)
if not allow_addons:
q &= Q(Q(category__isnull=True) | Q(category__is_addon=False))
qs = qs.filter(q)
vouchq = Q(hide_without_voucher=False)
if voucher:
if voucher.item_id:
vouchq |= Q(pk=voucher.item_id)
qs = qs.filter(pk=voucher.item_id)
elif voucher.quota_id:
qs = qs.filter(quotas__in=[voucher.quota_id])
return qs.filter(vouchq)
class ItemQuerySet(models.QuerySet): class ItemQuerySet(models.QuerySet):
def filter_available(self, channel='web', voucher=None, allow_addons=False): def filter_available(self, channel='web', voucher=None, allow_addons=False):
q = ( return filter_available(self, channel, voucher, allow_addons)
# IMPORTANT: If this is updated, also update the ItemVariation query
# in models/event.py: EventMixin.annotated()
Q(active=True)
& Q(Q(available_from__isnull=True) | Q(available_from__lte=now()))
& Q(Q(available_until__isnull=True) | Q(available_until__gte=now()))
& Q(sales_channels__contains=channel) & Q(require_bundling=False)
)
if not allow_addons:
q &= Q(Q(category__isnull=True) | Q(category__is_addon=False))
qs = self.filter(q)
vouchq = Q(hide_without_voucher=False)
if voucher: class ItemQuerySetManager(ScopedManager(organizer='event__organizer').__class__):
if voucher.item_id: def __init__(self):
vouchq |= Q(pk=voucher.item_id) super().__init__()
qs = qs.filter(pk=voucher.item_id) self._queryset_class = ItemQuerySet
elif voucher.quota_id:
qs = qs.filter(quotas__in=[voucher.quota_id]) def filter_available(self, channel='web', voucher=None, allow_addons=False):
return qs.filter(vouchq) return filter_available(self.get_queryset(), channel, voucher, allow_addons)
class Item(LoggedModel): class Item(LoggedModel):
@@ -226,7 +240,7 @@ class Item(LoggedModel):
:type sales_channels: bool :type sales_channels: bool
""" """
objects = ItemQuerySet.as_manager() objects = ItemQuerySetManager()
event = models.ForeignKey( event = models.ForeignKey(
Event, Event,
@@ -591,6 +605,8 @@ class ItemVariation(models.Model):
'discounted one. This is just a cosmetic setting and will not actually impact pricing.') 'discounted one. This is just a cosmetic setting and will not actually impact pricing.')
) )
objects = ScopedManager(organizer='item__event__organizer')
class Meta: class Meta:
verbose_name = _("Product variation") verbose_name = _("Product variation")
verbose_name_plural = _("Product variations") verbose_name_plural = _("Product variations")
@@ -985,6 +1001,8 @@ class Question(LoggedModel):
) )
dependency_value = models.TextField(null=True, blank=True) dependency_value = models.TextField(null=True, blank=True)
objects = ScopedManager(organizer='event__organizer')
class Meta: class Meta:
verbose_name = _("Question") verbose_name = _("Question")
verbose_name_plural = _("Questions") verbose_name_plural = _("Questions")
@@ -1234,6 +1252,8 @@ class Quota(LoggedModel):
cached_availability_paid_orders = models.PositiveIntegerField(null=True, blank=True) cached_availability_paid_orders = models.PositiveIntegerField(null=True, blank=True)
cached_availability_time = models.DateTimeField(null=True, blank=True) cached_availability_time = models.DateTimeField(null=True, blank=True)
objects = ScopedManager(organizer='event__organizer')
class Meta: class Meta:
verbose_name = _("Quota") verbose_name = _("Quota")
verbose_name_plural = _("Quotas") verbose_name_plural = _("Quotas")

View File

@@ -26,6 +26,7 @@ from django.utils.functional import cached_property
from django.utils.timezone import make_aware, now from django.utils.timezone import make_aware, now
from django.utils.translation import pgettext_lazy, ugettext_lazy as _ from django.utils.translation import pgettext_lazy, ugettext_lazy as _
from django_countries.fields import Country, CountryField from django_countries.fields import Country, CountryField
from django_scopes import ScopedManager, scopes_disabled
from i18nfield.strings import LazyI18nString from i18nfield.strings import LazyI18nString
from jsonfallback.fields import FallbackJSONField from jsonfallback.fields import FallbackJSONField
@@ -186,6 +187,8 @@ class Order(LockModel, LoggedModel):
verbose_name=_('E-mail address verified') verbose_name=_('E-mail address verified')
) )
objects = ScopedManager(organizer='event__organizer')
class Meta: class Meta:
verbose_name = _("Order") verbose_name = _("Order")
verbose_name_plural = _("Orders") verbose_name_plural = _("Orders")
@@ -231,6 +234,7 @@ class Order(LockModel, LoggedModel):
return self.all_fees(manager='objects') return self.all_fees(manager='objects')
@cached_property @cached_property
@scopes_disabled()
def count_positions(self): def count_positions(self):
if hasattr(self, 'pcnt'): if hasattr(self, 'pcnt'):
return self.pcnt or 0 return self.pcnt or 0
@@ -254,6 +258,7 @@ class Order(LockModel, LoggedModel):
return None return None
@property @property
@scopes_disabled()
def payment_refund_sum(self): def payment_refund_sum(self):
payment_sum = self.payments.filter( payment_sum = self.payments.filter(
state__in=(OrderPayment.PAYMENT_STATE_CONFIRMED, OrderPayment.PAYMENT_STATE_REFUNDED) state__in=(OrderPayment.PAYMENT_STATE_CONFIRMED, OrderPayment.PAYMENT_STATE_REFUNDED)
@@ -265,6 +270,7 @@ class Order(LockModel, LoggedModel):
return payment_sum - refund_sum return payment_sum - refund_sum
@property @property
@scopes_disabled()
def pending_sum(self): def pending_sum(self):
total = self.total total = self.total
if self.status == Order.STATUS_CANCELED: if self.status == Order.STATUS_CANCELED:
@@ -439,6 +445,7 @@ class Order(LockModel, LoggedModel):
return round_decimal(fee, self.event.currency) return round_decimal(fee, self.event.currency)
@property @property
@scopes_disabled()
def user_cancel_allowed(self) -> bool: def user_cancel_allowed(self) -> bool:
""" """
Returns whether or not this order can be canceled by the user. Returns whether or not this order can be canceled by the user.
@@ -822,6 +829,8 @@ class QuestionAnswer(models.Model):
max_length=255 max_length=255
) )
objects = ScopedManager(organizer='question__event__organizer')
@property @property
def backend_file_url(self): def backend_file_url(self):
if self.file: if self.file:
@@ -1145,6 +1154,8 @@ class OrderPayment(models.Model):
) )
migrated = models.BooleanField(default=False) migrated = models.BooleanField(default=False)
objects = ScopedManager(organizer='order__event__organizer')
class Meta: class Meta:
ordering = ('local_id',) ordering = ('local_id',)
@@ -1501,6 +1512,8 @@ class OrderRefund(models.Model):
null=True, blank=True null=True, blank=True
) )
objects = ScopedManager(organizer='order__event__organizer')
class Meta: class Meta:
ordering = ('local_id',) ordering = ('local_id',)
@@ -1562,7 +1575,7 @@ class OrderRefund(models.Model):
super().save(*args, **kwargs) super().save(*args, **kwargs)
class ActivePositionManager(models.Manager): class ActivePositionManager(ScopedManager(organizer='order__event__organizer').__class__):
def get_queryset(self): def get_queryset(self):
return super().get_queryset().filter(canceled=False) return super().get_queryset().filter(canceled=False)
@@ -1639,7 +1652,7 @@ class OrderFee(models.Model):
) )
canceled = models.BooleanField(default=False) canceled = models.BooleanField(default=False)
all = models.Manager() all = ScopedManager(organizer='order__event__organizer')
objects = ActivePositionManager() objects = ActivePositionManager()
@property @property
@@ -1744,7 +1757,7 @@ class OrderPosition(AbstractPosition):
) )
canceled = models.BooleanField(default=False) canceled = models.BooleanField(default=False)
all = models.Manager() all = ScopedManager(organizer='order__event__organizer')
objects = ActivePositionManager() objects = ActivePositionManager()
class Meta: class Meta:
@@ -1951,6 +1964,8 @@ class CartPosition(AbstractPosition):
) )
is_bundled = models.BooleanField(default=False) is_bundled = models.BooleanField(default=False)
objects = ScopedManager(organizer='event__organizer')
class Meta: class Meta:
verbose_name = _("Cart position") verbose_name = _("Cart position")
verbose_name_plural = _("Cart positions") verbose_name_plural = _("Cart positions")
@@ -2000,6 +2015,8 @@ class InvoiceAddress(models.Model):
blank=True blank=True
) )
objects = ScopedManager(organizer='order__event__organizer')
def save(self, **kwargs): def save(self, **kwargs):
if self.order: if self.order:
self.order.touch() self.order.touch()

View File

@@ -8,6 +8,7 @@ from django.db.models import Q
from django.utils.crypto import get_random_string from django.utils.crypto import get_random_string
from django.utils.timezone import now from django.utils.timezone import now
from django.utils.translation import pgettext_lazy, ugettext_lazy as _ from django.utils.translation import pgettext_lazy, ugettext_lazy as _
from django_scopes import ScopedManager
from ..decimal import round_decimal from ..decimal import round_decimal
from .base import LoggedModel from .base import LoggedModel
@@ -173,6 +174,8 @@ class Voucher(LoggedModel):
"convenience.") "convenience.")
) )
objects = ScopedManager(organizer='event__organizer')
class Meta: class Meta:
verbose_name = _("Voucher") verbose_name = _("Voucher")
verbose_name_plural = _("Vouchers") verbose_name_plural = _("Vouchers")

View File

@@ -4,6 +4,7 @@ from django.core.exceptions import ValidationError
from django.db import models, transaction from django.db import models, transaction
from django.utils.timezone import now from django.utils.timezone import now
from django.utils.translation import pgettext_lazy, ugettext_lazy as _ from django.utils.translation import pgettext_lazy, ugettext_lazy as _
from django_scopes import ScopedManager
from pretix.base.i18n import language from pretix.base.i18n import language
from pretix.base.models import Voucher from pretix.base.models import Voucher
@@ -67,6 +68,8 @@ class WaitingListEntry(LoggedModel):
) )
priority = models.IntegerField(default=0) priority = models.IntegerField(default=0)
objects = ScopedManager(organizer='event__organizer')
class Meta: class Meta:
verbose_name = _("Waiting list entry") verbose_name = _("Waiting list entry")
verbose_name_plural = _("Waiting list entries") verbose_name_plural = _("Waiting list entries")

View File

@@ -10,6 +10,7 @@ from django.db.models import Q
from django.dispatch import receiver from django.dispatch import receiver
from django.utils.timezone import make_aware, now from django.utils.timezone import make_aware, now
from django.utils.translation import pgettext_lazy, ugettext as _ from django.utils.translation import pgettext_lazy, ugettext as _
from django_scopes import scopes_disabled
from pretix.base.i18n import language from pretix.base.i18n import language
from pretix.base.models import ( from pretix.base.models import (
@@ -23,7 +24,7 @@ from pretix.base.reldate import RelativeDateWrapper
from pretix.base.services.checkin import _save_answers from pretix.base.services.checkin import _save_answers
from pretix.base.services.locking import LockTimeoutException, NoLockManager from pretix.base.services.locking import LockTimeoutException, NoLockManager
from pretix.base.services.pricing import get_price from pretix.base.services.pricing import get_price
from pretix.base.services.tasks import ProfiledTask from pretix.base.services.tasks import ProfiledEventTask
from pretix.base.settings import PERSON_NAME_SCHEMES from pretix.base.settings import PERSON_NAME_SCHEMES
from pretix.base.templatetags.rich_text import rich_text from pretix.base.templatetags.rich_text import rich_text
from pretix.celery_app import app from pretix.celery_app import app
@@ -902,7 +903,7 @@ def get_fees(event, request, total, invoice_address, provider):
return fees return fees
@app.task(base=ProfiledTask, bind=True, max_retries=5, default_retry_delay=1, throws=(CartError,)) @app.task(base=ProfiledEventTask, bind=True, max_retries=5, default_retry_delay=1, throws=(CartError,))
def add_items_to_cart(self, event: int, items: List[dict], cart_id: str=None, locale='en', def add_items_to_cart(self, event: int, items: List[dict], cart_id: str=None, locale='en',
invoice_address: int=None, widget_data=None, sales_channel='web') -> None: invoice_address: int=None, widget_data=None, sales_channel='web') -> None:
""" """
@@ -913,12 +914,11 @@ def add_items_to_cart(self, event: int, items: List[dict], cart_id: str=None, lo
:raises CartError: On any error that occured :raises CartError: On any error that occured
""" """
with language(locale): with language(locale):
event = Event.objects.get(id=event)
ia = False ia = False
if invoice_address: if invoice_address:
try: try:
ia = InvoiceAddress.objects.get(pk=invoice_address) with scopes_disabled():
ia = InvoiceAddress.objects.get(pk=invoice_address)
except InvoiceAddress.DoesNotExist: except InvoiceAddress.DoesNotExist:
pass pass
@@ -934,8 +934,8 @@ def add_items_to_cart(self, event: int, items: List[dict], cart_id: str=None, lo
raise CartError(error_messages['busy']) raise CartError(error_messages['busy'])
@app.task(base=ProfiledTask, bind=True, max_retries=5, default_retry_delay=1, throws=(CartError,)) @app.task(base=ProfiledEventTask, bind=True, max_retries=5, default_retry_delay=1, throws=(CartError,))
def remove_cart_position(self, event: int, position: int, cart_id: str=None, locale='en') -> None: def remove_cart_position(self, event: Event, position: int, cart_id: str=None, locale='en') -> None:
""" """
Removes a list of items from a user's cart. Removes a list of items from a user's cart.
:param event: The event ID in question :param event: The event ID in question
@@ -943,7 +943,6 @@ def remove_cart_position(self, event: int, position: int, cart_id: str=None, loc
:param session: Session ID of a guest :param session: Session ID of a guest
""" """
with language(locale): with language(locale):
event = Event.objects.get(id=event)
try: try:
try: try:
cm = CartManager(event=event, cart_id=cart_id) cm = CartManager(event=event, cart_id=cart_id)
@@ -955,15 +954,14 @@ def remove_cart_position(self, event: int, position: int, cart_id: str=None, loc
raise CartError(error_messages['busy']) raise CartError(error_messages['busy'])
@app.task(base=ProfiledTask, bind=True, max_retries=5, default_retry_delay=1, throws=(CartError,)) @app.task(base=ProfiledEventTask, bind=True, max_retries=5, default_retry_delay=1, throws=(CartError,))
def clear_cart(self, event: int, cart_id: str=None, locale='en') -> None: def clear_cart(self, event: Event, cart_id: str=None, locale='en') -> None:
""" """
Removes a list of items from a user's cart. Removes a list of items from a user's cart.
:param event: The event ID in question :param event: The event ID in question
:param session: Session ID of a guest :param session: Session ID of a guest
""" """
with language(locale): with language(locale):
event = Event.objects.get(id=event)
try: try:
try: try:
cm = CartManager(event=event, cart_id=cart_id) cm = CartManager(event=event, cart_id=cart_id)
@@ -975,8 +973,8 @@ def clear_cart(self, event: int, cart_id: str=None, locale='en') -> None:
raise CartError(error_messages['busy']) raise CartError(error_messages['busy'])
@app.task(base=ProfiledTask, bind=True, max_retries=5, default_retry_delay=1, throws=(CartError,)) @app.task(base=ProfiledEventTask, bind=True, max_retries=5, default_retry_delay=1, throws=(CartError,))
def set_cart_addons(self, event: int, addons: List[dict], cart_id: str=None, locale='en', def set_cart_addons(self, event: Event, addons: List[dict], cart_id: str=None, locale='en',
invoice_address: int=None, sales_channel='web') -> None: invoice_address: int=None, sales_channel='web') -> None:
""" """
Removes a list of items from a user's cart. Removes a list of items from a user's cart.
@@ -985,12 +983,11 @@ def set_cart_addons(self, event: int, addons: List[dict], cart_id: str=None, loc
:param session: Session ID of a guest :param session: Session ID of a guest
""" """
with language(locale): with language(locale):
event = Event.objects.get(id=event)
ia = False ia = False
if invoice_address: if invoice_address:
try: try:
ia = InvoiceAddress.objects.get(pk=invoice_address) with scopes_disabled():
ia = InvoiceAddress.objects.get(pk=invoice_address)
except InvoiceAddress.DoesNotExist: except InvoiceAddress.DoesNotExist:
pass pass
try: try:

View File

@@ -2,6 +2,7 @@ from datetime import timedelta
from django.dispatch import receiver from django.dispatch import receiver
from django.utils.timezone import now from django.utils.timezone import now
from django_scopes import scopes_disabled
from pretix.base.models import CachedCombinedTicket, CachedTicket from pretix.base.models import CachedCombinedTicket, CachedTicket
@@ -10,6 +11,7 @@ from ..signals import periodic_task
@receiver(signal=periodic_task) @receiver(signal=periodic_task)
@scopes_disabled()
def clean_cart_positions(sender, **kwargs): def clean_cart_positions(sender, **kwargs):
for cp in CartPosition.objects.filter(expires__lt=now() - timedelta(days=14), addon_to__isnull=False): for cp in CartPosition.objects.filter(expires__lt=now() - timedelta(days=14), addon_to__isnull=False):
cp.delete() cp.delete()
@@ -20,12 +22,14 @@ def clean_cart_positions(sender, **kwargs):
@receiver(signal=periodic_task) @receiver(signal=periodic_task)
@scopes_disabled()
def clean_cached_files(sender, **kwargs): def clean_cached_files(sender, **kwargs):
for cf in CachedFile.objects.filter(expires__isnull=False, expires__lt=now()): for cf in CachedFile.objects.filter(expires__isnull=False, expires__lt=now()):
cf.delete() cf.delete()
@receiver(signal=periodic_task) @receiver(signal=periodic_task)
@scopes_disabled()
def clean_cached_tickets(sender, **kwargs): def clean_cached_tickets(sender, **kwargs):
for cf in CachedTicket.objects.filter(created__lte=now() - timedelta(days=30)): for cf in CachedTicket.objects.filter(created__lte=now() - timedelta(days=30)):
cf.delete() cf.delete()

View File

@@ -6,7 +6,7 @@ from django.utils.translation import ugettext
from pretix.base.i18n import LazyLocaleException, language from pretix.base.i18n import LazyLocaleException, language
from pretix.base.models import CachedFile, Event, cachedfile_name from pretix.base.models import CachedFile, Event, cachedfile_name
from pretix.base.services.tasks import ProfiledTask from pretix.base.services.tasks import ProfiledEventTask
from pretix.base.signals import register_data_exporters from pretix.base.signals import register_data_exporters
from pretix.celery_app import app from pretix.celery_app import app
@@ -15,9 +15,8 @@ class ExportError(LazyLocaleException):
pass pass
@app.task(base=ProfiledTask, throws=(ExportError,)) @app.task(base=ProfiledEventTask, throws=(ExportError,))
def export(event: str, fileid: str, provider: str, form_data: Dict[str, Any]) -> None: def export(event: Event, fileid: str, provider: str, form_data: Dict[str, Any]) -> None:
event = Event.objects.get(id=event)
file = CachedFile.objects.get(id=fileid) file = CachedFile.objects.get(id=fileid)
with language(event.settings.locale), override(event.settings.timezone): with language(event.settings.locale), override(event.settings.timezone):
responses = register_data_exporters.send(event) responses = register_data_exporters.send(event)

View File

@@ -15,6 +15,7 @@ from django.utils import timezone
from django.utils.timezone import now from django.utils.timezone import now
from django.utils.translation import pgettext, ugettext as _ from django.utils.translation import pgettext, ugettext as _
from django_countries.fields import Country from django_countries.fields import Country
from django_scopes import scope, scopes_disabled
from i18nfield.strings import LazyI18nString from i18nfield.strings import LazyI18nString
from pretix.base.i18n import language from pretix.base.i18n import language
@@ -244,16 +245,18 @@ def generate_invoice(order: Order, trigger_pdf=True):
@app.task(base=TransactionAwareTask) @app.task(base=TransactionAwareTask)
def invoice_pdf_task(invoice: int): def invoice_pdf_task(invoice: int):
i = Invoice.objects.get(pk=invoice) with scopes_disabled():
if i.shredded: i = Invoice.objects.get(pk=invoice)
return None with scope(organizer=i.order.event.organizer):
if i.file: if i.shredded:
i.file.delete() return None
with language(i.locale): if i.file:
fname, ftype, fcontent = i.event.invoice_renderer.generate(i) i.file.delete()
i.file.save(fname, ContentFile(fcontent)) with language(i.locale):
i.save() fname, ftype, fcontent = i.event.invoice_renderer.generate(i)
return i.file.name i.file.save(fname, ContentFile(fcontent))
i.save()
return i.file.name
def invoice_qualified(order: Order): def invoice_qualified(order: Order):

View File

@@ -10,6 +10,7 @@ from django.conf import settings
from django.core.mail import EmailMultiAlternatives, get_connection from django.core.mail import EmailMultiAlternatives, get_connection
from django.template.loader import get_template from django.template.loader import get_template
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django_scopes import scope, scopes_disabled
from i18nfield.strings import LazyI18nString from i18nfield.strings import LazyI18nString
from pretix.base.email import ClassicMailRenderer from pretix.base.email import ClassicMailRenderer
@@ -234,83 +235,87 @@ def mail_send_task(self, *args, to: List[str], subject: str, body: str, html: st
pass pass
if event: if event:
event = Event.objects.get(id=event) with scopes_disabled():
event = Event.objects.get(id=event)
backend = event.get_mail_backend() backend = event.get_mail_backend()
cm = lambda: scope(organizer=event.organizer) # noqa
else: else:
backend = get_connection(fail_silently=False) backend = get_connection(fail_silently=False)
cm = lambda: scopes_disabled() # noqa
if event: with cm():
if order: if event:
try: if order:
order = event.orders.get(pk=order) try:
except Order.DoesNotExist: order = event.orders.get(pk=order)
order = None except Order.DoesNotExist:
else: order = None
if position: else:
try: if position:
position = order.positions.get(pk=position) try:
except OrderPosition.DoesNotExist: position = order.positions.get(pk=position)
attach_tickets = False except OrderPosition.DoesNotExist:
if attach_tickets: attach_tickets = False
args = [] if attach_tickets:
attach_size = 0 args = []
for name, ct in get_tickets_for_order(order, base_position=position): attach_size = 0
content = ct.file.read() for name, ct in get_tickets_for_order(order, base_position=position):
args.append((name, content, ct.type)) content = ct.file.read()
attach_size += len(content) args.append((name, content, ct.type))
attach_size += len(content)
if attach_size < 4 * 1024 * 1024: if attach_size < 4 * 1024 * 1024:
# Do not attach more than 4MB, it will bounce way to often. # Do not attach more than 4MB, it will bounce way to often.
for a in args: for a in args:
try: try:
email.attach(*a) email.attach(*a)
except: except:
pass pass
else: else:
order.log_action( order.log_action(
'pretix.event.order.email.attachments.skipped', 'pretix.event.order.email.attachments.skipped',
data={ data={
'subject': 'Attachments skipped', 'subject': 'Attachments skipped',
'message': 'Attachment have not been send because {} bytes are likely too large to arrive.'.format(attach_size), 'message': 'Attachment have not been send because {} bytes are likely too large to arrive.'.format(attach_size),
'recipient': '', 'recipient': '',
'invoices': [], 'invoices': [],
} }
) )
email = email_filter.send_chained(event, 'message', message=email, order=order) email = email_filter.send_chained(event, 'message', message=email, order=order)
try: try:
backend.send_messages([email]) backend.send_messages([email])
except smtplib.SMTPResponseException as e: except smtplib.SMTPResponseException as e:
if e.smtp_code in (101, 111, 421, 422, 431, 442, 447, 452): if e.smtp_code in (101, 111, 421, 422, 431, 442, 447, 452):
self.retry(max_retries=5, countdown=2 ** (self.request.retries * 2)) self.retry(max_retries=5, countdown=2 ** (self.request.retries * 2))
logger.exception('Error sending email') logger.exception('Error sending email')
if order: if order:
order.log_action( order.log_action(
'pretix.event.order.email.error', 'pretix.event.order.email.error',
data={ data={
'subject': 'SMTP code {}'.format(e.smtp_code), 'subject': 'SMTP code {}'.format(e.smtp_code),
'message': e.smtp_error.decode() if isinstance(e.smtp_error, bytes) else str(e.smtp_error), 'message': e.smtp_error.decode() if isinstance(e.smtp_error, bytes) else str(e.smtp_error),
'recipient': '', 'recipient': '',
'invoices': [], 'invoices': [],
} }
) )
raise SendMailException('Failed to send an email to {}.'.format(to)) raise SendMailException('Failed to send an email to {}.'.format(to))
except Exception as e: except Exception as e:
if order: if order:
order.log_action( order.log_action(
'pretix.event.order.email.error', 'pretix.event.order.email.error',
data={ data={
'subject': 'Internal error', 'subject': 'Internal error',
'message': str(e), 'message': str(e),
'recipient': '', 'recipient': '',
'invoices': [], 'invoices': [],
} }
) )
logger.exception('Error sending email') logger.exception('Error sending email')
raise SendMailException('Failed to send an email to {}.'.format(to)) raise SendMailException('Failed to send an email to {}.'.format(to))
def mail_send(*args, **kwargs): def mail_send(*args, **kwargs):

View File

@@ -1,5 +1,6 @@
from django.conf import settings from django.conf import settings
from django.template.loader import get_template from django.template.loader import get_template
from django_scopes import scope, scopes_disabled
from inlinestyler.utils import inline_css from inlinestyler.utils import inline_css
from pretix.base.i18n import language from pretix.base.i18n import language
@@ -12,6 +13,7 @@ from pretix.helpers.urls import build_absolute_uri
@app.task(base=TransactionAwareTask) @app.task(base=TransactionAwareTask)
@scopes_disabled()
def notify(logentry_id: int): def notify(logentry_id: int):
logentry = LogEntry.all.get(id=logentry_id) logentry = LogEntry.all.get(id=logentry_id)
if not logentry.event: if not logentry.event:
@@ -66,17 +68,22 @@ def notify(logentry_id: int):
@app.task(base=ProfiledTask) @app.task(base=ProfiledTask)
def send_notification(logentry_id: int, action_type: str, user_id: int, method: str): def send_notification(logentry_id: int, action_type: str, user_id: int, method: str):
logentry = LogEntry.all.get(id=logentry_id) logentry = LogEntry.all.get(id=logentry_id)
user = User.objects.get(id=user_id) if logentry.event:
types = get_all_notification_types(logentry.event) sm = lambda: scope(organizer=logentry.event.organizer) # noqa
notification_type = types.get(action_type) else:
if not notification_type: sm = lambda: scopes_disabled() # noqa
return # Ignore, e.g. plugin not active for this event with sm():
user = User.objects.get(id=user_id)
types = get_all_notification_types(logentry.event)
notification_type = types.get(action_type)
if not notification_type:
return # Ignore, e.g. plugin not active for this event
with language(user.locale): with language(user.locale):
notification = notification_type.build_notification(logentry) notification = notification_type.build_notification(logentry)
if method == "mail": if method == "mail":
send_notification_mail(notification, user) send_notification_mail(notification, user)
def send_notification_mail(notification: Notification, user: User): def send_notification_mail(notification: Notification, user: User):

View File

@@ -16,6 +16,7 @@ from django.utils.formats import date_format
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.timezone import make_aware, now from django.utils.timezone import make_aware, now
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django_scopes import scopes_disabled
from pretix.api.models import OAuthApplication from pretix.api.models import OAuthApplication
from pretix.base.i18n import ( from pretix.base.i18n import (
@@ -42,7 +43,7 @@ from pretix.base.services.invoices import (
from pretix.base.services.locking import LockTimeoutException, NoLockManager from pretix.base.services.locking import LockTimeoutException, NoLockManager
from pretix.base.services.mail import SendMailException from pretix.base.services.mail import SendMailException
from pretix.base.services.pricing import get_price from pretix.base.services.pricing import get_price
from pretix.base.services.tasks import ProfiledTask from pretix.base.services.tasks import ProfiledEventTask, ProfiledTask
from pretix.base.settings import PERSON_NAME_SCHEMES from pretix.base.settings import PERSON_NAME_SCHEMES
from pretix.base.signals import ( from pretix.base.signals import (
allow_ticket_download, order_approved, order_canceled, order_changed, allow_ticket_download, order_approved, order_canceled, order_changed,
@@ -715,10 +716,8 @@ def _order_placed_email_attendee(event: Event, order: Order, position: OrderPosi
logger.exception('Order received email could not be sent to attendee') logger.exception('Order received email could not be sent to attendee')
def _perform_order(event: str, payment_provider: str, position_ids: List[str], def _perform_order(event: Event, payment_provider: str, position_ids: List[str],
email: str, locale: str, address: int, meta_info: dict=None, sales_channel: str='web'): email: str, locale: str, address: int, meta_info: dict=None, sales_channel: str='web'):
event = Event.objects.get(id=event)
if payment_provider: if payment_provider:
pprov = event.get_payment_providers().get(payment_provider) pprov = event.get_payment_providers().get(payment_provider)
if not pprov: if not pprov:
@@ -732,7 +731,8 @@ def _perform_order(event: str, payment_provider: str, position_ids: List[str],
addr = None addr = None
if address is not None: if address is not None:
try: try:
addr = InvoiceAddress.objects.get(pk=address) with scopes_disabled():
addr = InvoiceAddress.objects.get(pk=address)
except InvoiceAddress.DoesNotExist: except InvoiceAddress.DoesNotExist:
pass pass
@@ -804,6 +804,7 @@ def _perform_order(event: str, payment_provider: str, position_ids: List[str],
@receiver(signal=periodic_task) @receiver(signal=periodic_task)
@scopes_disabled()
def expire_orders(sender, **kwargs): def expire_orders(sender, **kwargs):
eventcache = {} eventcache = {}
@@ -818,6 +819,7 @@ def expire_orders(sender, **kwargs):
@receiver(signal=periodic_task) @receiver(signal=periodic_task)
@scopes_disabled()
def send_expiry_warnings(sender, **kwargs): def send_expiry_warnings(sender, **kwargs):
eventcache = {} eventcache = {}
today = now().replace(hour=0, minute=0, second=0) today = now().replace(hour=0, minute=0, second=0)
@@ -875,6 +877,7 @@ def send_expiry_warnings(sender, **kwargs):
@receiver(signal=periodic_task) @receiver(signal=periodic_task)
@scopes_disabled()
def send_download_reminders(sender, **kwargs): def send_download_reminders(sender, **kwargs):
today = now().replace(hour=0, minute=0, second=0, microsecond=0) today = now().replace(hour=0, minute=0, second=0, microsecond=0)
@@ -1497,8 +1500,8 @@ class OrderChangeManager:
return pprov return pprov
@app.task(base=ProfiledTask, bind=True, max_retries=5, default_retry_delay=1, throws=(OrderError,)) @app.task(base=ProfiledEventTask, bind=True, max_retries=5, default_retry_delay=1, throws=(OrderError,))
def perform_order(self, event: str, payment_provider: str, positions: List[str], def perform_order(self, event: Event, payment_provider: str, positions: List[str],
email: str=None, locale: str=None, address: int=None, meta_info: dict=None, email: str=None, locale: str=None, address: int=None, meta_info: dict=None,
sales_channel: str='web'): sales_channel: str='web'):
with language(locale): with language(locale):
@@ -1513,6 +1516,7 @@ def perform_order(self, event: str, payment_provider: str, positions: List[str],
@app.task(base=ProfiledTask, bind=True, max_retries=5, default_retry_delay=1, throws=(OrderError,)) @app.task(base=ProfiledTask, bind=True, max_retries=5, default_retry_delay=1, throws=(OrderError,))
@scopes_disabled()
def cancel_order(self, order: int, user: int=None, send_mail: bool=True, api_token=None, oauth_application=None, def cancel_order(self, order: int, user: int=None, send_mail: bool=True, api_token=None, oauth_application=None,
device=None, cancellation_fee=None, try_auto_refund=False): device=None, cancellation_fee=None, try_auto_refund=False):
try: try:

View File

@@ -4,6 +4,7 @@ from django.conf import settings
from django.db.models import Max, Q from django.db.models import Max, Q
from django.dispatch import receiver from django.dispatch import receiver
from django.utils.timezone import now from django.utils.timezone import now
from django_scopes import scopes_disabled
from pretix.base.models import Event, LogEntry from pretix.base.models import Event, LogEntry
from pretix.celery_app import app from pretix.celery_app import app
@@ -17,6 +18,7 @@ def build_all_quota_caches(sender, **kwargs):
@app.task @app.task
@scopes_disabled()
def refresh_quota_caches(): def refresh_quota_caches():
# Active events # Active events
active = LogEntry.objects.using(settings.DATABASE_REPLICA).filter( active = LogEntry.objects.using(settings.DATABASE_REPLICA).filter(

View File

@@ -11,14 +11,13 @@ from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from pretix.base.models import CachedFile, Event, cachedfile_name from pretix.base.models import CachedFile, Event, cachedfile_name
from pretix.base.services.tasks import ProfiledTask from pretix.base.services.tasks import ProfiledEventTask
from pretix.base.shredder import ShredError from pretix.base.shredder import ShredError
from pretix.celery_app import app from pretix.celery_app import app
@app.task(base=ProfiledTask) @app.task(base=ProfiledEventTask)
def export(event: str, shredders: List[str]) -> None: def export(event: Event, shredders: List[str]) -> None:
event = Event.objects.get(id=event)
known_shredders = event.get_data_shredders() known_shredders = event.get_data_shredders()
with NamedTemporaryFile() as rawfile: with NamedTemporaryFile() as rawfile:
@@ -63,9 +62,8 @@ def export(event: str, shredders: List[str]) -> None:
return cf.pk return cf.pk
@app.task(base=ProfiledTask, throws=(ShredError,)) @app.task(base=ProfiledEventTask, throws=(ShredError,))
def shred(event: str, fileid: str, confirm_code: str) -> None: def shred(event: Event, fileid: str, confirm_code: str) -> None:
event = Event.objects.get(id=event)
known_shredders = event.get_data_shredders() known_shredders = event.get_data_shredders()
try: try:
cf = CachedFile.objects.get(pk=fileid) cf = CachedFile.objects.get(pk=fileid)

View File

@@ -14,10 +14,12 @@ import time
from django.conf import settings from django.conf import settings
from django.db import transaction from django.db import transaction
from django_scopes import scope, scopes_disabled
from pretix.base.metrics import ( from pretix.base.metrics import (
pretix_task_duration_seconds, pretix_task_runs_total, pretix_task_duration_seconds, pretix_task_runs_total,
) )
from pretix.base.models import Event
from pretix.celery_app import app from pretix.celery_app import app
@@ -61,6 +63,35 @@ class ProfiledTask(app.Task):
return super().on_success(retval, task_id, args, kwargs) return super().on_success(retval, task_id, args, kwargs)
class EventTask(app.Task):
def __call__(self, *args, **kwargs):
if 'event_id' in kwargs:
event_id = kwargs.get('event_id')
with scopes_disabled():
event = Event.objects.select_related('organizer').get(pk=event_id)
del kwargs['event_id']
kwargs['event'] = event
elif 'event' in kwargs:
event_id = kwargs.get('event')
with scopes_disabled():
event = Event.objects.select_related('organizer').get(pk=event_id)
kwargs['event'] = event
else:
args = list(args)
event_id = args[0]
with scopes_disabled():
event = Event.objects.select_related('organizer').get(pk=event_id)
args[0] = event
with scope(organizer=event.organizer):
ret = super().__call__(*args, **kwargs)
return ret
class ProfiledEventTask(ProfiledTask, EventTask):
pass
class TransactionAwareTask(ProfiledTask): class TransactionAwareTask(ProfiledTask):
""" """
Task class which is aware of django db transactions and only executes tasks Task class which is aware of django db transactions and only executes tasks

View File

@@ -4,13 +4,14 @@ import os
from django.core.files.base import ContentFile from django.core.files.base import ContentFile
from django.utils.timezone import now from django.utils.timezone import now
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django_scopes import scopes_disabled
from pretix.base.i18n import language from pretix.base.i18n import language
from pretix.base.models import ( from pretix.base.models import (
CachedCombinedTicket, CachedTicket, Event, InvoiceAddress, Order, CachedCombinedTicket, CachedTicket, Event, InvoiceAddress, Order,
OrderPosition, OrderPosition,
) )
from pretix.base.services.tasks import ProfiledTask from pretix.base.services.tasks import EventTask, ProfiledTask
from pretix.base.settings import PERSON_NAME_SCHEMES from pretix.base.settings import PERSON_NAME_SCHEMES
from pretix.base.signals import allow_ticket_download, register_ticket_outputs from pretix.base.signals import allow_ticket_download, register_ticket_outputs
from pretix.celery_app import app from pretix.celery_app import app
@@ -57,10 +58,11 @@ def generate_order(order: int, provider: str):
@app.task(base=ProfiledTask) @app.task(base=ProfiledTask)
def generate(model: str, pk: int, provider: str): def generate(model: str, pk: int, provider: str):
if model == 'order': with scopes_disabled():
return generate_order(pk, provider) if model == 'order':
elif model == 'orderposition': return generate_order(pk, provider)
return generate_orderposition(pk, provider) elif model == 'orderposition':
return generate_orderposition(pk, provider)
class DummyRollbackException(Exception): class DummyRollbackException(Exception):
@@ -165,9 +167,8 @@ def get_tickets_for_order(order, base_position=None):
return tickets return tickets
@app.task(base=ProfiledTask) @app.task(base=EventTask)
def invalidate_cache(event: int, item: int=None, provider: str=None, order: int=None, **kwargs): def invalidate_cache(event: Event, item: int=None, provider: str=None, order: int=None, **kwargs):
event = Event.objects.get(id=event)
qs = CachedTicket.objects.filter(order_position__order__event=event) qs = CachedTicket.objects.filter(order_position__order__event=event)
qsc = CachedCombinedTicket.objects.filter(order__event=event) qsc = CachedCombinedTicket.objects.filter(order__event=event)

View File

@@ -6,6 +6,7 @@ import requests
from django.dispatch import receiver from django.dispatch import receiver
from django.utils.timezone import now from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _, ugettext_noop from django.utils.translation import ugettext_lazy as _, ugettext_noop
from django_scopes import scopes_disabled
from i18nfield.strings import LazyI18nString from i18nfield.strings import LazyI18nString
from pretix import __version__ from pretix import __version__
@@ -29,6 +30,7 @@ def run_update_check(sender, **kwargs):
@app.task @app.task
@scopes_disabled()
def update_check(): def update_check():
gs = GlobalSettingsObject() gs = GlobalSettingsObject()

View File

@@ -1,17 +1,17 @@
import sys import sys
from django.dispatch import receiver from django.dispatch import receiver
from django_scopes import scopes_disabled
from pretix.base.models import Event, User, WaitingListEntry from pretix.base.models import Event, User, WaitingListEntry
from pretix.base.models.waitinglist import WaitingListException from pretix.base.models.waitinglist import WaitingListException
from pretix.base.services.tasks import ProfiledTask from pretix.base.services.tasks import EventTask
from pretix.base.signals import periodic_task from pretix.base.signals import periodic_task
from pretix.celery_app import app from pretix.celery_app import app
@app.task(base=ProfiledTask) @app.task(base=EventTask)
def assign_automatically(event_id: int, user_id: int=None, subevent_id: int=None): def assign_automatically(event: Event, user_id: int=None, subevent_id: int=None):
event = Event.objects.get(id=event_id)
if user_id: if user_id:
user = User.objects.get(id=user_id) user = User.objects.get(id=user_id)
else: else:
@@ -69,6 +69,7 @@ def assign_automatically(event_id: int, user_id: int=None, subevent_id: int=None
@receiver(signal=periodic_task) @receiver(signal=periodic_task)
@scopes_disabled()
def process_waitinglist(sender, **kwargs): def process_waitinglist(sender, **kwargs):
qs = Event.objects.filter( qs = Event.objects.filter(
live=True live=True

View File

@@ -3,6 +3,7 @@ import hmac
from django.conf import settings from django.conf import settings
from django.http import HttpResponse from django.http import HttpResponse
from django_scopes import scopes_disabled
from .. import metrics from .. import metrics
@@ -15,6 +16,7 @@ def unauthed_response():
return response return response
@scopes_disabled()
def serve_metrics(request): def serve_metrics(request):
if not settings.METRICS_ENABLED: if not settings.METRICS_ENABLED:
return unauthed_response() return unauthed_response()

View File

@@ -5,6 +5,7 @@ from django.conf import settings
from django.db.models import Q from django.db.models import Q
from django.urls import Resolver404, get_script_prefix, resolve from django.urls import Resolver404, get_script_prefix, resolve
from django.utils.translation import get_language from django.utils.translation import get_language
from django_scopes import scope
from pretix.base.models.auth import StaffSession from pretix.base.models.auth import StaffSession
from pretix.base.settings import GlobalSettingsObject from pretix.base.settings import GlobalSettingsObject
@@ -53,10 +54,11 @@ def contextprocessor(request):
ctx['has_domain'] = request.event.organizer.domains.exists() ctx['has_domain'] = request.event.organizer.domains.exists()
if not request.event.testmode: if not request.event.testmode:
complain_testmode_orders = request.event.cache.get('complain_testmode_orders') with scope(organizer=request.organizer):
if complain_testmode_orders is None: complain_testmode_orders = request.event.cache.get('complain_testmode_orders')
complain_testmode_orders = request.event.orders.filter(testmode=True).exists() if complain_testmode_orders is None:
request.event.cache.set('complain_testmode_orders', complain_testmode_orders, 30) complain_testmode_orders = request.event.orders.filter(testmode=True).exists()
request.event.cache.set('complain_testmode_orders', complain_testmode_orders, 30)
ctx['complain_testmode_orders'] = complain_testmode_orders ctx['complain_testmode_orders'] = complain_testmode_orders
else: else:
ctx['complain_testmode_orders'] = False ctx['complain_testmode_orders'] = False

View File

@@ -1,6 +1,9 @@
from django import forms from django import forms
from django.urls import reverse from django.urls import reverse
from django.utils.translation import pgettext_lazy from django.utils.translation import pgettext_lazy
from django_scopes.forms import (
SafeModelChoiceField, SafeModelMultipleChoiceField,
)
from pretix.base.models.checkin import CheckinList from pretix.base.models.checkin import CheckinList
from pretix.control.forms.widgets import Select2 from pretix.control.forms.widgets import Select2
@@ -44,3 +47,7 @@ class CheckinListForm(forms.ModelForm):
'data-inverse-dependency': '<[name$=all_products]' 'data-inverse-dependency': '<[name$=all_products]'
}), }),
} }
field_classes = {
'limit_products': SafeModelMultipleChoiceField,
'subevent': SafeModelChoiceField,
}

View File

@@ -6,6 +6,9 @@ from django.urls import reverse
from django.utils.translation import ( from django.utils.translation import (
pgettext_lazy, ugettext as __, ugettext_lazy as _, pgettext_lazy, ugettext as __, ugettext_lazy as _,
) )
from django_scopes.forms import (
SafeModelChoiceField, SafeModelMultipleChoiceField,
)
from i18nfield.forms import I18nFormField, I18nTextarea from i18nfield.forms import I18nFormField, I18nTextarea
from pretix.base.channels import get_all_sales_channels from pretix.base.channels import get_all_sales_channels
@@ -94,6 +97,10 @@ class QuestionForm(I18nModelForm):
), ),
'dependency_value': forms.Select, 'dependency_value': forms.Select,
} }
field_classes = {
'items': SafeModelMultipleChoiceField,
'dependency_question': SafeModelChoiceField,
}
class QuestionOptionForm(I18nModelForm): class QuestionOptionForm(I18nModelForm):
@@ -159,6 +166,9 @@ class QuotaForm(I18nModelForm):
'size', 'size',
'subevent' 'subevent'
] ]
field_classes = {
'subevent': SafeModelChoiceField,
}
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
creating = not self.instance.pk creating = not self.instance.pk

View File

@@ -192,7 +192,7 @@ class OrderPositionAddForm(forms.Form):
label=_('Product') label=_('Product')
) )
addon_to = forms.ModelChoiceField( addon_to = forms.ModelChoiceField(
OrderPosition.objects.none(), OrderPosition.all.none(),
required=False, required=False,
label=_('Add-on to'), label=_('Add-on to'),
) )

View File

@@ -6,6 +6,7 @@ from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator from django.core.validators import RegexValidator
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.translation import pgettext_lazy, ugettext_lazy as _ from django.utils.translation import pgettext_lazy, ugettext_lazy as _
from django_scopes.forms import SafeModelMultipleChoiceField
from i18nfield.forms import I18nFormField, I18nTextarea from i18nfield.forms import I18nFormField, I18nTextarea
from pretix.api.models import WebHook from pretix.api.models import WebHook
@@ -149,6 +150,9 @@ class TeamForm(forms.ModelForm):
'data-inverse-dependency': '#id_all_events' 'data-inverse-dependency': '#id_all_events'
}), }),
} }
field_classes = {
'limit_events': SafeModelMultipleChoiceField
}
def clean(self): def clean(self):
data = super().clean() data = super().clean()
@@ -177,6 +181,9 @@ class DeviceForm(forms.ModelForm):
'data-inverse-dependency': '#id_all_events' 'data-inverse-dependency': '#id_all_events'
}), }),
} }
field_classes = {
'limit_events': SafeModelMultipleChoiceField
}
class OrganizerSettingsForm(SettingsForm): class OrganizerSettingsForm(SettingsForm):
@@ -307,3 +314,6 @@ class WebHookForm(forms.ModelForm):
'data-inverse-dependency': '#id_all_events' 'data-inverse-dependency': '#id_all_events'
}), }),
} }
field_classes = {
'limit_events': SafeModelMultipleChoiceField
}

View File

@@ -3,6 +3,7 @@ from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.db.models.functions import Lower from django.db.models.functions import Lower
from django.urls import reverse from django.urls import reverse
from django.utils.translation import pgettext_lazy, ugettext_lazy as _ from django.utils.translation import pgettext_lazy, ugettext_lazy as _
from django_scopes.forms import SafeModelChoiceField
from pretix.base.forms import I18nModelForm from pretix.base.forms import I18nModelForm
from pretix.base.models import Item, Voucher from pretix.base.models import Item, Voucher
@@ -35,6 +36,7 @@ class VoucherForm(I18nModelForm):
] ]
field_classes = { field_classes = {
'valid_until': SplitDateTimeField, 'valid_until': SplitDateTimeField,
'subevent': SafeModelChoiceField,
} }
widgets = { widgets = {
'valid_until': SplitDateTimePickerWidget(), 'valid_until': SplitDateTimePickerWidget(),
@@ -199,6 +201,7 @@ class VoucherBulkForm(VoucherForm):
] ]
field_classes = { field_classes = {
'valid_until': SplitDateTimeField, 'valid_until': SplitDateTimeField,
'subevent': SafeModelChoiceField,
} }
widgets = { widgets = {
'valid_until': SplitDateTimePickerWidget(), 'valid_until': SplitDateTimePickerWidget(),

View File

@@ -4,10 +4,11 @@ from django.conf import settings
from django.contrib.auth import REDIRECT_FIELD_NAME, logout from django.contrib.auth import REDIRECT_FIELD_NAME, logout
from django.http import Http404 from django.http import Http404
from django.shortcuts import get_object_or_404, redirect, resolve_url from django.shortcuts import get_object_or_404, redirect, resolve_url
from django.template.response import TemplateResponse
from django.urls import get_script_prefix, resolve, reverse from django.urls import get_script_prefix, resolve, reverse
from django.utils.deprecation import MiddlewareMixin
from django.utils.encoding import force_str from django.utils.encoding import force_str
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django_scopes import scope
from hijack.templatetags.hijack_tags import is_hijacked from hijack.templatetags.hijack_tags import is_hijacked
from pretix.base.models import Event, Organizer from pretix.base.models import Event, Organizer
@@ -17,7 +18,7 @@ from pretix.helpers.security import (
) )
class PermissionMiddleware(MiddlewareMixin): class PermissionMiddleware:
""" """
This middleware enforces all requests to the control app to require login. This middleware enforces all requests to the control app to require login.
Additionally, it enforces all requests to "control:event." URLs Additionally, it enforces all requests to "control:event." URLs
@@ -34,6 +35,10 @@ class PermissionMiddleware(MiddlewareMixin):
"user.settings.notifications.off", "user.settings.notifications.off",
) )
def __init__(self, get_response=None):
self.get_response = get_response
super().__init__()
def _login_redirect(self, request): def _login_redirect(self, request):
# Taken from django/contrib/auth/decorators.py # Taken from django/contrib/auth/decorators.py
path = request.build_absolute_uri() path = request.build_absolute_uri()
@@ -52,19 +57,19 @@ class PermissionMiddleware(MiddlewareMixin):
return redirect_to_login( return redirect_to_login(
path, resolved_login_url, REDIRECT_FIELD_NAME) path, resolved_login_url, REDIRECT_FIELD_NAME)
def process_request(self, request): def __call__(self, request):
url = resolve(request.path_info) url = resolve(request.path_info)
url_name = url.url_name url_name = url.url_name
if not request.path.startswith(get_script_prefix() + 'control'): if not request.path.startswith(get_script_prefix() + 'control'):
# This middleware should only touch the /control subpath # This middleware should only touch the /control subpath
return return self.get_response(request)
if hasattr(request, 'organizer'): if hasattr(request, 'organizer'):
# If the user is on a organizer's subdomain, he should be redirected to pretix # If the user is on a organizer's subdomain, he should be redirected to pretix
return redirect(urljoin(settings.SITE_URL, request.get_full_path())) return redirect(urljoin(settings.SITE_URL, request.get_full_path()))
if url_name in self.EXCEPTIONS: if url_name in self.EXCEPTIONS:
return return self.get_response(request)
if not request.user.is_authenticated: if not request.user.is_authenticated:
return self._login_redirect(request) return self._login_redirect(request)
@@ -79,10 +84,11 @@ class PermissionMiddleware(MiddlewareMixin):
return redirect(reverse('control:user.reauth') + '?next=' + quote(request.get_full_path())) return redirect(reverse('control:user.reauth') + '?next=' + quote(request.get_full_path()))
if 'event' in url.kwargs and 'organizer' in url.kwargs: if 'event' in url.kwargs and 'organizer' in url.kwargs:
request.event = Event.objects.filter( with scope(organizer=None):
slug=url.kwargs['event'], request.event = Event.objects.filter(
organizer__slug=url.kwargs['organizer'], slug=url.kwargs['event'],
).select_related('organizer').first() organizer__slug=url.kwargs['organizer'],
).select_related('organizer').first()
if not request.event or not request.user.has_event_permission(request.event.organizer, request.event, if not request.event or not request.user.has_event_permission(request.event.organizer, request.event,
request=request): request=request):
raise Http404(_("The selected event was not found or you " raise Http404(_("The selected event was not found or you "
@@ -104,6 +110,12 @@ class PermissionMiddleware(MiddlewareMixin):
else: else:
request.orgapermset = request.user.get_organizer_permission_set(request.organizer) request.orgapermset = request.user.get_organizer_permission_set(request.organizer)
with scope(organizer=getattr(request, 'organizer', None)):
r = self.get_response(request)
if isinstance(r, TemplateResponse):
r = r.render()
return r
class AuditLogMiddleware: class AuditLogMiddleware:

View File

@@ -7,6 +7,7 @@ from pretix.base.models import (
CachedFile, Event, OrderPosition, cachedfile_name, CachedFile, Event, OrderPosition, cachedfile_name,
) )
from pretix.base.services.orders import OrderError from pretix.base.services.orders import OrderError
from pretix.base.services.tasks import EventTask
from pretix.celery_app import app from pretix.celery_app import app
from .exporters import render_pdf from .exporters import render_pdf
@@ -14,8 +15,8 @@ from .exporters import render_pdf
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@app.task(throws=(OrderError,)) @app.task(base=EventTask, throws=(OrderError,))
def badges_create_pdf(fileid: int, event: int, positions: List[int]) -> int: def badges_create_pdf(event: int, fileid: int, positions: List[int]) -> int:
file = CachedFile.objects.get(id=fileid) file = CachedFile.objects.get(id=fileid)
event = Event.objects.get(id=event) event = Event.objects.get(id=event)

View File

@@ -223,7 +223,7 @@ class OrderPrintDo(EventPermissionRequiredMixin, AsyncAction, View):
else: else:
positions = [p.pk for p in order.positions.all()] positions = [p.pk for p in order.positions.all()]
return self.do( return self.do(
str(cf.id),
self.request.event.pk, self.request.event.pk,
str(cf.id),
positions, positions,
) )

View File

@@ -9,6 +9,7 @@ from django.db import transaction
from django.db.models import Q from django.db.models import Q
from django.utils.formats import date_format from django.utils.formats import date_format
from django.utils.translation import ugettext, ugettext_noop from django.utils.translation import ugettext, ugettext_noop
from django_scopes import scope, scopes_disabled
from pretix.base.i18n import language from pretix.base.i18n import language
from pretix.base.models import ( from pretix.base.models import (
@@ -194,51 +195,53 @@ def _get_unknown_transactions(job: BankImportJob, data: list, event: Event=None,
@app.task(base=TransactionAwareTask, bind=True, max_retries=5, default_retry_delay=1) @app.task(base=TransactionAwareTask, bind=True, max_retries=5, default_retry_delay=1)
def process_banktransfers(self, job: int, data: list) -> None: def process_banktransfers(self, job: int, data: list) -> None:
with language("en"): # We'll translate error messages at display time with language("en"): # We'll translate error messages at display time
job = BankImportJob.objects.get(pk=job) with scopes_disabled():
job.state = BankImportJob.STATE_RUNNING job = BankImportJob.objects.get(pk=job)
job.save() with scope(organizer=job.organizer or job.event.organizer):
prefixes = [] job.state = BankImportJob.STATE_RUNNING
job.save()
prefixes = []
try:
# Delete left-over transactions from a failed run before so they can reimported
BankTransaction.objects.filter(state=BankTransaction.STATE_UNCHECKED, **job.owner_kwargs).delete()
transactions = _get_unknown_transactions(job, data, **job.owner_kwargs)
code_len = settings.ENTROPY['order_code']
if job.event:
pattern = re.compile(job.event.slug.upper() + r"[ \-_]*([A-Z0-9]{%s})" % code_len)
else:
if not prefixes:
prefixes = [e.slug.upper().replace(".", r"\.").replace("-", r"[\- ]*")
for e in job.organizer.events.all()]
pattern = re.compile("(%s)[ \\-_]*([A-Z0-9]{%s})" % ("|".join(prefixes), code_len))
for trans in transactions:
match = pattern.search(trans.reference.replace(" ", "").replace("\n", "").upper())
if match:
if job.event:
code = match.group(1)
_handle_transaction(trans, code, event=job.event)
else:
slug = match.group(1)
code = match.group(2)
_handle_transaction(trans, code, organizer=job.organizer, slug=slug)
else:
trans.state = BankTransaction.STATE_NOMATCH
trans.save()
except LockTimeoutException:
try: try:
self.retry() # Delete left-over transactions from a failed run before so they can reimported
except MaxRetriesExceededError: BankTransaction.objects.filter(state=BankTransaction.STATE_UNCHECKED, **job.owner_kwargs).delete()
logger.exception('Maximum number of retries exceeded for task.')
transactions = _get_unknown_transactions(job, data, **job.owner_kwargs)
code_len = settings.ENTROPY['order_code']
if job.event:
pattern = re.compile(job.event.slug.upper() + r"[ \-_]*([A-Z0-9]{%s})" % code_len)
else:
if not prefixes:
prefixes = [e.slug.upper().replace(".", r"\.").replace("-", r"[\- ]*")
for e in job.organizer.events.all()]
pattern = re.compile("(%s)[ \\-_]*([A-Z0-9]{%s})" % ("|".join(prefixes), code_len))
for trans in transactions:
match = pattern.search(trans.reference.replace(" ", "").replace("\n", "").upper())
if match:
if job.event:
code = match.group(1)
_handle_transaction(trans, code, event=job.event)
else:
slug = match.group(1)
code = match.group(2)
_handle_transaction(trans, code, organizer=job.organizer, slug=slug)
else:
trans.state = BankTransaction.STATE_NOMATCH
trans.save()
except LockTimeoutException:
try:
self.retry()
except MaxRetriesExceededError:
logger.exception('Maximum number of retries exceeded for task.')
job.state = BankImportJob.STATE_ERROR
job.save()
except Exception as e:
job.state = BankImportJob.STATE_ERROR job.state = BankImportJob.STATE_ERROR
job.save() job.save()
except Exception as e: raise e
job.state = BankImportJob.STATE_ERROR else:
job.save() job.state = BankImportJob.STATE_COMPLETED
raise e job.save()
else:
job.state = BankImportJob.STATE_COMPLETED
job.save()

View File

@@ -13,6 +13,7 @@ from django.utils.translation import ugettext_lazy as _
from django.views.decorators.clickjacking import xframe_options_exempt from django.views.decorators.clickjacking import xframe_options_exempt
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST from django.views.decorators.http import require_POST
from django_scopes import scopes_disabled
from paypalrestsdk.openid_connect import Tokeninfo from paypalrestsdk.openid_connect import Tokeninfo
from pretix.base.models import Event, Order, OrderPayment, OrderRefund, Quota from pretix.base.models import Event, Order, OrderPayment, OrderRefund, Quota
@@ -133,6 +134,7 @@ def abort(request, *args, **kwargs):
@csrf_exempt @csrf_exempt
@require_POST @require_POST
@scopes_disabled()
def webhook(request, *args, **kwargs): def webhook(request, *args, **kwargs):
event_body = request.body.decode('utf-8').strip() event_body = request.body.decode('utf-8').strip()
event_json = json.loads(event_body) event_json = json.loads(event_body)

View File

@@ -1,6 +1,9 @@
from django import forms from django import forms
from django.urls import reverse from django.urls import reverse
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django_scopes.forms import (
SafeModelChoiceField, SafeModelMultipleChoiceField,
)
from pretix.control.forms.widgets import Select2 from pretix.control.forms.widgets import Select2
from pretix.plugins.pretixdroid.models import AppConfiguration from pretix.plugins.pretixdroid.models import AppConfiguration
@@ -16,6 +19,10 @@ class AppConfigurationForm(forms.ModelForm):
}), }),
'app': forms.RadioSelect 'app': forms.RadioSelect
} }
field_classes = {
'items': SafeModelMultipleChoiceField,
'list': SafeModelChoiceField,
}
def __init__(self, **kwargs): def __init__(self, **kwargs):
self.event = kwargs.pop('event') self.event = kwargs.pop('event')

View File

@@ -17,6 +17,7 @@ from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from django.views.generic import TemplateView, View from django.views.generic import TemplateView, View
from django_scopes import scope, scopes_disabled
from pretix.base.models import Checkin, Event, Order, OrderPosition from pretix.base.models import Checkin, Event, Order, OrderPosition
from pretix.base.models.event import SubEvent from pretix.base.models.event import SubEvent
@@ -124,34 +125,35 @@ class ConfigView(EventPermissionRequiredMixin, TemplateView):
class ApiView(View): class ApiView(View):
@method_decorator(csrf_exempt) @method_decorator(csrf_exempt)
def dispatch(self, request, **kwargs): def dispatch(self, request, **kwargs):
try: with scopes_disabled():
self.event = Event.objects.get( try:
slug=self.kwargs['event'], self.event = Event.objects.get(
organizer__slug=self.kwargs['organizer'] slug=self.kwargs['event'],
) organizer__slug=self.kwargs['organizer']
except Event.DoesNotExist: )
return HttpResponseNotFound('Unknown event') except Event.DoesNotExist:
return HttpResponseNotFound('Unknown event')
with scope(organizer=self.event.organizer):
try:
self.config = self.event.appconfiguration_set.get(key=request.GET.get("key", "-unset-"))
except AppConfiguration.DoesNotExist:
return HttpResponseForbidden('Invalid key')
try: self.subevent = None
self.config = self.event.appconfiguration_set.get(key=request.GET.get("key", "-unset-")) if self.event.has_subevents:
except AppConfiguration.DoesNotExist: if self.config.list.subevent:
return HttpResponseForbidden('Invalid key') self.subevent = self.config.list.subevent
if 'subevent' in kwargs and kwargs['subevent'] != str(self.subevent.pk):
self.subevent = None return HttpResponseForbidden('Invalid subevent selected.')
if self.event.has_subevents: elif 'subevent' in kwargs:
if self.config.list.subevent: self.subevent = get_object_or_404(SubEvent, event=self.event, pk=kwargs['subevent'])
self.subevent = self.config.list.subevent else:
if 'subevent' in kwargs and kwargs['subevent'] != str(self.subevent.pk): return HttpResponseForbidden('No subevent selected.')
return HttpResponseForbidden('Invalid subevent selected.')
elif 'subevent' in kwargs:
self.subevent = get_object_or_404(SubEvent, event=self.event, pk=kwargs['subevent'])
else: else:
return HttpResponseForbidden('No subevent selected.') if 'subevent' in kwargs:
else: return HttpResponseForbidden('Subevents not enabled.')
if 'subevent' in kwargs:
return HttpResponseForbidden('Subevents not enabled.')
return super().dispatch(request, **kwargs) return super().dispatch(request, **kwargs)
class ApiRedeemView(ApiView): class ApiRedeemView(ApiView):

View File

@@ -5,15 +5,14 @@ from i18nfield.strings import LazyI18nString
from pretix.base.i18n import language from pretix.base.i18n import language
from pretix.base.models import Event, InvoiceAddress, Order, User from pretix.base.models import Event, InvoiceAddress, Order, User
from pretix.base.services.mail import SendMailException, mail from pretix.base.services.mail import SendMailException, mail
from pretix.base.services.tasks import ProfiledTask from pretix.base.services.tasks import ProfiledEventTask
from pretix.celery_app import app from pretix.celery_app import app
from pretix.multidomain.urlreverse import build_absolute_uri from pretix.multidomain.urlreverse import build_absolute_uri
@app.task(base=ProfiledTask) @app.task(base=ProfiledEventTask)
def send_mails(event: int, user: int, subject: dict, message: dict, orders: list, items: list, recipients: str) -> None: def send_mails(event: Event, user: int, subject: dict, message: dict, orders: list, items: list, recipients: str) -> None:
failures = [] failures = []
event = Event.objects.get(pk=event)
user = User.objects.get(pk=user) if user else None user = User.objects.get(pk=user) if user else None
orders = Order.objects.filter(pk__in=orders, event=event) orders = Order.objects.filter(pk__in=orders, event=event)
subject = LazyI18nString(subject) subject = LazyI18nString(subject)

View File

@@ -1,5 +1,6 @@
import stripe import stripe
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from django_scopes import scopes_disabled
from pretix.base.models import Event from pretix.base.models import Event
from pretix.base.settings import GlobalSettingsObject from pretix.base.settings import GlobalSettingsObject
@@ -8,6 +9,7 @@ from pretix.base.settings import GlobalSettingsObject
class Command(BaseCommand): class Command(BaseCommand):
help = "Detect country for Stripe Connect accounts connected with pretix 2.0 (required for payment request buttons)" help = "Detect country for Stripe Connect accounts connected with pretix 2.0 (required for payment request buttons)"
@scopes_disabled()
def handle(self, *args, **options): def handle(self, *args, **options):
cache = {} cache = {}
gs = GlobalSettingsObject() gs = GlobalSettingsObject()

View File

@@ -5,6 +5,7 @@ import stripe
from django.conf import settings from django.conf import settings
from pretix.base.models import Event from pretix.base.models import Event
from pretix.base.services.tasks import EventTask
from pretix.celery_app import app from pretix.celery_app import app
from pretix.multidomain.urlreverse import get_domain from pretix.multidomain.urlreverse import get_domain
from pretix.plugins.stripe.models import RegisteredApplePayDomain from pretix.plugins.stripe.models import RegisteredApplePayDomain
@@ -27,7 +28,7 @@ def get_stripe_account_key(prov):
return prov.settings.publishable_key return prov.settings.publishable_key
@app.task(max_retries=5, default_retry_delay=1) @app.task(base=EventTask, max_retries=5, default_retry_delay=1)
def stripe_verify_domain(event_id, domain): def stripe_verify_domain(event_id, domain):
from pretix.plugins.stripe.payment import StripeCC from pretix.plugins.stripe.payment import StripeCC
event = Event.objects.get(pk=event_id) event = Event.objects.get(pk=event_id)

View File

@@ -17,6 +17,7 @@ from django.views import View
from django.views.decorators.clickjacking import xframe_options_exempt from django.views.decorators.clickjacking import xframe_options_exempt
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST from django.views.decorators.http import require_POST
from django_scopes import scopes_disabled
from pretix.base.models import Event, Order, OrderPayment, Quota from pretix.base.models import Event, Order, OrderPayment, Quota
from pretix.base.payment import PaymentException from pretix.base.payment import PaymentException
@@ -140,6 +141,7 @@ def oauth_return(request, *args, **kwargs):
@csrf_exempt @csrf_exempt
@require_POST @require_POST
@scopes_disabled()
def webhook(request, *args, **kwargs): def webhook(request, *args, **kwargs):
event_json = json.loads(request.body.decode('utf-8')) event_json = json.loads(request.body.decode('utf-8'))

View File

@@ -12,6 +12,7 @@ from django.utils.translation import (
get_language, pgettext_lazy, ugettext_lazy as _, get_language, pgettext_lazy, ugettext_lazy as _,
) )
from django.views.generic.base import TemplateResponseMixin from django.views.generic.base import TemplateResponseMixin
from django_scopes import scopes_disabled
from pretix.base.models import Order from pretix.base.models import Order
from pretix.base.models.orders import InvoiceAddress, OrderPayment from pretix.base.models.orders import InvoiceAddress, OrderPayment
@@ -114,7 +115,10 @@ class BaseCheckoutFlowStep:
self.request._checkout_flow_invoice_address = InvoiceAddress() self.request._checkout_flow_invoice_address = InvoiceAddress()
else: else:
try: try:
self.request._checkout_flow_invoice_address = InvoiceAddress.objects.get(pk=iapk, order__isnull=True) with scopes_disabled():
self.request._checkout_flow_invoice_address = InvoiceAddress.objects.get(
pk=iapk, order__isnull=True
)
except InvoiceAddress.DoesNotExist: except InvoiceAddress.DoesNotExist:
self.request._checkout_flow_invoice_address = InvoiceAddress() self.request._checkout_flow_invoice_address = InvoiceAddress()
return self.request._checkout_flow_invoice_address return self.request._checkout_flow_invoice_address

View File

@@ -4,6 +4,7 @@ from django.conf import settings
from django.core.files.base import ContentFile, File from django.core.files.base import ContentFile, File
from django.core.files.storage import default_storage from django.core.files.storage import default_storage
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from django_scopes import scopes_disabled
from pretix.base.models import Event_SettingsStore, Organizer_SettingsStore from pretix.base.models import Event_SettingsStore, Organizer_SettingsStore
from pretix.base.settings import GlobalSettingsObject from pretix.base.settings import GlobalSettingsObject
@@ -15,6 +16,7 @@ from ...style import regenerate_css, regenerate_organizer_css
class Command(BaseCommand): class Command(BaseCommand):
help = "Re-generate all custom stylesheets and scripts" help = "Re-generate all custom stylesheets and scripts"
@scopes_disabled()
def handle(self, *args, **options): def handle(self, *args, **options):
for es in Organizer_SettingsStore.objects.filter(key="presale_css_file"): for es in Organizer_SettingsStore.objects.filter(key="presale_css_file"):
regenerate_organizer_css.apply_async(args=(es.object_id,)) regenerate_organizer_css.apply_async(args=(es.object_id,))

View File

@@ -1,25 +1,32 @@
from django.urls import resolve from django.urls import resolve
from django.utils.deprecation import MiddlewareMixin from django_scopes import scope
from pretix.presale.signals import process_response from pretix.presale.signals import process_response
from .utils import _detect_event from .utils import _detect_event
class EventMiddleware(MiddlewareMixin): class EventMiddleware:
def process_request(self, request): def __init__(self, get_response=None):
self.get_response = get_response
super().__init__()
def __call__(self, request):
url = resolve(request.path_info) url = resolve(request.path_info)
request._namespace = url.namespace request._namespace = url.namespace
if url.namespace != 'presale': if url.namespace != 'presale':
return return self.get_response(request)
if 'organizer' in url.kwargs or 'event' in url.kwargs: if 'organizer' in url.kwargs or 'event' in url.kwargs:
redirect = _detect_event(request, require_live=url.url_name != 'event.widget.productlist') redirect = _detect_event(request, require_live=url.url_name != 'event.widget.productlist')
if redirect: if redirect:
return redirect return redirect
def process_response(self, request, response): with scope(organizer=getattr(request, 'organizer', None)):
if hasattr(request, '_namespace') and request._namespace == 'presale' and hasattr(request, 'event'): response = self.get_response(request)
for receiver, r in process_response.send(request.event, request=request, response=response):
response = r if hasattr(request, '_namespace') and request._namespace == 'presale' and hasattr(request, 'event'):
for receiver, r in process_response.send(request.event, request=request, response=response):
response = r
return response return response

View File

@@ -11,9 +11,10 @@ from django.core.files.base import ContentFile
from django.core.files.storage import default_storage from django.core.files.storage import default_storage
from django.dispatch import Signal from django.dispatch import Signal
from django.templatetags.static import static as _static from django.templatetags.static import static as _static
from django_scopes import scope
from pretix.base.models import Event, Event_SettingsStore, Organizer from pretix.base.models import Event, Event_SettingsStore, Organizer
from pretix.base.services.tasks import ProfiledTask from pretix.base.services.tasks import ProfiledEventTask, ProfiledTask
from pretix.celery_app import app from pretix.celery_app import app
from pretix.multidomain.urlreverse import get_domain from pretix.multidomain.urlreverse import get_domain
from pretix.presale.signals import sass_postamble, sass_preamble from pretix.presale.signals import sass_postamble, sass_preamble
@@ -78,10 +79,8 @@ def compile_scss(object, file="main.scss", fonts=True):
return css, checksum return css, checksum
@app.task(base=ProfiledTask) @app.task(base=ProfiledEventTask)
def regenerate_css(event_id: int): def regenerate_css(event):
event = Event.objects.select_related('organizer').get(pk=event_id)
# main.scss # main.scss
css, checksum = compile_scss(event) css, checksum = compile_scss(event)
fname = 'pub/{}/{}/presale.{}.css'.format(event.organizer.slug, event.slug, checksum[:16]) fname = 'pub/{}/{}/presale.{}.css'.format(event.organizer.slug, event.slug, checksum[:16])
@@ -105,28 +104,29 @@ def regenerate_css(event_id: int):
def regenerate_organizer_css(organizer_id: int): def regenerate_organizer_css(organizer_id: int):
organizer = Organizer.objects.get(pk=organizer_id) organizer = Organizer.objects.get(pk=organizer_id)
# main.scss with scope(organizer=organizer):
css, checksum = compile_scss(organizer) # main.scss
fname = 'pub/{}/presale.{}.css'.format(organizer.slug, checksum[:16]) css, checksum = compile_scss(organizer)
if organizer.settings.get('presale_css_checksum', '') != checksum: fname = 'pub/{}/presale.{}.css'.format(organizer.slug, checksum[:16])
newname = default_storage.save(fname, ContentFile(css.encode('utf-8'))) if organizer.settings.get('presale_css_checksum', '') != checksum:
organizer.settings.set('presale_css_file', newname) newname = default_storage.save(fname, ContentFile(css.encode('utf-8')))
organizer.settings.set('presale_css_checksum', checksum) organizer.settings.set('presale_css_file', newname)
organizer.settings.set('presale_css_checksum', checksum)
# widget.scss # widget.scss
css, checksum = compile_scss(organizer, file='widget.scss', fonts=False) css, checksum = compile_scss(organizer, file='widget.scss', fonts=False)
fname = 'pub/{}/widget.{}.css'.format(organizer.slug, checksum[:16]) fname = 'pub/{}/widget.{}.css'.format(organizer.slug, checksum[:16])
if organizer.settings.get('presale_widget_css_checksum', '') != checksum: if organizer.settings.get('presale_widget_css_checksum', '') != checksum:
newname = default_storage.save(fname, ContentFile(css.encode('utf-8'))) newname = default_storage.save(fname, ContentFile(css.encode('utf-8')))
organizer.settings.set('presale_widget_css_file', newname) organizer.settings.set('presale_widget_css_file', newname)
organizer.settings.set('presale_widget_css_checksum', checksum) organizer.settings.set('presale_widget_css_checksum', checksum)
non_inherited_events = set(Event_SettingsStore.objects.filter( non_inherited_events = set(Event_SettingsStore.objects.filter(
object__organizer=organizer, key__in=affected_keys object__organizer=organizer, key__in=affected_keys
).values_list('object_id', flat=True)) ).values_list('object_id', flat=True))
for event in organizer.events.all(): for event in organizer.events.all():
if event.pk not in non_inherited_events: if event.pk not in non_inherited_events:
regenerate_css.apply_async(args=(event.pk,)) regenerate_css.apply_async(args=(event.pk,))
register_fonts = Signal() register_fonts = Signal()

View File

@@ -8,6 +8,7 @@ from django.http import Http404
from django.shortcuts import redirect from django.shortcuts import redirect
from django.urls import resolve from django.urls import resolve
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django_scopes import scope
from pretix.base.middleware import LocaleMiddleware from pretix.base.middleware import LocaleMiddleware
from pretix.base.models import Event, Organizer from pretix.base.models import Event, Organizer
@@ -17,6 +18,7 @@ from pretix.presale.signals import process_request, process_response
SessionStore = import_module(settings.SESSION_ENGINE).SessionStore SessionStore = import_module(settings.SESSION_ENGINE).SessionStore
@scope(organizer=None)
def _detect_event(request, require_live=True, require_plugin=None): def _detect_event(request, require_live=True, require_plugin=None):
if hasattr(request, '_event_detected'): if hasattr(request, '_event_detected'):
return return
@@ -151,10 +153,11 @@ def _event_view(function=None, require_live=True, require_plugin=None):
if ret: if ret:
return ret return ret
else: else:
response = func(request=request, *args, **kwargs) with scope(organizer=getattr(request, 'organizer', None)):
for receiver, r in process_response.send(request.event, request=request, response=response): response = func(request=request, *args, **kwargs)
response = r for receiver, r in process_response.send(request.event, request=request, response=response):
return response response = r
return response
for attrname in dir(func): for attrname in dir(func):
# Preserve flags like csrf_exempt # Preserve flags like csrf_exempt

View File

@@ -9,6 +9,7 @@ from django.db.models import Prefetch, Sum
from django.utils.decorators import available_attrs from django.utils.decorators import available_attrs
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.timezone import now from django.utils.timezone import now
from django_scopes import scopes_disabled
from pretix.base.i18n import language from pretix.base.i18n import language
from pretix.base.models import ( from pretix.base.models import (
@@ -40,7 +41,10 @@ class CartMixin:
self.request._checkout_flow_invoice_address = InvoiceAddress() self.request._checkout_flow_invoice_address = InvoiceAddress()
else: else:
try: try:
self.request._checkout_flow_invoice_address = InvoiceAddress.objects.get(pk=iapk, order__isnull=True) with scopes_disabled():
self.request._checkout_flow_invoice_address = InvoiceAddress.objects.get(
pk=iapk, order__isnull=True
)
except InvoiceAddress.DoesNotExist: except InvoiceAddress.DoesNotExist:
self.request._checkout_flow_invoice_address = InvoiceAddress() self.request._checkout_flow_invoice_address = InvoiceAddress()
return self.request._checkout_flow_invoice_address return self.request._checkout_flow_invoice_address
@@ -215,7 +219,8 @@ def get_cart_invoice_address(request):
request._checkout_flow_invoice_address = InvoiceAddress() request._checkout_flow_invoice_address = InvoiceAddress()
else: else:
try: try:
request._checkout_flow_invoice_address = InvoiceAddress.objects.get(pk=iapk, order__isnull=True) with scopes_disabled():
request._checkout_flow_invoice_address = InvoiceAddress.objects.get(pk=iapk, order__isnull=True)
except InvoiceAddress.DoesNotExist: except InvoiceAddress.DoesNotExist:
request._checkout_flow_invoice_address = InvoiceAddress() request._checkout_flow_invoice_address = InvoiceAddress()
return request._checkout_flow_invoice_address return request._checkout_flow_invoice_address

View File

@@ -17,6 +17,7 @@ from django.utils.timezone import now
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.views.decorators.clickjacking import xframe_options_exempt from django.views.decorators.clickjacking import xframe_options_exempt
from django.views.generic import TemplateView, View from django.views.generic import TemplateView, View
from django_scopes import scopes_disabled
from pretix.base.models import ( from pretix.base.models import (
CartPosition, InvoiceAddress, QuestionAnswer, SubEvent, Voucher, CartPosition, InvoiceAddress, QuestionAnswer, SubEvent, Voucher,
@@ -80,7 +81,8 @@ class CartActionMixin:
return InvoiceAddress() return InvoiceAddress()
try: try:
return InvoiceAddress.objects.get(pk=iapk, order__isnull=True) with scopes_disabled():
return InvoiceAddress.objects.get(pk=iapk, order__isnull=True)
except InvoiceAddress.DoesNotExist: except InvoiceAddress.DoesNotExist:
return InvoiceAddress() return InvoiceAddress()

View File

@@ -343,6 +343,7 @@ MIDDLEWARE = [
'pretix.base.middleware.LocaleMiddleware', 'pretix.base.middleware.LocaleMiddleware',
'pretix.base.middleware.SecurityMiddleware', 'pretix.base.middleware.SecurityMiddleware',
'pretix.presale.middleware.EventMiddleware', 'pretix.presale.middleware.EventMiddleware',
'pretix.api.middleware.ApiScopeMiddleware',
] ]
try: try:

View File

@@ -0,0 +1,10 @@
from django_scopes import scope
def classscope(attr='o'):
def wrap(fn):
def wrapped(self, *args, **kwargs):
with scope(organizer=getattr(self, attr)):
return fn(self, *args, **kwargs)
return wrapped
return wrap

View File

@@ -12,6 +12,7 @@ from pretix.settings import * # NOQA
DATA_DIR = tmpdir.name DATA_DIR = tmpdir.name
LOG_DIR = os.path.join(DATA_DIR, 'logs') LOG_DIR = os.path.join(DATA_DIR, 'logs')
MEDIA_ROOT = os.path.join(DATA_DIR, 'media') MEDIA_ROOT = os.path.join(DATA_DIR, 'media')
SITE_URL = "http://example.com"
atexit.register(tmpdir.cleanup) atexit.register(tmpdir.cleanup)

View File

@@ -9,6 +9,7 @@ django-formset-js-improved==0.5.0.2
django-compressor==2.2.* django-compressor==2.2.*
django-hierarkey==1.0.*,>=1.0.3 django-hierarkey==1.0.*,>=1.0.3
django-filter==2.1.* django-filter==2.1.*
django-scopes==1.1.*
reportlab==3.5.* reportlab==3.5.*
PyPDF2==1.26.* PyPDF2==1.26.*
Pillow==5.* Pillow==5.*

View File

@@ -97,6 +97,7 @@ setup(
'django-compressor==2.2.*', 'django-compressor==2.2.*',
'django-hierarkey==1.0.*,>=1.0.2', 'django-hierarkey==1.0.*,>=1.0.2',
'django-filter==2.1.*', 'django-filter==2.1.*',
'django-scopes==1.1.*',
'reportlab==3.5.*', 'reportlab==3.5.*',
'Pillow==5.*', 'Pillow==5.*',
'PyPDF2==1.26.*', 'PyPDF2==1.26.*',

View File

@@ -1,7 +1,9 @@
from datetime import datetime from datetime import datetime
import pytest import pytest
from django.test import utils
from django.utils.timezone import now from django.utils.timezone import now
from django_scopes import scopes_disabled
from pytz import UTC from pytz import UTC
from rest_framework.test import APIClient from rest_framework.test import APIClient
@@ -15,16 +17,19 @@ def client():
@pytest.fixture @pytest.fixture
@scopes_disabled()
def organizer(): def organizer():
return Organizer.objects.create(name='Dummy', slug='dummy') return Organizer.objects.create(name='Dummy', slug='dummy')
@pytest.fixture @pytest.fixture
@scopes_disabled()
def meta_prop(organizer): def meta_prop(organizer):
return organizer.meta_properties.create(name="type", default="Concert") return organizer.meta_properties.create(name="type", default="Concert")
@pytest.fixture @pytest.fixture
@scopes_disabled()
def event(organizer, meta_prop): def event(organizer, meta_prop):
e = Event.objects.create( e = Event.objects.create(
organizer=organizer, name='Dummy', slug='dummy', organizer=organizer, name='Dummy', slug='dummy',
@@ -37,6 +42,7 @@ def event(organizer, meta_prop):
@pytest.fixture @pytest.fixture
@scopes_disabled()
def event2(organizer, meta_prop): def event2(organizer, meta_prop):
e = Event.objects.create( e = Event.objects.create(
organizer=organizer, name='Dummy2', slug='dummy2', organizer=organizer, name='Dummy2', slug='dummy2',
@@ -48,6 +54,7 @@ def event2(organizer, meta_prop):
@pytest.fixture @pytest.fixture
@scopes_disabled()
def event3(organizer, meta_prop): def event3(organizer, meta_prop):
e = Event.objects.create( e = Event.objects.create(
organizer=organizer, name='Dummy3', slug='dummy3', organizer=organizer, name='Dummy3', slug='dummy3',
@@ -59,6 +66,7 @@ def event3(organizer, meta_prop):
@pytest.fixture @pytest.fixture
@scopes_disabled()
def team(organizer): def team(organizer):
return Team.objects.create( return Team.objects.create(
organizer=organizer, organizer=organizer,
@@ -73,6 +81,7 @@ def team(organizer):
@pytest.fixture @pytest.fixture
@scopes_disabled()
def device(organizer): def device(organizer):
return Device.objects.create( return Device.objects.create(
organizer=organizer, organizer=organizer,
@@ -89,6 +98,7 @@ def user():
@pytest.fixture @pytest.fixture
@scopes_disabled()
def user_client(client, team, user): def user_client(client, team, user):
team.can_view_orders = True team.can_view_orders = True
team.can_view_vouchers = True team.can_view_vouchers = True
@@ -100,6 +110,7 @@ def user_client(client, team, user):
@pytest.fixture @pytest.fixture
@scopes_disabled()
def token_client(client, team): def token_client(client, team):
team.can_view_orders = True team.can_view_orders = True
team.can_view_vouchers = True team.can_view_vouchers = True
@@ -117,6 +128,7 @@ def device_client(client, device):
@pytest.fixture @pytest.fixture
@scopes_disabled()
def subevent(event, meta_prop): def subevent(event, meta_prop):
event.has_subevents = True event.has_subevents = True
event.save() event.save()
@@ -127,6 +139,7 @@ def subevent(event, meta_prop):
@pytest.fixture @pytest.fixture
@scopes_disabled()
def subevent2(event2, meta_prop): def subevent2(event2, meta_prop):
event2.has_subevents = True event2.has_subevents = True
event2.save() event2.save()
@@ -137,10 +150,15 @@ def subevent2(event2, meta_prop):
@pytest.fixture @pytest.fixture
@scopes_disabled()
def taxrule(event): def taxrule(event):
return event.tax_rules.create(name="VAT", rate=19) return event.tax_rules.create(name="VAT", rate=19)
@pytest.fixture @pytest.fixture
@scopes_disabled()
def taxrule2(event2): def taxrule2(event2):
return event2.tax_rules.create(name="VAT", rate=25) return event2.tax_rules.create(name="VAT", rate=25)
utils.setup_databases = scopes_disabled()(utils.setup_databases)

View File

@@ -13,7 +13,6 @@ def test_no_auth(client):
def test_session_auth_no_teams(client, user): def test_session_auth_no_teams(client, user):
client.login(email=user.email, password='dummy') client.login(email=user.email, password='dummy')
resp = client.get('/api/v1/organizers/') resp = client.get('/api/v1/organizers/')
print(resp.data)
assert resp.status_code == 200 assert resp.status_code == 200
assert len(resp.data['results']) == 0 assert len(resp.data['results']) == 0

View File

@@ -5,6 +5,7 @@ from unittest import mock
import pytest import pytest
from django.utils.timezone import now from django.utils.timezone import now
from django_scopes import scopes_disabled
from pytz import UTC from pytz import UTC
from pretix.base.models import Question from pretix.base.models import Question
@@ -175,7 +176,8 @@ def test_cartpos_create(token_client, organizer, event, item, quota, question):
), format='json', data=res ), format='json', data=res
) )
assert resp.status_code == 201 assert resp.status_code == 201
cp = CartPosition.objects.get(pk=resp.data['id']) with scopes_disabled():
cp = CartPosition.objects.get(pk=resp.data['id'])
assert cp.price == Decimal('23.00') assert cp.price == Decimal('23.00')
assert cp.item == item assert cp.item == item
assert cp.attendee_name_parts == {'full_name': 'Peter'} assert cp.attendee_name_parts == {'full_name': 'Peter'}
@@ -193,7 +195,8 @@ def test_cartpos_create_name_optional(token_client, organizer, event, item, quot
), format='json', data=res ), format='json', data=res
) )
assert resp.status_code == 201 assert resp.status_code == 201
cp = CartPosition.objects.get(pk=resp.data['id']) with scopes_disabled():
cp = CartPosition.objects.get(pk=resp.data['id'])
assert cp.price == Decimal('23.00') assert cp.price == Decimal('23.00')
assert cp.item == item assert cp.item == item
assert cp.attendee_name_parts == {} assert cp.attendee_name_parts == {}
@@ -217,7 +220,8 @@ def test_cartpos_create_legacy_name(token_client, organizer, event, item, quota,
), format='json', data=res ), format='json', data=res
) )
assert resp.status_code == 201 assert resp.status_code == 201
cp = CartPosition.objects.get(pk=resp.data['id']) with scopes_disabled():
cp = CartPosition.objects.get(pk=resp.data['id'])
assert cp.price == Decimal('23.00') assert cp.price == Decimal('23.00')
assert cp.item == item assert cp.item == item
assert cp.attendee_name_parts == {'_legacy': 'Peter'} assert cp.attendee_name_parts == {'_legacy': 'Peter'}
@@ -247,7 +251,8 @@ def test_cartpos_cart_id_optional(token_client, organizer, event, item, quota, q
), format='json', data=res ), format='json', data=res
) )
assert resp.status_code == 201 assert resp.status_code == 201
cp = CartPosition.objects.get(pk=resp.data['id']) with scopes_disabled():
cp = CartPosition.objects.get(pk=resp.data['id'])
assert cp.price == Decimal('23.00') assert cp.price == Decimal('23.00')
assert cp.item == item assert cp.item == item
assert len(cp.cart_id) > 48 assert len(cp.cart_id) > 48
@@ -300,7 +305,8 @@ def test_cartpos_create_item_validation(token_client, organizer, event, item, it
assert resp.status_code == 400 assert resp.status_code == 400
assert resp.data == {'item': ['The specified item does not belong to this event.']} assert resp.data == {'item': ['The specified item does not belong to this event.']}
var2 = item2.variations.create(value="A") with scopes_disabled():
var2 = item2.variations.create(value="A")
res['item'] = item.pk res['item'] = item.pk
res['variation'] = var2.pk res['variation'] = var2.pk
@@ -312,7 +318,8 @@ def test_cartpos_create_item_validation(token_client, organizer, event, item, it
assert resp.status_code == 400 assert resp.status_code == 400
assert resp.data == {'non_field_errors': ['You cannot specify a variation for this item.']} assert resp.data == {'non_field_errors': ['You cannot specify a variation for this item.']}
var1 = item.variations.create(value="A") with scopes_disabled():
var1 = item.variations.create(value="A")
res['item'] = item.pk res['item'] = item.pk
res['variation'] = var1.pk res['variation'] = var1.pk
resp = token_client.post( resp = token_client.post(
@@ -361,7 +368,8 @@ def test_cartpos_expires_optional(token_client, organizer, event, item, quota, q
), format='json', data=res ), format='json', data=res
) )
assert resp.status_code == 201 assert resp.status_code == 201
cp = CartPosition.objects.get(pk=resp.data['id']) with scopes_disabled():
cp = CartPosition.objects.get(pk=resp.data['id'])
assert cp.price == Decimal('23.00') assert cp.price == Decimal('23.00')
assert cp.item == item assert cp.item == item
assert cp.expires - now() > datetime.timedelta(minutes=25) assert cp.expires - now() > datetime.timedelta(minutes=25)
@@ -410,7 +418,8 @@ def test_cartpos_create_answer_validation(token_client, organizer, event, item,
assert resp.data == { assert resp.data == {
'answers': [{'non_field_errors': ['You need to specify options if the question is of a choice type.']}]} 'answers': [{'non_field_errors': ['You need to specify options if the question is of a choice type.']}]}
question.options.create(answer="L") with scopes_disabled():
question.options.create(answer="L")
res['answers'][0]['options'] = [ res['answers'][0]['options'] = [
question.options.first().pk, question.options.first().pk,
question.options.last().pk, question.options.last().pk,
@@ -445,8 +454,9 @@ def test_cartpos_create_answer_validation(token_client, organizer, event, item,
), format='json', data=res ), format='json', data=res
) )
assert resp.status_code == 201 assert resp.status_code == 201
pos = CartPosition.objects.get(pk=resp.data['id']) with scopes_disabled():
answ = pos.answers.first() pos = CartPosition.objects.get(pk=resp.data['id'])
answ = pos.answers.first()
assert answ.question == question assert answ.question == question
assert answ.answer == "XL, L" assert answ.answer == "XL, L"
@@ -460,8 +470,9 @@ def test_cartpos_create_answer_validation(token_client, organizer, event, item,
), format='json', data=res ), format='json', data=res
) )
assert resp.status_code == 201 assert resp.status_code == 201
pos = CartPosition.objects.get(pk=resp.data['id']) with scopes_disabled():
answ = pos.answers.first() pos = CartPosition.objects.get(pk=resp.data['id'])
answ = pos.answers.first()
assert answ.answer == "3.45" assert answ.answer == "3.45"
question.type = Question.TYPE_NUMBER question.type = Question.TYPE_NUMBER
@@ -486,8 +497,9 @@ def test_cartpos_create_answer_validation(token_client, organizer, event, item,
), format='json', data=res ), format='json', data=res
) )
assert resp.status_code == 201 assert resp.status_code == 201
pos = CartPosition.objects.get(pk=resp.data['id']) with scopes_disabled():
answ = pos.answers.first() pos = CartPosition.objects.get(pk=resp.data['id'])
answ = pos.answers.first()
assert answ.answer == "True" assert answ.answer == "True"
question.type = Question.TYPE_BOOLEAN question.type = Question.TYPE_BOOLEAN
@@ -499,8 +511,9 @@ def test_cartpos_create_answer_validation(token_client, organizer, event, item,
), format='json', data=res ), format='json', data=res
) )
assert resp.status_code == 201 assert resp.status_code == 201
pos = CartPosition.objects.get(pk=resp.data['id']) with scopes_disabled():
answ = pos.answers.first() pos = CartPosition.objects.get(pk=resp.data['id'])
answ = pos.answers.first()
assert answ.answer == "False" assert answ.answer == "False"
question.type = Question.TYPE_BOOLEAN question.type = Question.TYPE_BOOLEAN
@@ -523,8 +536,9 @@ def test_cartpos_create_answer_validation(token_client, organizer, event, item,
), format='json', data=res ), format='json', data=res
) )
assert resp.status_code == 201 assert resp.status_code == 201
pos = CartPosition.objects.get(pk=resp.data['id']) with scopes_disabled():
answ = pos.answers.first() pos = CartPosition.objects.get(pk=resp.data['id'])
answ = pos.answers.first()
assert answ.answer == "2018-05-14" assert answ.answer == "2018-05-14"
question.type = Question.TYPE_DATE question.type = Question.TYPE_DATE
@@ -548,8 +562,9 @@ def test_cartpos_create_answer_validation(token_client, organizer, event, item,
), format='json', data=res ), format='json', data=res
) )
assert resp.status_code == 201 assert resp.status_code == 201
pos = CartPosition.objects.get(pk=resp.data['id']) with scopes_disabled():
answ = pos.answers.first() pos = CartPosition.objects.get(pk=resp.data['id'])
answ = pos.answers.first()
assert answ.answer == "2018-05-14 13:00:00+00:00" assert answ.answer == "2018-05-14 13:00:00+00:00"
question.type = Question.TYPE_DATETIME question.type = Question.TYPE_DATETIME
@@ -574,8 +589,9 @@ def test_cartpos_create_answer_validation(token_client, organizer, event, item,
), format='json', data=res ), format='json', data=res
) )
assert resp.status_code == 201 assert resp.status_code == 201
pos = CartPosition.objects.get(pk=resp.data['id']) with scopes_disabled():
answ = pos.answers.first() pos = CartPosition.objects.get(pk=resp.data['id'])
answ = pos.answers.first()
assert answ.answer == "13:00:00" assert answ.answer == "13:00:00"
question.type = Question.TYPE_TIME question.type = Question.TYPE_TIME

View File

@@ -6,6 +6,7 @@ from unittest import mock
import pytest import pytest
from django.utils.timezone import now from django.utils.timezone import now
from django_countries.fields import Country from django_countries.fields import Country
from django_scopes import scopes_disabled
from i18nfield.strings import LazyI18nString from i18nfield.strings import LazyI18nString
from pytz import UTC from pytz import UTC
@@ -157,7 +158,8 @@ def test_list_list(token_client, organizer, event, clist, item, subevent):
resp = token_client.get( resp = token_client.get(
'/api/v1/organizers/{}/events/{}/checkinlists/?subevent={}'.format(organizer.slug, event.slug, subevent.pk)) '/api/v1/organizers/{}/events/{}/checkinlists/?subevent={}'.format(organizer.slug, event.slug, subevent.pk))
assert [res] == resp.data['results'] assert [res] == resp.data['results']
se2 = event.subevents.create(name="Foobar", date_from=datetime.datetime(2017, 12, 27, 10, 0, 0, tzinfo=UTC)) with scopes_disabled():
se2 = event.subevents.create(name="Foobar", date_from=datetime.datetime(2017, 12, 27, 10, 0, 0, tzinfo=UTC))
resp = token_client.get( resp = token_client.get(
'/api/v1/organizers/{}/events/{}/checkinlists/?subevent={}'.format(organizer.slug, event.slug, se2.pk)) '/api/v1/organizers/{}/events/{}/checkinlists/?subevent={}'.format(organizer.slug, event.slug, se2.pk))
assert [] == resp.data['results'] assert [] == resp.data['results']
@@ -188,10 +190,11 @@ def test_list_create(token_client, organizer, event, item, item_on_wrong_event):
format='json' format='json'
) )
assert resp.status_code == 201 assert resp.status_code == 201
cl = CheckinList.objects.get(pk=resp.data['id']) with scopes_disabled():
assert cl.name == "VIP" cl = CheckinList.objects.get(pk=resp.data['id'])
assert cl.limit_products.count() == 1 assert cl.name == "VIP"
assert not cl.all_products assert cl.limit_products.count() == 1
assert not cl.all_products
resp = token_client.post( resp = token_client.post(
'/api/v1/organizers/{}/events/{}/checkinlists/'.format(organizer.slug, event.slug), '/api/v1/organizers/{}/events/{}/checkinlists/'.format(organizer.slug, event.slug),
@@ -271,18 +274,20 @@ def test_list_update(token_client, organizer, event, clist):
format='json' format='json'
) )
assert resp.status_code == 200 assert resp.status_code == 200
cl = CheckinList.objects.get(pk=resp.data['id']) with scopes_disabled():
cl = CheckinList.objects.get(pk=resp.data['id'])
assert cl.name == "VIP" assert cl.name == "VIP"
@pytest.mark.django_db @pytest.mark.django_db
def test_list_all_items_positions(token_client, organizer, event, clist, clist_all, item, other_item, order): def test_list_all_items_positions(token_client, organizer, event, clist, clist_all, item, other_item, order):
p1 = dict(TEST_ORDERPOSITION1_RES) with scopes_disabled():
p1["id"] = order.positions.first().pk p1 = dict(TEST_ORDERPOSITION1_RES)
p1["item"] = item.pk p1["id"] = order.positions.first().pk
p2 = dict(TEST_ORDERPOSITION2_RES) p1["item"] = item.pk
p2["id"] = order.positions.last().pk p2 = dict(TEST_ORDERPOSITION2_RES)
p2["item"] = other_item.pk p2["id"] = order.positions.last().pk
p2["item"] = other_item.pk
# All items # All items
resp = token_client.get('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/?ordering=positionid'.format( resp = token_client.get('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/?ordering=positionid'.format(
@@ -292,7 +297,8 @@ def test_list_all_items_positions(token_client, organizer, event, clist, clist_a
assert [p1, p2] == resp.data['results'] assert [p1, p2] == resp.data['results']
# Check-ins on other list ignored # Check-ins on other list ignored
order.positions.first().checkins.create(list=clist) with scopes_disabled():
order.positions.first().checkins.create(list=clist)
resp = token_client.get('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/?ordering=positionid'.format( resp = token_client.get('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/?ordering=positionid'.format(
organizer.slug, event.slug, clist_all.pk organizer.slug, event.slug, clist_all.pk
)) ))
@@ -305,7 +311,8 @@ def test_list_all_items_positions(token_client, organizer, event, clist, clist_a
assert [] == resp.data['results'] assert [] == resp.data['results']
# Only checked in # Only checked in
c = order.positions.first().checkins.create(list=clist_all) with scopes_disabled():
c = order.positions.first().checkins.create(list=clist_all)
p1['checkins'] = [ p1['checkins'] = [
{ {
'list': clist_all.pk, 'list': clist_all.pk,
@@ -341,7 +348,8 @@ def test_list_all_items_positions(token_client, organizer, event, clist, clist_a
# Order by checkin date # Order by checkin date
time.sleep(1) time.sleep(1)
c = order.positions.last().checkins.create(list=clist_all) with scopes_disabled():
c = order.positions.last().checkins.create(list=clist_all)
p2['checkins'] = [ p2['checkins'] = [
{ {
'list': clist_all.pk, 'list': clist_all.pk,
@@ -388,7 +396,8 @@ def test_list_all_items_positions(token_client, organizer, event, clist, clist_a
@pytest.mark.django_db @pytest.mark.django_db
def test_list_limited_items_positions(token_client, organizer, event, clist, item, order): def test_list_limited_items_positions(token_client, organizer, event, clist, item, order):
p1 = dict(TEST_ORDERPOSITION1_RES) p1 = dict(TEST_ORDERPOSITION1_RES)
p1["id"] = order.positions.first().pk with scopes_disabled():
p1["id"] = order.positions.first().pk
p1["item"] = item.pk p1["item"] = item.pk
# All items # All items
@@ -402,12 +411,13 @@ def test_list_limited_items_positions(token_client, organizer, event, clist, ite
@pytest.mark.django_db @pytest.mark.django_db
def test_list_limited_items_position_detail(token_client, organizer, event, clist, item, order): def test_list_limited_items_position_detail(token_client, organizer, event, clist, item, order):
p1 = dict(TEST_ORDERPOSITION1_RES) p1 = dict(TEST_ORDERPOSITION1_RES)
p1["id"] = order.positions.first().pk with scopes_disabled():
p1["id"] = order.positions.first().pk
p1["item"] = item.pk p1["item"] = item.pk
# All items # All items
resp = token_client.get('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/'.format( resp = token_client.get('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/'.format(
organizer.slug, event.slug, clist.pk, order.positions.first().pk organizer.slug, event.slug, clist.pk, p1["id"]
)) ))
assert resp.status_code == 200 assert resp.status_code == 200
assert p1 == resp.data assert p1 == resp.data
@@ -415,12 +425,13 @@ def test_list_limited_items_position_detail(token_client, organizer, event, clis
@pytest.mark.django_db @pytest.mark.django_db
def test_status(token_client, organizer, event, clist_all, item, other_item, order): def test_status(token_client, organizer, event, clist_all, item, other_item, order):
op = order.positions.first() with scopes_disabled():
var1 = item.variations.create(value="XS") op = order.positions.first()
var2 = item.variations.create(value="S") var1 = item.variations.create(value="XS")
op.variation = var1 var2 = item.variations.create(value="S")
op.save() op.variation = var1
Checkin.objects.create(position=op, list=clist_all) op.save()
Checkin.objects.create(position=op, list=clist_all)
resp = token_client.get('/api/v1/organizers/{}/events/{}/checkinlists/{}/status/'.format( resp = token_client.get('/api/v1/organizers/{}/events/{}/checkinlists/{}/status/'.format(
organizer.slug, event.slug, clist_all.pk, organizer.slug, event.slug, clist_all.pk,
)) ))
@@ -464,21 +475,25 @@ def test_status(token_client, organizer, event, clist_all, item, other_item, ord
def test_custom_datetime(token_client, organizer, clist, event, order): def test_custom_datetime(token_client, organizer, clist, event, order):
dt = now() - datetime.timedelta(days=1) dt = now() - datetime.timedelta(days=1)
dt = dt.replace(microsecond=0) dt = dt.replace(microsecond=0)
with scopes_disabled():
p = order.positions.first().pk
resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format(
organizer.slug, event.slug, clist.pk, order.positions.first().pk organizer.slug, event.slug, clist.pk, p
), { ), {
'datetime': dt.isoformat() 'datetime': dt.isoformat()
}, format='json') }, format='json')
assert resp.status_code == 201 assert resp.status_code == 201
assert resp.data['status'] == 'ok' assert resp.data['status'] == 'ok'
assert Checkin.objects.last().datetime == dt with scopes_disabled():
assert Checkin.objects.last().datetime == dt
@pytest.mark.django_db @pytest.mark.django_db
def test_name_fallback(token_client, organizer, clist, event, order): def test_name_fallback(token_client, organizer, clist, event, order):
order.invoice_address.name_parts = {'_legacy': 'Paul'} order.invoice_address.name_parts = {'_legacy': 'Paul'}
order.invoice_address.save() order.invoice_address.save()
op = order.positions.first() with scopes_disabled():
op = order.positions.first()
op.attendee_name_cached = None op.attendee_name_cached = None
op.attendee_name_parts = {} op.attendee_name_parts = {}
op.save() op.save()
@@ -493,8 +508,10 @@ def test_name_fallback(token_client, organizer, clist, event, order):
@pytest.mark.django_db @pytest.mark.django_db
def test_by_secret(token_client, organizer, clist, event, order): def test_by_secret(token_client, organizer, clist, event, order):
with scopes_disabled():
p = order.positions.first()
resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format(
organizer.slug, event.slug, clist.pk, order.positions.first().secret organizer.slug, event.slug, clist.pk, p.secret
), {}, format='json') ), {}, format='json')
assert resp.status_code == 201 assert resp.status_code == 201
assert resp.data['status'] == 'ok' assert resp.data['status'] == 'ok'
@@ -502,13 +519,15 @@ def test_by_secret(token_client, organizer, clist, event, order):
@pytest.mark.django_db @pytest.mark.django_db
def test_only_once(token_client, organizer, clist, event, order): def test_only_once(token_client, organizer, clist, event, order):
with scopes_disabled():
p = order.positions.first()
resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format(
organizer.slug, event.slug, clist.pk, order.positions.first().pk organizer.slug, event.slug, clist.pk, p.pk
), {}, format='json') ), {}, format='json')
assert resp.status_code == 201 assert resp.status_code == 201
assert resp.data['status'] == 'ok' assert resp.data['status'] == 'ok'
resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format(
organizer.slug, event.slug, clist.pk, order.positions.first().pk organizer.slug, event.slug, clist.pk, p.pk
), {}, format='json') ), {}, format='json')
assert resp.status_code == 400 assert resp.status_code == 400
assert resp.data['status'] == 'error' assert resp.data['status'] == 'error'
@@ -517,13 +536,15 @@ def test_only_once(token_client, organizer, clist, event, order):
@pytest.mark.django_db @pytest.mark.django_db
def test_reupload_same_nonce(token_client, organizer, clist, event, order): def test_reupload_same_nonce(token_client, organizer, clist, event, order):
with scopes_disabled():
p = order.positions.first()
resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format(
organizer.slug, event.slug, clist.pk, order.positions.first().pk organizer.slug, event.slug, clist.pk, p.pk
), {'nonce': 'foobar'}, format='json') ), {'nonce': 'foobar'}, format='json')
assert resp.status_code == 201 assert resp.status_code == 201
assert resp.data['status'] == 'ok' assert resp.data['status'] == 'ok'
resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format(
organizer.slug, event.slug, clist.pk, order.positions.first().pk organizer.slug, event.slug, clist.pk, p.pk
), {'nonce': 'foobar'}, format='json') ), {'nonce': 'foobar'}, format='json')
assert resp.status_code == 201 assert resp.status_code == 201
assert resp.data['status'] == 'ok' assert resp.data['status'] == 'ok'
@@ -531,13 +552,15 @@ def test_reupload_same_nonce(token_client, organizer, clist, event, order):
@pytest.mark.django_db @pytest.mark.django_db
def test_multiple_different_list(token_client, organizer, clist, clist_all, event, order): def test_multiple_different_list(token_client, organizer, clist, clist_all, event, order):
with scopes_disabled():
p = order.positions.first()
resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format(
organizer.slug, event.slug, clist.pk, order.positions.first().pk organizer.slug, event.slug, clist.pk, p.pk
), {'nonce': 'foobar'}, format='json') ), {'nonce': 'foobar'}, format='json')
assert resp.status_code == 201 assert resp.status_code == 201
assert resp.data['status'] == 'ok' assert resp.data['status'] == 'ok'
resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format(
organizer.slug, event.slug, clist_all.pk, order.positions.first().pk organizer.slug, event.slug, clist_all.pk, p.pk
), {'nonce': 'baz'}, format='json') ), {'nonce': 'baz'}, format='json')
assert resp.status_code == 201 assert resp.status_code == 201
assert resp.data['status'] == 'ok' assert resp.data['status'] == 'ok'
@@ -545,13 +568,15 @@ def test_multiple_different_list(token_client, organizer, clist, clist_all, even
@pytest.mark.django_db @pytest.mark.django_db
def test_forced_multiple(token_client, organizer, clist, event, order): def test_forced_multiple(token_client, organizer, clist, event, order):
with scopes_disabled():
p = order.positions.first()
resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format(
organizer.slug, event.slug, clist.pk, order.positions.first().pk organizer.slug, event.slug, clist.pk, p.pk
), {}, format='json') ), {}, format='json')
assert resp.status_code == 201 assert resp.status_code == 201
assert resp.data['status'] == 'ok' assert resp.data['status'] == 'ok'
resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format(
organizer.slug, event.slug, clist.pk, order.positions.first().pk organizer.slug, event.slug, clist.pk, p.pk
), {'force': True}, format='json') ), {'force': True}, format='json')
assert resp.status_code == 201 assert resp.status_code == 201
assert resp.data['status'] == 'ok' assert resp.data['status'] == 'ok'
@@ -559,17 +584,19 @@ def test_forced_multiple(token_client, organizer, clist, event, order):
@pytest.mark.django_db @pytest.mark.django_db
def test_require_paid(token_client, organizer, clist, event, order): def test_require_paid(token_client, organizer, clist, event, order):
with scopes_disabled():
p = order.positions.first()
order.status = Order.STATUS_PENDING order.status = Order.STATUS_PENDING
order.save() order.save()
resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format(
organizer.slug, event.slug, clist.pk, order.positions.first().pk organizer.slug, event.slug, clist.pk, p.pk
), {}, format='json') ), {}, format='json')
assert resp.status_code == 400 assert resp.status_code == 400
assert resp.data['status'] == 'error' assert resp.data['status'] == 'error'
assert resp.data['reason'] == 'unpaid' assert resp.data['reason'] == 'unpaid'
resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format(
organizer.slug, event.slug, clist.pk, order.positions.first().pk organizer.slug, event.slug, clist.pk, p.pk
), {'ignore_unpaid': True}, format='json') ), {'ignore_unpaid': True}, format='json')
assert resp.status_code == 400 assert resp.status_code == 400
assert resp.data['status'] == 'error' assert resp.data['status'] == 'error'
@@ -579,14 +606,14 @@ def test_require_paid(token_client, organizer, clist, event, order):
clist.save() clist.save()
resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format(
organizer.slug, event.slug, clist.pk, order.positions.first().pk organizer.slug, event.slug, clist.pk, p.pk
), {}, format='json') ), {}, format='json')
assert resp.status_code == 400 assert resp.status_code == 400
assert resp.data['status'] == 'error' assert resp.data['status'] == 'error'
assert resp.data['reason'] == 'unpaid' assert resp.data['reason'] == 'unpaid'
resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format(
organizer.slug, event.slug, clist.pk, order.positions.first().pk organizer.slug, event.slug, clist.pk, p.pk
), {'ignore_unpaid': True}, format='json') ), {'ignore_unpaid': True}, format='json')
assert resp.status_code == 201 assert resp.status_code == 201
assert resp.data['status'] == 'ok' assert resp.data['status'] == 'ok'
@@ -603,88 +630,105 @@ def question(event, item):
@pytest.mark.django_db @pytest.mark.django_db
def test_question_number(token_client, organizer, clist, event, order, question): def test_question_number(token_client, organizer, clist, event, order, question):
question[0].options.all().delete() with scopes_disabled():
p = order.positions.first()
question[0].options.all().delete()
question[0].type = 'N' question[0].type = 'N'
question[0].save() question[0].save()
resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format(
organizer.slug, event.slug, clist.pk, order.positions.first().pk organizer.slug, event.slug, clist.pk, p.pk
), {}, format='json') ), {}, format='json')
assert resp.status_code == 400 assert resp.status_code == 400
assert resp.data['status'] == 'incomplete' assert resp.data['status'] == 'incomplete'
assert resp.data['questions'] == [QuestionSerializer(question[0]).data] with scopes_disabled():
assert resp.data['questions'] == [QuestionSerializer(question[0]).data]
resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format(
organizer.slug, event.slug, clist.pk, order.positions.first().pk organizer.slug, event.slug, clist.pk, p.pk
), {'answers': {question[0].pk: "3.24"}}, format='json') ), {'answers': {question[0].pk: "3.24"}}, format='json')
print(resp.data)
assert resp.status_code == 201 assert resp.status_code == 201
assert resp.data['status'] == 'ok' assert resp.data['status'] == 'ok'
assert order.positions.first().answers.get(question=question[0]).answer == '3.24' with scopes_disabled():
assert order.positions.first().answers.get(question=question[0]).answer == '3.24'
@pytest.mark.django_db @pytest.mark.django_db
def test_question_choice(token_client, organizer, clist, event, order, question): def test_question_choice(token_client, organizer, clist, event, order, question):
with scopes_disabled():
p = order.positions.first()
resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format(
organizer.slug, event.slug, clist.pk, order.positions.first().pk organizer.slug, event.slug, clist.pk, p.pk
), {}, format='json') ), {}, format='json')
assert resp.status_code == 400 assert resp.status_code == 400
assert resp.data['status'] == 'incomplete' assert resp.data['status'] == 'incomplete'
assert resp.data['questions'] == [QuestionSerializer(question[0]).data] with scopes_disabled():
assert resp.data['questions'] == [QuestionSerializer(question[0]).data]
resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format(
organizer.slug, event.slug, clist.pk, order.positions.first().pk organizer.slug, event.slug, clist.pk, p.pk
), {'answers': {question[0].pk: str(question[1].pk)}}, format='json') ), {'answers': {question[0].pk: str(question[1].pk)}}, format='json')
assert resp.status_code == 201 assert resp.status_code == 201
assert resp.data['status'] == 'ok' assert resp.data['status'] == 'ok'
assert order.positions.first().answers.get(question=question[0]).answer == 'M' with scopes_disabled():
assert list(order.positions.first().answers.get(question=question[0]).options.all()) == [question[1]] assert order.positions.first().answers.get(question=question[0]).answer == 'M'
assert list(order.positions.first().answers.get(question=question[0]).options.all()) == [question[1]]
@pytest.mark.django_db @pytest.mark.django_db
def test_question_invalid(token_client, organizer, clist, event, order, question): def test_question_invalid(token_client, organizer, clist, event, order, question):
with scopes_disabled():
p = order.positions.first()
resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format(
organizer.slug, event.slug, clist.pk, order.positions.first().pk organizer.slug, event.slug, clist.pk, p.pk
), {'answers': {question[0].pk: "A"}}, format='json') ), {'answers': {question[0].pk: "A"}}, format='json')
assert resp.status_code == 400 assert resp.status_code == 400
assert resp.data['status'] == 'incomplete' assert resp.data['status'] == 'incomplete'
assert resp.data['questions'] == [QuestionSerializer(question[0]).data] with scopes_disabled():
assert resp.data['questions'] == [QuestionSerializer(question[0]).data]
@pytest.mark.django_db @pytest.mark.django_db
def test_question_required(token_client, organizer, clist, event, order, question): def test_question_required(token_client, organizer, clist, event, order, question):
with scopes_disabled():
p = order.positions.first()
question[0].required = True question[0].required = True
question[0].save() question[0].save()
resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format(
organizer.slug, event.slug, clist.pk, order.positions.first().pk organizer.slug, event.slug, clist.pk, p.pk
), {}, format='json') ), {}, format='json')
assert resp.status_code == 400 assert resp.status_code == 400
assert resp.data['status'] == 'incomplete' assert resp.data['status'] == 'incomplete'
assert resp.data['questions'] == [QuestionSerializer(question[0]).data] with scopes_disabled():
assert resp.data['questions'] == [QuestionSerializer(question[0]).data]
resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format(
organizer.slug, event.slug, clist.pk, order.positions.first().pk organizer.slug, event.slug, clist.pk, p.pk
), {'answers': {question[0].pk: ""}}, format='json') ), {'answers': {question[0].pk: ""}}, format='json')
assert resp.status_code == 400 assert resp.status_code == 400
assert resp.data['status'] == 'incomplete' assert resp.data['status'] == 'incomplete'
assert resp.data['questions'] == [QuestionSerializer(question[0]).data] with scopes_disabled():
assert resp.data['questions'] == [QuestionSerializer(question[0]).data]
@pytest.mark.django_db @pytest.mark.django_db
def test_question_optional(token_client, organizer, clist, event, order, question): def test_question_optional(token_client, organizer, clist, event, order, question):
with scopes_disabled():
p = order.positions.first()
question[0].required = False question[0].required = False
question[0].save() question[0].save()
resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format(
organizer.slug, event.slug, clist.pk, order.positions.first().pk organizer.slug, event.slug, clist.pk, p.pk
), {}, format='json') ), {}, format='json')
assert resp.status_code == 400 assert resp.status_code == 400
assert resp.data['status'] == 'incomplete' assert resp.data['status'] == 'incomplete'
assert resp.data['questions'] == [QuestionSerializer(question[0]).data] with scopes_disabled():
assert resp.data['questions'] == [QuestionSerializer(question[0]).data]
resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format(
organizer.slug, event.slug, clist.pk, order.positions.first().pk organizer.slug, event.slug, clist.pk, p.pk
), {'answers': {question[0].pk: ""}}, format='json') ), {'answers': {question[0].pk: ""}}, format='json')
assert resp.status_code == 201 assert resp.status_code == 201
assert resp.data['status'] == 'ok' assert resp.data['status'] == 'ok'
@@ -692,20 +736,24 @@ def test_question_optional(token_client, organizer, clist, event, order, questio
@pytest.mark.django_db @pytest.mark.django_db
def test_question_multiple_choice(token_client, organizer, clist, event, order, question): def test_question_multiple_choice(token_client, organizer, clist, event, order, question):
with scopes_disabled():
p = order.positions.first()
question[0].type = 'M' question[0].type = 'M'
question[0].save() question[0].save()
resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format(
organizer.slug, event.slug, clist.pk, order.positions.first().pk organizer.slug, event.slug, clist.pk, p.pk
), {}, format='json') ), {}, format='json')
assert resp.status_code == 400 assert resp.status_code == 400
assert resp.data['status'] == 'incomplete' assert resp.data['status'] == 'incomplete'
assert resp.data['questions'] == [QuestionSerializer(question[0]).data] with scopes_disabled():
assert resp.data['questions'] == [QuestionSerializer(question[0]).data]
resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format(
organizer.slug, event.slug, clist.pk, order.positions.first().pk organizer.slug, event.slug, clist.pk, p.pk
), {'answers': {question[0].pk: "{},{}".format(question[1].pk, question[2].pk)}}, format='json') ), {'answers': {question[0].pk: "{},{}".format(question[1].pk, question[2].pk)}}, format='json')
assert resp.status_code == 201 assert resp.status_code == 201
assert resp.data['status'] == 'ok' assert resp.data['status'] == 'ok'
assert order.positions.first().answers.get(question=question[0]).answer == 'M, L' with scopes_disabled():
assert set(order.positions.first().answers.get(question=question[0]).options.all()) == {question[1], question[2]} assert order.positions.first().answers.get(question=question[0]).answer == 'M, L'
assert set(order.positions.first().answers.get(question=question[0]).options.all()) == {question[1], question[2]}

View File

@@ -5,6 +5,7 @@ from unittest import mock
import pytest import pytest
from django.conf import settings from django.conf import settings
from django_countries.fields import Country from django_countries.fields import Country
from django_scopes import scopes_disabled
from pytz import UTC from pytz import UTC
from pretix.base.models import Event, InvoiceAddress, Order, OrderPosition from pretix.base.models import Event, InvoiceAddress, Order, OrderPosition
@@ -161,11 +162,12 @@ def test_event_create(token_client, organizer, event, meta_prop):
format='json' format='json'
) )
assert resp.status_code == 201 assert resp.status_code == 201
assert not organizer.events.get(slug="2030").testmode with scopes_disabled():
assert organizer.events.get(slug="2030").meta_values.filter( assert not organizer.events.get(slug="2030").testmode
property__name=meta_prop.name, value="Conference" assert organizer.events.get(slug="2030").meta_values.filter(
).exists() property__name=meta_prop.name, value="Conference"
assert organizer.events.get(slug="2030").plugins == settings.PRETIX_PLUGINS_DEFAULT ).exists()
assert organizer.events.get(slug="2030").plugins == settings.PRETIX_PLUGINS_DEFAULT
resp = token_client.post( resp = token_client.post(
'/api/v1/organizers/{}/events/'.format(organizer.slug), '/api/v1/organizers/{}/events/'.format(organizer.slug),
@@ -278,13 +280,14 @@ def test_event_create_with_clone(token_client, organizer, event, meta_prop):
) )
assert resp.status_code == 201 assert resp.status_code == 201
cloned_event = Event.objects.get(organizer=organizer.pk, slug='2030') with scopes_disabled():
assert cloned_event.plugins == 'pretix.plugins.ticketoutputpdf' cloned_event = Event.objects.get(organizer=organizer.pk, slug='2030')
assert cloned_event.is_public is False assert cloned_event.plugins == 'pretix.plugins.ticketoutputpdf'
assert cloned_event.testmode assert cloned_event.is_public is False
assert organizer.events.get(slug="2030").meta_values.filter( assert cloned_event.testmode
property__name=meta_prop.name, value="Conference" assert organizer.events.get(slug="2030").meta_values.filter(
).exists() property__name=meta_prop.name, value="Conference"
).exists()
resp = token_client.post( resp = token_client.post(
'/api/v1/organizers/{}/events/{}/clone/'.format(organizer.slug, event.slug), '/api/v1/organizers/{}/events/{}/clone/'.format(organizer.slug, event.slug),
@@ -310,12 +313,13 @@ def test_event_create_with_clone(token_client, organizer, event, meta_prop):
) )
assert resp.status_code == 201 assert resp.status_code == 201
cloned_event = Event.objects.get(organizer=organizer.pk, slug='2031') with scopes_disabled():
assert cloned_event.plugins == "pretix.plugins.banktransfer,pretix.plugins.ticketoutputpdf" cloned_event = Event.objects.get(organizer=organizer.pk, slug='2031')
assert cloned_event.is_public is True assert cloned_event.plugins == "pretix.plugins.banktransfer,pretix.plugins.ticketoutputpdf"
assert organizer.events.get(slug="2031").meta_values.filter( assert cloned_event.is_public is True
property__name=meta_prop.name, value="Conference" assert organizer.events.get(slug="2031").meta_values.filter(
).exists() property__name=meta_prop.name, value="Conference"
).exists()
resp = token_client.post( resp = token_client.post(
'/api/v1/organizers/{}/events/{}/clone/'.format(organizer.slug, event.slug), '/api/v1/organizers/{}/events/{}/clone/'.format(organizer.slug, event.slug),
@@ -339,8 +343,9 @@ def test_event_create_with_clone(token_client, organizer, event, meta_prop):
) )
assert resp.status_code == 201 assert resp.status_code == 201
cloned_event = Event.objects.get(organizer=organizer.pk, slug='2032') with scopes_disabled():
assert cloned_event.plugins == "" cloned_event = Event.objects.get(organizer=organizer.pk, slug='2032')
assert cloned_event.plugins == ""
@pytest.mark.django_db @pytest.mark.django_db
@@ -388,11 +393,12 @@ def test_event_update(token_client, organizer, event, item, meta_prop):
format='json' format='json'
) )
assert resp.status_code == 200 assert resp.status_code == 200
event = Event.objects.get(organizer=organizer.pk, slug=resp.data['slug']) with scopes_disabled():
assert event.currency == "DKK" event = Event.objects.get(organizer=organizer.pk, slug=resp.data['slug'])
assert organizer.events.get(slug=resp.data['slug']).meta_values.filter( assert event.currency == "DKK"
property__name=meta_prop.name, value="Conference" assert organizer.events.get(slug=resp.data['slug']).meta_values.filter(
).exists() property__name=meta_prop.name, value="Conference"
).exists()
resp = token_client.patch( resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug), '/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
@@ -447,9 +453,10 @@ def test_event_update(token_client, organizer, event, item, meta_prop):
format='json' format='json'
) )
assert resp.status_code == 200 assert resp.status_code == 200
assert organizer.events.get(slug=resp.data['slug']).meta_values.filter( with scopes_disabled():
property__name=meta_prop.name, value="Workshop" assert organizer.events.get(slug=resp.data['slug']).meta_values.filter(
).exists() property__name=meta_prop.name, value="Workshop"
).exists()
resp = token_client.patch( resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug), '/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
@@ -460,9 +467,10 @@ def test_event_update(token_client, organizer, event, item, meta_prop):
format='json' format='json'
) )
assert resp.status_code == 200 assert resp.status_code == 200
assert not organizer.events.get(slug=resp.data['slug']).meta_values.filter( with scopes_disabled():
property__name=meta_prop.name assert not organizer.events.get(slug=resp.data['slug']).meta_values.filter(
).exists() property__name=meta_prop.name
).exists()
resp = token_client.patch( resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug), '/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
@@ -598,7 +606,8 @@ def test_event_detail(token_client, organizer, event, team):
def test_event_delete(token_client, organizer, event): def test_event_delete(token_client, organizer, event):
resp = token_client.delete('/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug)) resp = token_client.delete('/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug))
assert resp.status_code == 204 assert resp.status_code == 204
assert not organizer.events.filter(pk=event.id).exists() with scopes_disabled():
assert not organizer.events.filter(pk=event.id).exists()
@pytest.mark.django_db @pytest.mark.django_db
@@ -607,4 +616,5 @@ def test_event_with_order_position_not_delete(token_client, organizer, event, it
assert resp.status_code == 403 assert resp.status_code == 403
assert resp.content.decode() == '{"detail":"The event can not be deleted as it already contains orders. Please ' \ assert resp.content.decode() == '{"detail":"The event can not be deleted as it already contains orders. Please ' \
'set \'live\' to false to hide the event and take the shop offline instead."}' 'set \'live\' to false to hide the event and take the shop offline instead."}'
assert organizer.events.filter(pk=event.id).exists() with scopes_disabled():
assert organizer.events.filter(pk=event.id).exists()

View File

@@ -5,6 +5,7 @@ from unittest import mock
import pytest import pytest
from django_countries.fields import Country from django_countries.fields import Country
from django_scopes import scopes_disabled
from pytz import UTC from pytz import UTC
from pretix.base.models import ( from pretix.base.models import (
@@ -169,7 +170,8 @@ def test_category_update(token_client, organizer, event, team, category):
format='json' format='json'
) )
assert resp.status_code == 200 assert resp.status_code == 200
assert ItemCategory.objects.get(pk=category.pk).name == {"en": "Test"} with scopes_disabled():
assert ItemCategory.objects.get(pk=category.pk).name == {"en": "Test"}
@pytest.mark.django_db @pytest.mark.django_db
@@ -189,8 +191,9 @@ def test_category_delete(token_client, organizer, event, category3, item):
resp = token_client.delete( resp = token_client.delete(
'/api/v1/organizers/{}/events/{}/categories/{}/'.format(organizer.slug, event.slug, category3.pk)) '/api/v1/organizers/{}/events/{}/categories/{}/'.format(organizer.slug, event.slug, category3.pk))
assert resp.status_code == 204 assert resp.status_code == 204
assert not event.categories.filter(pk=category3.id).exists() with scopes_disabled():
assert Item.objects.get(pk=item.pk).category is None assert not event.categories.filter(pk=category3.id).exists()
assert Item.objects.get(pk=item.pk).category is None
@pytest.fixture @pytest.fixture
@@ -308,7 +311,8 @@ def test_item_detail(token_client, organizer, event, team, item):
@pytest.mark.django_db @pytest.mark.django_db
def test_item_detail_variations(token_client, organizer, event, team, item): def test_item_detail_variations(token_client, organizer, event, team, item):
var = item.variations.create(value="Children") with scopes_disabled():
var = item.variations.create(value="Children")
res = dict(TEST_ITEM_RES) res = dict(TEST_ITEM_RES)
res["id"] = item.pk res["id"] = item.pk
res["variations"] = [{ res["variations"] = [{
@@ -349,8 +353,9 @@ def test_item_detail_addons(token_client, organizer, event, team, item, category
@pytest.mark.django_db @pytest.mark.django_db
def test_item_detail_bundles(token_client, organizer, event, team, item, category): def test_item_detail_bundles(token_client, organizer, event, team, item, category):
i = event.items.create(name="Included thing", default_price=2) with scopes_disabled():
item.bundles.create(bundled_item=i, count=1, designated_price=2) i = event.items.create(name="Included thing", default_price=2)
item.bundles.create(bundled_item=i, count=1, designated_price=2)
res = dict(TEST_ITEM_RES) res = dict(TEST_ITEM_RES)
res["id"] = item.pk res["id"] = item.pk
@@ -398,7 +403,8 @@ def test_item_create(token_client, organizer, event, item, category, taxrule):
format='json' format='json'
) )
assert resp.status_code == 201 assert resp.status_code == 201
assert Item.objects.get(pk=resp.data['id']).sales_channels == ["web", "pretixpos"] with scopes_disabled():
assert Item.objects.get(pk=resp.data['id']).sales_channels == ["web", "pretixpos"]
@pytest.mark.django_db @pytest.mark.django_db
@@ -445,9 +451,10 @@ def test_item_create_with_variation(token_client, organizer, event, item, catego
format='json' format='json'
) )
assert resp.status_code == 201 assert resp.status_code == 201
new_item = Item.objects.get(pk=resp.data['id']) with scopes_disabled():
assert new_item.variations.first().value.localize('de') == "Kommentar" new_item = Item.objects.get(pk=resp.data['id'])
assert new_item.variations.first().value.localize('en') == "Comment" assert new_item.variations.first().value.localize('de') == "Kommentar"
assert new_item.variations.first().value.localize('en') == "Comment"
@pytest.mark.django_db @pytest.mark.django_db
@@ -490,10 +497,11 @@ def test_item_create_with_addon(token_client, organizer, event, item, category,
format='json' format='json'
) )
assert resp.status_code == 201 assert resp.status_code == 201
item = Item.objects.get(pk=resp.data['id']) with scopes_disabled():
assert item.addons.first().addon_category == category item = Item.objects.get(pk=resp.data['id'])
assert item.addons.first().max_count == 10 assert item.addons.first().addon_category == category
assert 2 == Item.objects.all().count() assert item.addons.first().max_count == 10
assert 2 == Item.objects.all().count()
resp = token_client.post( resp = token_client.post(
'/api/v1/organizers/{}/events/{}/items/'.format(organizer.slug, event.slug), '/api/v1/organizers/{}/events/{}/items/'.format(organizer.slug, event.slug),
@@ -534,7 +542,8 @@ def test_item_create_with_addon(token_client, organizer, event, item, category,
) )
assert resp.status_code == 400 assert resp.status_code == 400
assert resp.content.decode() == '{"addons":["The add-on\'s category must belong to the same event as the item."]}' assert resp.content.decode() == '{"addons":["The add-on\'s category must belong to the same event as the item."]}'
assert 2 == Item.objects.all().count() with scopes_disabled():
assert 2 == Item.objects.all().count()
resp = token_client.post( resp = token_client.post(
'/api/v1/organizers/{}/events/{}/items/'.format(organizer.slug, event.slug), '/api/v1/organizers/{}/events/{}/items/'.format(organizer.slug, event.slug),
@@ -575,7 +584,8 @@ def test_item_create_with_addon(token_client, organizer, event, item, category,
) )
assert resp.status_code == 400 assert resp.status_code == 400
assert resp.content.decode() == '{"addons":["The maximum count needs to be greater than the minimum count."]}' assert resp.content.decode() == '{"addons":["The maximum count needs to be greater than the minimum count."]}'
assert 2 == Item.objects.all().count() with scopes_disabled():
assert 2 == Item.objects.all().count()
resp = token_client.post( resp = token_client.post(
'/api/v1/organizers/{}/events/{}/items/'.format(organizer.slug, event.slug), '/api/v1/organizers/{}/events/{}/items/'.format(organizer.slug, event.slug),
@@ -619,12 +629,14 @@ def test_item_create_with_addon(token_client, organizer, event, item, category,
'{"addons":["The minimum count needs to be equal to or greater than zero."]}', '{"addons":["The minimum count needs to be equal to or greater than zero."]}',
'{"addons":[{"min_count":["Ensure this value is greater than or equal to 0."]}]}', # mysql '{"addons":[{"min_count":["Ensure this value is greater than or equal to 0."]}]}', # mysql
] ]
assert 2 == Item.objects.all().count() with scopes_disabled():
assert 2 == Item.objects.all().count()
@pytest.mark.django_db @pytest.mark.django_db
def test_item_create_with_bundle(token_client, organizer, event, item, category, item2, taxrule): def test_item_create_with_bundle(token_client, organizer, event, item, category, item2, taxrule):
i = event.items.create(name="Included thing", default_price=2) with scopes_disabled():
i = event.items.create(name="Included thing", default_price=2)
resp = token_client.post( resp = token_client.post(
'/api/v1/organizers/{}/events/{}/items/'.format(organizer.slug, event.slug), '/api/v1/organizers/{}/events/{}/items/'.format(organizer.slug, event.slug),
{ {
@@ -662,8 +674,9 @@ def test_item_create_with_bundle(token_client, organizer, event, item, category,
format='json' format='json'
) )
assert resp.status_code == 201 assert resp.status_code == 201
item = Item.objects.get(pk=resp.data['id']) with scopes_disabled():
b = item.bundles.first() item = Item.objects.get(pk=resp.data['id'])
b = item.bundles.first()
assert b.bundled_item == i assert b.bundled_item == i
assert b.bundled_variation is None assert b.bundled_variation is None
assert b.count == 2 assert b.count == 2
@@ -708,7 +721,8 @@ def test_item_create_with_bundle(token_client, organizer, event, item, category,
assert resp.status_code == 400 assert resp.status_code == 400
assert resp.content.decode() == '{"bundles":["The bundled item must belong to the same event as the item."]}' assert resp.content.decode() == '{"bundles":["The bundled item must belong to the same event as the item."]}'
v = item2.variations.create(value="foo") with scopes_disabled():
v = item2.variations.create(value="foo")
resp = token_client.post( resp = token_client.post(
'/api/v1/organizers/{}/events/{}/items/'.format(organizer.slug, event.slug), '/api/v1/organizers/{}/events/{}/items/'.format(organizer.slug, event.slug),
{ {
@@ -760,7 +774,8 @@ def test_item_update(token_client, organizer, event, item, category, item2, cate
format='json' format='json'
) )
assert resp.status_code == 200 assert resp.status_code == 200
assert Item.objects.get(pk=item.pk).max_per_order == 2 with scopes_disabled():
assert Item.objects.get(pk=item.pk).max_per_order == 2
resp = token_client.patch( resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/items/{}/'.format(organizer.slug, event.slug, item.pk), '/api/v1/organizers/{}/events/{}/items/{}/'.format(organizer.slug, event.slug, item.pk),
@@ -896,21 +911,24 @@ def test_item_update_with_addon(token_client, organizer, event, item, category):
def test_items_delete(token_client, organizer, event, item): def test_items_delete(token_client, organizer, event, item):
resp = token_client.delete('/api/v1/organizers/{}/events/{}/items/{}/'.format(organizer.slug, event.slug, item.pk)) resp = token_client.delete('/api/v1/organizers/{}/events/{}/items/{}/'.format(organizer.slug, event.slug, item.pk))
assert resp.status_code == 204 assert resp.status_code == 204
assert not event.items.filter(pk=item.id).exists() with scopes_disabled():
assert not event.items.filter(pk=item.id).exists()
@pytest.mark.django_db @pytest.mark.django_db
def test_items_with_order_position_not_delete(token_client, organizer, event, item, order_position): def test_items_with_order_position_not_delete(token_client, organizer, event, item, order_position):
resp = token_client.delete('/api/v1/organizers/{}/events/{}/items/{}/'.format(organizer.slug, event.slug, item.pk)) resp = token_client.delete('/api/v1/organizers/{}/events/{}/items/{}/'.format(organizer.slug, event.slug, item.pk))
assert resp.status_code == 403 assert resp.status_code == 403
assert event.items.filter(pk=item.id).exists() with scopes_disabled():
assert event.items.filter(pk=item.id).exists()
@pytest.mark.django_db @pytest.mark.django_db
def test_items_with_cart_position_delete(token_client, organizer, event, item, cart_position): def test_items_with_cart_position_delete(token_client, organizer, event, item, cart_position):
resp = token_client.delete('/api/v1/organizers/{}/events/{}/items/{}/'.format(organizer.slug, event.slug, item.pk)) resp = token_client.delete('/api/v1/organizers/{}/events/{}/items/{}/'.format(organizer.slug, event.slug, item.pk))
assert resp.status_code == 204 assert resp.status_code == 204
assert not event.items.filter(pk=item.id).exists() with scopes_disabled():
assert not event.items.filter(pk=item.id).exists()
@pytest.fixture @pytest.fixture
@@ -996,7 +1014,8 @@ def test_variations_create(token_client, organizer, event, item, variation):
format='json' format='json'
) )
assert resp.status_code == 201 assert resp.status_code == 201
var = ItemVariation.objects.get(pk=resp.data['id']) with scopes_disabled():
var = ItemVariation.objects.get(pk=resp.data['id'])
assert var.position == 1 assert var.position == 1
assert var.price == 23.0 assert var.price == 23.0
@@ -1060,40 +1079,47 @@ def test_variations_update(token_client, organizer, event, item, item3, variatio
def test_variations_delete(token_client, organizer, event, item, variations, order): def test_variations_delete(token_client, organizer, event, item, variations, order):
resp = token_client.delete('/api/v1/organizers/{}/events/{}/items/{}/variations/{}/'.format(organizer.slug, event.slug, item.pk, variations[0].pk)) resp = token_client.delete('/api/v1/organizers/{}/events/{}/items/{}/variations/{}/'.format(organizer.slug, event.slug, item.pk, variations[0].pk))
assert resp.status_code == 204 assert resp.status_code == 204
assert not item.variations.filter(pk=variations[0].pk).exists() with scopes_disabled():
assert not item.variations.filter(pk=variations[0].pk).exists()
@pytest.mark.django_db @pytest.mark.django_db
def test_variations_with_order_position_not_delete(token_client, organizer, event, item, order, variations, order_position): def test_variations_with_order_position_not_delete(token_client, organizer, event, item, order, variations, order_position):
assert item.variations.filter(pk=variations[0].id).exists() with scopes_disabled():
assert item.variations.filter(pk=variations[0].id).exists()
resp = token_client.delete('/api/v1/organizers/{}/events/{}/items/{}/variations/{}/'.format(organizer.slug, event.slug, item.pk, variations[0].pk)) resp = token_client.delete('/api/v1/organizers/{}/events/{}/items/{}/variations/{}/'.format(organizer.slug, event.slug, item.pk, variations[0].pk))
assert resp.status_code == 403 assert resp.status_code == 403
assert resp.content.decode() == '{"detail":"This variation cannot be deleted because it has already been ordered ' \ assert resp.content.decode() == '{"detail":"This variation cannot be deleted because it has already been ordered ' \
'by a user or currently is in a users\'s cart. Please set the variation as ' \ 'by a user or currently is in a users\'s cart. Please set the variation as ' \
'\'inactive\' instead."}' '\'inactive\' instead."}'
assert item.variations.filter(pk=variations[0].id).exists() with scopes_disabled():
assert item.variations.filter(pk=variations[0].id).exists()
@pytest.mark.django_db @pytest.mark.django_db
def test_variations_with_cart_position_not_delete(token_client, organizer, event, item, variations, cart_position): def test_variations_with_cart_position_not_delete(token_client, organizer, event, item, variations, cart_position):
assert item.variations.filter(pk=variations[0].id).exists() with scopes_disabled():
assert item.variations.filter(pk=variations[0].id).exists()
resp = token_client.delete('/api/v1/organizers/{}/events/{}/items/{}/variations/{}/'.format(organizer.slug, event.slug, item.pk, variations[0].pk)) resp = token_client.delete('/api/v1/organizers/{}/events/{}/items/{}/variations/{}/'.format(organizer.slug, event.slug, item.pk, variations[0].pk))
assert resp.status_code == 403 assert resp.status_code == 403
assert resp.content.decode() == '{"detail":"This variation cannot be deleted because it has already been ordered ' \ assert resp.content.decode() == '{"detail":"This variation cannot be deleted because it has already been ordered ' \
'by a user or currently is in a users\'s cart. Please set the variation as ' \ 'by a user or currently is in a users\'s cart. Please set the variation as ' \
'\'inactive\' instead."}' '\'inactive\' instead."}'
assert item.variations.filter(pk=variations[0].id).exists() with scopes_disabled():
assert item.variations.filter(pk=variations[0].id).exists()
@pytest.mark.django_db @pytest.mark.django_db
def test_only_variation_not_delete(token_client, organizer, event, item, variation): def test_only_variation_not_delete(token_client, organizer, event, item, variation):
assert item.variations.filter(pk=variation.id).exists() with scopes_disabled():
assert item.variations.filter(pk=variation.id).exists()
resp = token_client.delete('/api/v1/organizers/{}/events/{}/items/{}/variations/{}/'.format(organizer.slug, event.slug, item.pk, variation.pk)) resp = token_client.delete('/api/v1/organizers/{}/events/{}/items/{}/variations/{}/'.format(organizer.slug, event.slug, item.pk, variation.pk))
assert resp.status_code == 403 assert resp.status_code == 403
assert resp.content.decode() == '{"detail":"This variation cannot be deleted because it is the only variation. ' \ assert resp.content.decode() == '{"detail":"This variation cannot be deleted because it is the only variation. ' \
'Changing a product with variations to a product without variations is not ' \ 'Changing a product with variations to a product without variations is not ' \
'allowed."}' 'allowed."}'
assert item.variations.filter(pk=variation.id).exists() with scopes_disabled():
assert item.variations.filter(pk=variation.id).exists()
@pytest.fixture @pytest.fixture
@@ -1144,7 +1170,8 @@ def test_bundles_create(token_client, organizer, event, item, item2, item3):
format='json' format='json'
) )
assert resp.status_code == 201 assert resp.status_code == 201
b = ItemBundle.objects.get(pk=resp.data['id']) with scopes_disabled():
b = ItemBundle.objects.get(pk=resp.data['id'])
assert b.bundled_item == item3 assert b.bundled_item == item3
assert b.bundled_variation is None assert b.bundled_variation is None
assert b.designated_price == 1.5 assert b.designated_price == 1.5
@@ -1176,7 +1203,8 @@ def test_bundles_create(token_client, organizer, event, item, item2, item3):
assert resp.status_code == 400 assert resp.status_code == 400
assert resp.content.decode() == '{"non_field_errors":["The bundled item must not be the same item as the bundling one."]}' assert resp.content.decode() == '{"non_field_errors":["The bundled item must not be the same item as the bundling one."]}'
item3.bundles.create(bundled_item=item, count=1, designated_price=3) with scopes_disabled():
item3.bundles.create(bundled_item=item, count=1, designated_price=3)
resp = token_client.post( resp = token_client.post(
'/api/v1/organizers/{}/events/{}/items/{}/bundles/'.format(organizer.slug, event.slug, item.pk), '/api/v1/organizers/{}/events/{}/items/{}/bundles/'.format(organizer.slug, event.slug, item.pk),
{ {
@@ -1201,7 +1229,8 @@ def test_bundles_update(token_client, organizer, event, item, bundle):
format='json' format='json'
) )
assert resp.status_code == 200 assert resp.status_code == 200
a = ItemBundle.objects.get(pk=bundle.pk) with scopes_disabled():
a = ItemBundle.objects.get(pk=bundle.pk)
assert a.count == 3 assert a.count == 3
@@ -1210,7 +1239,8 @@ def test_bundles_delete(token_client, organizer, event, item, bundle):
resp = token_client.delete('/api/v1/organizers/{}/events/{}/items/{}/bundles/{}/'.format(organizer.slug, event.slug, resp = token_client.delete('/api/v1/organizers/{}/events/{}/items/{}/bundles/{}/'.format(organizer.slug, event.slug,
item.pk, bundle.pk)) item.pk, bundle.pk))
assert resp.status_code == 204 assert resp.status_code == 204
assert not item.bundles.filter(pk=bundle.id).exists() with scopes_disabled():
assert not item.bundles.filter(pk=bundle.id).exists()
@pytest.fixture @pytest.fixture
@@ -1270,7 +1300,8 @@ def test_addons_create(token_client, organizer, event, item, category, category2
format='json' format='json'
) )
assert resp.status_code == 201 assert resp.status_code == 201
addon = ItemAddOn.objects.get(pk=resp.data['id']) with scopes_disabled():
addon = ItemAddOn.objects.get(pk=resp.data['id'])
assert addon.position == 1 assert addon.position == 1
assert addon.addon_category == category assert addon.addon_category == category
@@ -1315,7 +1346,8 @@ def test_addons_update(token_client, organizer, event, item, addon):
format='json' format='json'
) )
assert resp.status_code == 200 assert resp.status_code == 200
a = ItemAddOn.objects.get(pk=addon.pk) with scopes_disabled():
a = ItemAddOn.objects.get(pk=addon.pk)
assert a.min_count == 100 assert a.min_count == 100
assert a.max_count == 101 assert a.max_count == 101
@@ -1337,7 +1369,8 @@ def test_addons_delete(token_client, organizer, event, item, addon):
resp = token_client.delete('/api/v1/organizers/{}/events/{}/items/{}/addons/{}/'.format(organizer.slug, event.slug, resp = token_client.delete('/api/v1/organizers/{}/events/{}/items/{}/addons/{}/'.format(organizer.slug, event.slug,
item.pk, addon.pk)) item.pk, addon.pk))
assert resp.status_code == 204 assert resp.status_code == 204
assert not item.addons.filter(pk=addon.id).exists() with scopes_disabled():
assert not item.addons.filter(pk=addon.id).exists()
@pytest.fixture @pytest.fixture
@@ -1372,7 +1405,8 @@ def test_quota_list(token_client, organizer, event, quota, item, subevent):
resp = token_client.get( resp = token_client.get(
'/api/v1/organizers/{}/events/{}/quotas/?subevent={}'.format(organizer.slug, event.slug, subevent.pk)) '/api/v1/organizers/{}/events/{}/quotas/?subevent={}'.format(organizer.slug, event.slug, subevent.pk))
assert [res] == resp.data['results'] assert [res] == resp.data['results']
se2 = event.subevents.create(name="Foobar", date_from=datetime(2017, 12, 27, 10, 0, 0, tzinfo=UTC)) with scopes_disabled():
se2 = event.subevents.create(name="Foobar", date_from=datetime(2017, 12, 27, 10, 0, 0, tzinfo=UTC))
resp = token_client.get( resp = token_client.get(
'/api/v1/organizers/{}/events/{}/quotas/?subevent={}'.format(organizer.slug, event.slug, se2.pk)) '/api/v1/organizers/{}/events/{}/quotas/?subevent={}'.format(organizer.slug, event.slug, se2.pk))
assert [] == resp.data['results'] assert [] == resp.data['results']
@@ -1404,7 +1438,8 @@ def test_quota_create(token_client, organizer, event, event2, item):
format='json' format='json'
) )
assert resp.status_code == 201 assert resp.status_code == 201
quota = Quota.objects.get(pk=resp.data['id']) with scopes_disabled():
quota = Quota.objects.get(pk=resp.data['id'])
assert quota.name == "Ticket Quota" assert quota.name == "Ticket Quota"
assert quota.size == 200 assert quota.size == 200
@@ -1550,7 +1585,8 @@ def test_quota_update(token_client, organizer, event, quota, item):
format='json' format='json'
) )
assert resp.status_code == 200 assert resp.status_code == 200
quota = Quota.objects.get(pk=resp.data['id']) with scopes_disabled():
quota = Quota.objects.get(pk=resp.data['id'])
assert quota.name == "Ticket Quota Update" assert quota.name == "Ticket Quota Update"
assert quota.size == 111 assert quota.size == 111
assert quota.all_logentries().count() == 1 assert quota.all_logentries().count() == 1
@@ -1566,7 +1602,8 @@ def test_quota_update_unchanged(token_client, organizer, event, quota, item):
format='json' format='json'
) )
assert resp.status_code == 200 assert resp.status_code == 200
quota = Quota.objects.get(pk=resp.data['id']) with scopes_disabled():
quota = Quota.objects.get(pk=resp.data['id'])
assert quota.size == 200 assert quota.size == 200
assert quota.all_logentries().count() == 0 assert quota.all_logentries().count() == 0
@@ -1575,7 +1612,8 @@ def test_quota_update_unchanged(token_client, organizer, event, quota, item):
def test_quota_delete(token_client, organizer, event, quota): def test_quota_delete(token_client, organizer, event, quota):
resp = token_client.delete('/api/v1/organizers/{}/events/{}/quotas/{}/'.format(organizer.slug, event.slug, quota.pk)) resp = token_client.delete('/api/v1/organizers/{}/events/{}/quotas/{}/'.format(organizer.slug, event.slug, quota.pk))
assert resp.status_code == 204 assert resp.status_code == 204
assert not event.quotas.filter(pk=quota.id).exists() with scopes_disabled():
assert not event.quotas.filter(pk=quota.id).exists()
@pytest.mark.django_db @pytest.mark.django_db
@@ -1690,11 +1728,12 @@ def test_question_create(token_client, organizer, event, event2, item):
format='json' format='json'
) )
assert resp.status_code == 201 assert resp.status_code == 201
question = Question.objects.get(pk=resp.data['id']) with scopes_disabled():
assert question.question == "What's your name?" question = Question.objects.get(pk=resp.data['id'])
assert question.type == "S" assert question.question == "What's your name?"
assert question.identifier is not None assert question.type == "S"
assert len(question.items.all()) == 1 assert question.identifier is not None
assert len(question.items.all()) == 1
resp = token_client.post( resp = token_client.post(
'/api/v1/organizers/{}/events/{}/questions/'.format(organizer.slug, event2.slug), '/api/v1/organizers/{}/events/{}/questions/'.format(organizer.slug, event2.slug),
@@ -1784,7 +1823,8 @@ def test_question_create(token_client, organizer, event, event2, item):
format='json' format='json'
) )
assert resp.status_code == 201 assert resp.status_code == 201
q2 = Question.objects.get(pk=resp.data['id']) with scopes_disabled():
q2 = Question.objects.get(pk=resp.data['id'])
assert q2.dependency_question == question assert q2.dependency_question == question
@@ -1799,14 +1839,16 @@ def test_question_update(token_client, organizer, event, question):
format='json' format='json'
) )
assert resp.status_code == 200 assert resp.status_code == 200
question = Question.objects.get(pk=resp.data['id']) with scopes_disabled():
question = Question.objects.get(pk=resp.data['id'])
assert question.question == "What's your shoe size?" assert question.question == "What's your shoe size?"
assert question.type == "N" assert question.type == "N"
@pytest.mark.django_db @pytest.mark.django_db
def test_question_update_circular_dependency(token_client, organizer, event, question): def test_question_update_circular_dependency(token_client, organizer, event, question):
q2 = event.questions.create(question="T-Shirt size", type="B", identifier="FOO", dependency_question=question) with scopes_disabled():
q2 = event.questions.create(question="T-Shirt size", type="B", identifier="FOO", dependency_question=question)
resp = token_client.patch( resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/questions/{}/'.format(organizer.slug, event.slug, question.pk), '/api/v1/organizers/{}/events/{}/questions/{}/'.format(organizer.slug, event.slug, question.pk),
{ {
@@ -1836,7 +1878,8 @@ def test_question_update_options(token_client, organizer, event, question, item)
def test_question_delete(token_client, organizer, event, question): def test_question_delete(token_client, organizer, event, question):
resp = token_client.delete('/api/v1/organizers/{}/events/{}/questions/{}/'.format(organizer.slug, event.slug, question.pk)) resp = token_client.delete('/api/v1/organizers/{}/events/{}/questions/{}/'.format(organizer.slug, event.slug, question.pk))
assert resp.status_code == 204 assert resp.status_code == 204
assert not event.questions.filter(pk=question.id).exists() with scopes_disabled():
assert not event.questions.filter(pk=question.id).exists()
TEST_OPTIONS_RES = { TEST_OPTIONS_RES = {
@@ -1881,7 +1924,8 @@ def test_options_create(token_client, organizer, event, question):
format='json' format='json'
) )
assert resp.status_code == 201 assert resp.status_code == 201
option = QuestionOption.objects.get(pk=resp.data['id']) with scopes_disabled():
option = QuestionOption.objects.get(pk=resp.data['id'])
assert option.answer == "A" assert option.answer == "A"
resp = token_client.post( resp = token_client.post(
@@ -1907,7 +1951,8 @@ def test_options_update(token_client, organizer, event, question, option):
format='json' format='json'
) )
assert resp.status_code == 200 assert resp.status_code == 200
a = QuestionOption.objects.get(pk=option.pk) with scopes_disabled():
a = QuestionOption.objects.get(pk=option.pk)
assert a.answer == "B" assert a.answer == "B"
@@ -1917,7 +1962,8 @@ def test_options_delete(token_client, organizer, event, question, option):
organizer.slug, event.slug, question.pk, option.pk organizer.slug, event.slug, question.pk, option.pk
)) ))
assert resp.status_code == 204 assert resp.status_code == 204
assert not question.options.filter(pk=option.id).exists() with scopes_disabled():
assert not question.options.filter(pk=option.id).exists()
@pytest.mark.django_db @pytest.mark.django_db
@@ -1948,11 +1994,12 @@ def test_question_create_with_option(token_client, organizer, event, item):
format='json' format='json'
) )
assert resp.status_code == 201 assert resp.status_code == 201
question = Question.objects.get(pk=resp.data['id']) with scopes_disabled():
assert str(question.options.first().answer) == "A" question = Question.objects.get(pk=resp.data['id'])
assert question.options.first().identifier is not None assert str(question.options.first().answer) == "A"
assert str(question.options.last().answer) == "B" assert question.options.first().identifier is not None
assert 2 == question.options.count() assert str(question.options.last().answer) == "B"
assert 2 == question.options.count()
resp = token_client.post( resp = token_client.post(
'/api/v1/organizers/{}/events/{}/questions/'.format(organizer.slug, event.slug), '/api/v1/organizers/{}/events/{}/questions/'.format(organizer.slug, event.slug),

File diff suppressed because it is too large Load Diff

View File

@@ -4,6 +4,7 @@ from unittest import mock
import pytest import pytest
from django_countries.fields import Country from django_countries.fields import Country
from django_scopes import scopes_disabled
from pytz import UTC from pytz import UTC
from pretix.base.models import InvoiceAddress, Order, OrderPosition from pretix.base.models import InvoiceAddress, Order, OrderPosition
@@ -159,9 +160,10 @@ def test_subevent_create(token_client, organizer, event, subevent, meta_prop, it
) )
assert resp.status_code == 201 assert resp.status_code == 201
assert not subevent.active assert not subevent.active
assert subevent.meta_values.filter( with scopes_disabled():
property__name=meta_prop.name, value="Workshop" assert subevent.meta_values.filter(
).exists() property__name=meta_prop.name, value="Workshop"
).exists()
resp = token_client.post( resp = token_client.post(
'/api/v1/organizers/{}/events/{}/subevents/'.format(organizer.slug, event.slug), '/api/v1/organizers/{}/events/{}/subevents/'.format(organizer.slug, event.slug),
@@ -217,7 +219,8 @@ def test_subevent_create(token_client, organizer, event, subevent, meta_prop, it
) )
assert resp.status_code == 201 assert resp.status_code == 201
assert item.default_price == Decimal('23.00') assert item.default_price == Decimal('23.00')
assert event.subevents.get(id=resp.data['id']).item_price_overrides[item.pk] == Decimal('23.42') with scopes_disabled():
assert event.subevents.get(id=resp.data['id']).item_price_overrides[item.pk] == Decimal('23.42')
resp = token_client.post( resp = token_client.post(
'/api/v1/organizers/{}/events/{}/subevents/'.format(organizer.slug, event.slug), '/api/v1/organizers/{}/events/{}/subevents/'.format(organizer.slug, event.slug),
@@ -261,7 +264,8 @@ def test_subevent_update(token_client, organizer, event, subevent, item, item2,
format='json' format='json'
) )
assert resp.status_code == 200 assert resp.status_code == 200
subevent = event.subevents.get(id=subevent.id) with scopes_disabled():
subevent = event.subevents.get(id=subevent.id)
assert subevent.date_from == datetime(2018, 12, 27, 10, 0, tzinfo=UTC) assert subevent.date_from == datetime(2018, 12, 27, 10, 0, tzinfo=UTC)
assert subevent.date_to == datetime(2018, 12, 28, 10, 0, tzinfo=UTC) assert subevent.date_to == datetime(2018, 12, 28, 10, 0, tzinfo=UTC)
@@ -297,9 +301,10 @@ def test_subevent_update(token_client, organizer, event, subevent, item, item2,
format='json' format='json'
) )
assert resp.status_code == 200 assert resp.status_code == 200
assert organizer.events.get(slug=event.slug).subevents.get(id=resp.data['id']).meta_values.filter( with scopes_disabled():
property__name=meta_prop.name, value="Conference" assert organizer.events.get(slug=event.slug).subevents.get(id=resp.data['id']).meta_values.filter(
).exists() property__name=meta_prop.name, value="Conference"
).exists()
resp = token_client.patch( resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk), '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
@@ -310,9 +315,10 @@ def test_subevent_update(token_client, organizer, event, subevent, item, item2,
format='json' format='json'
) )
assert resp.status_code == 200 assert resp.status_code == 200
assert not subevent.meta_values.filter( with scopes_disabled():
property__name=meta_prop.name assert not subevent.meta_values.filter(
).exists() property__name=meta_prop.name
).exists()
resp = token_client.patch( resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk), '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
@@ -339,7 +345,8 @@ def test_subevent_update(token_client, organizer, event, subevent, item, item2,
format='json' format='json'
) )
assert resp.status_code == 200 assert resp.status_code == 200
assert subevent.items.get(id=item.pk).default_price == Decimal('23.00') with scopes_disabled():
assert subevent.items.get(id=item.pk).default_price == Decimal('23.00')
assert subevent.item_price_overrides[item.pk] == Decimal('99.99') assert subevent.item_price_overrides[item.pk] == Decimal('99.99')
resp = token_client.patch( resp = token_client.patch(
@@ -355,7 +362,8 @@ def test_subevent_update(token_client, organizer, event, subevent, item, item2,
format='json' format='json'
) )
assert resp.status_code == 200 assert resp.status_code == 200
assert event.subevents.get(id=subevent.id).item_price_overrides[item.pk] == Decimal('88.88') with scopes_disabled():
assert event.subevents.get(id=subevent.id).item_price_overrides[item.pk] == Decimal('88.88')
resp = token_client.patch( resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk), '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
@@ -370,7 +378,8 @@ def test_subevent_update(token_client, organizer, event, subevent, item, item2,
format='json' format='json'
) )
assert resp.status_code == 200 assert resp.status_code == 200
assert item.pk not in event.subevents.get(id=subevent.id).item_price_overrides with scopes_disabled():
assert item.pk not in event.subevents.get(id=subevent.id).item_price_overrides
resp = token_client.patch( resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk), '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
@@ -385,7 +394,8 @@ def test_subevent_update(token_client, organizer, event, subevent, item, item2,
format='json' format='json'
) )
assert resp.status_code == 200 assert resp.status_code == 200
assert event.subevents.get(id=subevent.id).item_price_overrides[item.pk] == Decimal('12.34') with scopes_disabled():
assert event.subevents.get(id=subevent.id).item_price_overrides[item.pk] == Decimal('12.34')
resp = token_client.patch( resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk), '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
@@ -395,7 +405,8 @@ def test_subevent_update(token_client, organizer, event, subevent, item, item2,
format='json' format='json'
) )
assert resp.status_code == 200 assert resp.status_code == 200
assert item.pk not in event.subevents.get(id=subevent.id).item_price_overrides with scopes_disabled():
assert item.pk not in event.subevents.get(id=subevent.id).item_price_overrides
resp = token_client.patch( resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk), '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
@@ -440,8 +451,9 @@ def test_subevent_update(token_client, organizer, event, subevent, item, item2,
format='json' format='json'
) )
assert resp.status_code == 200 assert resp.status_code == 200
assert subevent.variations.get(id=variations[0].pk).default_price == Decimal('12.00') with scopes_disabled():
assert subevent.var_price_overrides[variations[0].pk] == Decimal('99.99') assert subevent.variations.get(id=variations[0].pk).default_price == Decimal('12.00')
assert subevent.var_price_overrides[variations[0].pk] == Decimal('99.99')
resp = token_client.patch( resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk), '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
@@ -456,7 +468,8 @@ def test_subevent_update(token_client, organizer, event, subevent, item, item2,
format='json' format='json'
) )
assert resp.status_code == 200 assert resp.status_code == 200
assert event.subevents.get(id=subevent.id).var_price_overrides[variations[0].pk] == Decimal('88.88') with scopes_disabled():
assert event.subevents.get(id=subevent.id).var_price_overrides[variations[0].pk] == Decimal('88.88')
resp = token_client.patch( resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk), '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
@@ -471,7 +484,8 @@ def test_subevent_update(token_client, organizer, event, subevent, item, item2,
format='json' format='json'
) )
assert resp.status_code == 200 assert resp.status_code == 200
assert variations[0].pk not in event.subevents.get(id=subevent.id).var_price_overrides with scopes_disabled():
assert variations[0].pk not in event.subevents.get(id=subevent.id).var_price_overrides
resp = token_client.patch( resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk), '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
@@ -486,7 +500,8 @@ def test_subevent_update(token_client, organizer, event, subevent, item, item2,
format='json' format='json'
) )
assert resp.status_code == 200 assert resp.status_code == 200
assert event.subevents.get(id=subevent.id).var_price_overrides[variations[0].pk] == Decimal('12.34') with scopes_disabled():
assert event.subevents.get(id=subevent.id).var_price_overrides[variations[0].pk] == Decimal('12.34')
resp = token_client.patch( resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk), '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
@@ -496,7 +511,8 @@ def test_subevent_update(token_client, organizer, event, subevent, item, item2,
format='json' format='json'
) )
assert resp.status_code == 200 assert resp.status_code == 200
assert variations[0].pk not in event.subevents.get(id=subevent.id).var_price_overrides with scopes_disabled():
assert variations[0].pk not in event.subevents.get(id=subevent.id).var_price_overrides
resp = token_client.patch( resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk), '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
@@ -544,7 +560,8 @@ def test_subevent_delete(token_client, organizer, event, subevent):
resp = token_client.delete('/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, resp = token_client.delete('/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug,
subevent.pk)) subevent.pk))
assert resp.status_code == 204 assert resp.status_code == 204
assert not event.subevents.filter(pk=subevent.id).exists() with scopes_disabled():
assert not event.subevents.filter(pk=subevent.id).exists()
@pytest.mark.django_db @pytest.mark.django_db
@@ -554,4 +571,5 @@ def test_subevent_with_order_position_not_delete(token_client, organizer, event,
assert resp.status_code == 403 assert resp.status_code == 403
assert resp.content.decode() == '{"detail":"The sub-event can not be deleted as it has already been used in ' \ assert resp.content.decode() == '{"detail":"The sub-event can not be deleted as it has already been used in ' \
'orders. Please set \'active\' to false instead to hide it from users."}' 'orders. Please set \'active\' to false instead to hide it from users."}'
assert event.subevents.filter(pk=subevent.id).exists() with scopes_disabled():
assert event.subevents.filter(pk=subevent.id).exists()

View File

@@ -1,6 +1,7 @@
from decimal import Decimal from decimal import Decimal
import pytest import pytest
from django_scopes import scopes_disabled
from pretix.base.models import TaxRule from pretix.base.models import TaxRule
@@ -80,7 +81,8 @@ def test_rule_delete(token_client, organizer, event, taxrule):
@pytest.mark.django_db @pytest.mark.django_db
def test_rule_delete_forbidden(token_client, organizer, event, taxrule): def test_rule_delete_forbidden(token_client, organizer, event, taxrule):
event.items.create(name="Budget Ticket", default_price=23, tax_rule=taxrule) with scopes_disabled():
event.items.create(name="Budget Ticket", default_price=23, tax_rule=taxrule)
resp = token_client.delete( resp = token_client.delete(
'/api/v1/organizers/{}/events/{}/taxrules/{}/'.format(organizer.slug, event.slug, taxrule.pk), '/api/v1/organizers/{}/events/{}/taxrules/{}/'.format(organizer.slug, event.slug, taxrule.pk),
) )

View File

@@ -5,6 +5,7 @@ from decimal import Decimal
import pytest import pytest
from django.utils import timezone from django.utils import timezone
from django.utils.timezone import now from django.utils.timezone import now
from django_scopes import scopes_disabled
from pytz import UTC from pytz import UTC
from pretix.base.models import Event, Voucher from pretix.base.models import Event, Voucher
@@ -58,7 +59,8 @@ def test_voucher_list(token_client, organizer, event, voucher, item, quota, sube
i2 = copy.copy(item) i2 = copy.copy(item)
i2.pk = None i2.pk = None
i2.save() i2.save()
var2 = i2.variations.create(value="foo") with scopes_disabled():
var2 = i2.variations.create(value="foo")
resp = token_client.get('/api/v1/organizers/{}/events/{}/vouchers/'.format(organizer.slug, event.slug)) resp = token_client.get('/api/v1/organizers/{}/events/{}/vouchers/'.format(organizer.slug, event.slug))
assert resp.status_code == 200 assert resp.status_code == 200
@@ -136,9 +138,10 @@ def test_voucher_list(token_client, organizer, event, voucher, item, quota, sube
) )
assert [] == resp.data['results'] assert [] == resp.data['results']
var = item.variations.create(value='VIP') with scopes_disabled():
voucher.variation = var var = item.variations.create(value='VIP')
voucher.save() voucher.variation = var
voucher.save()
res['variation'] = var.pk res['variation'] = var.pk
resp = token_client.get( resp = token_client.get(
'/api/v1/organizers/{}/events/{}/vouchers/?variation={}'.format(organizer.slug, event.slug, var.pk) '/api/v1/organizers/{}/events/{}/vouchers/?variation={}'.format(organizer.slug, event.slug, var.pk)
@@ -208,7 +211,8 @@ def test_voucher_list(token_client, organizer, event, voucher, item, quota, sube
resp = token_client.get( resp = token_client.get(
'/api/v1/organizers/{}/events/{}/vouchers/?subevent={}'.format(organizer.slug, event.slug, subevent.pk)) '/api/v1/organizers/{}/events/{}/vouchers/?subevent={}'.format(organizer.slug, event.slug, subevent.pk))
assert [res] == resp.data['results'] assert [res] == resp.data['results']
se2 = event.subevents.create(name="Foobar", date_from=datetime.datetime(2017, 12, 27, 10, 0, 0, tzinfo=UTC)) with scopes_disabled():
se2 = event.subevents.create(name="Foobar", date_from=datetime.datetime(2017, 12, 27, 10, 0, 0, tzinfo=UTC))
resp = token_client.get( resp = token_client.get(
'/api/v1/organizers/{}/events/{}/vouchers/?subevent={}'.format(organizer.slug, event.slug, '/api/v1/organizers/{}/events/{}/vouchers/?subevent={}'.format(organizer.slug, event.slug,
se2.pk)) se2.pk))
@@ -237,7 +241,8 @@ def create_voucher(token_client, organizer, event, data, expected_failure=False)
assert resp.status_code == 400 assert resp.status_code == 400
else: else:
assert resp.status_code == 201 assert resp.status_code == 201
return Voucher.objects.get(pk=resp.data['id']) with scopes_disabled():
return Voucher.objects.get(pk=resp.data['id'])
@pytest.mark.django_db @pytest.mark.django_db
@@ -324,7 +329,8 @@ def test_create_non_blocking_item_voucher(token_client, organizer, event, item):
@pytest.mark.django_db @pytest.mark.django_db
def test_create_non_blocking_variation_voucher(token_client, organizer, event, item): def test_create_non_blocking_variation_voucher(token_client, organizer, event, item):
variation = item.variations.create(value="XL") with scopes_disabled():
variation = item.variations.create(value="XL")
v = create_voucher( v = create_voucher(
token_client, organizer, event, token_client, organizer, event,
data={ data={
@@ -394,7 +400,8 @@ def test_create_blocking_item_voucher_quota_full_invalid(token_client, organizer
@pytest.mark.django_db @pytest.mark.django_db
def test_create_blocking_variation_voucher_quota_free(token_client, organizer, event, item, quota): def test_create_blocking_variation_voucher_quota_free(token_client, organizer, event, item, quota):
variation = item.variations.create(value="XL") with scopes_disabled():
variation = item.variations.create(value="XL")
quota.variations.add(variation) quota.variations.add(variation)
v = create_voucher( v = create_voucher(
token_client, organizer, event, token_client, organizer, event,
@@ -421,7 +428,8 @@ def test_create_short_code(token_client, organizer, event, item):
@pytest.mark.django_db @pytest.mark.django_db
def test_create_blocking_variation_voucher_quota_full(token_client, organizer, event, item, quota): def test_create_blocking_variation_voucher_quota_full(token_client, organizer, event, item, quota):
variation = item.variations.create(value="XL") with scopes_disabled():
variation = item.variations.create(value="XL")
quota.variations.add(variation) quota.variations.add(variation)
quota.size = 0 quota.size = 0
quota.save() quota.save()
@@ -463,7 +471,8 @@ def test_create_blocking_quota_voucher_quota_full(token_client, organizer, event
@pytest.mark.django_db @pytest.mark.django_db
def test_create_duplicate_code(token_client, organizer, event, quota): def test_create_duplicate_code(token_client, organizer, event, quota):
v = event.vouchers.create(quota=quota) with scopes_disabled():
v = event.vouchers.create(quota=quota)
create_voucher( create_voucher(
token_client, organizer, event, token_client, organizer, event,
data={ data={
@@ -501,11 +510,12 @@ def test_subevent_required_for_blocking(token_client, organizer, event, item, su
@pytest.mark.django_db @pytest.mark.django_db
def test_subevent_blocking_quota_free(token_client, organizer, event, item, quota, subevent): def test_subevent_blocking_quota_free(token_client, organizer, event, item, quota, subevent):
se2 = event.subevents.create(name="Bar", date_from=now()) with scopes_disabled():
quota.subevent = subevent se2 = event.subevents.create(name="Bar", date_from=now())
quota.save() quota.subevent = subevent
q2 = event.quotas.create(event=event, name='Tickets', size=0, subevent=se2) quota.save()
q2.items.add(item) q2 = event.quotas.create(event=event, name='Tickets', size=0, subevent=se2)
q2.items.add(item)
v = create_voucher( v = create_voucher(
token_client, organizer, event, token_client, organizer, event,
@@ -521,12 +531,13 @@ def test_subevent_blocking_quota_free(token_client, organizer, event, item, quot
@pytest.mark.django_db @pytest.mark.django_db
def test_subevent_blocking_quota_full(token_client, organizer, event, item, quota, subevent): def test_subevent_blocking_quota_full(token_client, organizer, event, item, quota, subevent):
se2 = event.subevents.create(name="Bar", date_from=now()) with scopes_disabled():
quota.subevent = subevent se2 = event.subevents.create(name="Bar", date_from=now())
quota.size = 0 quota.subevent = subevent
quota.save() quota.size = 0
q2 = event.quotas.create(event=event, name='Tickets', size=5, subevent=se2) quota.save()
q2.items.add(item) q2 = event.quotas.create(event=event, name='Tickets', size=5, subevent=se2)
q2.items.add(item)
create_voucher( create_voucher(
token_client, organizer, event, token_client, organizer, event,
@@ -553,15 +564,16 @@ def change_voucher(token_client, organizer, event, voucher, data, expected_failu
@pytest.mark.django_db @pytest.mark.django_db
def test_change_to_item_of_other_event(token_client, organizer, event, item): def test_change_to_item_of_other_event(token_client, organizer, event, item):
e2 = Event.objects.create( with scopes_disabled():
organizer=organizer, e2 = Event.objects.create(
name='Dummy2', organizer=organizer,
slug='dummy2', name='Dummy2',
date_from=datetime.datetime(2017, 12, 27, 10, 0, 0, tzinfo=UTC), slug='dummy2',
plugins='pretix.plugins.banktransfer,pretix.plugins.ticketoutputpdf' date_from=datetime.datetime(2017, 12, 27, 10, 0, 0, tzinfo=UTC),
) plugins='pretix.plugins.banktransfer,pretix.plugins.ticketoutputpdf'
ticket2 = e2.items.create(name='Late-bird ticket', default_price=23) )
v = event.vouchers.create(item=item) ticket2 = e2.items.create(name='Late-bird ticket', default_price=23)
v = event.vouchers.create(item=item)
change_voucher( change_voucher(
token_client, organizer, event, v, token_client, organizer, event, v,
data={ data={
@@ -575,7 +587,8 @@ def test_change_to_item_of_other_event(token_client, organizer, event, item):
@pytest.mark.django_db @pytest.mark.django_db
def test_change_non_blocking_voucher(token_client, organizer, event, item, quota): def test_change_non_blocking_voucher(token_client, organizer, event, item, quota):
v = event.vouchers.create(item=item) with scopes_disabled():
v = event.vouchers.create(item=item)
change_voucher( change_voucher(
token_client, organizer, event, v, token_client, organizer, event, v,
data={ data={
@@ -589,7 +602,8 @@ def test_change_non_blocking_voucher(token_client, organizer, event, item, quota
@pytest.mark.django_db @pytest.mark.django_db
def test_change_voucher_reduce_max_usages(token_client, organizer, event, item, quota): def test_change_voucher_reduce_max_usages(token_client, organizer, event, item, quota):
v = event.vouchers.create(item=item, max_usages=5, redeemed=3) with scopes_disabled():
v = event.vouchers.create(item=item, max_usages=5, redeemed=3)
change_voucher( change_voucher(
token_client, organizer, event, v, token_client, organizer, event, v,
data={ data={
@@ -604,7 +618,8 @@ def test_change_voucher_reduce_max_usages(token_client, organizer, event, item,
def test_change_blocking_voucher_unchanged_quota_full(token_client, organizer, event, item, quota): def test_change_blocking_voucher_unchanged_quota_full(token_client, organizer, event, item, quota):
quota.size = 0 quota.size = 0
quota.save() quota.save()
v = event.vouchers.create(item=item, block_quota=True) with scopes_disabled():
v = event.vouchers.create(item=item, block_quota=True)
change_voucher( change_voucher(
token_client, organizer, event, v, token_client, organizer, event, v,
data={ data={
@@ -620,7 +635,8 @@ def test_change_blocking_voucher_unchanged_quota_full(token_client, organizer, e
def test_change_voucher_to_blocking_quota_full(token_client, organizer, event, item, quota): def test_change_voucher_to_blocking_quota_full(token_client, organizer, event, item, quota):
quota.size = 0 quota.size = 0
quota.save() quota.save()
v = event.vouchers.create(item=item) with scopes_disabled():
v = event.vouchers.create(item=item)
change_voucher( change_voucher(
token_client, organizer, event, v, token_client, organizer, event, v,
data={ data={
@@ -632,7 +648,8 @@ def test_change_voucher_to_blocking_quota_full(token_client, organizer, event, i
@pytest.mark.django_db @pytest.mark.django_db
def test_change_voucher_to_blocking_quota_free(token_client, organizer, event, item, quota): def test_change_voucher_to_blocking_quota_free(token_client, organizer, event, item, quota):
v = event.vouchers.create(item=item) with scopes_disabled():
v = event.vouchers.create(item=item)
change_voucher( change_voucher(
token_client, organizer, event, v, token_client, organizer, event, v,
data={ data={
@@ -646,8 +663,9 @@ def test_change_voucher_to_blocking_quota_free(token_client, organizer, event, i
def test_change_voucher_validity_to_valid_quota_full(token_client, organizer, event, item, quota): def test_change_voucher_validity_to_valid_quota_full(token_client, organizer, event, item, quota):
quota.size = 0 quota.size = 0
quota.save() quota.save()
v = event.vouchers.create(item=item, valid_until=now() - datetime.timedelta(days=3), with scopes_disabled():
block_quota=True) v = event.vouchers.create(item=item, valid_until=now() - datetime.timedelta(days=3),
block_quota=True)
change_voucher( change_voucher(
token_client, organizer, event, v, token_client, organizer, event, v,
data={ data={
@@ -660,8 +678,9 @@ def test_change_voucher_validity_to_valid_quota_full(token_client, organizer, ev
@pytest.mark.django_db @pytest.mark.django_db
def test_change_voucher_validity_to_valid_quota_free(token_client, organizer, event, item, quota): def test_change_voucher_validity_to_valid_quota_free(token_client, organizer, event, item, quota):
v = event.vouchers.create(item=item, valid_until=now() - datetime.timedelta(days=3), with scopes_disabled():
block_quota=True) v = event.vouchers.create(item=item, valid_until=now() - datetime.timedelta(days=3),
block_quota=True)
change_voucher( change_voucher(
token_client, organizer, event, v, token_client, organizer, event, v,
data={ data={
@@ -673,9 +692,10 @@ def test_change_voucher_validity_to_valid_quota_free(token_client, organizer, ev
@pytest.mark.django_db @pytest.mark.django_db
def test_change_item_of_blocking_voucher_quota_free(token_client, organizer, event, item, quota): def test_change_item_of_blocking_voucher_quota_free(token_client, organizer, event, item, quota):
ticket2 = event.items.create(name='Late-bird ticket', default_price=23) with scopes_disabled():
quota.items.add(ticket2) ticket2 = event.items.create(name='Late-bird ticket', default_price=23)
v = event.vouchers.create(item=item, block_quota=True) quota.items.add(ticket2)
v = event.vouchers.create(item=item, block_quota=True)
change_voucher( change_voucher(
token_client, organizer, event, v, token_client, organizer, event, v,
data={ data={
@@ -687,10 +707,11 @@ def test_change_item_of_blocking_voucher_quota_free(token_client, organizer, eve
@pytest.mark.django_db @pytest.mark.django_db
def test_change_item_of_blocking_voucher_quota_full(token_client, organizer, event, item, quota): def test_change_item_of_blocking_voucher_quota_full(token_client, organizer, event, item, quota):
ticket2 = event.items.create(name='Late-bird ticket', default_price=23) with scopes_disabled():
quota2 = event.quotas.create(name='Late', size=0) ticket2 = event.items.create(name='Late-bird ticket', default_price=23)
quota2.items.add(ticket2) quota2 = event.quotas.create(name='Late', size=0)
v = event.vouchers.create(item=item, block_quota=True) quota2.items.add(ticket2)
v = event.vouchers.create(item=item, block_quota=True)
change_voucher( change_voucher(
token_client, organizer, event, v, token_client, organizer, event, v,
data={ data={
@@ -702,14 +723,15 @@ def test_change_item_of_blocking_voucher_quota_full(token_client, organizer, eve
@pytest.mark.django_db @pytest.mark.django_db
def test_change_variation_of_blocking_voucher_quota_free(token_client, organizer, event): def test_change_variation_of_blocking_voucher_quota_free(token_client, organizer, event):
shirt = event.items.create(name='Shirt', default_price=23) with scopes_disabled():
vs = shirt.variations.create(value='S') shirt = event.items.create(name='Shirt', default_price=23)
vm = shirt.variations.create(value='M') vs = shirt.variations.create(value='S')
qs = event.quotas.create(name='S', size=2) vm = shirt.variations.create(value='M')
qs.variations.add(vs) qs = event.quotas.create(name='S', size=2)
qm = event.quotas.create(name='M', size=2) qs.variations.add(vs)
qm.variations.add(vm) qm = event.quotas.create(name='M', size=2)
v = event.vouchers.create(item=shirt, variation=vs, block_quota=True) qm.variations.add(vm)
v = event.vouchers.create(item=shirt, variation=vs, block_quota=True)
change_voucher( change_voucher(
token_client, organizer, event, v, token_client, organizer, event, v,
data={ data={
@@ -721,13 +743,14 @@ def test_change_variation_of_blocking_voucher_quota_free(token_client, organizer
@pytest.mark.django_db @pytest.mark.django_db
def test_change_variation_of_blocking_voucher_without_quota_change(token_client, organizer, event): def test_change_variation_of_blocking_voucher_without_quota_change(token_client, organizer, event):
shirt = event.items.create(name='Shirt', default_price=23) with scopes_disabled():
vs = shirt.variations.create(value='S') shirt = event.items.create(name='Shirt', default_price=23)
vm = shirt.variations.create(value='M') vs = shirt.variations.create(value='S')
q = event.quotas.create(name='S', size=0) vm = shirt.variations.create(value='M')
q.variations.add(vs) q = event.quotas.create(name='S', size=0)
q.variations.add(vm) q.variations.add(vs)
v = event.vouchers.create(item=shirt, variation=vs, block_quota=True) q.variations.add(vm)
v = event.vouchers.create(item=shirt, variation=vs, block_quota=True)
change_voucher( change_voucher(
token_client, organizer, event, v, token_client, organizer, event, v,
data={ data={
@@ -739,14 +762,15 @@ def test_change_variation_of_blocking_voucher_without_quota_change(token_client,
@pytest.mark.django_db @pytest.mark.django_db
def test_change_variation_of_blocking_voucher_quota_full(token_client, organizer, event): def test_change_variation_of_blocking_voucher_quota_full(token_client, organizer, event):
shirt = event.items.create(name='Shirt', default_price=23) with scopes_disabled():
vs = shirt.variations.create(value='S') shirt = event.items.create(name='Shirt', default_price=23)
vm = shirt.variations.create(value='M') vs = shirt.variations.create(value='S')
qs = event.quotas.create(name='S', size=2) vm = shirt.variations.create(value='M')
qs.variations.add(vs) qs = event.quotas.create(name='S', size=2)
qm = event.quotas.create(name='M', size=0) qs.variations.add(vs)
qm.variations.add(vm) qm = event.quotas.create(name='M', size=0)
v = event.vouchers.create(item=shirt, variation=vs, block_quota=True) qm.variations.add(vm)
v = event.vouchers.create(item=shirt, variation=vs, block_quota=True)
change_voucher( change_voucher(
token_client, organizer, event, v, token_client, organizer, event, v,
data={ data={
@@ -758,9 +782,10 @@ def test_change_variation_of_blocking_voucher_quota_full(token_client, organizer
@pytest.mark.django_db @pytest.mark.django_db
def test_change_quota_of_blocking_voucher_quota_free(token_client, organizer, event): def test_change_quota_of_blocking_voucher_quota_free(token_client, organizer, event):
qs = event.quotas.create(name='S', size=2) with scopes_disabled():
qm = event.quotas.create(name='M', size=2) qs = event.quotas.create(name='S', size=2)
v = event.vouchers.create(quota=qs, block_quota=True) qm = event.quotas.create(name='M', size=2)
v = event.vouchers.create(quota=qs, block_quota=True)
change_voucher( change_voucher(
token_client, organizer, event, v, token_client, organizer, event, v,
data={ data={
@@ -772,9 +797,10 @@ def test_change_quota_of_blocking_voucher_quota_free(token_client, organizer, ev
@pytest.mark.django_db @pytest.mark.django_db
def test_change_quota_of_blocking_voucher_quota_full(token_client, organizer, event): def test_change_quota_of_blocking_voucher_quota_full(token_client, organizer, event):
qs = event.quotas.create(name='S', size=2) with scopes_disabled():
qm = event.quotas.create(name='M', size=0) qs = event.quotas.create(name='S', size=2)
v = event.vouchers.create(quota=qs, block_quota=True) qm = event.quotas.create(name='M', size=0)
v = event.vouchers.create(quota=qs, block_quota=True)
change_voucher( change_voucher(
token_client, organizer, event, v, token_client, organizer, event, v,
data={ data={
@@ -786,11 +812,12 @@ def test_change_quota_of_blocking_voucher_quota_full(token_client, organizer, ev
@pytest.mark.django_db @pytest.mark.django_db
def test_change_item_of_blocking_voucher_without_quota_change(token_client, organizer, event, item, quota): def test_change_item_of_blocking_voucher_without_quota_change(token_client, organizer, event, item, quota):
quota.size = 0 with scopes_disabled():
quota.save() quota.size = 0
ticket2 = event.items.create(name='Standard Ticket', default_price=23) quota.save()
quota.items.add(ticket2) ticket2 = event.items.create(name='Standard Ticket', default_price=23)
v = event.vouchers.create(item=item, block_quota=True) quota.items.add(ticket2)
v = event.vouchers.create(item=item, block_quota=True)
change_voucher( change_voucher(
token_client, organizer, event, v, token_client, organizer, event, v,
data={ data={
@@ -802,8 +829,9 @@ def test_change_item_of_blocking_voucher_without_quota_change(token_client, orga
@pytest.mark.django_db @pytest.mark.django_db
def test_change_code_to_duplicate(token_client, organizer, event, item, quota): def test_change_code_to_duplicate(token_client, organizer, event, item, quota):
v1 = event.vouchers.create(quota=quota) with scopes_disabled():
v2 = event.vouchers.create(quota=quota) v1 = event.vouchers.create(quota=quota)
v2 = event.vouchers.create(quota=quota)
change_voucher( change_voucher(
token_client, organizer, event, v1, token_client, organizer, event, v1,
data={ data={
@@ -815,13 +843,14 @@ def test_change_code_to_duplicate(token_client, organizer, event, item, quota):
@pytest.mark.django_db @pytest.mark.django_db
def test_change_subevent_blocking_quota_free(token_client, organizer, event, item, quota, subevent): def test_change_subevent_blocking_quota_free(token_client, organizer, event, item, quota, subevent):
quota.subevent = subevent with scopes_disabled():
quota.save() quota.subevent = subevent
se2 = event.subevents.create(name="Bar", date_from=now()) quota.save()
q2 = event.quotas.create(event=event, name='Tickets', size=5, subevent=se2) se2 = event.subevents.create(name="Bar", date_from=now())
q2.items.add(item) q2 = event.quotas.create(event=event, name='Tickets', size=5, subevent=se2)
q2.items.add(item)
v = event.vouchers.create(item=item, block_quota=True, subevent=subevent) v = event.vouchers.create(item=item, block_quota=True, subevent=subevent)
change_voucher( change_voucher(
token_client, organizer, event, v, token_client, organizer, event, v,
data={ data={
@@ -833,13 +862,14 @@ def test_change_subevent_blocking_quota_free(token_client, organizer, event, ite
@pytest.mark.django_db @pytest.mark.django_db
def test_change_subevent_blocking_quota_full(token_client, organizer, event, item, quota, subevent): def test_change_subevent_blocking_quota_full(token_client, organizer, event, item, quota, subevent):
quota.subevent = subevent with scopes_disabled():
quota.save() quota.subevent = subevent
se2 = event.subevents.create(name="Bar", date_from=now()) quota.save()
q2 = event.quotas.create(event=event, name='Tickets', size=0, subevent=se2) se2 = event.subevents.create(name="Bar", date_from=now())
q2.items.add(item) q2 = event.quotas.create(event=event, name='Tickets', size=0, subevent=se2)
q2.items.add(item)
v = event.vouchers.create(item=item, block_quota=True, subevent=subevent) v = event.vouchers.create(item=item, block_quota=True, subevent=subevent)
change_voucher( change_voucher(
token_client, organizer, event, v, token_client, organizer, event, v,
data={ data={
@@ -851,27 +881,32 @@ def test_change_subevent_blocking_quota_full(token_client, organizer, event, ite
@pytest.mark.django_db @pytest.mark.django_db
def test_delete_voucher(token_client, organizer, event, quota): def test_delete_voucher(token_client, organizer, event, quota):
v = event.vouchers.create(quota=quota) with scopes_disabled():
v = event.vouchers.create(quota=quota)
resp = token_client.delete( resp = token_client.delete(
'/api/v1/organizers/{}/events/{}/vouchers/{}/'.format(organizer.slug, event.slug, v.pk), '/api/v1/organizers/{}/events/{}/vouchers/{}/'.format(organizer.slug, event.slug, v.pk),
) )
assert resp.status_code == 204 assert resp.status_code == 204
assert not event.vouchers.filter(pk=v.id).exists() with scopes_disabled():
assert not event.vouchers.filter(pk=v.id).exists()
@pytest.mark.django_db @pytest.mark.django_db
def test_delete_voucher_redeemed(token_client, organizer, event, quota): def test_delete_voucher_redeemed(token_client, organizer, event, quota):
v = event.vouchers.create(quota=quota, redeemed=1) with scopes_disabled():
v = event.vouchers.create(quota=quota, redeemed=1)
resp = token_client.delete( resp = token_client.delete(
'/api/v1/organizers/{}/events/{}/vouchers/{}/'.format(organizer.slug, event.slug, v.pk), '/api/v1/organizers/{}/events/{}/vouchers/{}/'.format(organizer.slug, event.slug, v.pk),
) )
assert resp.status_code == 403 assert resp.status_code == 403
assert event.vouchers.filter(pk=v.id).exists() with scopes_disabled():
assert event.vouchers.filter(pk=v.id).exists()
@pytest.mark.django_db @pytest.mark.django_db
def test_redeemed_is_not_writable(token_client, organizer, event, item): def test_redeemed_is_not_writable(token_client, organizer, event, item):
v = event.vouchers.create(item=item) with scopes_disabled():
v = event.vouchers.create(item=item)
change_voucher( change_voucher(
token_client, organizer, event, v, token_client, organizer, event, v,
data={ data={
@@ -919,13 +954,14 @@ def test_create_multiple_vouchers(token_client, organizer, event, item):
], format='json' ], format='json'
) )
assert resp.status_code == 201 assert resp.status_code == 201
assert Voucher.objects.count() == 2 with scopes_disabled():
assert resp.data[0]['code'] == 'ABCDEFGHI' assert Voucher.objects.count() == 2
v1 = Voucher.objects.get(code='ABCDEFGHI') assert resp.data[0]['code'] == 'ABCDEFGHI'
assert not v1.block_quota v1 = Voucher.objects.get(code='ABCDEFGHI')
assert resp.data[1]['code'] == 'JKLMNOPQR' assert not v1.block_quota
v2 = Voucher.objects.get(code='JKLMNOPQR') assert resp.data[1]['code'] == 'JKLMNOPQR'
assert v2.block_quota v2 = Voucher.objects.get(code='JKLMNOPQR')
assert v2.block_quota
@pytest.mark.django_db @pytest.mark.django_db
@@ -967,7 +1003,8 @@ def test_create_multiple_vouchers_one_invalid(token_client, organizer, event, it
) )
assert resp.status_code == 400 assert resp.status_code == 400
assert resp.data == [{}, {'code': ['Ensure this field has at least 5 characters.']}] assert resp.data == [{}, {'code': ['Ensure this field has at least 5 characters.']}]
assert Voucher.objects.count() == 0 with scopes_disabled():
assert Voucher.objects.count() == 0
@pytest.mark.django_db @pytest.mark.django_db
@@ -1009,4 +1046,5 @@ def test_create_multiple_vouchers_duplicate_code(token_client, organizer, event,
) )
assert resp.status_code == 400 assert resp.status_code == 400
assert resp.data == [{}, {'code': ['Duplicate voucher code in request.']}] assert resp.data == [{}, {'code': ['Duplicate voucher code in request.']}]
assert Voucher.objects.count() == 0 with scopes_disabled():
assert Voucher.objects.count() == 0

View File

@@ -3,6 +3,7 @@ import datetime
from unittest import mock from unittest import mock
import pytest import pytest
from django_scopes import scopes_disabled
from pytz import UTC from pytz import UTC
from pretix.base.models import WaitingListEntry from pretix.base.models import WaitingListEntry
@@ -44,8 +45,9 @@ TEST_WLE_RES = {
@pytest.mark.django_db @pytest.mark.django_db
def test_wle_list(token_client, organizer, event, wle, item, subevent): def test_wle_list(token_client, organizer, event, wle, item, subevent):
var = item.variations.create(value="Children") with scopes_disabled():
var2 = item.variations.create(value="Children") var = item.variations.create(value="Children")
var2 = item.variations.create(value="Children")
res = dict(TEST_WLE_RES) res = dict(TEST_WLE_RES)
wle.variation = var wle.variation = var
wle.save() wle.save()
@@ -97,7 +99,8 @@ def test_wle_list(token_client, organizer, event, wle, item, subevent):
'/api/v1/organizers/{}/events/{}/waitinglistentries/?has_voucher=true'.format(organizer.slug, event.slug)) '/api/v1/organizers/{}/events/{}/waitinglistentries/?has_voucher=true'.format(organizer.slug, event.slug))
assert [] == resp.data['results'] assert [] == resp.data['results']
v = event.vouchers.create(item=item, price_mode='set', value=12, tag='Foo') with scopes_disabled():
v = event.vouchers.create(item=item, price_mode='set', value=12, tag='Foo')
wle.voucher = v wle.voucher = v
wle.save() wle.save()
res['voucher'] = v.pk res['voucher'] = v.pk
@@ -112,7 +115,8 @@ def test_wle_list(token_client, organizer, event, wle, item, subevent):
resp = token_client.get( resp = token_client.get(
'/api/v1/organizers/{}/events/{}/waitinglistentries/?subevent={}'.format(organizer.slug, event.slug, subevent.pk)) '/api/v1/organizers/{}/events/{}/waitinglistentries/?subevent={}'.format(organizer.slug, event.slug, subevent.pk))
assert [res] == resp.data['results'] assert [res] == resp.data['results']
se2 = event.subevents.create(name="Foobar", date_from=datetime.datetime(2017, 12, 27, 10, 0, 0, tzinfo=UTC)) with scopes_disabled():
se2 = event.subevents.create(name="Foobar", date_from=datetime.datetime(2017, 12, 27, 10, 0, 0, tzinfo=UTC))
resp = token_client.get( resp = token_client.get(
'/api/v1/organizers/{}/events/{}/waitinglistentries/?subevent={}'.format(organizer.slug, event.slug, '/api/v1/organizers/{}/events/{}/waitinglistentries/?subevent={}'.format(organizer.slug, event.slug,
se2.pk)) se2.pk))
@@ -136,19 +140,22 @@ def test_delete_wle(token_client, organizer, event, wle, item):
'/api/v1/organizers/{}/events/{}/waitinglistentries/{}/'.format(organizer.slug, event.slug, wle.pk), '/api/v1/organizers/{}/events/{}/waitinglistentries/{}/'.format(organizer.slug, event.slug, wle.pk),
) )
assert resp.status_code == 204 assert resp.status_code == 204
assert not event.waitinglistentries.filter(pk=wle.id).exists() with scopes_disabled():
assert not event.waitinglistentries.filter(pk=wle.id).exists()
@pytest.mark.django_db @pytest.mark.django_db
def test_delete_wle_assigned(token_client, organizer, event, wle, item): def test_delete_wle_assigned(token_client, organizer, event, wle, item):
v = event.vouchers.create(item=item, price_mode='set', value=12, tag='Foo') with scopes_disabled():
v = event.vouchers.create(item=item, price_mode='set', value=12, tag='Foo')
wle.voucher = v wle.voucher = v
wle.save() wle.save()
resp = token_client.delete( resp = token_client.delete(
'/api/v1/organizers/{}/events/{}/waitinglistentries/{}/'.format(organizer.slug, event.slug, wle.pk), '/api/v1/organizers/{}/events/{}/waitinglistentries/{}/'.format(organizer.slug, event.slug, wle.pk),
) )
assert resp.status_code == 403 assert resp.status_code == 403
assert event.waitinglistentries.filter(pk=wle.id).exists() with scopes_disabled():
assert event.waitinglistentries.filter(pk=wle.id).exists()
def create_wle(token_client, organizer, event, data, expected_failure=False): def create_wle(token_client, organizer, event, data, expected_failure=False):
@@ -159,9 +166,9 @@ def create_wle(token_client, organizer, event, data, expected_failure=False):
if expected_failure: if expected_failure:
assert resp.status_code == 400 assert resp.status_code == 400
else: else:
print(resp.data)
assert resp.status_code == 201 assert resp.status_code == 201
return WaitingListEntry.objects.get(pk=resp.data['id']) with scopes_disabled():
return WaitingListEntry.objects.get(pk=resp.data['id'])
@pytest.mark.django_db @pytest.mark.django_db
@@ -205,7 +212,8 @@ def test_wle_require_fields(token_client, organizer, event, item, quota):
}, },
expected_failure=True expected_failure=True
) )
v = item.variations.create(value="S") with scopes_disabled():
v = item.variations.create(value="S")
create_wle( create_wle(
token_client, organizer, event, token_client, organizer, event,
data={ data={
@@ -300,7 +308,8 @@ def test_wle_change_email(token_client, organizer, event, item, wle, quota):
@pytest.mark.django_db @pytest.mark.django_db
def test_wle_change_assigned(token_client, organizer, event, item, wle, quota): def test_wle_change_assigned(token_client, organizer, event, item, wle, quota):
v = event.vouchers.create(item=item, price_mode='set', value=12, tag='Foo') with scopes_disabled():
v = event.vouchers.create(item=item, price_mode='set', value=12, tag='Foo')
wle.voucher = v wle.voucher = v
wle.save() wle.save()
change_wle( change_wle(
@@ -315,8 +324,9 @@ def test_wle_change_assigned(token_client, organizer, event, item, wle, quota):
@pytest.mark.django_db @pytest.mark.django_db
def test_wle_change_to_available_item(token_client, organizer, event, item, wle, quota): def test_wle_change_to_available_item(token_client, organizer, event, item, wle, quota):
i = event.items.create(name="Budget Ticket", default_price=23) with scopes_disabled():
q = event.quotas.create(name="Budget Ticket", size=1) i = event.items.create(name="Budget Ticket", default_price=23)
q = event.quotas.create(name="Budget Ticket", size=1)
q.items.add(i) q.items.add(i)
change_wle( change_wle(
token_client, organizer, event, wle, token_client, organizer, event, wle,
@@ -330,9 +340,10 @@ def test_wle_change_to_available_item(token_client, organizer, event, item, wle,
@pytest.mark.django_db @pytest.mark.django_db
def test_wle_change_to_unavailable_item(token_client, organizer, event, item, wle, quota): def test_wle_change_to_unavailable_item(token_client, organizer, event, item, wle, quota):
i = event.items.create(name="Budget Ticket", default_price=23) with scopes_disabled():
v = i.variations.create(value="S") i = event.items.create(name="Budget Ticket", default_price=23)
q = event.quotas.create(name="Budget Ticket", size=0) v = i.variations.create(value="S")
q = event.quotas.create(name="Budget Ticket", size=0)
q.items.add(i) q.items.add(i)
q.variations.add(v) q.variations.add(v)
change_wle( change_wle(
@@ -349,9 +360,10 @@ def test_wle_change_to_unavailable_item(token_client, organizer, event, item, wl
@pytest.mark.django_db @pytest.mark.django_db
def test_wle_change_to_unavailable_item_missing_var(token_client, organizer, event, item, wle, quota): def test_wle_change_to_unavailable_item_missing_var(token_client, organizer, event, item, wle, quota):
i = event.items.create(name="Budget Ticket", default_price=23) with scopes_disabled():
v = i.variations.create(value="S") i = event.items.create(name="Budget Ticket", default_price=23)
q = event.quotas.create(name="Budget Ticket", size=0) v = i.variations.create(value="S")
q = event.quotas.create(name="Budget Ticket", size=0)
q.items.add(i) q.items.add(i)
q.variations.add(v) q.variations.add(v)
change_wle( change_wle(

View File

@@ -1,6 +1,7 @@
import copy import copy
import pytest import pytest
from django_scopes import scopes_disabled
from pretix.api.models import WebHook from pretix.api.models import WebHook
@@ -64,12 +65,13 @@ def test_hook_create(token_client, organizer, event):
format='json' format='json'
) )
assert resp.status_code == 201 assert resp.status_code == 201
cl = WebHook.objects.get(pk=resp.data['id']) with scopes_disabled():
assert cl.target_url == "https://google.com" cl = WebHook.objects.get(pk=resp.data['id'])
assert cl.limit_events.count() == 1 assert cl.target_url == "https://google.com"
assert set(cl.listeners.values_list('action_type', flat=True)) == {'pretix.event.order.placed', assert cl.limit_events.count() == 1
'pretix.event.order.paid'} assert set(cl.listeners.values_list('action_type', flat=True)) == {'pretix.event.order.placed',
assert not cl.all_events 'pretix.event.order.paid'}
assert not cl.all_events
@pytest.mark.django_db @pytest.mark.django_db
@@ -136,9 +138,10 @@ def test_hook_patch_url(token_client, organizer, event, webhook):
assert resp.status_code == 200 assert resp.status_code == 200
webhook.refresh_from_db() webhook.refresh_from_db()
assert webhook.target_url == "https://pretix.eu" assert webhook.target_url == "https://pretix.eu"
assert webhook.limit_events.count() == 1 with scopes_disabled():
assert set(webhook.listeners.values_list('action_type', flat=True)) == {'pretix.event.order.placed', assert webhook.limit_events.count() == 1
'pretix.event.order.paid'} assert set(webhook.listeners.values_list('action_type', flat=True)) == {'pretix.event.order.placed',
'pretix.event.order.paid'}
assert webhook.enabled assert webhook.enabled
@@ -153,9 +156,10 @@ def test_hook_patch_types(token_client, organizer, event, webhook):
) )
assert resp.status_code == 200 assert resp.status_code == 200
webhook.refresh_from_db() webhook.refresh_from_db()
assert webhook.limit_events.count() == 1 with scopes_disabled():
assert set(webhook.listeners.values_list('action_type', flat=True)) == {'pretix.event.order.placed', assert webhook.limit_events.count() == 1
'pretix.event.order.canceled'} assert set(webhook.listeners.values_list('action_type', flat=True)) == {'pretix.event.order.placed',
'pretix.event.order.canceled'}
assert webhook.enabled assert webhook.enabled

View File

@@ -6,13 +6,13 @@ class SoupTest(TestCase):
def get_doc(self, *args, **kwargs): def get_doc(self, *args, **kwargs):
response = self.client.get(*args, **kwargs) response = self.client.get(*args, **kwargs)
return BeautifulSoup(response.rendered_content, "lxml") return BeautifulSoup(response.render().content, "lxml")
def post_doc(self, *args, **kwargs): def post_doc(self, *args, **kwargs):
kwargs['follow'] = True kwargs['follow'] = True
response = self.client.post(*args, **kwargs) response = self.client.post(*args, **kwargs)
try: try:
return BeautifulSoup(response.rendered_content, "lxml") return BeautifulSoup(response.render().content, "lxml")
except AttributeError: except AttributeError:
return BeautifulSoup(response.content, "lxml") return BeautifulSoup(response.content, "lxml")

View File

@@ -7,6 +7,7 @@ from django.core.serializers.json import DjangoJSONEncoder
from django.db import DatabaseError, transaction from django.db import DatabaseError, transaction
from django.utils.timezone import now from django.utils.timezone import now
from django_countries.fields import Country from django_countries.fields import Country
from django_scopes import scope, scopes_disabled
from pretix.base.models import ( from pretix.base.models import (
Event, Invoice, InvoiceAddress, Item, ItemVariation, Order, OrderPosition, Event, Invoice, InvoiceAddress, Item, ItemVariation, Order, OrderPosition,
@@ -24,72 +25,74 @@ from pretix.base.settings import GlobalSettingsObject
@pytest.fixture @pytest.fixture
def env(): def env():
o = Organizer.objects.create(name='Dummy', slug='dummy') o = Organizer.objects.create(name='Dummy', slug='dummy')
event = Event.objects.create( with scope(organizer=o):
organizer=o, name='Dummy', slug='dummy', event = Event.objects.create(
date_from=now(), plugins='pretix.plugins.banktransfer' organizer=o, name='Dummy', slug='dummy',
) date_from=now(), plugins='pretix.plugins.banktransfer'
o = Order.objects.create( )
code='FOO', event=event, email='dummy@dummy.test', o = Order.objects.create(
status=Order.STATUS_PENDING, code='FOO', event=event, email='dummy@dummy.test',
datetime=now(), expires=now() + timedelta(days=10), status=Order.STATUS_PENDING,
total=0, locale='en' datetime=now(), expires=now() + timedelta(days=10),
) total=0, locale='en'
tr = event.tax_rules.create(rate=Decimal('19.00')) )
o.fees.create(fee_type=OrderFee.FEE_TYPE_PAYMENT, value=Decimal('0.25'), tax_rate=Decimal('19.00'), tr = event.tax_rules.create(rate=Decimal('19.00'))
tax_value=Decimal('0.05'), tax_rule=tr) o.fees.create(fee_type=OrderFee.FEE_TYPE_PAYMENT, value=Decimal('0.25'), tax_rate=Decimal('19.00'),
ticket = Item.objects.create(event=event, name='Early-bird ticket', tax_value=Decimal('0.05'), tax_rule=tr)
category=None, default_price=23, tax_rule=tr, ticket = Item.objects.create(event=event, name='Early-bird ticket',
admission=True) category=None, default_price=23, tax_rule=tr,
t_shirt = Item.objects.create(event=event, name='T-Shirt', admission=True)
category=None, default_price=42, tax_rule=tr, t_shirt = Item.objects.create(event=event, name='T-Shirt',
admission=True) category=None, default_price=42, tax_rule=tr,
variation = ItemVariation.objects.create(value='M', item=t_shirt) admission=True)
OrderPosition.objects.create( variation = ItemVariation.objects.create(value='M', item=t_shirt)
order=o, OrderPosition.objects.create(
item=ticket, order=o,
variation=None, item=ticket,
price=Decimal("23.00"), variation=None,
positionid=1, price=Decimal("23.00"),
) positionid=1,
OrderPosition.objects.create( )
order=o, OrderPosition.objects.create(
item=t_shirt, order=o,
variation=variation, item=t_shirt,
price=Decimal("42.00"), variation=variation,
positionid=2, price=Decimal("42.00"),
) positionid=2,
OrderPosition.objects.create( )
order=o, OrderPosition.objects.create(
item=t_shirt, order=o,
variation=variation, item=t_shirt,
price=Decimal("42.00"), variation=variation,
positionid=3, price=Decimal("42.00"),
canceled=True positionid=3,
) canceled=True
gs = GlobalSettingsObject() )
gs.settings.ecb_rates_date = date.today() gs = GlobalSettingsObject()
gs.settings.ecb_rates_dict = json.dumps({ gs.settings.ecb_rates_date = date.today()
"USD": "1.1648", gs.settings.ecb_rates_dict = json.dumps({
"RON": "4.5638", "USD": "1.1648",
"CZK": "26.024", "RON": "4.5638",
"BGN": "1.9558", "CZK": "26.024",
"HRK": "7.4098", "BGN": "1.9558",
"EUR": "1.0000", "HRK": "7.4098",
"NOK": "9.3525", "EUR": "1.0000",
"HUF": "305.15", "NOK": "9.3525",
"DKK": "7.4361", "HUF": "305.15",
"PLN": "4.2408", "DKK": "7.4361",
"GBP": "0.89350", "PLN": "4.2408",
"SEK": "9.5883" "GBP": "0.89350",
}, cls=DjangoJSONEncoder) "SEK": "9.5883"
return event, o }, cls=DjangoJSONEncoder)
yield event, o
@pytest.mark.django_db @pytest.mark.django_db
def test_locale_setting(env): def test_locale_setting(env):
event, order = env event, order = env
event.settings.set('invoice_language', 'de') event.settings.set('invoice_language', 'de')
inv = generate_invoice(order) with scopes_disabled():
inv = generate_invoice(order)
assert inv.locale == 'de' assert inv.locale == 'de'

View File

@@ -2,6 +2,7 @@ import time
import pytest import pytest
from django.utils.timezone import now from django.utils.timezone import now
from django_scopes import scope, scopes_disabled
from pretix.base.models import Event, Organizer from pretix.base.models import Event, Organizer
from pretix.base.services import locking from pretix.base.services import locking
@@ -17,16 +18,18 @@ def event():
organizer=o, name='Dummy', slug='dummy', organizer=o, name='Dummy', slug='dummy',
date_from=now() date_from=now()
) )
return event with scope(organizer=o):
yield event
@pytest.mark.django_db @pytest.mark.django_db
def test_locking_exclusive(event): def test_locking_exclusive(event):
with event.lock(): with event.lock():
with pytest.raises(LockTimeoutException): with pytest.raises(LockTimeoutException):
ev = Event.objects.get(id=event.id) with scopes_disabled():
with ev.lock(): ev = Event.objects.get(id=event.id)
pass with ev.lock():
pass
@pytest.mark.django_db @pytest.mark.django_db

View File

@@ -5,6 +5,7 @@ from django.conf import settings
from django.core import mail as djmail from django.core import mail as djmail
from django.utils.timezone import now from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django_scopes import scope
from pretix.base.models import Event, Organizer, User from pretix.base.models import Event, Organizer, User
from pretix.base.services.mail import mail from pretix.base.services.mail import mail
@@ -20,7 +21,8 @@ def env():
user = User.objects.create_user('dummy@dummy.dummy', 'dummy') user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
user.email = 'dummy@dummy.dummy' user.email = 'dummy@dummy.dummy'
user.save() user.save()
return event, user, o with scope(organizer=o):
yield event, user, o
@pytest.mark.django_db @pytest.mark.django_db

File diff suppressed because it is too large Load Diff

View File

@@ -5,6 +5,7 @@ import pytest
from django.core import mail as djmail from django.core import mail as djmail
from django.db import transaction from django.db import transaction
from django.utils.timezone import now from django.utils.timezone import now
from django_scopes import scope
from pretix.base.models import ( from pretix.base.models import (
Event, Item, Order, OrderPosition, Organizer, User, Event, Item, Order, OrderPosition, Organizer, User,
@@ -18,7 +19,8 @@ def event():
organizer=o, name='Dummy', slug='dummy', organizer=o, name='Dummy', slug='dummy',
date_from=now() date_from=now()
) )
return event with scope(organizer=o):
yield event
@pytest.fixture @pytest.fixture

View File

@@ -7,6 +7,7 @@ from django.core import mail as djmail
from django.test import TestCase from django.test import TestCase
from django.utils.timezone import make_aware, now from django.utils.timezone import make_aware, now
from django_countries.fields import Country from django_countries.fields import Country
from django_scopes import scope
from pretix.base.decimal import round_decimal from pretix.base.decimal import round_decimal
from pretix.base.models import ( from pretix.base.models import (
@@ -21,9 +22,10 @@ from pretix.base.services.orders import (
OrderChangeManager, OrderError, _create_order, approve_order, cancel_order, OrderChangeManager, OrderError, _create_order, approve_order, cancel_order,
deny_order, expire_orders, send_download_reminders, send_expiry_warnings, deny_order, expire_orders, send_download_reminders, send_expiry_warnings,
) )
from pretix.testutils.scope import classscope
@pytest.fixture @pytest.fixture(scope='function')
def event(): def event():
o = Organizer.objects.create(name='Dummy', slug='dummy') o = Organizer.objects.create(name='Dummy', slug='dummy')
event = Event.objects.create( event = Event.objects.create(
@@ -31,7 +33,8 @@ def event():
date_from=now(), date_from=now(),
plugins='pretix.plugins.banktransfer' plugins='pretix.plugins.banktransfer'
) )
return event with scope(organizer=o):
yield event
@pytest.mark.django_db @pytest.mark.django_db
@@ -312,42 +315,47 @@ def test_deny(event):
class PaymentReminderTests(TestCase): class PaymentReminderTests(TestCase):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
o = Organizer.objects.create(name='Dummy', slug='dummy') self.o = Organizer.objects.create(name='Dummy', slug='dummy')
self.event = Event.objects.create( with scope(organizer=self.o):
organizer=o, name='Dummy', slug='dummy', self.event = Event.objects.create(
date_from=now() + timedelta(days=2), organizer=self.o, name='Dummy', slug='dummy',
plugins='pretix.plugins.banktransfer' date_from=now() + timedelta(days=2),
) plugins='pretix.plugins.banktransfer'
self.order = Order.objects.create( )
code='FOO', event=self.event, email='dummy@dummy.test', self.order = Order.objects.create(
status=Order.STATUS_PENDING, locale='en', code='FOO', event=self.event, email='dummy@dummy.test',
datetime=now() - timedelta(hours=4), status=Order.STATUS_PENDING, locale='en',
expires=now() - timedelta(hours=4) + timedelta(days=10), datetime=now() - timedelta(hours=4),
total=Decimal('46.00'), expires=now() - timedelta(hours=4) + timedelta(days=10),
) total=Decimal('46.00'),
self.ticket = Item.objects.create(event=self.event, name='Early-bird ticket', )
default_price=Decimal('23.00'), admission=True) self.ticket = Item.objects.create(event=self.event, name='Early-bird ticket',
self.op1 = OrderPosition.objects.create( default_price=Decimal('23.00'), admission=True)
order=self.order, item=self.ticket, variation=None, self.op1 = OrderPosition.objects.create(
price=Decimal("23.00"), attendee_name_parts={'full_name': "Peter"}, positionid=1 order=self.order, item=self.ticket, variation=None,
) price=Decimal("23.00"), attendee_name_parts={'full_name': "Peter"}, positionid=1
djmail.outbox = [] )
djmail.outbox = []
@classscope(attr='o')
def test_disabled(self): def test_disabled(self):
send_expiry_warnings(sender=self.event) send_expiry_warnings(sender=self.event)
assert len(djmail.outbox) == 0 assert len(djmail.outbox) == 0
@classscope(attr='o')
def test_sent_once(self): def test_sent_once(self):
self.event.settings.mail_days_order_expire_warning = 12 self.event.settings.mail_days_order_expire_warning = 12
send_expiry_warnings(sender=self.event) send_expiry_warnings(sender=self.event)
assert len(djmail.outbox) == 1 assert len(djmail.outbox) == 1
@classscope(attr='o')
def test_paid(self): def test_paid(self):
self.order.status = Order.STATUS_PAID self.order.status = Order.STATUS_PAID
self.order.save() self.order.save()
send_expiry_warnings(sender=self.event) send_expiry_warnings(sender=self.event)
assert len(djmail.outbox) == 0 assert len(djmail.outbox) == 0
@classscope(attr='o')
def test_sent_days(self): def test_sent_days(self):
self.event.settings.mail_days_order_expire_warning = 9 self.event.settings.mail_days_order_expire_warning = 9
send_expiry_warnings(sender=self.event) send_expiry_warnings(sender=self.event)
@@ -356,6 +364,7 @@ class PaymentReminderTests(TestCase):
send_expiry_warnings(sender=self.event) send_expiry_warnings(sender=self.event)
assert len(djmail.outbox) == 1 assert len(djmail.outbox) == 1
@classscope(attr='o')
def test_sent_not_immediately_after_purchase(self): def test_sent_not_immediately_after_purchase(self):
self.order.datetime = now() self.order.datetime = now()
self.order.expires = now() + timedelta(hours=3) self.order.expires = now() + timedelta(hours=3)
@@ -368,31 +377,34 @@ class PaymentReminderTests(TestCase):
class DownloadReminderTests(TestCase): class DownloadReminderTests(TestCase):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
o = Organizer.objects.create(name='Dummy', slug='dummy') self.o = Organizer.objects.create(name='Dummy', slug='dummy')
self.event = Event.objects.create( with scope(organizer=self.o):
organizer=o, name='Dummy', slug='dummy', self.event = Event.objects.create(
date_from=now() + timedelta(days=2), organizer=self.o, name='Dummy', slug='dummy',
plugins='pretix.plugins.banktransfer' date_from=now() + timedelta(days=2),
) plugins='pretix.plugins.banktransfer'
self.order = Order.objects.create( )
code='FOO', event=self.event, email='dummy@dummy.test', self.order = Order.objects.create(
status=Order.STATUS_PAID, locale='en', code='FOO', event=self.event, email='dummy@dummy.test',
datetime=now() - timedelta(hours=4), status=Order.STATUS_PAID, locale='en',
expires=now() - timedelta(hours=4) + timedelta(days=10), datetime=now() - timedelta(hours=4),
total=Decimal('46.00'), expires=now() - timedelta(hours=4) + timedelta(days=10),
) total=Decimal('46.00'),
self.ticket = Item.objects.create(event=self.event, name='Early-bird ticket', )
default_price=Decimal('23.00'), admission=True) self.ticket = Item.objects.create(event=self.event, name='Early-bird ticket',
self.op1 = OrderPosition.objects.create( default_price=Decimal('23.00'), admission=True)
order=self.order, item=self.ticket, variation=None, self.op1 = OrderPosition.objects.create(
price=Decimal("23.00"), attendee_name_parts={"full_name": "Peter"}, positionid=1 order=self.order, item=self.ticket, variation=None,
) price=Decimal("23.00"), attendee_name_parts={"full_name": "Peter"}, positionid=1
djmail.outbox = [] )
djmail.outbox = []
@classscope(attr='o')
def test_disabled(self): def test_disabled(self):
send_download_reminders(sender=self.event) send_download_reminders(sender=self.event)
assert len(djmail.outbox) == 0 assert len(djmail.outbox) == 0
@classscope(attr='o')
def test_sent_once(self): def test_sent_once(self):
self.event.settings.mail_days_download_reminder = 2 self.event.settings.mail_days_download_reminder = 2
send_download_reminders(sender=self.event) send_download_reminders(sender=self.event)
@@ -401,6 +413,7 @@ class DownloadReminderTests(TestCase):
send_download_reminders(sender=self.event) send_download_reminders(sender=self.event)
assert len(djmail.outbox) == 1 assert len(djmail.outbox) == 1
@classscope(attr='o')
def test_send_to_attendees(self): def test_send_to_attendees(self):
self.event.settings.mail_send_download_reminder_attendee = True self.event.settings.mail_send_download_reminder_attendee = True
self.event.settings.mail_days_download_reminder = 2 self.event.settings.mail_days_download_reminder = 2
@@ -413,6 +426,7 @@ class DownloadReminderTests(TestCase):
assert '/ticket/' in djmail.outbox[1].body assert '/ticket/' in djmail.outbox[1].body
assert '/order/' not in djmail.outbox[1].body assert '/order/' not in djmail.outbox[1].body
@classscope(attr='o')
def test_send_not_to_attendees_with_same_address(self): def test_send_not_to_attendees_with_same_address(self):
self.event.settings.mail_send_download_reminder_attendee = True self.event.settings.mail_send_download_reminder_attendee = True
self.event.settings.mail_days_download_reminder = 2 self.event.settings.mail_days_download_reminder = 2
@@ -423,6 +437,7 @@ class DownloadReminderTests(TestCase):
assert djmail.outbox[0].to == ['dummy@dummy.test'] assert djmail.outbox[0].to == ['dummy@dummy.test']
assert '/order/' in djmail.outbox[0].body assert '/order/' in djmail.outbox[0].body
@classscope(attr='o')
def test_sent_paid_only(self): def test_sent_paid_only(self):
self.event.settings.mail_days_download_reminder = 2 self.event.settings.mail_days_download_reminder = 2
self.order.status = Order.STATUS_PENDING self.order.status = Order.STATUS_PENDING
@@ -430,11 +445,13 @@ class DownloadReminderTests(TestCase):
send_download_reminders(sender=self.event) send_download_reminders(sender=self.event)
assert len(djmail.outbox) == 0 assert len(djmail.outbox) == 0
@classscope(attr='o')
def test_not_sent_too_early(self): def test_not_sent_too_early(self):
self.event.settings.mail_days_download_reminder = 1 self.event.settings.mail_days_download_reminder = 1
send_download_reminders(sender=self.event) send_download_reminders(sender=self.event)
assert len(djmail.outbox) == 0 assert len(djmail.outbox) == 0
@classscope(attr='o')
def test_not_sent_too_soon_after_purchase(self): def test_not_sent_too_soon_after_purchase(self):
self.order.datetime = now() self.order.datetime = now()
self.order.save() self.order.save()
@@ -446,42 +463,47 @@ class DownloadReminderTests(TestCase):
class OrderCancelTests(TestCase): class OrderCancelTests(TestCase):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
o = Organizer.objects.create(name='Dummy', slug='dummy') self.o = Organizer.objects.create(name='Dummy', slug='dummy')
self.event = Event.objects.create(organizer=o, name='Dummy', slug='dummy', date_from=now(), with scope(organizer=self.o):
plugins='tests.testdummy') self.event = Event.objects.create(organizer=self.o, name='Dummy', slug='dummy', date_from=now(),
self.order = Order.objects.create( plugins='tests.testdummy')
code='FOO', event=self.event, email='dummy@dummy.test', self.order = Order.objects.create(
status=Order.STATUS_PENDING, locale='en', code='FOO', event=self.event, email='dummy@dummy.test',
datetime=now(), expires=now() + timedelta(days=10), status=Order.STATUS_PENDING, locale='en',
total=Decimal('46.00'), datetime=now(), expires=now() + timedelta(days=10),
) total=Decimal('46.00'),
self.ticket = Item.objects.create(event=self.event, name='Early-bird ticket', )
default_price=Decimal('23.00'), admission=True) self.ticket = Item.objects.create(event=self.event, name='Early-bird ticket',
self.op1 = OrderPosition.objects.create( default_price=Decimal('23.00'), admission=True)
order=self.order, item=self.ticket, variation=None, self.op1 = OrderPosition.objects.create(
price=Decimal("23.00"), attendee_name_parts={'full_name': "Peter"}, positionid=1 order=self.order, item=self.ticket, variation=None,
) price=Decimal("23.00"), attendee_name_parts={'full_name': "Peter"}, positionid=1
self.op2 = OrderPosition.objects.create( )
order=self.order, item=self.ticket, variation=None, self.op2 = OrderPosition.objects.create(
price=Decimal("23.00"), attendee_name_parts={'full_name': "Dieter"}, positionid=2 order=self.order, item=self.ticket, variation=None,
) price=Decimal("23.00"), attendee_name_parts={'full_name': "Dieter"}, positionid=2
generate_invoice(self.order) )
djmail.outbox = [] generate_invoice(self.order)
djmail.outbox = []
@classscope(attr='o')
def test_cancel_canceled(self): def test_cancel_canceled(self):
self.order.status = Order.STATUS_CANCELED self.order.status = Order.STATUS_CANCELED
self.order.save() self.order.save()
with pytest.raises(OrderError): with pytest.raises(OrderError):
cancel_order(self.order.pk) cancel_order(self.order.pk)
@classscope(attr='o')
def test_cancel_send_mail(self): def test_cancel_send_mail(self):
cancel_order(self.order.pk, send_mail=True) cancel_order(self.order.pk, send_mail=True)
assert len(djmail.outbox) == 1 assert len(djmail.outbox) == 1
@classscope(attr='o')
def test_cancel_send_no_mail(self): def test_cancel_send_no_mail(self):
cancel_order(self.order.pk, send_mail=False) cancel_order(self.order.pk, send_mail=False)
assert len(djmail.outbox) == 0 assert len(djmail.outbox) == 0
@classscope(attr='o')
def test_cancel_unpaid(self): def test_cancel_unpaid(self):
cancel_order(self.order.pk) cancel_order(self.order.pk)
self.order.refresh_from_db() self.order.refresh_from_db()
@@ -489,6 +511,7 @@ class OrderCancelTests(TestCase):
assert self.order.all_logentries().last().action_type == 'pretix.event.order.canceled' assert self.order.all_logentries().last().action_type == 'pretix.event.order.canceled'
assert self.order.invoices.count() == 2 assert self.order.invoices.count() == 2
@classscope(attr='o')
def test_cancel_unpaid_with_voucher(self): def test_cancel_unpaid_with_voucher(self):
self.op1.voucher = self.event.vouchers.create(item=self.ticket, redeemed=1) self.op1.voucher = self.event.vouchers.create(item=self.ticket, redeemed=1)
self.op1.save() self.op1.save()
@@ -500,6 +523,7 @@ class OrderCancelTests(TestCase):
assert self.op1.voucher.redeemed == 0 assert self.op1.voucher.redeemed == 0
assert self.order.invoices.count() == 2 assert self.order.invoices.count() == 2
@classscope(attr='o')
def test_cancel_paid(self): def test_cancel_paid(self):
self.order.status = Order.STATUS_PAID self.order.status = Order.STATUS_PAID
self.order.save() self.order.save()
@@ -509,6 +533,7 @@ class OrderCancelTests(TestCase):
assert self.order.all_logentries().last().action_type == 'pretix.event.order.canceled' assert self.order.all_logentries().last().action_type == 'pretix.event.order.canceled'
assert self.order.invoices.count() == 2 assert self.order.invoices.count() == 2
@classscope(attr='o')
def test_cancel_paid_with_too_high_fee(self): def test_cancel_paid_with_too_high_fee(self):
self.order.status = Order.STATUS_PAID self.order.status = Order.STATUS_PAID
self.order.save() self.order.save()
@@ -519,6 +544,7 @@ class OrderCancelTests(TestCase):
assert self.order.status == Order.STATUS_PAID assert self.order.status == Order.STATUS_PAID
assert self.order.total == 46 assert self.order.total == 46
@classscope(attr='o')
def test_cancel_paid_with_fee(self): def test_cancel_paid_with_fee(self):
f = self.order.fees.create(fee_type=OrderFee.FEE_TYPE_SHIPPING, value=2.5) f = self.order.fees.create(fee_type=OrderFee.FEE_TYPE_SHIPPING, value=2.5)
self.order.status = Order.STATUS_PAID self.order.status = Order.STATUS_PAID
@@ -543,6 +569,7 @@ class OrderCancelTests(TestCase):
assert self.order.invoices.count() == 3 assert self.order.invoices.count() == 3
assert not self.order.invoices.last().is_cancellation assert not self.order.invoices.last().is_cancellation
@classscope(attr='o')
def test_auto_refund_possible(self): def test_auto_refund_possible(self):
p1 = self.order.payments.create( p1 = self.order.payments.create(
amount=Decimal('46.00'), amount=Decimal('46.00'),
@@ -558,6 +585,7 @@ class OrderCancelTests(TestCase):
assert self.order.all_logentries().filter(action_type='pretix.event.order.refund.created').exists() assert self.order.all_logentries().filter(action_type='pretix.event.order.refund.created').exists()
assert not self.order.all_logentries().filter(action_type='pretix.event.order.refund.requested').exists() assert not self.order.all_logentries().filter(action_type='pretix.event.order.refund.requested').exists()
@classscope(attr='o')
def test_auto_refund_impossible(self): def test_auto_refund_impossible(self):
self.order.payments.create( self.order.payments.create(
amount=Decimal('46.00'), amount=Decimal('46.00'),
@@ -572,39 +600,40 @@ class OrderCancelTests(TestCase):
class OrderChangeManagerTests(TestCase): class OrderChangeManagerTests(TestCase):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
o = Organizer.objects.create(name='Dummy', slug='dummy') self.o = Organizer.objects.create(name='Dummy', slug='dummy')
self.event = Event.objects.create(organizer=o, name='Dummy', slug='dummy', date_from=now(), with scope(organizer=self.o):
plugins='pretix.plugins.banktransfer') self.event = Event.objects.create(organizer=self.o, name='Dummy', slug='dummy', date_from=now(),
self.order = Order.objects.create( plugins='pretix.plugins.banktransfer')
code='FOO', event=self.event, email='dummy@dummy.test', self.order = Order.objects.create(
status=Order.STATUS_PENDING, locale='en', code='FOO', event=self.event, email='dummy@dummy.test',
datetime=now(), expires=now() + timedelta(days=10), status=Order.STATUS_PENDING, locale='en',
total=Decimal('46.00'), datetime=now(), expires=now() + timedelta(days=10),
) total=Decimal('46.00'),
self.order.payments.create( )
provider='banktransfer', state=OrderPayment.PAYMENT_STATE_CREATED, amount=self.order.total self.order.payments.create(
) provider='banktransfer', state=OrderPayment.PAYMENT_STATE_CREATED, amount=self.order.total
self.tr7 = self.event.tax_rules.create(rate=Decimal('7.00')) )
self.tr19 = self.event.tax_rules.create(rate=Decimal('19.00')) self.tr7 = self.event.tax_rules.create(rate=Decimal('7.00'))
self.ticket = Item.objects.create(event=self.event, name='Early-bird ticket', tax_rule=self.tr7, self.tr19 = self.event.tax_rules.create(rate=Decimal('19.00'))
default_price=Decimal('23.00'), admission=True) self.ticket = Item.objects.create(event=self.event, name='Early-bird ticket', tax_rule=self.tr7,
self.ticket2 = Item.objects.create(event=self.event, name='Other ticket', tax_rule=self.tr7, default_price=Decimal('23.00'), admission=True)
default_price=Decimal('23.00'), admission=True) self.ticket2 = Item.objects.create(event=self.event, name='Other ticket', tax_rule=self.tr7,
self.shirt = Item.objects.create(event=self.event, name='T-Shirt', tax_rule=self.tr19, default_price=Decimal('23.00'), admission=True)
default_price=Decimal('12.00')) self.shirt = Item.objects.create(event=self.event, name='T-Shirt', tax_rule=self.tr19,
self.op1 = OrderPosition.objects.create( default_price=Decimal('12.00'))
order=self.order, item=self.ticket, variation=None, self.op1 = OrderPosition.objects.create(
price=Decimal("23.00"), attendee_name_parts={'full_name': "Peter"}, positionid=1 order=self.order, item=self.ticket, variation=None,
) price=Decimal("23.00"), attendee_name_parts={'full_name': "Peter"}, positionid=1
self.op2 = OrderPosition.objects.create( )
order=self.order, item=self.ticket, variation=None, self.op2 = OrderPosition.objects.create(
price=Decimal("23.00"), attendee_name_parts={'full_name': "Dieter"}, positionid=2 order=self.order, item=self.ticket, variation=None,
) price=Decimal("23.00"), attendee_name_parts={'full_name': "Dieter"}, positionid=2
self.ocm = OrderChangeManager(self.order, None) )
self.quota = self.event.quotas.create(name='Test', size=None) self.ocm = OrderChangeManager(self.order, None)
self.quota.items.add(self.ticket) self.quota = self.event.quotas.create(name='Test', size=None)
self.quota.items.add(self.ticket2) self.quota.items.add(self.ticket)
self.quota.items.add(self.shirt) self.quota.items.add(self.ticket2)
self.quota.items.add(self.shirt)
def _enable_reverse_charge(self): def _enable_reverse_charge(self):
self.tr7.eu_reverse_charge = True self.tr7.eu_reverse_charge = True
@@ -618,6 +647,7 @@ class OrderChangeManagerTests(TestCase):
country=Country('AT') country=Country('AT')
) )
@classscope(attr='o')
def test_multiple_commits_forbidden(self): def test_multiple_commits_forbidden(self):
self.ocm.change_price(self.op1, Decimal('10.00')) self.ocm.change_price(self.op1, Decimal('10.00'))
self.ocm.commit() self.ocm.commit()
@@ -625,6 +655,7 @@ class OrderChangeManagerTests(TestCase):
with self.assertRaises(OrderError): with self.assertRaises(OrderError):
self.ocm.commit() self.ocm.commit()
@classscope(attr='o')
def test_change_subevent_quota_required(self): def test_change_subevent_quota_required(self):
self.event.has_subevents = True self.event.has_subevents = True
self.event.save() self.event.save()
@@ -637,6 +668,7 @@ class OrderChangeManagerTests(TestCase):
with self.assertRaises(OrderError): with self.assertRaises(OrderError):
self.ocm.change_subevent(self.op1, se2) self.ocm.change_subevent(self.op1, se2)
@classscope(attr='o')
def test_change_subevent_success(self): def test_change_subevent_success(self):
self.event.has_subevents = True self.event.has_subevents = True
self.event.save() self.event.save()
@@ -656,6 +688,7 @@ class OrderChangeManagerTests(TestCase):
assert self.op1.price == Decimal('23.00') assert self.op1.price == Decimal('23.00')
assert self.order.total == self.op1.price + self.op2.price assert self.order.total == self.op1.price + self.op2.price
@classscope(attr='o')
def test_change_subevent_with_price_success(self): def test_change_subevent_with_price_success(self):
self.event.has_subevents = True self.event.has_subevents = True
self.event.save() self.event.save()
@@ -676,6 +709,7 @@ class OrderChangeManagerTests(TestCase):
assert self.op1.price == Decimal('12.00') assert self.op1.price == Decimal('12.00')
assert self.order.total == self.op1.price + self.op2.price assert self.order.total == self.op1.price + self.op2.price
@classscope(attr='o')
def test_change_subevent_sold_out(self): def test_change_subevent_sold_out(self):
self.event.has_subevents = True self.event.has_subevents = True
self.event.save() self.event.save()
@@ -693,11 +727,13 @@ class OrderChangeManagerTests(TestCase):
self.op1.refresh_from_db() self.op1.refresh_from_db()
assert self.op1.subevent == se1 assert self.op1.subevent == se1
@classscope(attr='o')
def test_change_item_quota_required(self): def test_change_item_quota_required(self):
self.quota.delete() self.quota.delete()
with self.assertRaises(OrderError): with self.assertRaises(OrderError):
self.ocm.change_item(self.op1, self.shirt, None) self.ocm.change_item(self.op1, self.shirt, None)
@classscope(attr='o')
def test_change_item_keep_price(self): def test_change_item_keep_price(self):
p = self.op1.price p = self.op1.price
self.ocm.change_item(self.op1, self.shirt, None) self.ocm.change_item(self.op1, self.shirt, None)
@@ -709,6 +745,7 @@ class OrderChangeManagerTests(TestCase):
assert self.op1.tax_value == Decimal('3.67') assert self.op1.tax_value == Decimal('3.67')
assert self.op1.tax_rule == self.shirt.tax_rule assert self.op1.tax_rule == self.shirt.tax_rule
@classscope(attr='o')
def test_change_item_success(self): def test_change_item_success(self):
self.ocm.change_item(self.op1, self.shirt, None) self.ocm.change_item(self.op1, self.shirt, None)
self.ocm.commit() self.ocm.commit()
@@ -720,6 +757,7 @@ class OrderChangeManagerTests(TestCase):
assert round_decimal(self.op1.price * (1 - 100 / (100 + self.op1.tax_rate))) == self.op1.tax_value assert round_decimal(self.op1.price * (1 - 100 / (100 + self.op1.tax_rate))) == self.op1.tax_value
assert self.order.total == self.op1.price + self.op2.price assert self.order.total == self.op1.price + self.op2.price
@classscope(attr='o')
def test_change_item_with_price_success(self): def test_change_item_with_price_success(self):
self.ocm.change_item(self.op1, self.shirt, None) self.ocm.change_item(self.op1, self.shirt, None)
self.ocm.change_price(self.op1, Decimal('12.00')) self.ocm.change_price(self.op1, Decimal('12.00'))
@@ -732,6 +770,7 @@ class OrderChangeManagerTests(TestCase):
assert round_decimal(self.op1.price * (1 - 100 / (100 + self.op1.tax_rate))) == self.op1.tax_value assert round_decimal(self.op1.price * (1 - 100 / (100 + self.op1.tax_rate))) == self.op1.tax_value
assert self.order.total == self.op1.price + self.op2.price assert self.order.total == self.op1.price + self.op2.price
@classscope(attr='o')
def test_change_price_success(self): def test_change_price_success(self):
self.ocm.change_price(self.op1, Decimal('24.00')) self.ocm.change_price(self.op1, Decimal('24.00'))
self.ocm.commit() self.ocm.commit()
@@ -742,6 +781,7 @@ class OrderChangeManagerTests(TestCase):
assert round_decimal(self.op1.price * (1 - 100 / (100 + self.op1.tax_rate))) == self.op1.tax_value assert round_decimal(self.op1.price * (1 - 100 / (100 + self.op1.tax_rate))) == self.op1.tax_value
assert self.order.total == self.op1.price + self.op2.price assert self.order.total == self.op1.price + self.op2.price
@classscope(attr='o')
def test_change_price_net_success(self): def test_change_price_net_success(self):
self.tr7.price_includes_tax = False self.tr7.price_includes_tax = False
self.tr7.save() self.tr7.save()
@@ -754,6 +794,7 @@ class OrderChangeManagerTests(TestCase):
assert round_decimal(self.op1.price * (1 - 100 / (100 + self.op1.tax_rate))) == self.op1.tax_value assert round_decimal(self.op1.price * (1 - 100 / (100 + self.op1.tax_rate))) == self.op1.tax_value
assert self.order.total == self.op1.price + self.op2.price assert self.order.total == self.op1.price + self.op2.price
@classscope(attr='o')
def test_cancel_success(self): def test_cancel_success(self):
self.ocm.cancel(self.op1) self.ocm.cancel(self.op1)
self.ocm.commit() self.ocm.commit()
@@ -763,6 +804,7 @@ class OrderChangeManagerTests(TestCase):
self.op1.refresh_from_db() self.op1.refresh_from_db()
assert self.op1.canceled assert self.op1.canceled
@classscope(attr='o')
def test_cancel_with_addon(self): def test_cancel_with_addon(self):
self.shirt.category = self.event.categories.create(name='Add-ons', is_addon=True) self.shirt.category = self.event.categories.create(name='Add-ons', is_addon=True)
self.ticket.addons.create(addon_category=self.shirt.category) self.ticket.addons.create(addon_category=self.shirt.category)
@@ -781,6 +823,7 @@ class OrderChangeManagerTests(TestCase):
assert self.op1.canceled assert self.op1.canceled
assert self.op1.addons.first().canceled assert self.op1.addons.first().canceled
@classscope(attr='o')
def test_free_to_paid(self): def test_free_to_paid(self):
self.order.status = Order.STATUS_PAID self.order.status = Order.STATUS_PAID
self.order.save() self.order.save()
@@ -796,6 +839,7 @@ class OrderChangeManagerTests(TestCase):
assert self.op1.price == Decimal('24.00') assert self.op1.price == Decimal('24.00')
assert self.order.status == Order.STATUS_PENDING assert self.order.status == Order.STATUS_PENDING
@classscope(attr='o')
def test_cancel_all_in_order(self): def test_cancel_all_in_order(self):
self.ocm.cancel(self.op1) self.ocm.cancel(self.op1)
self.ocm.cancel(self.op2) self.ocm.cancel(self.op2)
@@ -803,9 +847,11 @@ class OrderChangeManagerTests(TestCase):
self.ocm.commit() self.ocm.commit()
assert self.order.positions.count() == 2 assert self.order.positions.count() == 2
@classscope(attr='o')
def test_empty(self): def test_empty(self):
self.ocm.commit() self.ocm.commit()
@classscope(attr='o')
def test_quota_unlimited(self): def test_quota_unlimited(self):
q = self.event.quotas.create(name='Test', size=None) q = self.event.quotas.create(name='Test', size=None)
q.items.add(self.shirt) q.items.add(self.shirt)
@@ -814,6 +860,7 @@ class OrderChangeManagerTests(TestCase):
self.op1.refresh_from_db() self.op1.refresh_from_db()
assert self.op1.item == self.shirt assert self.op1.item == self.shirt
@classscope(attr='o')
def test_quota_full(self): def test_quota_full(self):
q = self.event.quotas.create(name='Test', size=0) q = self.event.quotas.create(name='Test', size=0)
q.items.add(self.shirt) q.items.add(self.shirt)
@@ -823,6 +870,7 @@ class OrderChangeManagerTests(TestCase):
self.op1.refresh_from_db() self.op1.refresh_from_db()
assert self.op1.item == self.ticket assert self.op1.item == self.ticket
@classscope(attr='o')
def test_quota_ignore(self): def test_quota_ignore(self):
q = self.event.quotas.create(name='Test', size=0) q = self.event.quotas.create(name='Test', size=0)
q.items.add(self.shirt) q.items.add(self.shirt)
@@ -831,6 +879,7 @@ class OrderChangeManagerTests(TestCase):
self.op1.refresh_from_db() self.op1.refresh_from_db()
assert self.op1.item == self.shirt assert self.op1.item == self.shirt
@classscope(attr='o')
def test_quota_full_but_in_same(self): def test_quota_full_but_in_same(self):
q = self.event.quotas.create(name='Test', size=0) q = self.event.quotas.create(name='Test', size=0)
q.items.add(self.shirt) q.items.add(self.shirt)
@@ -840,6 +889,7 @@ class OrderChangeManagerTests(TestCase):
self.op1.refresh_from_db() self.op1.refresh_from_db()
assert self.op1.item == self.shirt assert self.op1.item == self.shirt
@classscope(attr='o')
def test_multiple_quotas_shared_full(self): def test_multiple_quotas_shared_full(self):
q1 = self.event.quotas.create(name='Test', size=0) q1 = self.event.quotas.create(name='Test', size=0)
q2 = self.event.quotas.create(name='Test', size=2) q2 = self.event.quotas.create(name='Test', size=2)
@@ -851,6 +901,7 @@ class OrderChangeManagerTests(TestCase):
self.op1.refresh_from_db() self.op1.refresh_from_db()
assert self.op1.item == self.shirt assert self.op1.item == self.shirt
@classscope(attr='o')
def test_multiple_quotas_unshared_full(self): def test_multiple_quotas_unshared_full(self):
q1 = self.event.quotas.create(name='Test', size=2) q1 = self.event.quotas.create(name='Test', size=2)
q2 = self.event.quotas.create(name='Test', size=0) q2 = self.event.quotas.create(name='Test', size=0)
@@ -863,6 +914,7 @@ class OrderChangeManagerTests(TestCase):
self.op1.refresh_from_db() self.op1.refresh_from_db()
assert self.op1.item == self.ticket assert self.op1.item == self.ticket
@classscope(attr='o')
def test_multiple_items_success(self): def test_multiple_items_success(self):
q1 = self.event.quotas.create(name='Test', size=2) q1 = self.event.quotas.create(name='Test', size=2)
q1.items.add(self.shirt) q1.items.add(self.shirt)
@@ -874,6 +926,7 @@ class OrderChangeManagerTests(TestCase):
assert self.op1.item == self.shirt assert self.op1.item == self.shirt
assert self.op2.item == self.shirt assert self.op2.item == self.shirt
@classscope(attr='o')
def test_multiple_items_quotas_partially_full(self): def test_multiple_items_quotas_partially_full(self):
q1 = self.event.quotas.create(name='Test', size=1) q1 = self.event.quotas.create(name='Test', size=1)
q1.items.add(self.shirt) q1.items.add(self.shirt)
@@ -886,6 +939,7 @@ class OrderChangeManagerTests(TestCase):
assert self.op1.item == self.ticket assert self.op1.item == self.ticket
assert self.op2.item == self.ticket assert self.op2.item == self.ticket
@classscope(attr='o')
def test_payment_fee_calculation(self): def test_payment_fee_calculation(self):
self.event.settings.set('tax_rate_default', self.tr19.pk) self.event.settings.set('tax_rate_default', self.tr19.pk)
prov = self.ocm._get_payment_provider() prov = self.ocm._get_payment_provider()
@@ -899,6 +953,7 @@ class OrderChangeManagerTests(TestCase):
assert fee.tax_rate == Decimal('19.00') assert fee.tax_rate == Decimal('19.00')
assert round_decimal(fee.value * (1 - 100 / (100 + fee.tax_rate))) == fee.tax_value assert round_decimal(fee.value * (1 - 100 / (100 + fee.tax_rate))) == fee.tax_value
@classscope(attr='o')
def test_pending_free_order_stays_pending(self): def test_pending_free_order_stays_pending(self):
self.event.settings.set('tax_rate_default', self.tr19.pk) self.event.settings.set('tax_rate_default', self.tr19.pk)
self.ocm.change_price(self.op1, Decimal('0.00')) self.ocm.change_price(self.op1, Decimal('0.00'))
@@ -914,6 +969,7 @@ class OrderChangeManagerTests(TestCase):
self.order.refresh_from_db() self.order.refresh_from_db()
assert self.order.status == Order.STATUS_PENDING assert self.order.status == Order.STATUS_PENDING
@classscope(attr='o')
def test_require_pending(self): def test_require_pending(self):
self.order.status = Order.STATUS_PAID self.order.status = Order.STATUS_PAID
self.order.save() self.order.save()
@@ -922,6 +978,7 @@ class OrderChangeManagerTests(TestCase):
self.op1.refresh_from_db() self.op1.refresh_from_db()
assert self.op1.item == self.shirt assert self.op1.item == self.shirt
@classscope(attr='o')
def test_change_price_to_free_marked_as_paid(self): def test_change_price_to_free_marked_as_paid(self):
self.ocm.change_price(self.op1, Decimal('0.00')) self.ocm.change_price(self.op1, Decimal('0.00'))
self.ocm.change_price(self.op2, Decimal('0.00')) self.ocm.change_price(self.op2, Decimal('0.00'))
@@ -931,6 +988,7 @@ class OrderChangeManagerTests(TestCase):
assert self.order.status == Order.STATUS_PAID assert self.order.status == Order.STATUS_PAID
assert self.order.payments.last().provider == 'free' assert self.order.payments.last().provider == 'free'
@classscope(attr='o')
def test_change_price_to_free_require_approval(self): def test_change_price_to_free_require_approval(self):
self.order.require_approval = True self.order.require_approval = True
self.order.save() self.order.save()
@@ -942,6 +1000,7 @@ class OrderChangeManagerTests(TestCase):
assert self.order.total == 0 assert self.order.total == 0
assert self.order.status == Order.STATUS_PENDING assert self.order.status == Order.STATUS_PENDING
@classscope(attr='o')
def test_change_paid_same_price(self): def test_change_paid_same_price(self):
self.order.status = Order.STATUS_PAID self.order.status = Order.STATUS_PAID
self.order.save() self.order.save()
@@ -951,6 +1010,7 @@ class OrderChangeManagerTests(TestCase):
assert self.order.total == 46 assert self.order.total == 46
assert self.order.status == Order.STATUS_PAID assert self.order.status == Order.STATUS_PAID
@classscope(attr='o')
def test_change_paid_different_price(self): def test_change_paid_different_price(self):
self.order.status = Order.STATUS_PAID self.order.status = Order.STATUS_PAID
self.order.save() self.order.save()
@@ -960,6 +1020,7 @@ class OrderChangeManagerTests(TestCase):
assert self.order.total == Decimal('28.00') assert self.order.total == Decimal('28.00')
assert self.order.status == Order.STATUS_PAID assert self.order.status == Order.STATUS_PAID
@classscope(attr='o')
def test_change_paid_to_pending(self): def test_change_paid_to_pending(self):
self.order.status = Order.STATUS_PAID self.order.status = Order.STATUS_PAID
self.order.save() self.order.save()
@@ -975,6 +1036,7 @@ class OrderChangeManagerTests(TestCase):
assert self.order.pending_sum == Decimal('2.00') assert self.order.pending_sum == Decimal('2.00')
assert self.order.status == Order.STATUS_PENDING assert self.order.status == Order.STATUS_PENDING
@classscope(attr='o')
def test_change_paid_stays_paid_when_overpaid(self): def test_change_paid_stays_paid_when_overpaid(self):
self.order.status = Order.STATUS_PAID self.order.status = Order.STATUS_PAID
self.order.save() self.order.save()
@@ -996,11 +1058,13 @@ class OrderChangeManagerTests(TestCase):
assert self.order.pending_sum == Decimal('0.00') assert self.order.pending_sum == Decimal('0.00')
assert self.order.status == Order.STATUS_PAID assert self.order.status == Order.STATUS_PAID
@classscope(attr='o')
def test_add_item_quota_required(self): def test_add_item_quota_required(self):
self.quota.delete() self.quota.delete()
with self.assertRaises(OrderError): with self.assertRaises(OrderError):
self.ocm.add_position(self.shirt, None, None, None) self.ocm.add_position(self.shirt, None, None, None)
@classscope(attr='o')
def test_add_item_success(self): def test_add_item_success(self):
self.ocm.add_position(self.shirt, None, None, None) self.ocm.add_position(self.shirt, None, None, None)
self.ocm.commit() self.ocm.commit()
@@ -1014,6 +1078,7 @@ class OrderChangeManagerTests(TestCase):
assert self.order.total == self.op1.price + self.op2.price + nop.price assert self.order.total == self.op1.price + self.op2.price + nop.price
assert nop.positionid == 3 assert nop.positionid == 3
@classscope(attr='o')
def test_add_item_net_price_success(self): def test_add_item_net_price_success(self):
self.tr19.price_includes_tax = False self.tr19.price_includes_tax = False
self.tr19.save() self.tr19.save()
@@ -1029,6 +1094,7 @@ class OrderChangeManagerTests(TestCase):
assert self.order.total == self.op1.price + self.op2.price + nop.price assert self.order.total == self.op1.price + self.op2.price + nop.price
assert nop.positionid == 3 assert nop.positionid == 3
@classscope(attr='o')
def test_add_item_reverse_charge(self): def test_add_item_reverse_charge(self):
self._enable_reverse_charge() self._enable_reverse_charge()
self.ocm.add_position(self.shirt, None, None, None) self.ocm.add_position(self.shirt, None, None, None)
@@ -1043,6 +1109,7 @@ class OrderChangeManagerTests(TestCase):
assert self.order.total == self.op1.price + self.op2.price + nop.price assert self.order.total == self.op1.price + self.op2.price + nop.price
assert nop.positionid == 3 assert nop.positionid == 3
@classscope(attr='o')
def test_add_item_custom_price(self): def test_add_item_custom_price(self):
self.ocm.add_position(self.shirt, None, Decimal('13.00'), None) self.ocm.add_position(self.shirt, None, Decimal('13.00'), None)
self.ocm.commit() self.ocm.commit()
@@ -1055,6 +1122,7 @@ class OrderChangeManagerTests(TestCase):
assert round_decimal(nop.price * (1 - 100 / (100 + self.shirt.tax_rule.rate))) == nop.tax_value assert round_decimal(nop.price * (1 - 100 / (100 + self.shirt.tax_rule.rate))) == nop.tax_value
assert self.order.total == self.op1.price + self.op2.price + nop.price assert self.order.total == self.op1.price + self.op2.price + nop.price
@classscope(attr='o')
def test_add_item_custom_price_tax_always_included(self): def test_add_item_custom_price_tax_always_included(self):
self.tr19.price_includes_tax = False self.tr19.price_includes_tax = False
self.tr19.save() self.tr19.save()
@@ -1069,6 +1137,7 @@ class OrderChangeManagerTests(TestCase):
assert round_decimal(nop.price * (1 - 100 / (100 + self.shirt.tax_rule.rate))) == nop.tax_value assert round_decimal(nop.price * (1 - 100 / (100 + self.shirt.tax_rule.rate))) == nop.tax_value
assert self.order.total == self.op1.price + self.op2.price + nop.price assert self.order.total == self.op1.price + self.op2.price + nop.price
@classscope(attr='o')
def test_add_item_quota_full(self): def test_add_item_quota_full(self):
q1 = self.event.quotas.create(name='Test', size=0) q1 = self.event.quotas.create(name='Test', size=0)
q1.items.add(self.shirt) q1.items.add(self.shirt)
@@ -1077,6 +1146,7 @@ class OrderChangeManagerTests(TestCase):
self.ocm.commit() self.ocm.commit()
assert self.order.positions.count() == 2 assert self.order.positions.count() == 2
@classscope(attr='o')
def test_add_item_addon(self): def test_add_item_addon(self):
self.shirt.category = self.event.categories.create(name='Add-ons', is_addon=True) self.shirt.category = self.event.categories.create(name='Add-ons', is_addon=True)
self.ticket.addons.create(addon_category=self.shirt.category) self.ticket.addons.create(addon_category=self.shirt.category)
@@ -1088,6 +1158,7 @@ class OrderChangeManagerTests(TestCase):
assert nop.item == self.shirt assert nop.item == self.shirt
assert nop.addon_to == self.op1 assert nop.addon_to == self.op1
@classscope(attr='o')
def test_add_item_addon_invalid(self): def test_add_item_addon_invalid(self):
with self.assertRaises(OrderError): with self.assertRaises(OrderError):
self.ocm.add_position(self.shirt, None, Decimal('13.00'), self.op1) self.ocm.add_position(self.shirt, None, Decimal('13.00'), self.op1)
@@ -1095,12 +1166,14 @@ class OrderChangeManagerTests(TestCase):
with self.assertRaises(OrderError): with self.assertRaises(OrderError):
self.ocm.add_position(self.shirt, None, Decimal('13.00'), None) self.ocm.add_position(self.shirt, None, Decimal('13.00'), None)
@classscope(attr='o')
def test_add_item_subevent_required(self): def test_add_item_subevent_required(self):
self.event.has_subevents = True self.event.has_subevents = True
self.event.save() self.event.save()
with self.assertRaises(OrderError): with self.assertRaises(OrderError):
self.ocm.add_position(self.ticket, None, None, None) self.ocm.add_position(self.ticket, None, None, None)
@classscope(attr='o')
def test_add_item_subevent_price(self): def test_add_item_subevent_price(self):
self.event.has_subevents = True self.event.has_subevents = True
self.event.save() self.event.save()
@@ -1118,6 +1191,7 @@ class OrderChangeManagerTests(TestCase):
assert nop.price == Decimal('12.00') assert nop.price == Decimal('12.00')
assert nop.subevent == se1 assert nop.subevent == se1
@classscope(attr='o')
def test_reissue_invoice(self): def test_reissue_invoice(self):
generate_invoice(self.order) generate_invoice(self.order)
assert self.order.invoices.count() == 1 assert self.order.invoices.count() == 1
@@ -1125,6 +1199,7 @@ class OrderChangeManagerTests(TestCase):
self.ocm.commit() self.ocm.commit()
assert self.order.invoices.count() == 3 assert self.order.invoices.count() == 3
@classscope(attr='o')
def test_dont_reissue_invoice_on_free_product_changes(self): def test_dont_reissue_invoice_on_free_product_changes(self):
self.event.settings.invoice_include_free = False self.event.settings.invoice_include_free = False
generate_invoice(self.order) generate_invoice(self.order)
@@ -1133,6 +1208,7 @@ class OrderChangeManagerTests(TestCase):
self.ocm.commit() self.ocm.commit()
assert self.order.invoices.count() == 1 assert self.order.invoices.count() == 1
@classscope(attr='o')
def test_recalculate_reverse_charge(self): def test_recalculate_reverse_charge(self):
self.event.settings.set('tax_rate_default', self.tr19.pk) self.event.settings.set('tax_rate_default', self.tr19.pk)
prov = self.ocm._get_payment_provider() prov = self.ocm._get_payment_provider()
@@ -1179,6 +1255,7 @@ class OrderChangeManagerTests(TestCase):
assert fee.tax_rate == Decimal('19.00') assert fee.tax_rate == Decimal('19.00')
assert fee.tax_value == Decimal('0.05') assert fee.tax_value == Decimal('0.05')
@classscope(attr='o')
def test_split_simple(self): def test_split_simple(self):
old_secret = self.op2.secret old_secret = self.op2.secret
self.ocm.split(self.op2) self.ocm.split(self.op2)
@@ -1198,6 +1275,7 @@ class OrderChangeManagerTests(TestCase):
assert not self.order.invoices.exists() assert not self.order.invoices.exists()
assert not o2.invoices.exists() assert not o2.invoices.exists()
@classscope(attr='o')
def test_split_require_approval(self): def test_split_require_approval(self):
self.op2.item.require_approval = True self.op2.item.require_approval = True
self.op2.item.save() self.op2.item.save()
@@ -1222,6 +1300,7 @@ class OrderChangeManagerTests(TestCase):
assert not self.order.invoices.exists() assert not self.order.invoices.exists()
assert not o2.invoices.exists() assert not o2.invoices.exists()
@classscope(attr='o')
def test_split_pending_payment_fees(self): def test_split_pending_payment_fees(self):
# Set payment fees # Set payment fees
self.event.settings.set('tax_rate_default', self.tr19.pk) self.event.settings.set('tax_rate_default', self.tr19.pk)
@@ -1262,6 +1341,7 @@ class OrderChangeManagerTests(TestCase):
assert o2.positions.count() == 1 assert o2.positions.count() == 1
assert o2.fees.count() == 1 assert o2.fees.count() == 1
@classscope(attr='o')
def test_split_paid_no_payment_fees(self): def test_split_paid_no_payment_fees(self):
self.order.status = Order.STATUS_PAID self.order.status = Order.STATUS_PAID
self.order.save() self.order.save()
@@ -1299,6 +1379,7 @@ class OrderChangeManagerTests(TestCase):
assert p.amount == Decimal('23.00') assert p.amount == Decimal('23.00')
assert p.state == OrderPayment.PAYMENT_STATE_CONFIRMED assert p.state == OrderPayment.PAYMENT_STATE_CONFIRMED
@classscope(attr='o')
def test_split_invoice_address(self): def test_split_invoice_address(self):
ia = InvoiceAddress.objects.create( ia = InvoiceAddress.objects.create(
order=self.order, is_business=True, vat_id='ATU1234567', vat_id_validated=True, order=self.order, is_business=True, vat_id='ATU1234567', vat_id_validated=True,
@@ -1325,6 +1406,7 @@ class OrderChangeManagerTests(TestCase):
assert o2.invoice_address != ia assert o2.invoice_address != ia
assert o2.invoice_address.company == 'Sample' assert o2.invoice_address.company == 'Sample'
@classscope(attr='o')
def test_change_price_of_pending_order_with_payment(self): def test_change_price_of_pending_order_with_payment(self):
self.order.status = Order.STATUS_PENDING self.order.status = Order.STATUS_PENDING
self.order.save() self.order.save()
@@ -1337,6 +1419,7 @@ class OrderChangeManagerTests(TestCase):
assert self.order.payments.last().state == OrderPayment.PAYMENT_STATE_CANCELED assert self.order.payments.last().state == OrderPayment.PAYMENT_STATE_CANCELED
assert self.order.payments.last().amount == Decimal('46.00') assert self.order.payments.last().amount == Decimal('46.00')
@classscope(attr='o')
def test_split_reverse_charge(self): def test_split_reverse_charge(self):
ia = self._enable_reverse_charge() ia = self._enable_reverse_charge()
@@ -1393,6 +1476,7 @@ class OrderChangeManagerTests(TestCase):
assert o2.invoice_address != ia assert o2.invoice_address != ia
assert o2.invoice_address.vat_id_validated is True assert o2.invoice_address.vat_id_validated is True
@classscope(attr='o')
def test_split_other_fees(self): def test_split_other_fees(self):
# Check if reverse charge is active # Check if reverse charge is active
self.order.fees.create(fee_type=OrderFee.FEE_TYPE_SHIPPING, tax_rule=self.tr19, value=Decimal('2.50')) self.order.fees.create(fee_type=OrderFee.FEE_TYPE_SHIPPING, tax_rule=self.tr19, value=Decimal('2.50'))
@@ -1424,12 +1508,14 @@ class OrderChangeManagerTests(TestCase):
assert o2.positions.first().price == Decimal('23.00') assert o2.positions.first().price == Decimal('23.00')
assert o2.fees.count() == 1 assert o2.fees.count() == 1
@classscope(attr='o')
def test_split_to_empty(self): def test_split_to_empty(self):
self.ocm.split(self.op1) self.ocm.split(self.op1)
self.ocm.split(self.op2) self.ocm.split(self.op2)
with self.assertRaises(OrderError): with self.assertRaises(OrderError):
self.ocm.commit() self.ocm.commit()
@classscope(attr='o')
def test_split_paid_payment_fees(self): def test_split_paid_payment_fees(self):
# Set payment fees # Set payment fees
self.event.settings.set('tax_rate_default', self.tr19.pk) self.event.settings.set('tax_rate_default', self.tr19.pk)
@@ -1472,6 +1558,7 @@ class OrderChangeManagerTests(TestCase):
assert o2.total == Decimal('23.00') assert o2.total == Decimal('23.00')
assert o2.fees.count() == 0 assert o2.fees.count() == 0
@classscope(attr='o')
def test_split_invoice(self): def test_split_invoice(self):
generate_invoice(self.order) generate_invoice(self.order)
assert self.order.invoices.count() == 1 assert self.order.invoices.count() == 1
@@ -1487,6 +1574,7 @@ class OrderChangeManagerTests(TestCase):
assert o2.invoices.count() == 1 assert o2.invoices.count() == 1
assert o2.invoices.last().lines.count() == 1 assert o2.invoices.last().lines.count() == 1
@classscope(attr='o')
def test_split_to_free_invoice(self): def test_split_to_free_invoice(self):
self.event.settings.invoice_include_free = False self.event.settings.invoice_include_free = False
self.ocm.change_price(self.op2, Decimal('0.00')) self.ocm.change_price(self.op2, Decimal('0.00'))
@@ -1508,6 +1596,7 @@ class OrderChangeManagerTests(TestCase):
assert self.order.invoices.last().lines.count() == 1 assert self.order.invoices.last().lines.count() == 1
assert o2.invoices.count() == 0 assert o2.invoices.count() == 0
@classscope(attr='o')
def test_split_to_original_free(self): def test_split_to_original_free(self):
self.ocm.change_price(self.op2, Decimal('0.00')) self.ocm.change_price(self.op2, Decimal('0.00'))
self.ocm.commit() self.ocm.commit()
@@ -1525,6 +1614,7 @@ class OrderChangeManagerTests(TestCase):
assert o2.total == Decimal('23.00') assert o2.total == Decimal('23.00')
assert o2.status == Order.STATUS_PENDING assert o2.status == Order.STATUS_PENDING
@classscope(attr='o')
def test_split_to_new_free(self): def test_split_to_new_free(self):
self.ocm.change_price(self.op2, Decimal('0.00')) self.ocm.change_price(self.op2, Decimal('0.00'))
self.ocm.commit() self.ocm.commit()

View File

@@ -4,6 +4,7 @@ from decimal import Decimal
import pytest import pytest
import pytz import pytz
from django.utils.timezone import now from django.utils.timezone import now
from django_scopes import scope
from tests.testdummy.payment import DummyPaymentProvider from tests.testdummy.payment import DummyPaymentProvider
from pretix.base.models import ( from pretix.base.models import (
@@ -19,7 +20,8 @@ def event():
organizer=o, name='Dummy', slug='dummy', organizer=o, name='Dummy', slug='dummy',
date_from=now() date_from=now()
) )
return event with scope(organizer=o):
yield event
@pytest.mark.django_db @pytest.mark.django_db

View File

@@ -1,6 +1,7 @@
import pytest import pytest
from django.test import RequestFactory from django.test import RequestFactory
from django.utils.timezone import now from django.utils.timezone import now
from django_scopes import scope
from pretix.base.models import Event, Organizer, Team, User from pretix.base.models import Event, Organizer, Team, User
from pretix.multidomain.middlewares import SessionMiddleware from pretix.multidomain.middlewares import SessionMiddleware
@@ -8,7 +9,9 @@ from pretix.multidomain.middlewares import SessionMiddleware
@pytest.fixture @pytest.fixture
def organizer(): def organizer():
return Organizer.objects.create(name='Dummy', slug='dummy') o = Organizer.objects.create(name='Dummy', slug='dummy')
with scope(organizer=o):
yield o
@pytest.fixture @pytest.fixture
@@ -251,25 +254,26 @@ def test_list_of_events(event, user, admin, admin_request):
team2.limit_events.add(event) team2.limit_events.add(event)
team3.limit_events.add(event3) team3.limit_events.add(event3)
events = list(user.get_events_with_any_permission(request=admin_request)) with scope(organizer=[event.organizer, orga2]):
assert event in events events = list(user.get_events_with_any_permission(request=admin_request))
assert event2 in events assert event in events
assert event3 in events assert event2 in events
assert event4 not in events assert event3 in events
assert event4 not in events
events = list(user.get_events_with_permission('can_change_event_settings', request=admin_request)) events = list(user.get_events_with_permission('can_change_event_settings', request=admin_request))
assert event not in events assert event not in events
assert event2 not in events assert event2 not in events
assert event3 in events assert event3 in events
assert event4 not in events assert event4 not in events
assert set(event.get_users_with_any_permission()) == {user} assert set(event.get_users_with_any_permission()) == {user}
assert set(event2.get_users_with_any_permission()) == {user} assert set(event2.get_users_with_any_permission()) == {user}
assert set(event3.get_users_with_any_permission()) == {user} assert set(event3.get_users_with_any_permission()) == {user}
assert set(event4.get_users_with_any_permission()) == set() assert set(event4.get_users_with_any_permission()) == set()
assert set(event.get_users_with_permission('can_change_event_settings')) == set() assert set(event.get_users_with_permission('can_change_event_settings')) == set()
assert set(event2.get_users_with_permission('can_change_event_settings')) == set() assert set(event2.get_users_with_permission('can_change_event_settings')) == set()
assert set(event3.get_users_with_permission('can_change_event_settings')) == {user} assert set(event3.get_users_with_permission('can_change_event_settings')) == {user}
assert set(event4.get_users_with_permission('can_change_event_settings')) == set() assert set(event4.get_users_with_permission('can_change_event_settings')) == set()
assert set(event.get_users_with_permission('can_change_orders')) == {user} assert set(event.get_users_with_permission('can_change_orders')) == {user}

View File

@@ -2,6 +2,7 @@ from datetime import datetime, time
import pytest import pytest
import pytz import pytz
from django_scopes import scope
from pretix.base.models import Event, Organizer from pretix.base.models import Event, Organizer
from pretix.base.reldate import RelativeDate, RelativeDateWrapper from pretix.base.reldate import RelativeDate, RelativeDateWrapper
@@ -41,27 +42,28 @@ def test_relative_date_without_time(event):
@pytest.mark.django_db @pytest.mark.django_db
def test_relative_date_other_base_point(event): def test_relative_date_other_base_point(event):
rdw = RelativeDateWrapper(RelativeDate(days_before=1, time=None, base_date_name='presale_start')) with scope(organizer=event.organizer):
assert rdw.datetime(event) == TOKYO.localize(datetime(2017, 11, 30, 5, 0, 0)) rdw = RelativeDateWrapper(RelativeDate(days_before=1, time=None, base_date_name='presale_start'))
assert rdw.to_string() == 'RELDATE/1/-/presale_start/' assert rdw.datetime(event) == TOKYO.localize(datetime(2017, 11, 30, 5, 0, 0))
assert rdw.to_string() == 'RELDATE/1/-/presale_start/'
# presale_end is unset, defaults to date_from # presale_end is unset, defaults to date_from
rdw = RelativeDateWrapper(RelativeDate(days_before=1, time=None, base_date_name='presale_end')) rdw = RelativeDateWrapper(RelativeDate(days_before=1, time=None, base_date_name='presale_end'))
assert rdw.datetime(event) == TOKYO.localize(datetime(2017, 12, 26, 5, 0, 0)) assert rdw.datetime(event) == TOKYO.localize(datetime(2017, 12, 26, 5, 0, 0))
assert rdw.to_string() == 'RELDATE/1/-/presale_end/' assert rdw.to_string() == 'RELDATE/1/-/presale_end/'
# subevent base # subevent base
se = event.subevents.create(name="SE1", date_from=TOKYO.localize(datetime(2017, 11, 27, 5, 0, 0))) se = event.subevents.create(name="SE1", date_from=TOKYO.localize(datetime(2017, 11, 27, 5, 0, 0)))
rdw = RelativeDateWrapper(RelativeDate(days_before=1, time=None, base_date_name='date_from')) rdw = RelativeDateWrapper(RelativeDate(days_before=1, time=None, base_date_name='date_from'))
assert rdw.datetime(se) == TOKYO.localize(datetime(2017, 11, 26, 5, 0, 0)) assert rdw.datetime(se) == TOKYO.localize(datetime(2017, 11, 26, 5, 0, 0))
# presale_start is unset on subevent, default to event # presale_start is unset on subevent, default to event
rdw = RelativeDateWrapper(RelativeDate(days_before=1, time=None, base_date_name='presale_start')) rdw = RelativeDateWrapper(RelativeDate(days_before=1, time=None, base_date_name='presale_start'))
assert rdw.datetime(se) == TOKYO.localize(datetime(2017, 11, 30, 5, 0, 0)) assert rdw.datetime(se) == TOKYO.localize(datetime(2017, 11, 30, 5, 0, 0))
# presale_end is unset on all, default to date_from of subevent # presale_end is unset on all, default to date_from of subevent
rdw = RelativeDateWrapper(RelativeDate(days_before=1, time=None, base_date_name='presale_end')) rdw = RelativeDateWrapper(RelativeDate(days_before=1, time=None, base_date_name='presale_end'))
assert rdw.datetime(se) == TOKYO.localize(datetime(2017, 11, 26, 5, 0, 0)) assert rdw.datetime(se) == TOKYO.localize(datetime(2017, 11, 26, 5, 0, 0))
@pytest.mark.django_db @pytest.mark.django_db

View File

@@ -1,5 +1,6 @@
from django.test import TestCase from django.test import TestCase
from django.utils.timezone import now from django.utils.timezone import now
from django_scopes import scopes_disabled
from i18nfield.strings import LazyI18nString from i18nfield.strings import LazyI18nString
from pretix.base import settings from pretix.base import settings
@@ -43,7 +44,8 @@ class SettingsTestCase(TestCase):
sandbox['bar'] = 'baz' sandbox['bar'] = 'baz'
sandbox.baz = 42 sandbox.baz = 42
self.event = Event.objects.get(id=self.event.id) with scopes_disabled():
self.event = Event.objects.get(id=self.event.id)
sandbox = SettingsSandbox('testing', 'foo', self.event) sandbox = SettingsSandbox('testing', 'foo', self.event)
self.assertEqual(sandbox['bar'], 'baz') self.assertEqual(sandbox['bar'], 'baz')
self.assertEqual(sandbox.baz, '42') self.assertEqual(sandbox.baz, '42')

View File

@@ -6,6 +6,7 @@ from decimal import Decimal
import pytest import pytest
from django.core.files.base import ContentFile from django.core.files.base import ContentFile
from django.utils.timezone import now from django.utils.timezone import now
from django_scopes import scope
from pretix.base.models import ( from pretix.base.models import (
CachedCombinedTicket, CachedTicket, Event, InvoiceAddress, Order, CachedCombinedTicket, CachedTicket, Event, InvoiceAddress, Order,
@@ -27,7 +28,8 @@ def event():
organizer=o, name='Dummy', slug='dummy', organizer=o, name='Dummy', slug='dummy',
date_from=now(), plugins='pretix.plugins.banktransfer,pretix.plugins.ticketoutputpdf' date_from=now(), plugins='pretix.plugins.banktransfer,pretix.plugins.ticketoutputpdf'
) )
return event with scope(organizer=o):
yield event
@pytest.fixture @pytest.fixture

View File

@@ -4,6 +4,7 @@ from decimal import Decimal
import pytest import pytest
from django.utils.timezone import now from django.utils.timezone import now
from django_countries.fields import Country from django_countries.fields import Country
from django_scopes import scope
from pretix.base.models import Event, InvoiceAddress, Organizer, TaxRule from pretix.base.models import Event, InvoiceAddress, Organizer, TaxRule
@@ -15,7 +16,8 @@ def event():
organizer=o, name='Dummy', slug='dummy', organizer=o, name='Dummy', slug='dummy',
date_from=now() date_from=now()
) )
return event with scope(organizer=o):
yield event
@pytest.mark.django_db @pytest.mark.django_db

View File

@@ -3,6 +3,7 @@ from decimal import Decimal
import pytest import pytest
import pytz import pytz
from django_scopes import scope
from pretix.base.models import Event, Organizer from pretix.base.models import Event, Organizer
from pretix.base.timeline import timeline_for_event from pretix.base.timeline import timeline_for_event
@@ -29,7 +30,8 @@ def event():
date_from=datetime(2017, 10, 22, 12, 0, 0, tzinfo=tz), date_from=datetime(2017, 10, 22, 12, 0, 0, tzinfo=tz),
date_to=datetime(2017, 10, 23, 23, 0, 0, tzinfo=tz), date_to=datetime(2017, 10, 23, 23, 0, 0, tzinfo=tz),
) )
return event with scope(organizer=o):
yield event
@pytest.fixture @pytest.fixture

View File

@@ -3,6 +3,7 @@ from datetime import timedelta
from django.core import mail as djmail from django.core import mail as djmail
from django.test import TestCase from django.test import TestCase
from django.utils.timezone import now from django.utils.timezone import now
from django_scopes import scope
from pretix.base.models import ( from pretix.base.models import (
Event, Item, ItemVariation, Organizer, Quota, Voucher, WaitingListEntry, Event, Item, ItemVariation, Organizer, Quota, Voucher, WaitingListEntry,
@@ -11,28 +12,31 @@ from pretix.base.models.waitinglist import WaitingListException
from pretix.base.services.waitinglist import ( from pretix.base.services.waitinglist import (
assign_automatically, process_waitinglist, assign_automatically, process_waitinglist,
) )
from pretix.testutils.scope import classscope
class WaitingListTestCase(TestCase): class WaitingListTestCase(TestCase):
@classmethod @classmethod
def setUpTestData(cls): def setUpTestData(cls):
o = Organizer.objects.create(name='Dummy', slug='dummy') cls.o = Organizer.objects.create(name='Dummy', slug='dummy')
cls.event = Event.objects.create( cls.event = Event.objects.create(
organizer=o, name='Dummy', slug='dummy', organizer=cls.o, name='Dummy', slug='dummy',
date_from=now(), live=True date_from=now(), live=True
) )
def setUp(self): def setUp(self):
djmail.outbox = [] djmail.outbox = []
self.quota = Quota.objects.create(name="Test", size=2, event=self.event) with scope(organizer=self.o):
self.item1 = Item.objects.create(event=self.event, name="Ticket", default_price=23, self.quota = Quota.objects.create(name="Test", size=2, event=self.event)
admission=True) self.item1 = Item.objects.create(event=self.event, name="Ticket", default_price=23,
self.item2 = Item.objects.create(event=self.event, name="T-Shirt", default_price=23) admission=True)
self.item3 = Item.objects.create(event=self.event, name="Goodie", default_price=23) self.item2 = Item.objects.create(event=self.event, name="T-Shirt", default_price=23)
self.var1 = ItemVariation.objects.create(item=self.item2, value='S') self.item3 = Item.objects.create(event=self.event, name="Goodie", default_price=23)
self.var2 = ItemVariation.objects.create(item=self.item2, value='M') self.var1 = ItemVariation.objects.create(item=self.item2, value='S')
self.var3 = ItemVariation.objects.create(item=self.item3, value='Fancy') self.var2 = ItemVariation.objects.create(item=self.item2, value='M')
self.var3 = ItemVariation.objects.create(item=self.item3, value='Fancy')
@classscope(attr='o')
def test_send_unavailable(self): def test_send_unavailable(self):
self.quota.items.add(self.item1) self.quota.items.add(self.item1)
self.quota.size = 0 self.quota.size = 0
@@ -43,6 +47,7 @@ class WaitingListTestCase(TestCase):
with self.assertRaises(WaitingListException): with self.assertRaises(WaitingListException):
wle.send_voucher() wle.send_voucher()
@classscope(attr='o')
def test_send_double(self): def test_send_double(self):
self.quota.variations.add(self.var1) self.quota.variations.add(self.var1)
self.quota.size = 1 self.quota.size = 1
@@ -54,6 +59,7 @@ class WaitingListTestCase(TestCase):
with self.assertRaises(WaitingListException): with self.assertRaises(WaitingListException):
wle.send_voucher() wle.send_voucher()
@classscope(attr='o')
def test_send_variation(self): def test_send_variation(self):
wle = WaitingListEntry.objects.create( wle = WaitingListEntry.objects.create(
event=self.event, item=self.item2, variation=self.var1, email='foo@bar.com' event=self.event, item=self.item2, variation=self.var1, email='foo@bar.com'
@@ -72,6 +78,7 @@ class WaitingListTestCase(TestCase):
assert len(djmail.outbox) == 1 assert len(djmail.outbox) == 1
assert djmail.outbox[0].to == [wle.email] assert djmail.outbox[0].to == [wle.email]
@classscope(attr='o')
def test_send_custom_validity(self): def test_send_custom_validity(self):
self.event.settings.set('waiting_list_hours', 24) self.event.settings.set('waiting_list_hours', 24)
wle = WaitingListEntry.objects.create( wle = WaitingListEntry.objects.create(
@@ -83,103 +90,117 @@ class WaitingListTestCase(TestCase):
assert 3600 * 23 < (wle.voucher.valid_until - now()).seconds < 3600 * 24 assert 3600 * 23 < (wle.voucher.valid_until - now()).seconds < 3600 * 24
def test_send_auto(self): def test_send_auto(self):
self.quota.variations.add(self.var1) with scope(organizer=self.o):
self.quota.size = 7 self.quota.variations.add(self.var1)
self.quota.save() self.quota.size = 7
for i in range(10): self.quota.save()
WaitingListEntry.objects.create( for i in range(10):
event=self.event, item=self.item2, variation=self.var1, email='foo{}@bar.com'.format(i) WaitingListEntry.objects.create(
) event=self.event, item=self.item2, variation=self.var1, email='foo{}@bar.com'.format(i)
WaitingListEntry.objects.create( )
event=self.event, item=self.item1, email='bar{}@bar.com'.format(i) WaitingListEntry.objects.create(
) event=self.event, item=self.item1, email='bar{}@bar.com'.format(i)
)
assign_automatically.apply(args=(self.event.pk,)) assign_automatically.apply(args=(self.event.pk,))
assert WaitingListEntry.objects.filter(voucher__isnull=True).count() == 3 with scope(organizer=self.o):
assert Voucher.objects.count() == 17 assert WaitingListEntry.objects.filter(voucher__isnull=True).count() == 3
assert sorted(list(WaitingListEntry.objects.filter(voucher__isnull=True).values_list('email', flat=True))) == [ assert Voucher.objects.count() == 17
'foo7@bar.com', 'foo8@bar.com', 'foo9@bar.com' assert sorted(list(WaitingListEntry.objects.filter(voucher__isnull=True).values_list('email', flat=True))) == [
] 'foo7@bar.com', 'foo8@bar.com', 'foo9@bar.com'
]
def test_send_auto_respect_priority(self): def test_send_auto_respect_priority(self):
self.quota.variations.add(self.var1) with scope(organizer=self.o):
self.quota.size = 7 self.quota.variations.add(self.var1)
self.quota.save() self.quota.size = 7
for i in range(10): self.quota.save()
WaitingListEntry.objects.create( for i in range(10):
event=self.event, item=self.item2, variation=self.var1, email='foo{}@bar.com'.format(i), WaitingListEntry.objects.create(
priority=i event=self.event, item=self.item2, variation=self.var1, email='foo{}@bar.com'.format(i),
) priority=i
WaitingListEntry.objects.create( )
event=self.event, item=self.item1, email='bar{}@bar.com'.format(i), WaitingListEntry.objects.create(
priority=i event=self.event, item=self.item1, email='bar{}@bar.com'.format(i),
) priority=i
)
assign_automatically.apply(args=(self.event.pk,)) assign_automatically.apply(args=(self.event.pk,))
assert WaitingListEntry.objects.filter(voucher__isnull=True).count() == 3 with scope(organizer=self.o):
assert Voucher.objects.count() == 17 assert WaitingListEntry.objects.filter(voucher__isnull=True).count() == 3
assert sorted(list(WaitingListEntry.objects.filter(voucher__isnull=True).values_list('email', flat=True))) == [ assert Voucher.objects.count() == 17
'foo0@bar.com', 'foo1@bar.com', 'foo2@bar.com' assert sorted(list(WaitingListEntry.objects.filter(voucher__isnull=True).values_list('email', flat=True))) == [
] 'foo0@bar.com', 'foo1@bar.com', 'foo2@bar.com'
]
def test_send_auto_quota_infinite(self): def test_send_auto_quota_infinite(self):
self.quota.variations.add(self.var1) with scope(organizer=self.o):
self.quota.size = None self.quota.variations.add(self.var1)
self.quota.save() self.quota.size = None
for i in range(10): self.quota.save()
WaitingListEntry.objects.create( for i in range(10):
event=self.event, item=self.item2, variation=self.var1, email='foo{}@bar.com'.format(i) WaitingListEntry.objects.create(
) event=self.event, item=self.item2, variation=self.var1, email='foo{}@bar.com'.format(i)
WaitingListEntry.objects.create( )
event=self.event, item=self.item1, email='bar{}@bar.com'.format(i) WaitingListEntry.objects.create(
) event=self.event, item=self.item1, email='bar{}@bar.com'.format(i)
)
assign_automatically.apply(args=(self.event.pk,)) assign_automatically.apply(args=(self.event.pk,))
assert WaitingListEntry.objects.filter(voucher__isnull=True).count() == 10 with scope(organizer=self.o):
assert Voucher.objects.count() == 10 assert WaitingListEntry.objects.filter(voucher__isnull=True).count() == 10
assert Voucher.objects.count() == 10
def test_send_periodic_event_over(self): def test_send_periodic_event_over(self):
self.event.settings.set('waiting_list_enabled', True) self.event.settings.set('waiting_list_enabled', True)
self.event.settings.set('waiting_list_auto', True) self.event.settings.set('waiting_list_auto', True)
self.event.presale_end = now() - timedelta(days=1) self.event.presale_end = now() - timedelta(days=1)
self.event.save() self.event.save()
for i in range(5): with scope(organizer=self.o):
WaitingListEntry.objects.create( for i in range(5):
event=self.event, item=self.item2, variation=self.var1, email='foo{}@bar.com'.format(i) WaitingListEntry.objects.create(
) event=self.event, item=self.item2, variation=self.var1, email='foo{}@bar.com'.format(i)
)
process_waitinglist(None) process_waitinglist(None)
assert WaitingListEntry.objects.filter(voucher__isnull=True).count() == 5 with scope(organizer=self.o):
assert Voucher.objects.count() == 0 assert WaitingListEntry.objects.filter(voucher__isnull=True).count() == 5
self.event.presale_end = now() + timedelta(days=1) assert Voucher.objects.count() == 0
self.event.save() self.event.presale_end = now() + timedelta(days=1)
self.event.save()
def test_send_periodic(self): def test_send_periodic(self):
self.event.settings.set('waiting_list_enabled', True) self.event.settings.set('waiting_list_enabled', True)
self.event.settings.set('waiting_list_auto', True) self.event.settings.set('waiting_list_auto', True)
for i in range(5): with scope(organizer=self.o):
WaitingListEntry.objects.create( for i in range(5):
event=self.event, item=self.item2, variation=self.var1, email='foo{}@bar.com'.format(i) WaitingListEntry.objects.create(
) event=self.event, item=self.item2, variation=self.var1, email='foo{}@bar.com'.format(i)
)
process_waitinglist(None) process_waitinglist(None)
assert Voucher.objects.count() == 5 with scope(organizer=self.o):
assert Voucher.objects.count() == 5
def test_send_periodic_disabled(self): def test_send_periodic_disabled(self):
self.event.settings.set('waiting_list_enabled', True) self.event.settings.set('waiting_list_enabled', True)
self.event.settings.set('waiting_list_auto', False) self.event.settings.set('waiting_list_auto', False)
for i in range(5): with scope(organizer=self.o):
WaitingListEntry.objects.create( for i in range(5):
event=self.event, item=self.item2, variation=self.var1, email='foo{}@bar.com'.format(i) WaitingListEntry.objects.create(
) event=self.event, item=self.item2, variation=self.var1, email='foo{}@bar.com'.format(i)
)
process_waitinglist(None) process_waitinglist(None)
assert WaitingListEntry.objects.filter(voucher__isnull=True).count() == 5 with scope(organizer=self.o):
assert Voucher.objects.count() == 0 assert WaitingListEntry.objects.filter(voucher__isnull=True).count() == 5
assert Voucher.objects.count() == 0
def test_send_periodic_disabled2(self): def test_send_periodic_disabled2(self):
self.event.settings.set('waiting_list_enabled', False) self.event.settings.set('waiting_list_enabled', False)
self.event.settings.set('waiting_list_auto', True) self.event.settings.set('waiting_list_auto', True)
for i in range(5): with scope(organizer=self.o):
WaitingListEntry.objects.create( for i in range(5):
event=self.event, item=self.item2, variation=self.var1, email='foo{}@bar.com'.format(i) WaitingListEntry.objects.create(
) event=self.event, item=self.item2, variation=self.var1, email='foo{}@bar.com'.format(i)
)
process_waitinglist(None) process_waitinglist(None)
assert Voucher.objects.count() == 5 with scope(organizer=self.o):
assert Voucher.objects.count() == 5

View File

@@ -6,6 +6,7 @@ import pytest
import responses import responses
from django.db import transaction from django.db import transaction
from django.utils.timezone import now from django.utils.timezone import now
from django_scopes import scopes_disabled
from pretix.base.models import Event, Item, Order, OrderPosition, Organizer from pretix.base.models import Event, Item, Order, OrderPosition, Organizer
@@ -83,13 +84,14 @@ def test_webhook_trigger_event_specific(event, order, webhook, monkeypatch_on_co
"code": "FOO", "code": "FOO",
"action": "pretix.event.order.paid" "action": "pretix.event.order.paid"
} }
first = webhook.calls.last() with scopes_disabled():
assert first.webhook == webhook first = webhook.calls.last()
assert first.target_url == 'https://google.com' assert first.webhook == webhook
assert first.action_type == 'pretix.event.order.paid' assert first.target_url == 'https://google.com'
assert not first.is_retry assert first.action_type == 'pretix.event.order.paid'
assert first.return_code == 200 assert not first.is_retry
assert first.success assert first.return_code == 200
assert first.success
@pytest.mark.django_db @pytest.mark.django_db
@@ -170,8 +172,9 @@ def test_webhook_retry(event, order, webhook, monkeypatch_on_commit):
with transaction.atomic(): with transaction.atomic():
order.log_action('pretix.event.order.paid', {}) order.log_action('pretix.event.order.paid', {})
assert len(responses.calls) == 2 assert len(responses.calls) == 2
second = webhook.objects.first() with scopes_disabled():
first = webhook.objects.last() second = webhook.objects.first()
first = webhook.objects.last()
assert first.webhook == webhook assert first.webhook == webhook
assert first.target_url == 'https://google.com' assert first.target_url == 'https://google.com'

View File

@@ -1,4 +1,7 @@
import inspect
import pytest import pytest
from django_scopes import scopes_disabled
from xdist.dsession import DSession from xdist.dsession import DSession
CRASHED_ITEMS = set() CRASHED_ITEMS = set()
@@ -31,3 +34,16 @@ def pytest_configure(config):
self.sched.check_schedule(node) self.sched.check_schedule(node)
DSession.handle_crashitem = _handle_crashitem DSession.handle_crashitem = _handle_crashitem
@pytest.hookimpl(hookwrapper=True)
def pytest_fixture_setup(fixturedef, request):
"""
This hack automatically disables django-scopes for all fixtures which are not yield fixtures.
This saves us a *lot* of decorcators…
"""
if inspect.isgeneratorfunction(fixturedef.func):
yield
else:
with scopes_disabled():
yield

View File

@@ -239,7 +239,7 @@ class Login2FAFormTest(TestCase):
def test_totp_invalid(self): def test_totp_invalid(self):
response = self.client.get('/control/login/2fa') response = self.client.get('/control/login/2fa')
assert 'token' in response.rendered_content assert 'token' in response.content.decode()
d = TOTPDevice.objects.create(user=self.user, name='test') d = TOTPDevice.objects.create(user=self.user, name='test')
totp = TOTP(d.bin_key, d.step, d.t0, d.digits, d.drift) totp = TOTP(d.bin_key, d.step, d.t0, d.digits, d.drift)
totp.time = time.time() totp.time = time.time()
@@ -251,7 +251,7 @@ class Login2FAFormTest(TestCase):
def test_totp_valid(self): def test_totp_valid(self):
response = self.client.get('/control/login/2fa') response = self.client.get('/control/login/2fa')
assert 'token' in response.rendered_content assert 'token' in response.content.decode()
d = TOTPDevice.objects.create(user=self.user, name='test') d = TOTPDevice.objects.create(user=self.user, name='test')
totp = TOTP(d.bin_key, d.step, d.t0, d.digits, d.drift) totp = TOTP(d.bin_key, d.step, d.t0, d.digits, d.drift)
totp.time = time.time() totp.time = time.time()
@@ -274,7 +274,7 @@ class Login2FAFormTest(TestCase):
d = U2FDevice.objects.create(user=self.user, name='test', json_data="{}") d = U2FDevice.objects.create(user=self.user, name='test', json_data="{}")
response = self.client.get('/control/login/2fa') response = self.client.get('/control/login/2fa')
assert 'token' in response.rendered_content assert 'token' in response.content.decode()
response = self.client.post('/control/login/2fa'.format(d.pk), { response = self.client.post('/control/login/2fa'.format(d.pk), {
'token': '{"response": "true"}' 'token': '{"response": "true"}'
}) })
@@ -291,7 +291,7 @@ class Login2FAFormTest(TestCase):
d = U2FDevice.objects.create(user=self.user, name='test', json_data="{}") d = U2FDevice.objects.create(user=self.user, name='test', json_data="{}")
response = self.client.get('/control/login/2fa') response = self.client.get('/control/login/2fa')
assert 'token' in response.rendered_content assert 'token' in response.content.decode()
response = self.client.post('/control/login/2fa'.format(d.pk), { response = self.client.post('/control/login/2fa'.format(d.pk), {
'token': '{"response": "true"}' 'token': '{"response": "true"}'
}) })

View File

@@ -3,6 +3,7 @@ from decimal import Decimal
import pytest import pytest
from django.utils.timezone import now from django.utils.timezone import now
from django_scopes import scopes_disabled
from pretix.base.models import ( from pretix.base.models import (
Checkin, Event, Item, ItemAddOn, ItemCategory, LogEntry, Order, Checkin, Event, Item, ItemAddOn, ItemCategory, LogEntry, Order,
@@ -58,12 +59,14 @@ def dashboard_env():
@pytest.mark.django_db @pytest.mark.django_db
@scopes_disabled()
def test_dashboard(dashboard_env): def test_dashboard(dashboard_env):
c = checkin_widget(dashboard_env[0]) c = checkin_widget(dashboard_env[0])
assert '0/2' in c[0]['content'] assert '0/2' in c[0]['content']
@pytest.mark.django_db @pytest.mark.django_db
@scopes_disabled()
def test_dashboard_pending_not_count(dashboard_env): def test_dashboard_pending_not_count(dashboard_env):
c = checkin_widget(dashboard_env[0]) c = checkin_widget(dashboard_env[0])
order_pending = Order.objects.create( order_pending = Order.objects.create(
@@ -83,6 +86,7 @@ def test_dashboard_pending_not_count(dashboard_env):
@pytest.mark.django_db @pytest.mark.django_db
@scopes_disabled()
def test_dashboard_with_checkin(dashboard_env): def test_dashboard_with_checkin(dashboard_env):
op = OrderPosition.objects.get( op = OrderPosition.objects.get(
order=dashboard_env[3], order=dashboard_env[3],
@@ -256,11 +260,13 @@ def test_checkins_list_mixed(client, checkin_list_env, query, expected):
@pytest.mark.django_db @pytest.mark.django_db
def test_manual_checkins(client, checkin_list_env): def test_manual_checkins(client, checkin_list_env):
client.login(email='dummy@dummy.dummy', password='dummy') client.login(email='dummy@dummy.dummy', password='dummy')
assert not checkin_list_env[5][3].checkins.exists() with scopes_disabled():
assert not checkin_list_env[5][3].checkins.exists()
client.post('/control/event/dummy/dummy/checkinlists/{}/'.format(checkin_list_env[6].pk), { client.post('/control/event/dummy/dummy/checkinlists/{}/'.format(checkin_list_env[6].pk), {
'checkin': [checkin_list_env[5][3].pk] 'checkin': [checkin_list_env[5][3].pk]
}) })
assert checkin_list_env[5][3].checkins.exists() with scopes_disabled():
assert checkin_list_env[5][3].checkins.exists()
assert LogEntry.objects.filter( assert LogEntry.objects.filter(
action_type='pretix.event.checkin', object_id=checkin_list_env[5][3].order.pk action_type='pretix.event.checkin', object_id=checkin_list_env[5][3].order.pk
).exists() ).exists()
@@ -269,7 +275,8 @@ def test_manual_checkins(client, checkin_list_env):
@pytest.mark.django_db @pytest.mark.django_db
def test_manual_checkins_revert(client, checkin_list_env): def test_manual_checkins_revert(client, checkin_list_env):
client.login(email='dummy@dummy.dummy', password='dummy') client.login(email='dummy@dummy.dummy', password='dummy')
assert not checkin_list_env[5][3].checkins.exists() with scopes_disabled():
assert not checkin_list_env[5][3].checkins.exists()
client.post('/control/event/dummy/dummy/checkinlists/{}/'.format(checkin_list_env[6].pk), { client.post('/control/event/dummy/dummy/checkinlists/{}/'.format(checkin_list_env[6].pk), {
'checkin': [checkin_list_env[5][3].pk] 'checkin': [checkin_list_env[5][3].pk]
}) })
@@ -277,7 +284,8 @@ def test_manual_checkins_revert(client, checkin_list_env):
'checkin': [checkin_list_env[5][3].pk], 'checkin': [checkin_list_env[5][3].pk],
'revert': 'true' 'revert': 'true'
}) })
assert not checkin_list_env[5][3].checkins.exists() with scopes_disabled():
assert not checkin_list_env[5][3].checkins.exists()
assert LogEntry.objects.filter( assert LogEntry.objects.filter(
action_type='pretix.event.checkin', object_id=checkin_list_env[5][3].order.pk action_type='pretix.event.checkin', object_id=checkin_list_env[5][3].order.pk
).exists() ).exists()
@@ -381,11 +389,11 @@ def test_checkins_attendee_name_from_addon_available(client, checkin_list_with_a
class CheckinListFormTest(SoupTest): class CheckinListFormTest(SoupTest):
@scopes_disabled()
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy') self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
self.orga1 = Organizer.objects.create(name='CCC', slug='ccc') self.orga1 = Organizer.objects.create(name='CCC', slug='ccc')
self.orga2 = Organizer.objects.create(name='MRM', slug='mrm')
self.event1 = Event.objects.create( self.event1 = Event.objects.create(
organizer=self.orga1, name='30C3', slug='30c3', organizer=self.orga1, name='30C3', slug='30c3',
date_from=datetime(2013, 12, 26, tzinfo=timezone.utc), date_from=datetime(2013, 12, 26, tzinfo=timezone.utc),
@@ -404,12 +412,14 @@ class CheckinListFormTest(SoupTest):
doc = self.post_doc('/control/event/%s/%s/checkinlists/add' % (self.orga1.slug, self.event1.slug), form_data) doc = self.post_doc('/control/event/%s/%s/checkinlists/add' % (self.orga1.slug, self.event1.slug), form_data)
assert doc.select(".alert-success") assert doc.select(".alert-success")
self.assertIn("All", doc.select("#page-wrapper table")[0].text) self.assertIn("All", doc.select("#page-wrapper table")[0].text)
assert self.event1.checkin_lists.get( with scopes_disabled():
name='All', all_products=True assert self.event1.checkin_lists.get(
) name='All', all_products=True
)
def test_update(self): def test_update(self):
cl = self.event1.checkin_lists.create(name='All', all_products=True) with scopes_disabled():
cl = self.event1.checkin_lists.create(name='All', all_products=True)
doc = self.get_doc('/control/event/%s/%s/checkinlists/%s/change' % (self.orga1.slug, self.event1.slug, cl.id)) doc = self.get_doc('/control/event/%s/%s/checkinlists/%s/change' % (self.orga1.slug, self.event1.slug, cl.id))
form_data = extract_form_fields(doc.select('.container-fluid form')[0]) form_data = extract_form_fields(doc.select('.container-fluid form')[0])
form_data['all_products'] = '' form_data['all_products'] = ''
@@ -419,14 +429,17 @@ class CheckinListFormTest(SoupTest):
assert doc.select(".alert-success") assert doc.select(".alert-success")
cl.refresh_from_db() cl.refresh_from_db()
assert not cl.all_products assert not cl.all_products
assert list(cl.limit_products.all()) == [self.item_ticket] with scopes_disabled():
assert list(cl.limit_products.all()) == [self.item_ticket]
def test_delete(self): def test_delete(self):
cl = self.event1.checkin_lists.create(name='All', all_products=True) with scopes_disabled():
cl = self.event1.checkin_lists.create(name='All', all_products=True)
doc = self.get_doc('/control/event/%s/%s/checkinlists/%s/delete' % (self.orga1.slug, self.event1.slug, cl.id)) doc = self.get_doc('/control/event/%s/%s/checkinlists/%s/delete' % (self.orga1.slug, self.event1.slug, cl.id))
form_data = extract_form_fields(doc.select('.container-fluid form')[0]) form_data = extract_form_fields(doc.select('.container-fluid form')[0])
doc = self.post_doc('/control/event/%s/%s/checkinlists/%s/delete' % (self.orga1.slug, self.event1.slug, cl.id), doc = self.post_doc('/control/event/%s/%s/checkinlists/%s/delete' % (self.orga1.slug, self.event1.slug, cl.id),
form_data) form_data)
assert doc.select(".alert-success") assert doc.select(".alert-success")
self.assertNotIn("VAT", doc.select("#page-wrapper")[0].text) self.assertNotIn("VAT", doc.select("#page-wrapper")[0].text)
assert not self.event1.checkin_lists.exists() with scopes_disabled():
assert not self.event1.checkin_lists.exists()

View File

@@ -1,5 +1,6 @@
import pytest import pytest
from django.utils.timezone import now from django.utils.timezone import now
from django_scopes import scopes_disabled
from pretix.base.models import Device, Event, Organizer, Team, User from pretix.base.models import Device, Event, Organizer, Team, User
from pretix.base.models.devices import generate_api_token from pretix.base.models.devices import generate_api_token
@@ -40,7 +41,7 @@ def admin_team(organizer):
def test_list_of_devices(event, admin_user, client, device): def test_list_of_devices(event, admin_user, client, device):
client.login(email='dummy@dummy.dummy', password='dummy') client.login(email='dummy@dummy.dummy', password='dummy')
resp = client.get('/control/organizer/dummy/devices') resp = client.get('/control/organizer/dummy/devices')
assert 'Cashdesk' in resp.rendered_content assert 'Cashdesk' in resp.content.decode()
@pytest.mark.django_db @pytest.mark.django_db
@@ -50,11 +51,13 @@ def test_create_device(event, admin_user, admin_team, client):
'name': 'Foo', 'name': 'Foo',
'limit_events': str(event.pk), 'limit_events': str(event.pk),
}, follow=True) }, follow=True)
d = Device.objects.last() print(resp.status_code, resp.content)
assert d.name == 'Foo' with scopes_disabled():
assert not d.all_events d = Device.objects.last()
assert list(d.limit_events.all()) == [event] assert d.name == 'Foo'
assert d.initialization_token in resp.content.decode() assert not d.all_events
assert list(d.limit_events.all()) == [event]
assert d.initialization_token in resp.content.decode()
@pytest.mark.django_db @pytest.mark.django_db
@@ -67,13 +70,15 @@ def test_update_device(event, admin_user, admin_team, device, client):
device.refresh_from_db() device.refresh_from_db()
assert device.name == 'Cashdesk 2' assert device.name == 'Cashdesk 2'
assert not device.all_events assert not device.all_events
assert list(device.limit_events.all()) == [event] with scopes_disabled():
assert list(device.limit_events.all()) == [event]
@pytest.mark.django_db @pytest.mark.django_db
def test_revoke_device(event, admin_user, admin_team, device, client): def test_revoke_device(event, admin_user, admin_team, device, client):
client.login(email='dummy@dummy.dummy', password='dummy') client.login(email='dummy@dummy.dummy', password='dummy')
device.api_token = generate_api_token() with scopes_disabled():
device.api_token = generate_api_token()
device.initialized = now() device.initialized = now()
device.save() device.save()

View File

@@ -3,6 +3,7 @@ from decimal import Decimal
import pytz import pytz
from django.utils.timezone import now from django.utils.timezone import now
from django_scopes import scopes_disabled
from i18nfield.strings import LazyI18nString from i18nfield.strings import LazyI18nString
from pytz import timezone from pytz import timezone
from tests.base import SoupTest, extract_form_fields from tests.base import SoupTest, extract_form_fields
@@ -15,6 +16,7 @@ from pretix.testutils.mock import mocker_context
class EventsTest(SoupTest): class EventsTest(SoupTest):
@scopes_disabled()
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy') self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
@@ -49,7 +51,8 @@ class EventsTest(SoupTest):
self.assertNotIn("MRMCD14", tabletext) self.assertNotIn("MRMCD14", tabletext)
def test_quick_setup_later(self): def test_quick_setup_later(self):
self.event1.quotas.create(name='foo', size=2) with scopes_disabled():
self.event1.quotas.create(name='foo', size=2)
resp = self.client.get('/control/event/%s/%s/quickstart/' % (self.orga1.slug, self.event1.slug)) resp = self.client.get('/control/event/%s/%s/quickstart/' % (self.orga1.slug, self.event1.slug))
self.assertRedirects(resp, '/control/event/%s/%s/' % (self.orga1.slug, self.event1.slug)) self.assertRedirects(resp, '/control/event/%s/%s/' % (self.orga1.slug, self.event1.slug))
@@ -86,18 +89,19 @@ class EventsTest(SoupTest):
assert self.event1.settings.payment_banktransfer__enabled assert self.event1.settings.payment_banktransfer__enabled
assert self.event1.settings.get('payment_banktransfer_bank_details', as_type=LazyI18nString).localize('en') == "Foo" assert self.event1.settings.get('payment_banktransfer_bank_details', as_type=LazyI18nString).localize('en') == "Foo"
assert 'pretix.plugins.banktransfer' in self.event1.plugins assert 'pretix.plugins.banktransfer' in self.event1.plugins
assert self.event1.items.count() == 2 with scopes_disabled():
i = self.event1.items.first() assert self.event1.items.count() == 2
assert str(i.name) == "Normal ticket" i = self.event1.items.first()
assert i.default_price == Decimal('13.90') assert str(i.name) == "Normal ticket"
i = self.event1.items.last() assert i.default_price == Decimal('13.90')
assert str(i.name) == "Reduced ticket" i = self.event1.items.last()
assert i.default_price == Decimal('13.20') assert str(i.name) == "Reduced ticket"
assert self.event1.quotas.count() == 1 assert i.default_price == Decimal('13.20')
q = self.event1.quotas.first() assert self.event1.quotas.count() == 1
assert q.name == 'Tickets' q = self.event1.quotas.first()
assert q.size == 300 assert q.name == 'Tickets'
assert q.items.count() == 2 assert q.size == 300
assert q.items.count() == 2
def test_quick_setup_single_quota(self): def test_quick_setup_single_quota(self):
doc = self.get_doc('/control/event/%s/%s/quickstart/' % (self.orga1.slug, self.event1.slug)) doc = self.get_doc('/control/event/%s/%s/quickstart/' % (self.orga1.slug, self.event1.slug))
@@ -132,22 +136,23 @@ class EventsTest(SoupTest):
assert self.event1.settings.payment_banktransfer__enabled assert self.event1.settings.payment_banktransfer__enabled
assert self.event1.settings.get('payment_banktransfer_bank_details', as_type=LazyI18nString).localize('en') == "Foo" assert self.event1.settings.get('payment_banktransfer_bank_details', as_type=LazyI18nString).localize('en') == "Foo"
assert 'pretix.plugins.banktransfer' in self.event1.plugins assert 'pretix.plugins.banktransfer' in self.event1.plugins
assert self.event1.items.count() == 2 with scopes_disabled():
i = self.event1.items.first() assert self.event1.items.count() == 2
assert str(i.name) == "Normal ticket" i = self.event1.items.first()
assert i.default_price == Decimal('13.90') assert str(i.name) == "Normal ticket"
i = self.event1.items.last() assert i.default_price == Decimal('13.90')
assert str(i.name) == "Reduced ticket" i = self.event1.items.last()
assert i.default_price == Decimal('13.20') assert str(i.name) == "Reduced ticket"
assert self.event1.quotas.count() == 2 assert i.default_price == Decimal('13.20')
q = self.event1.quotas.first() assert self.event1.quotas.count() == 2
assert q.name == 'Normal ticket' q = self.event1.quotas.first()
assert q.size == 100 assert q.name == 'Normal ticket'
assert q.items.count() == 1 assert q.size == 100
q = self.event1.quotas.last() assert q.items.count() == 1
assert q.name == 'Reduced ticket' q = self.event1.quotas.last()
assert q.size == 50 assert q.name == 'Reduced ticket'
assert q.items.count() == 1 assert q.size == 50
assert q.items.count() == 1
def test_quick_setup_dual_quota(self): def test_quick_setup_dual_quota(self):
doc = self.get_doc('/control/event/%s/%s/quickstart/' % (self.orga1.slug, self.event1.slug)) doc = self.get_doc('/control/event/%s/%s/quickstart/' % (self.orga1.slug, self.event1.slug))
@@ -182,22 +187,23 @@ class EventsTest(SoupTest):
assert self.event1.settings.payment_banktransfer__enabled assert self.event1.settings.payment_banktransfer__enabled
assert self.event1.settings.get('payment_banktransfer_bank_details', as_type=LazyI18nString).localize('en') == "Foo" assert self.event1.settings.get('payment_banktransfer_bank_details', as_type=LazyI18nString).localize('en') == "Foo"
assert 'pretix.plugins.banktransfer' in self.event1.plugins assert 'pretix.plugins.banktransfer' in self.event1.plugins
assert self.event1.items.count() == 2 with scopes_disabled():
i = self.event1.items.first() assert self.event1.items.count() == 2
assert str(i.name) == "Normal ticket" i = self.event1.items.first()
assert i.default_price == Decimal('13.90') assert str(i.name) == "Normal ticket"
i = self.event1.items.last() assert i.default_price == Decimal('13.90')
assert str(i.name) == "Reduced ticket" i = self.event1.items.last()
assert i.default_price == Decimal('13.20') assert str(i.name) == "Reduced ticket"
assert self.event1.quotas.count() == 3 assert i.default_price == Decimal('13.20')
q = self.event1.quotas.first() assert self.event1.quotas.count() == 3
assert q.name == 'Normal ticket' q = self.event1.quotas.first()
assert q.size == 100 assert q.name == 'Normal ticket'
assert q.items.count() == 1 assert q.size == 100
q = self.event1.quotas.last() assert q.items.count() == 1
assert q.name == 'Tickets' q = self.event1.quotas.last()
assert q.size == 120 assert q.name == 'Tickets'
assert q.items.count() == 2 assert q.size == 120
assert q.items.count() == 2
def test_settings(self): def test_settings(self):
doc = self.get_doc('/control/event/%s/%s/settings/' % (self.orga1.slug, self.event1.slug)) doc = self.get_doc('/control/event/%s/%s/settings/' % (self.orga1.slug, self.event1.slug))
@@ -257,48 +263,52 @@ class EventsTest(SoupTest):
assert self.event1.testmode assert self.event1.testmode
def test_testmode_disable(self): def test_testmode_disable(self):
o = Order.objects.create( with scopes_disabled():
code='FOO', event=self.event1, email='dummy@dummy.test', o = Order.objects.create(
status=Order.STATUS_PENDING, code='FOO', event=self.event1, email='dummy@dummy.test',
datetime=now(), expires=now() + datetime.timedelta(days=10), status=Order.STATUS_PENDING,
total=14, locale='en', testmode=True datetime=now(), expires=now() + datetime.timedelta(days=10),
) total=14, locale='en', testmode=True
o2 = Order.objects.create( )
code='FOO2', event=self.event1, email='dummy@dummy.test', o2 = Order.objects.create(
status=Order.STATUS_PENDING, code='FOO2', event=self.event1, email='dummy@dummy.test',
datetime=now(), expires=now() + datetime.timedelta(days=10), status=Order.STATUS_PENDING,
total=14, locale='en' datetime=now(), expires=now() + datetime.timedelta(days=10),
) total=14, locale='en'
self.event1.testmode = True )
self.event1.save() self.event1.testmode = True
self.event1.save()
self.post_doc('/control/event/%s/%s/live/' % (self.orga1.slug, self.event1.slug), self.post_doc('/control/event/%s/%s/live/' % (self.orga1.slug, self.event1.slug),
{'testmode': 'false'}) {'testmode': 'false'})
self.event1.refresh_from_db() self.event1.refresh_from_db()
assert not self.event1.testmode assert not self.event1.testmode
assert Order.objects.filter(pk=o.pk).exists() with scopes_disabled():
assert Order.objects.filter(pk=o2.pk).exists() assert Order.objects.filter(pk=o.pk).exists()
assert Order.objects.filter(pk=o2.pk).exists()
def test_testmode_disable_delete(self): def test_testmode_disable_delete(self):
o = Order.objects.create( with scopes_disabled():
code='FOO', event=self.event1, email='dummy@dummy.test', o = Order.objects.create(
status=Order.STATUS_PENDING, code='FOO', event=self.event1, email='dummy@dummy.test',
datetime=now(), expires=now() + datetime.timedelta(days=10), status=Order.STATUS_PENDING,
total=14, locale='en', testmode=True datetime=now(), expires=now() + datetime.timedelta(days=10),
) total=14, locale='en', testmode=True
o2 = Order.objects.create( )
code='FOO2', event=self.event1, email='dummy@dummy.test', o2 = Order.objects.create(
status=Order.STATUS_PENDING, code='FOO2', event=self.event1, email='dummy@dummy.test',
datetime=now(), expires=now() + datetime.timedelta(days=10), status=Order.STATUS_PENDING,
total=14, locale='en' datetime=now(), expires=now() + datetime.timedelta(days=10),
) total=14, locale='en'
self.event1.testmode = True )
self.event1.save() self.event1.testmode = True
self.event1.save()
self.post_doc('/control/event/%s/%s/live/' % (self.orga1.slug, self.event1.slug), self.post_doc('/control/event/%s/%s/live/' % (self.orga1.slug, self.event1.slug),
{'testmode': 'false', 'delete': 'yes'}) {'testmode': 'false', 'delete': 'yes'})
self.event1.refresh_from_db() self.event1.refresh_from_db()
assert not self.event1.testmode assert not self.event1.testmode
assert not Order.objects.filter(pk=o.pk).exists() with scopes_disabled():
assert Order.objects.filter(pk=o2.pk).exists() assert not Order.objects.filter(pk=o.pk).exists()
assert Order.objects.filter(pk=o2.pk).exists()
def test_live_disable(self): def test_live_disable(self):
self.event1.live = True self.event1.live = True
@@ -309,9 +319,10 @@ class EventsTest(SoupTest):
assert not self.event1.live assert not self.event1.live
def test_live_ok(self): def test_live_ok(self):
self.event1.items.create(name='Test', default_price=5) with scopes_disabled():
self.event1.settings.set('payment_banktransfer__enabled', True) self.event1.items.create(name='Test', default_price=5)
self.event1.quotas.create(name='Test quota') self.event1.settings.set('payment_banktransfer__enabled', True)
self.event1.quotas.create(name='Test quota')
doc = self.get_doc('/control/event/%s/%s/live/' % (self.orga1.slug, self.event1.slug)) doc = self.get_doc('/control/event/%s/%s/live/' % (self.orga1.slug, self.event1.slug))
assert len(doc.select("input[name=live]")) assert len(doc.select("input[name=live]"))
self.post_doc('/control/event/%s/%s/live/' % (self.orga1.slug, self.event1.slug), self.post_doc('/control/event/%s/%s/live/' % (self.orga1.slug, self.event1.slug),
@@ -320,16 +331,18 @@ class EventsTest(SoupTest):
assert self.event1.live assert self.event1.live
def test_live_dont_require_payment_method_free(self): def test_live_dont_require_payment_method_free(self):
self.event1.items.create(name='Test', default_price=0) with scopes_disabled():
self.event1.settings.set('payment_banktransfer__enabled', False) self.event1.items.create(name='Test', default_price=0)
self.event1.quotas.create(name='Test quota') self.event1.settings.set('payment_banktransfer__enabled', False)
self.event1.quotas.create(name='Test quota')
doc = self.get_doc('/control/event/%s/%s/live/' % (self.orga1.slug, self.event1.slug)) doc = self.get_doc('/control/event/%s/%s/live/' % (self.orga1.slug, self.event1.slug))
assert len(doc.select("input[name=live]")) assert len(doc.select("input[name=live]"))
def test_live_require_payment_method(self): def test_live_require_payment_method(self):
self.event1.items.create(name='Test', default_price=5) with scopes_disabled():
self.event1.settings.set('payment_banktransfer__enabled', False) self.event1.items.create(name='Test', default_price=5)
self.event1.quotas.create(name='Test quota') self.event1.settings.set('payment_banktransfer__enabled', False)
self.event1.quotas.create(name='Test quota')
doc = self.get_doc('/control/event/%s/%s/live/' % (self.orga1.slug, self.event1.slug)) doc = self.get_doc('/control/event/%s/%s/live/' % (self.orga1.slug, self.event1.slug))
assert len(doc.select("input[name=live]")) == 0 assert len(doc.select("input[name=live]")) == 0
@@ -378,7 +391,8 @@ class EventsTest(SoupTest):
self.event1.save(update_fields=['presale_end']) self.event1.save(update_fields=['presale_end'])
def test_payment_settings_relative_date_payment_after_presale_end(self): def test_payment_settings_relative_date_payment_after_presale_end(self):
tr19 = self.event1.tax_rules.create(rate=Decimal('19.00')) with scopes_disabled():
tr19 = self.event1.tax_rules.create(rate=Decimal('19.00'))
self.event1.presale_end = self.event1.date_from - datetime.timedelta(days=5) self.event1.presale_end = self.event1.date_from - datetime.timedelta(days=5)
self.event1.save(update_fields=['presale_end']) self.event1.save(update_fields=['presale_end'])
doc = self.post_doc('/control/event/%s/%s/settings/payment' % (self.orga1.slug, self.event1.slug), { doc = self.post_doc('/control/event/%s/%s/settings/payment' % (self.orga1.slug, self.event1.slug), {
@@ -578,23 +592,24 @@ class EventsTest(SoupTest):
'copy-copy_from_event': '' 'copy-copy_from_event': ''
}) })
ev = Event.objects.get(slug='33c3') with scopes_disabled():
assert ev.name == LazyI18nString({'de': '33C3', 'en': '33C3'}) ev = Event.objects.get(slug='33c3')
assert ev.settings.locales == ['en', 'de'] assert ev.name == LazyI18nString({'de': '33C3', 'en': '33C3'})
assert ev.settings.locale == 'en' assert ev.settings.locales == ['en', 'de']
assert ev.currency == 'EUR' assert ev.settings.locale == 'en'
assert ev.settings.timezone == 'Europe/Berlin' assert ev.currency == 'EUR'
assert ev.organizer == self.orga1 assert ev.settings.timezone == 'Europe/Berlin'
assert ev.location == LazyI18nString({'de': 'Hamburg', 'en': 'Hamburg'}) assert ev.organizer == self.orga1
assert Team.objects.filter(limit_events=ev, members=self.user).exists() assert ev.location == LazyI18nString({'de': 'Hamburg', 'en': 'Hamburg'})
assert Team.objects.filter(limit_events=ev, members=self.user).exists()
berlin_tz = timezone('Europe/Berlin') berlin_tz = timezone('Europe/Berlin')
assert ev.date_from == berlin_tz.localize(datetime.datetime(2016, 12, 27, 10, 0, 0)).astimezone(pytz.utc) assert ev.date_from == berlin_tz.localize(datetime.datetime(2016, 12, 27, 10, 0, 0)).astimezone(pytz.utc)
assert ev.date_to == berlin_tz.localize(datetime.datetime(2016, 12, 30, 19, 0, 0)).astimezone(pytz.utc) assert ev.date_to == berlin_tz.localize(datetime.datetime(2016, 12, 30, 19, 0, 0)).astimezone(pytz.utc)
assert ev.presale_start == berlin_tz.localize(datetime.datetime(2016, 11, 1, 10, 0, 0)).astimezone(pytz.utc) assert ev.presale_start == berlin_tz.localize(datetime.datetime(2016, 11, 1, 10, 0, 0)).astimezone(pytz.utc)
assert ev.presale_end == berlin_tz.localize(datetime.datetime(2016, 11, 30, 18, 0, 0)).astimezone(pytz.utc) assert ev.presale_end == berlin_tz.localize(datetime.datetime(2016, 11, 30, 18, 0, 0)).astimezone(pytz.utc)
assert ev.tax_rules.filter(rate=Decimal('19.00')).exists() assert ev.tax_rules.filter(rate=Decimal('19.00')).exists()
def test_create_event_with_subevents_success(self): def test_create_event_with_subevents_success(self):
doc = self.get_doc('/control/events/add') doc = self.get_doc('/control/events/add')
@@ -635,20 +650,22 @@ class EventsTest(SoupTest):
'event_wizard-prefix': 'event_wizard', 'event_wizard-prefix': 'event_wizard',
'copy-copy_from_event': '' 'copy-copy_from_event': ''
}) })
ev = Event.objects.get(slug='33c3') with scopes_disabled():
assert ev.has_subevents ev = Event.objects.get(slug='33c3')
assert ev.subevents.count() == 1 assert ev.has_subevents
assert ev.subevents.count() == 1
def test_create_event_copy_success(self): def test_create_event_copy_success(self):
tr = self.event1.tax_rules.create( with scopes_disabled():
rate=19, name="VAT" tr = self.event1.tax_rules.create(
) rate=19, name="VAT"
self.event1.items.create( )
name='Early-bird ticket', self.event1.items.create(
category=None, default_price=23, tax_rule=tr, name='Early-bird ticket',
admission=True category=None, default_price=23, tax_rule=tr,
) admission=True
self.event1.settings.tax_rate_default = tr )
self.event1.settings.tax_rate_default = tr
doc = self.get_doc('/control/events/add') doc = self.get_doc('/control/events/add')
doc = self.post_doc('/control/events/add', { doc = self.post_doc('/control/events/add', {
@@ -688,34 +705,36 @@ class EventsTest(SoupTest):
'copy-copy_from_event': self.event1.pk 'copy-copy_from_event': self.event1.pk
}) })
ev = Event.objects.get(slug='33c3') with scopes_disabled():
assert ev.name == LazyI18nString({'de': '33C3', 'en': '33C3'}) ev = Event.objects.get(slug='33c3')
assert ev.settings.locales == ['en', 'de'] assert ev.name == LazyI18nString({'de': '33C3', 'en': '33C3'})
assert ev.settings.locale == 'en' assert ev.settings.locales == ['en', 'de']
assert ev.currency == 'EUR' assert ev.settings.locale == 'en'
assert ev.settings.timezone == 'Europe/Berlin' assert ev.currency == 'EUR'
assert ev.organizer == self.orga1 assert ev.settings.timezone == 'Europe/Berlin'
assert ev.location == LazyI18nString({'de': 'Hamburg', 'en': 'Hamburg'}) assert ev.organizer == self.orga1
assert Team.objects.filter(limit_events=ev, members=self.user).exists() assert ev.location == LazyI18nString({'de': 'Hamburg', 'en': 'Hamburg'})
assert ev.items.count() == 1 assert Team.objects.filter(limit_events=ev, members=self.user).exists()
assert ev.items.count() == 1
berlin_tz = timezone('Europe/Berlin') berlin_tz = timezone('Europe/Berlin')
assert ev.date_from == berlin_tz.localize(datetime.datetime(2016, 12, 27, 10, 0, 0)).astimezone(pytz.utc) assert ev.date_from == berlin_tz.localize(datetime.datetime(2016, 12, 27, 10, 0, 0)).astimezone(pytz.utc)
assert ev.date_to == berlin_tz.localize(datetime.datetime(2016, 12, 30, 19, 0, 0)).astimezone(pytz.utc) assert ev.date_to == berlin_tz.localize(datetime.datetime(2016, 12, 30, 19, 0, 0)).astimezone(pytz.utc)
assert ev.presale_start == berlin_tz.localize(datetime.datetime(2016, 11, 1, 10, 0, 0)).astimezone(pytz.utc) assert ev.presale_start == berlin_tz.localize(datetime.datetime(2016, 11, 1, 10, 0, 0)).astimezone(pytz.utc)
assert ev.presale_end == berlin_tz.localize(datetime.datetime(2016, 11, 30, 18, 0, 0)).astimezone(pytz.utc) assert ev.presale_end == berlin_tz.localize(datetime.datetime(2016, 11, 30, 18, 0, 0)).astimezone(pytz.utc)
assert ev.tax_rules.filter(rate=Decimal('19.00')).count() == 1 assert ev.tax_rules.filter(rate=Decimal('19.00')).count() == 1
def test_create_event_clone_success(self): def test_create_event_clone_success(self):
tr = self.event1.tax_rules.create( with scopes_disabled():
rate=19, name="VAT" tr = self.event1.tax_rules.create(
) rate=19, name="VAT"
self.event1.items.create( )
name='Early-bird ticket', self.event1.items.create(
category=None, default_price=23, tax_rule=tr, name='Early-bird ticket',
admission=True category=None, default_price=23, tax_rule=tr,
) admission=True
)
self.event1.settings.tax_rate_default = tr self.event1.settings.tax_rate_default = tr
doc = self.get_doc('/control/events/add?clone=' + str(self.event1.pk)) doc = self.get_doc('/control/events/add?clone=' + str(self.event1.pk))
tabletext = doc.select("form")[0].text tabletext = doc.select("form")[0].text
@@ -754,24 +773,25 @@ class EventsTest(SoupTest):
assert not doc.select("#id_copy-copy_from_event_1") assert not doc.select("#id_copy-copy_from_event_1")
ev = Event.objects.get(slug='33c3') with scopes_disabled():
assert ev.name == LazyI18nString({'de': '33C3', 'en': '33C3'}) ev = Event.objects.get(slug='33c3')
assert ev.settings.locales == ['en', 'de'] assert ev.name == LazyI18nString({'de': '33C3', 'en': '33C3'})
assert ev.settings.locale == 'en' assert ev.settings.locales == ['en', 'de']
assert ev.currency == 'EUR' assert ev.settings.locale == 'en'
assert ev.settings.timezone == 'Europe/Berlin' assert ev.currency == 'EUR'
assert ev.organizer == self.orga1 assert ev.settings.timezone == 'Europe/Berlin'
assert ev.location == LazyI18nString({'de': 'Hamburg', 'en': 'Hamburg'}) assert ev.organizer == self.orga1
assert Team.objects.filter(limit_events=ev, members=self.user).exists() assert ev.location == LazyI18nString({'de': 'Hamburg', 'en': 'Hamburg'})
assert ev.items.count() == 1 assert Team.objects.filter(limit_events=ev, members=self.user).exists()
assert ev.items.count() == 1
berlin_tz = timezone('Europe/Berlin') berlin_tz = timezone('Europe/Berlin')
assert ev.date_from == berlin_tz.localize(datetime.datetime(2016, 12, 27, 10, 0, 0)).astimezone(pytz.utc) assert ev.date_from == berlin_tz.localize(datetime.datetime(2016, 12, 27, 10, 0, 0)).astimezone(pytz.utc)
assert ev.date_to == berlin_tz.localize(datetime.datetime(2016, 12, 30, 19, 0, 0)).astimezone(pytz.utc) assert ev.date_to == berlin_tz.localize(datetime.datetime(2016, 12, 30, 19, 0, 0)).astimezone(pytz.utc)
assert ev.presale_start == berlin_tz.localize(datetime.datetime(2016, 11, 1, 10, 0, 0)).astimezone(pytz.utc) assert ev.presale_start == berlin_tz.localize(datetime.datetime(2016, 11, 1, 10, 0, 0)).astimezone(pytz.utc)
assert ev.presale_end == berlin_tz.localize(datetime.datetime(2016, 11, 30, 18, 0, 0)).astimezone(pytz.utc) assert ev.presale_end == berlin_tz.localize(datetime.datetime(2016, 11, 30, 18, 0, 0)).astimezone(pytz.utc)
assert ev.tax_rules.filter(rate=Decimal('19.00')).count() == 1 assert ev.tax_rules.filter(rate=Decimal('19.00')).count() == 1
def test_create_event_only_date_from(self): def test_create_event_only_date_from(self):
# date_to, presale_start & presale_end are optional fields # date_to, presale_start & presale_end are optional fields
@@ -806,19 +826,20 @@ class EventsTest(SoupTest):
'copy-copy_from_event': '' 'copy-copy_from_event': ''
}) })
ev = Event.objects.get(slug='33c3') with scopes_disabled():
assert ev.name == LazyI18nString({'en': '33C3'}) ev = Event.objects.get(slug='33c3')
assert ev.settings.locales == ['en'] assert ev.name == LazyI18nString({'en': '33C3'})
assert ev.settings.locale == 'en' assert ev.settings.locales == ['en']
assert ev.currency == 'EUR' assert ev.settings.locale == 'en'
assert ev.settings.timezone == 'UTC' assert ev.currency == 'EUR'
assert ev.organizer == self.orga1 assert ev.settings.timezone == 'UTC'
assert ev.location == LazyI18nString({'en': 'Hamburg'}) assert ev.organizer == self.orga1
assert Team.objects.filter(limit_events=ev, members=self.user).exists() assert ev.location == LazyI18nString({'en': 'Hamburg'})
assert ev.date_from == datetime.datetime(2016, 12, 27, 10, 0, 0, tzinfo=pytz.utc) assert Team.objects.filter(limit_events=ev, members=self.user).exists()
assert ev.date_to is None assert ev.date_from == datetime.datetime(2016, 12, 27, 10, 0, 0, tzinfo=pytz.utc)
assert ev.presale_start is None assert ev.date_to is None
assert ev.presale_end is None assert ev.presale_start is None
assert ev.presale_end is None
def test_create_event_missing_date_from(self): def test_create_event_missing_date_from(self):
# date_from is mandatory # date_from is mandatory
@@ -909,6 +930,7 @@ class EventsTest(SoupTest):
class SubEventsTest(SoupTest): class SubEventsTest(SoupTest):
@scopes_disabled()
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy') self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
@@ -967,22 +989,23 @@ class SubEventsTest(SoupTest):
'item-%d-price' % self.ticket.pk: '12' 'item-%d-price' % self.ticket.pk: '12'
}) })
assert doc.select(".alert-success") assert doc.select(".alert-success")
se = self.event1.subevents.first() with scopes_disabled():
assert str(se.name) == "SE2" se = self.event1.subevents.first()
assert se.active assert str(se.name) == "SE2"
assert se.date_from.isoformat() == "2017-07-01T10:00:00+00:00" assert se.active
assert se.date_to.isoformat() == "2017-07-01T12:00:00+00:00" assert se.date_from.isoformat() == "2017-07-01T10:00:00+00:00"
assert str(se.location) == "Hamburg" assert se.date_to.isoformat() == "2017-07-01T12:00:00+00:00"
assert se.presale_start.isoformat() == "2017-06-20T10:00:00+00:00" assert str(se.location) == "Hamburg"
assert not se.presale_end assert se.presale_start.isoformat() == "2017-06-20T10:00:00+00:00"
assert se.quotas.count() == 1 assert not se.presale_end
q = se.quotas.last() assert se.quotas.count() == 1
assert q.name == "Q1" q = se.quotas.last()
assert q.size == 50 assert q.name == "Q1"
assert list(q.items.all()) == [self.ticket] assert q.size == 50
sei = SubEventItem.objects.get(subevent=se, item=self.ticket) assert list(q.items.all()) == [self.ticket]
assert sei.price == 12 sei = SubEventItem.objects.get(subevent=se, item=self.ticket)
assert se.checkinlist_set.count() == 1 assert sei.price == 12
assert se.checkinlist_set.count() == 1
def test_modify(self): def test_modify(self):
doc = self.get_doc('/control/event/ccc/30c3/subevents/%d/' % self.subevent1.pk) doc = self.get_doc('/control/event/ccc/30c3/subevents/%d/' % self.subevent1.pk)
@@ -1022,14 +1045,15 @@ class SubEventsTest(SoupTest):
assert str(se.location) == "Hamburg" assert str(se.location) == "Hamburg"
assert se.presale_start.isoformat() == "2017-06-20T10:00:00+00:00" assert se.presale_start.isoformat() == "2017-06-20T10:00:00+00:00"
assert not se.presale_end assert not se.presale_end
assert se.quotas.count() == 1 with scopes_disabled():
q = se.quotas.last() assert se.quotas.count() == 1
assert q.name == "Q1" q = se.quotas.last()
assert q.size == 50 assert q.name == "Q1"
assert list(q.items.all()) == [self.ticket] assert q.size == 50
sei = SubEventItem.objects.get(subevent=se, item=self.ticket) assert list(q.items.all()) == [self.ticket]
assert sei.price == 12 sei = SubEventItem.objects.get(subevent=se, item=self.ticket)
assert se.checkinlist_set.count() == 1 assert sei.price == 12
assert se.checkinlist_set.count() == 1
def test_delete(self): def test_delete(self):
doc = self.get_doc('/control/event/ccc/30c3/subevents/%d/delete' % self.subevent1.pk) doc = self.get_doc('/control/event/ccc/30c3/subevents/%d/delete' % self.subevent1.pk)
@@ -1039,30 +1063,34 @@ class SubEventsTest(SoupTest):
# deleting the second event # deleting the second event
doc = self.post_doc('/control/event/ccc/30c3/subevents/%d/delete' % self.subevent2.pk, {}) doc = self.post_doc('/control/event/ccc/30c3/subevents/%d/delete' % self.subevent2.pk, {})
assert doc.select(".alert-success") assert doc.select(".alert-success")
assert not SubEvent.objects.filter(pk=self.subevent2.pk).exists() with scopes_disabled():
assert not SubEvent.objects.filter(pk=self.subevent1.pk).exists() assert not SubEvent.objects.filter(pk=self.subevent2.pk).exists()
assert not SubEvent.objects.filter(pk=self.subevent1.pk).exists()
def test_delete_with_orders(self): def test_delete_with_orders(self):
o = Order.objects.create( with scopes_disabled():
code='FOO', event=self.event1, email='dummy@dummy.test', o = Order.objects.create(
status=Order.STATUS_PENDING, code='FOO', event=self.event1, email='dummy@dummy.test',
datetime=now(), expires=now() + datetime.timedelta(days=10), status=Order.STATUS_PENDING,
total=14, locale='en' datetime=now(), expires=now() + datetime.timedelta(days=10),
) total=14, locale='en'
OrderPosition.objects.create( )
order=o, OrderPosition.objects.create(
item=self.ticket, order=o,
subevent=self.subevent1, item=self.ticket,
price=Decimal("14"), subevent=self.subevent1,
) price=Decimal("14"),
)
doc = self.get_doc('/control/event/ccc/30c3/subevents/%d/delete' % self.subevent1.pk, follow=True) doc = self.get_doc('/control/event/ccc/30c3/subevents/%d/delete' % self.subevent1.pk, follow=True)
assert doc.select(".alert-danger") assert doc.select(".alert-danger")
doc = self.post_doc('/control/event/ccc/30c3/subevents/%d/delete' % self.subevent1.pk, {}, follow=True) doc = self.post_doc('/control/event/ccc/30c3/subevents/%d/delete' % self.subevent1.pk, {}, follow=True)
assert doc.select(".alert-danger") assert doc.select(".alert-danger")
assert self.event1.subevents.filter(pk=self.subevent1.pk).exists() with scopes_disabled():
assert self.event1.subevents.filter(pk=self.subevent1.pk).exists()
def test_create_bulk(self): def test_create_bulk(self):
self.event1.subevents.all().delete() with scopes_disabled():
self.event1.subevents.all().delete()
self.event1.settings.timezone = 'Europe/Berlin' self.event1.settings.timezone = 'Europe/Berlin'
doc = self.get_doc('/control/event/ccc/30c3/subevents/bulk_add') doc = self.get_doc('/control/event/ccc/30c3/subevents/bulk_add')
@@ -1120,7 +1148,8 @@ class SubEventsTest(SoupTest):
'checkinlist_set-0-limit_products': str(self.ticket.pk), 'checkinlist_set-0-limit_products': str(self.ticket.pk),
}) })
assert doc.select(".alert-success") assert doc.select(".alert-success")
ses = list(self.event1.subevents.order_by('date_from')) with scopes_disabled():
ses = list(self.event1.subevents.order_by('date_from'))
assert len(ses) == 10 assert len(ses) == 10
assert str(ses[0].name) == "Foo" assert str(ses[0].name) == "Foo"
@@ -1128,25 +1157,28 @@ class SubEventsTest(SoupTest):
assert ses[0].date_to.isoformat() == "2018-04-03T13:29:31+00:00" assert ses[0].date_to.isoformat() == "2018-04-03T13:29:31+00:00"
assert not ses[0].presale_start assert not ses[0].presale_start
assert ses[0].presale_end.isoformat() == "2018-04-02T11:29:31+00:00" assert ses[0].presale_end.isoformat() == "2018-04-02T11:29:31+00:00"
assert ses[0].quotas.count() == 1 with scopes_disabled():
assert list(ses[0].quotas.first().items.all()) == [self.ticket] assert ses[0].quotas.count() == 1
assert SubEventItem.objects.get(subevent=ses[0], item=self.ticket).price == 16 assert list(ses[0].quotas.first().items.all()) == [self.ticket]
assert ses[0].checkinlist_set.count() == 1 assert SubEventItem.objects.get(subevent=ses[0], item=self.ticket).price == 16
assert ses[0].checkinlist_set.count() == 1
assert str(ses[1].name) == "Foo" assert str(ses[1].name) == "Foo"
assert ses[1].date_from.isoformat() == "2019-04-03T11:29:31+00:00" assert ses[1].date_from.isoformat() == "2019-04-03T11:29:31+00:00"
assert ses[1].date_to.isoformat() == "2019-04-03T13:29:31+00:00" assert ses[1].date_to.isoformat() == "2019-04-03T13:29:31+00:00"
assert not ses[1].presale_start assert not ses[1].presale_start
assert ses[1].presale_end.isoformat() == "2019-04-02T11:29:31+00:00" assert ses[1].presale_end.isoformat() == "2019-04-02T11:29:31+00:00"
assert ses[1].quotas.count() == 1 with scopes_disabled():
assert list(ses[1].quotas.first().items.all()) == [self.ticket] assert ses[1].quotas.count() == 1
assert SubEventItem.objects.get(subevent=ses[0], item=self.ticket).price == 16 assert list(ses[1].quotas.first().items.all()) == [self.ticket]
assert ses[1].checkinlist_set.count() == 1 assert SubEventItem.objects.get(subevent=ses[0], item=self.ticket).price == 16
assert ses[1].checkinlist_set.count() == 1
assert ses[-1].date_from.isoformat() == "2027-04-03T11:29:31+00:00" assert ses[-1].date_from.isoformat() == "2027-04-03T11:29:31+00:00"
def test_create_bulk_daily_interval(self): def test_create_bulk_daily_interval(self):
self.event1.subevents.all().delete() with scopes_disabled():
self.event1.subevents.all().delete()
self.event1.settings.timezone = 'Europe/Berlin' self.event1.settings.timezone = 'Europe/Berlin'
doc = self.get_doc('/control/event/ccc/30c3/subevents/bulk_add') doc = self.get_doc('/control/event/ccc/30c3/subevents/bulk_add')
@@ -1194,7 +1226,8 @@ class SubEventsTest(SoupTest):
'checkinlist_set-MAX_NUM_FORMS': '1000', 'checkinlist_set-MAX_NUM_FORMS': '1000',
}) })
assert doc.select(".alert-success") assert doc.select(".alert-success")
ses = list(self.event1.subevents.order_by('date_from')) with scopes_disabled():
ses = list(self.event1.subevents.order_by('date_from'))
assert len(ses) == 183 assert len(ses) == 183
assert ses[0].date_from.isoformat() == "2018-04-03T11:29:31+00:00" assert ses[0].date_from.isoformat() == "2018-04-03T11:29:31+00:00"
@@ -1202,7 +1235,8 @@ class SubEventsTest(SoupTest):
assert ses[-1].date_from.isoformat() == "2019-04-02T11:29:31+00:00" assert ses[-1].date_from.isoformat() == "2019-04-02T11:29:31+00:00"
def test_create_bulk_exclude(self): def test_create_bulk_exclude(self):
self.event1.subevents.all().delete() with scopes_disabled():
self.event1.subevents.all().delete()
self.event1.settings.timezone = 'Europe/Berlin' self.event1.settings.timezone = 'Europe/Berlin'
doc = self.get_doc('/control/event/ccc/30c3/subevents/bulk_add') doc = self.get_doc('/control/event/ccc/30c3/subevents/bulk_add')
@@ -1265,7 +1299,8 @@ class SubEventsTest(SoupTest):
'checkinlist_set-MAX_NUM_FORMS': '1000', 'checkinlist_set-MAX_NUM_FORMS': '1000',
}) })
assert doc.select(".alert-success") assert doc.select(".alert-success")
ses = list(self.event1.subevents.order_by('date_from')) with scopes_disabled():
ses = list(self.event1.subevents.order_by('date_from'))
assert len(ses) == 314 assert len(ses) == 314
assert ses[0].date_from.isoformat() == "2018-04-03T11:29:31+00:00" assert ses[0].date_from.isoformat() == "2018-04-03T11:29:31+00:00"
@@ -1273,7 +1308,8 @@ class SubEventsTest(SoupTest):
assert ses[6].date_from.isoformat() == "2018-04-10T11:29:31+00:00" assert ses[6].date_from.isoformat() == "2018-04-10T11:29:31+00:00"
def test_create_bulk_monthly_interval(self): def test_create_bulk_monthly_interval(self):
self.event1.subevents.all().delete() with scopes_disabled():
self.event1.subevents.all().delete()
self.event1.settings.timezone = 'Europe/Berlin' self.event1.settings.timezone = 'Europe/Berlin'
doc = self.post_doc('/control/event/ccc/30c3/subevents/bulk_add', { doc = self.post_doc('/control/event/ccc/30c3/subevents/bulk_add', {
@@ -1320,7 +1356,8 @@ class SubEventsTest(SoupTest):
'checkinlist_set-MAX_NUM_FORMS': '1000', 'checkinlist_set-MAX_NUM_FORMS': '1000',
}) })
assert doc.select(".alert-success") assert doc.select(".alert-success")
ses = list(self.event1.subevents.order_by('date_from')) with scopes_disabled():
ses = list(self.event1.subevents.order_by('date_from'))
assert len(ses) == 12 assert len(ses) == 12
assert ses[0].date_from.isoformat() == "2018-04-30T11:29:31+00:00" assert ses[0].date_from.isoformat() == "2018-04-30T11:29:31+00:00"
@@ -1328,7 +1365,8 @@ class SubEventsTest(SoupTest):
assert ses[-1].date_from.isoformat() == "2019-03-29T12:29:31+00:00" assert ses[-1].date_from.isoformat() == "2019-03-29T12:29:31+00:00"
def test_create_bulk_weekly_interval(self): def test_create_bulk_weekly_interval(self):
self.event1.subevents.all().delete() with scopes_disabled():
self.event1.subevents.all().delete()
self.event1.settings.timezone = 'Europe/Berlin' self.event1.settings.timezone = 'Europe/Berlin'
doc = self.post_doc('/control/event/ccc/30c3/subevents/bulk_add', { doc = self.post_doc('/control/event/ccc/30c3/subevents/bulk_add', {
@@ -1375,7 +1413,8 @@ class SubEventsTest(SoupTest):
'checkinlist_set-MAX_NUM_FORMS': '1000', 'checkinlist_set-MAX_NUM_FORMS': '1000',
}) })
assert doc.select(".alert-success") assert doc.select(".alert-success")
ses = list(self.event1.subevents.order_by('date_from')) with scopes_disabled():
ses = list(self.event1.subevents.order_by('date_from'))
assert len(ses) == 52 assert len(ses) == 52
assert ses[0].date_from.isoformat() == "2018-04-05T11:29:31+00:00" assert ses[0].date_from.isoformat() == "2018-04-05T11:29:31+00:00"
@@ -1385,25 +1424,27 @@ class SubEventsTest(SoupTest):
def test_delete_bulk(self): def test_delete_bulk(self):
self.subevent2.active = True self.subevent2.active = True
self.subevent2.save() self.subevent2.save()
o = Order.objects.create( with scopes_disabled():
code='FOO', event=self.event1, email='dummy@dummy.test', o = Order.objects.create(
status=Order.STATUS_PENDING, code='FOO', event=self.event1, email='dummy@dummy.test',
datetime=now(), expires=now() + datetime.timedelta(days=10), status=Order.STATUS_PENDING,
total=14, locale='en' datetime=now(), expires=now() + datetime.timedelta(days=10),
) total=14, locale='en'
OrderPosition.objects.create( )
order=o, OrderPosition.objects.create(
item=self.ticket, order=o,
subevent=self.subevent1, item=self.ticket,
price=Decimal("14"), subevent=self.subevent1,
) price=Decimal("14"),
)
doc = self.post_doc('/control/event/ccc/30c3/subevents/bulk_action', { doc = self.post_doc('/control/event/ccc/30c3/subevents/bulk_action', {
'subevent': [str(self.subevent1.pk), str(self.subevent2.pk)], 'subevent': [str(self.subevent1.pk), str(self.subevent2.pk)],
'action': 'delete_confirm' 'action': 'delete_confirm'
}, follow=True) }, follow=True)
assert doc.select(".alert-success") assert doc.select(".alert-success")
assert not self.event1.subevents.filter(pk=self.subevent2.pk).exists() with scopes_disabled():
assert self.event1.subevents.get(pk=self.subevent1.pk).active is False assert not self.event1.subevents.filter(pk=self.subevent2.pk).exists()
assert self.event1.subevents.get(pk=self.subevent1.pk).active is False
def test_disable_bulk(self): def test_disable_bulk(self):
self.subevent2.active = True self.subevent2.active = True
@@ -1413,7 +1454,8 @@ class SubEventsTest(SoupTest):
'action': 'disable' 'action': 'disable'
}, follow=True) }, follow=True)
assert doc.select(".alert-success") assert doc.select(".alert-success")
assert self.event1.subevents.get(pk=self.subevent2.pk).active is False with scopes_disabled():
assert self.event1.subevents.get(pk=self.subevent2.pk).active is False
def test_enable_bulk(self): def test_enable_bulk(self):
self.subevent2.active = False self.subevent2.active = False
@@ -1423,10 +1465,12 @@ class SubEventsTest(SoupTest):
'action': 'enable' 'action': 'enable'
}, follow=True) }, follow=True)
assert doc.select(".alert-success") assert doc.select(".alert-success")
assert self.event1.subevents.get(pk=self.subevent2.pk).active is True with scopes_disabled():
assert self.event1.subevents.get(pk=self.subevent2.pk).active is True
class EventDeletionTest(SoupTest): class EventDeletionTest(SoupTest):
@scopes_disabled()
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy') self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
@@ -1454,21 +1498,24 @@ class EventDeletionTest(SoupTest):
'slug': '30c3' 'slug': '30c3'
}) })
assert not self.orga1.events.exists() with scopes_disabled():
assert not self.orga1.events.exists()
def test_delete_wrong_slug(self): def test_delete_wrong_slug(self):
self.post_doc('/control/event/ccc/30c3/delete/', { self.post_doc('/control/event/ccc/30c3/delete/', {
'user_pw': 'dummy', 'user_pw': 'dummy',
'slug': '31c3' 'slug': '31c3'
}) })
assert self.orga1.events.exists() with scopes_disabled():
assert self.orga1.events.exists()
def test_delete_wrong_pw(self): def test_delete_wrong_pw(self):
self.post_doc('/control/event/ccc/30c3/delete/', { self.post_doc('/control/event/ccc/30c3/delete/', {
'user_pw': 'invalid', 'user_pw': 'invalid',
'slug': '30c3' 'slug': '30c3'
}) })
assert self.orga1.events.exists() with scopes_disabled():
assert self.orga1.events.exists()
def test_delete_orders(self): def test_delete_orders(self):
Order.objects.create( Order.objects.create(
@@ -1481,4 +1528,5 @@ class EventDeletionTest(SoupTest):
'user_pw': 'dummy', 'user_pw': 'dummy',
'slug': '30c3' 'slug': '30c3'
}) })
assert self.orga1.events.exists() with scopes_disabled():
assert self.orga1.events.exists()

View File

@@ -2,6 +2,7 @@ import datetime
from decimal import Decimal from decimal import Decimal
from django.utils.timezone import now from django.utils.timezone import now
from django_scopes import scopes_disabled
from tests.base import SoupTest, extract_form_fields from tests.base import SoupTest, extract_form_fields
from pretix.base.models import ( from pretix.base.models import (
@@ -11,6 +12,7 @@ from pretix.base.models import (
class ItemFormTest(SoupTest): class ItemFormTest(SoupTest):
@scopes_disabled()
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy') self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
@@ -47,11 +49,13 @@ class CategoriesTest(ItemFormTest):
assert doc.select(".alert-success") assert doc.select(".alert-success")
self.assertIn("T-Shirts", doc.select("#page-wrapper table")[0].text) self.assertIn("T-Shirts", doc.select("#page-wrapper table")[0].text)
self.assertNotIn("Entry tickets", doc.select("#page-wrapper table")[0].text) self.assertNotIn("Entry tickets", doc.select("#page-wrapper table")[0].text)
assert str(ItemCategory.objects.get(id=c.id).name) == 'T-Shirts' with scopes_disabled():
assert str(ItemCategory.objects.get(id=c.id).name) == 'T-Shirts'
def test_sort(self): def test_sort(self):
c1 = ItemCategory.objects.create(event=self.event1, name="Entry tickets", position=0) with scopes_disabled():
ItemCategory.objects.create(event=self.event1, name="T-Shirts", position=1) c1 = ItemCategory.objects.create(event=self.event1, name="Entry tickets", position=0)
ItemCategory.objects.create(event=self.event1, name="T-Shirts", position=1)
doc = self.get_doc('/control/event/%s/%s/categories/' % (self.orga1.slug, self.event1.slug)) doc = self.get_doc('/control/event/%s/%s/categories/' % (self.orga1.slug, self.event1.slug))
self.assertIn("Entry tickets", doc.select("table > tbody > tr")[0].text) self.assertIn("Entry tickets", doc.select("table > tbody > tr")[0].text)
self.assertIn("T-Shirts", doc.select("table > tbody > tr")[1].text) self.assertIn("T-Shirts", doc.select("table > tbody > tr")[1].text)
@@ -67,14 +71,16 @@ class CategoriesTest(ItemFormTest):
self.assertIn("T-Shirts", doc.select("table > tbody > tr")[1].text) self.assertIn("T-Shirts", doc.select("table > tbody > tr")[1].text)
def test_delete(self): def test_delete(self):
c = ItemCategory.objects.create(event=self.event1, name="Entry tickets") with scopes_disabled():
c = ItemCategory.objects.create(event=self.event1, name="Entry tickets")
doc = self.get_doc('/control/event/%s/%s/categories/%s/delete' % (self.orga1.slug, self.event1.slug, c.id)) doc = self.get_doc('/control/event/%s/%s/categories/%s/delete' % (self.orga1.slug, self.event1.slug, c.id))
form_data = extract_form_fields(doc.select('.container-fluid form')[0]) form_data = extract_form_fields(doc.select('.container-fluid form')[0])
doc = self.post_doc('/control/event/%s/%s/categories/%s/delete' % (self.orga1.slug, self.event1.slug, c.id), doc = self.post_doc('/control/event/%s/%s/categories/%s/delete' % (self.orga1.slug, self.event1.slug, c.id),
form_data) form_data)
assert doc.select(".alert-success") assert doc.select(".alert-success")
self.assertNotIn("Entry tickets", doc.select("#page-wrapper")[0].text) self.assertNotIn("Entry tickets", doc.select("#page-wrapper")[0].text)
assert not ItemCategory.objects.filter(id=c.id).exists() with scopes_disabled():
assert not ItemCategory.objects.filter(id=c.id).exists()
class QuestionsTest(ItemFormTest): class QuestionsTest(ItemFormTest):
@@ -90,8 +96,9 @@ class QuestionsTest(ItemFormTest):
self.assertIn("shoe size", doc.select("#page-wrapper table")[0].text) self.assertIn("shoe size", doc.select("#page-wrapper table")[0].text)
def test_update_choices(self): def test_update_choices(self):
c = Question.objects.create(event=self.event1, question="What country are you from?", type="C", required=True) with scopes_disabled():
o1 = c.options.create(answer='Germany') c = Question.objects.create(event=self.event1, question="What country are you from?", type="C", required=True)
o1 = c.options.create(answer='Germany')
doc = self.get_doc('/control/event/%s/%s/questions/%s/change' % (self.orga1.slug, self.event1.slug, c.id)) doc = self.get_doc('/control/event/%s/%s/questions/%s/change' % (self.orga1.slug, self.event1.slug, c.id))
form_data = extract_form_fields(doc.select('.container-fluid form')[0]) form_data = extract_form_fields(doc.select('.container-fluid form')[0])
form_data['form-TOTAL_FORMS'] = '1' form_data['form-TOTAL_FORMS'] = '1'
@@ -104,12 +111,14 @@ class QuestionsTest(ItemFormTest):
self.post_doc('/control/event/%s/%s/questions/%s/change' % (self.orga1.slug, self.event1.slug, c.id), self.post_doc('/control/event/%s/%s/questions/%s/change' % (self.orga1.slug, self.event1.slug, c.id),
form_data) form_data)
c.refresh_from_db() c.refresh_from_db()
assert c.options.exists() with scopes_disabled():
assert str(c.options.first().answer) == 'England' assert c.options.exists()
assert str(c.options.first().answer) == 'England'
def test_delete_choices(self): def test_delete_choices(self):
c = Question.objects.create(event=self.event1, question="What country are you from?", type="C", required=True) with scopes_disabled():
o1 = c.options.create(answer='Germany') c = Question.objects.create(event=self.event1, question="What country are you from?", type="C", required=True)
o1 = c.options.create(answer='Germany')
doc = self.get_doc('/control/event/%s/%s/questions/%s/change' % (self.orga1.slug, self.event1.slug, c.id)) doc = self.get_doc('/control/event/%s/%s/questions/%s/change' % (self.orga1.slug, self.event1.slug, c.id))
form_data = extract_form_fields(doc.select('.container-fluid form')[0]) form_data = extract_form_fields(doc.select('.container-fluid form')[0])
form_data['form-TOTAL_FORMS'] = '1' form_data['form-TOTAL_FORMS'] = '1'
@@ -123,10 +132,12 @@ class QuestionsTest(ItemFormTest):
self.post_doc('/control/event/%s/%s/questions/%s/change' % (self.orga1.slug, self.event1.slug, c.id), self.post_doc('/control/event/%s/%s/questions/%s/change' % (self.orga1.slug, self.event1.slug, c.id),
form_data) form_data)
c.refresh_from_db() c.refresh_from_db()
assert not c.options.exists() with scopes_disabled():
assert not c.options.exists()
def test_add_choices(self): def test_add_choices(self):
c = Question.objects.create(event=self.event1, question="What country are you from?", type="N", required=True) with scopes_disabled():
c = Question.objects.create(event=self.event1, question="What country are you from?", type="N", required=True)
doc = self.get_doc('/control/event/%s/%s/questions/%s/change' % (self.orga1.slug, self.event1.slug, c.id)) doc = self.get_doc('/control/event/%s/%s/questions/%s/change' % (self.orga1.slug, self.event1.slug, c.id))
form_data = extract_form_fields(doc.select('.container-fluid form')[0]) form_data = extract_form_fields(doc.select('.container-fluid form')[0])
form_data['type'] = 'C' form_data['type'] = 'C'
@@ -139,12 +150,14 @@ class QuestionsTest(ItemFormTest):
form_data['form-0-answer_0'] = 'Germany' form_data['form-0-answer_0'] = 'Germany'
self.post_doc('/control/event/%s/%s/questions/%s/change' % (self.orga1.slug, self.event1.slug, c.id), self.post_doc('/control/event/%s/%s/questions/%s/change' % (self.orga1.slug, self.event1.slug, c.id),
form_data) form_data)
c = Question.objects.get(id=c.id) with scopes_disabled():
assert c.options.exists() c = Question.objects.get(id=c.id)
assert str(c.options.first().answer) == 'Germany' assert c.options.exists()
assert str(c.options.first().answer) == 'Germany'
def test_update(self): def test_update(self):
c = Question.objects.create(event=self.event1, question="What is your shoe size?", type="N", required=True) with scopes_disabled():
c = Question.objects.create(event=self.event1, question="What is your shoe size?", type="N", required=True)
doc = self.get_doc('/control/event/%s/%s/questions/%s/change' % (self.orga1.slug, self.event1.slug, c.id)) doc = self.get_doc('/control/event/%s/%s/questions/%s/change' % (self.orga1.slug, self.event1.slug, c.id))
form_data = extract_form_fields(doc.select('.container-fluid form')[0]) form_data = extract_form_fields(doc.select('.container-fluid form')[0])
form_data['items'] = self.item1.id form_data['items'] = self.item1.id
@@ -153,13 +166,15 @@ class QuestionsTest(ItemFormTest):
form_data) form_data)
self.assertIn("How old", doc.select("#page-wrapper table")[0].text) self.assertIn("How old", doc.select("#page-wrapper table")[0].text)
self.assertNotIn("shoe size", doc.select("#page-wrapper table")[0].text) self.assertNotIn("shoe size", doc.select("#page-wrapper table")[0].text)
c = Question.objects.get(id=c.id) with scopes_disabled():
self.assertTrue(c.required) c = Question.objects.get(id=c.id)
assert str(Question.objects.get(id=c.id).question) == 'How old are you?' self.assertTrue(c.required)
assert str(Question.objects.get(id=c.id).question) == 'How old are you?'
def test_sort(self): def test_sort(self):
q1 = Question.objects.create(event=self.event1, question="Vegetarian?", type="N", required=True, position=0) with scopes_disabled():
Question.objects.create(event=self.event1, question="Food allergies?", position=1) q1 = Question.objects.create(event=self.event1, question="Vegetarian?", type="N", required=True, position=0)
Question.objects.create(event=self.event1, question="Food allergies?", position=1)
doc = self.get_doc('/control/event/%s/%s/questions/' % (self.orga1.slug, self.event1.slug)) doc = self.get_doc('/control/event/%s/%s/questions/' % (self.orga1.slug, self.event1.slug))
self.assertIn("Vegetarian?", doc.select("table > tbody > tr")[0].text) self.assertIn("Vegetarian?", doc.select("table > tbody > tr")[0].text)
self.assertIn("Food allergies?", doc.select("table > tbody > tr")[1].text) self.assertIn("Food allergies?", doc.select("table > tbody > tr")[1].text)
@@ -175,32 +190,35 @@ class QuestionsTest(ItemFormTest):
self.assertIn("Food allergies?", doc.select("table > tbody > tr")[1].text) self.assertIn("Food allergies?", doc.select("table > tbody > tr")[1].text)
def test_delete(self): def test_delete(self):
c = Question.objects.create(event=self.event1, question="What is your shoe size?", type="N", required=True) with scopes_disabled():
c = Question.objects.create(event=self.event1, question="What is your shoe size?", type="N", required=True)
doc = self.get_doc('/control/event/%s/%s/questions/%s/delete' % (self.orga1.slug, self.event1.slug, c.id)) doc = self.get_doc('/control/event/%s/%s/questions/%s/delete' % (self.orga1.slug, self.event1.slug, c.id))
form_data = extract_form_fields(doc.select('.container-fluid form')[0]) form_data = extract_form_fields(doc.select('.container-fluid form')[0])
doc = self.post_doc('/control/event/%s/%s/questions/%s/delete' % (self.orga1.slug, self.event1.slug, c.id), doc = self.post_doc('/control/event/%s/%s/questions/%s/delete' % (self.orga1.slug, self.event1.slug, c.id),
form_data) form_data)
assert doc.select(".alert-success") assert doc.select(".alert-success")
self.assertNotIn("shoe size", doc.select("#page-wrapper")[0].text) self.assertNotIn("shoe size", doc.select("#page-wrapper")[0].text)
assert not Question.objects.filter(id=c.id).exists() with scopes_disabled():
assert not Question.objects.filter(id=c.id).exists()
def test_question_view(self): def test_question_view(self):
c = Question.objects.create(event=self.event1, question="What is your shoe size?", type="N", required=True) with scopes_disabled():
c = Question.objects.create(event=self.event1, question="What is your shoe size?", type="N", required=True)
item1 = Item.objects.create(event=self.event1, name="Standard", default_price=0, position=1) item1 = Item.objects.create(event=self.event1, name="Standard", default_price=0, position=1)
o = Order.objects.create(code='FOO', event=self.event1, email='dummy@dummy.test', o = Order.objects.create(code='FOO', event=self.event1, email='dummy@dummy.test',
status=Order.STATUS_PENDING, datetime=now(), status=Order.STATUS_PENDING, datetime=now(),
expires=now() + datetime.timedelta(days=10), expires=now() + datetime.timedelta(days=10),
total=14, locale='en') total=14, locale='en')
op = OrderPosition.objects.create(order=o, item=item1, variation=None, price=Decimal("14"), op = OrderPosition.objects.create(order=o, item=item1, variation=None, price=Decimal("14"),
attendee_name_parts={'full_name': "Peter"}) attendee_name_parts={'full_name': "Peter"})
op.answers.create(question=c, answer='42') op.answers.create(question=c, answer='42')
op = OrderPosition.objects.create(order=o, item=item1, variation=None, price=Decimal("14"), op = OrderPosition.objects.create(order=o, item=item1, variation=None, price=Decimal("14"),
attendee_name_parts={'full_name': "Michael"}) attendee_name_parts={'full_name': "Michael"})
op.answers.create(question=c, answer='42') op.answers.create(question=c, answer='42')
op = OrderPosition.objects.create(order=o, item=item1, variation=None, price=Decimal("14"), op = OrderPosition.objects.create(order=o, item=item1, variation=None, price=Decimal("14"),
attendee_name_parts={'full_name': "Petra"}) attendee_name_parts={'full_name': "Petra"})
op.answers.create(question=c, answer='39') op.answers.create(question=c, answer='39')
doc = self.get_doc('/control/event/%s/%s/questions/%s/' % (self.orga1.slug, self.event1.slug, c.id)) doc = self.get_doc('/control/event/%s/%s/questions/%s/' % (self.orga1.slug, self.event1.slug, c.id))
tbl = doc.select('.container-fluid table.table-bordered tbody')[0] tbl = doc.select('.container-fluid table.table-bordered tbody')[0]
@@ -219,9 +237,10 @@ class QuestionsTest(ItemFormTest):
assert tbl.select('tr')[0].select('td')[0].text.strip() == '42' assert tbl.select('tr')[0].select('td')[0].text.strip() == '42'
def test_set_dependency(self): def test_set_dependency(self):
q1 = Question.objects.create(event=self.event1, question="What country are you from?", type="C", required=True) with scopes_disabled():
q2 = Question.objects.create(event=self.event1, question="What city are you from?", type="T", required=True) q1 = Question.objects.create(event=self.event1, question="What country are you from?", type="C", required=True)
o1 = q1.options.create(answer='Germany') q2 = Question.objects.create(event=self.event1, question="What city are you from?", type="T", required=True)
o1 = q1.options.create(answer='Germany')
doc = self.get_doc('/control/event/%s/%s/questions/%s/change' % (self.orga1.slug, self.event1.slug, q2.id)) doc = self.get_doc('/control/event/%s/%s/questions/%s/change' % (self.orga1.slug, self.event1.slug, q2.id))
form_data = extract_form_fields(doc.select('.container-fluid form')[0]) form_data = extract_form_fields(doc.select('.container-fluid form')[0])
form_data['items'] = self.item1.id form_data['items'] = self.item1.id
@@ -235,10 +254,11 @@ class QuestionsTest(ItemFormTest):
assert q2.dependency_value == o1.identifier assert q2.dependency_value == o1.identifier
def test_set_dependency_circular(self): def test_set_dependency_circular(self):
q1 = Question.objects.create(event=self.event1, question="What country are you from?", type="C", required=True) with scopes_disabled():
o1 = q1.options.create(answer='Germany') q1 = Question.objects.create(event=self.event1, question="What country are you from?", type="C", required=True)
q2 = Question.objects.create(event=self.event1, question="What city are you from?", type="C", required=True, o1 = q1.options.create(answer='Germany')
dependency_question=q1, dependency_value=o1.identifier) q2 = Question.objects.create(event=self.event1, question="What city are you from?", type="C", required=True,
dependency_question=q1, dependency_value=o1.identifier)
doc = self.get_doc('/control/event/%s/%s/questions/%s/change' % (self.orga1.slug, self.event1.slug, q1.id)) doc = self.get_doc('/control/event/%s/%s/questions/%s/change' % (self.orga1.slug, self.event1.slug, q1.id))
form_data = extract_form_fields(doc.select('.container-fluid form')[0]) form_data = extract_form_fields(doc.select('.container-fluid form')[0])
form_data['dependency_question'] = q2.pk form_data['dependency_question'] = q2.pk
@@ -248,8 +268,9 @@ class QuestionsTest(ItemFormTest):
assert not doc.select(".alert-success") assert not doc.select(".alert-success")
def test_set_dependency_to_non_choice(self): def test_set_dependency_to_non_choice(self):
q1 = Question.objects.create(event=self.event1, question="What country are you from?", type="N", required=True) with scopes_disabled():
q2 = Question.objects.create(event=self.event1, question="What city are you from?", type="T", required=True) q1 = Question.objects.create(event=self.event1, question="What country are you from?", type="N", required=True)
q2 = Question.objects.create(event=self.event1, question="What city are you from?", type="T", required=True)
doc = self.get_doc('/control/event/%s/%s/questions/%s/change' % (self.orga1.slug, self.event1.slug, q2.id)) doc = self.get_doc('/control/event/%s/%s/questions/%s/change' % (self.orga1.slug, self.event1.slug, q2.id))
form_data = extract_form_fields(doc.select('.container-fluid form')[0]) form_data = extract_form_fields(doc.select('.container-fluid form')[0])
form_data['dependency_question'] = q1.pk form_data['dependency_question'] = q1.pk
@@ -271,11 +292,12 @@ class QuotaTest(ItemFormTest):
self.assertIn("Full house", doc.select("#page-wrapper table")[0].text) self.assertIn("Full house", doc.select("#page-wrapper table")[0].text)
def test_update(self): def test_update(self):
c = Quota.objects.create(event=self.event1, name="Full house", size=500) with scopes_disabled():
item1 = Item.objects.create(event=self.event1, name="Standard", default_price=0) c = Quota.objects.create(event=self.event1, name="Full house", size=500)
item2 = Item.objects.create(event=self.event1, name="Business", default_price=0) item1 = Item.objects.create(event=self.event1, name="Standard", default_price=0)
ItemVariation.objects.create(item=item2, value="Silver") item2 = Item.objects.create(event=self.event1, name="Business", default_price=0)
ItemVariation.objects.create(item=item2, value="Gold") ItemVariation.objects.create(item=item2, value="Silver")
ItemVariation.objects.create(item=item2, value="Gold")
doc = self.get_doc('/control/event/%s/%s/quotas/%s/change' % (self.orga1.slug, self.event1.slug, c.id)) doc = self.get_doc('/control/event/%s/%s/quotas/%s/change' % (self.orga1.slug, self.event1.slug, c.id))
[i for i in doc.select('[name=itemvars]') if i.get('value') == str(item1.id)][0]['checked'] = 'checked' [i for i in doc.select('[name=itemvars]') if i.get('value') == str(item1.id)][0]['checked'] = 'checked'
form_data = extract_form_fields(doc.select('.container-fluid form')[0]) form_data = extract_form_fields(doc.select('.container-fluid form')[0])
@@ -285,35 +307,41 @@ class QuotaTest(ItemFormTest):
doc = self.get_doc('/control/event/%s/%s/quotas/' % (self.orga1.slug, self.event1.slug)) doc = self.get_doc('/control/event/%s/%s/quotas/' % (self.orga1.slug, self.event1.slug))
self.assertIn("350", doc.select("#page-wrapper table")[0].text) self.assertIn("350", doc.select("#page-wrapper table")[0].text)
self.assertNotIn("500", doc.select("#page-wrapper table")[0].text) self.assertNotIn("500", doc.select("#page-wrapper table")[0].text)
assert Quota.objects.get(id=c.id).size == 350 with scopes_disabled():
assert item1 in Quota.objects.get(id=c.id).items.all() assert Quota.objects.get(id=c.id).size == 350
assert item1 in Quota.objects.get(id=c.id).items.all()
def test_update_subevent(self): def test_update_subevent(self):
self.event1.has_subevents = True self.event1.has_subevents = True
self.event1.save() self.event1.save()
se1 = self.event1.subevents.create(name="Foo", date_from=now()) with scopes_disabled():
se2 = self.event1.subevents.create(name="Bar", date_from=now()) se1 = self.event1.subevents.create(name="Foo", date_from=now())
c = Quota.objects.create(event=self.event1, name="Full house", size=500, subevent=se1) se2 = self.event1.subevents.create(name="Bar", date_from=now())
c = Quota.objects.create(event=self.event1, name="Full house", size=500, subevent=se1)
doc = self.get_doc('/control/event/%s/%s/quotas/%s/change' % (self.orga1.slug, self.event1.slug, c.id)) doc = self.get_doc('/control/event/%s/%s/quotas/%s/change' % (self.orga1.slug, self.event1.slug, c.id))
form_data = extract_form_fields(doc.select('.container-fluid form')[0]) form_data = extract_form_fields(doc.select('.container-fluid form')[0])
form_data['subevent'] = se2.pk form_data['subevent'] = se2.pk
self.post_doc('/control/event/%s/%s/quotas/%s/change' % (self.orga1.slug, self.event1.slug, c.id), self.post_doc('/control/event/%s/%s/quotas/%s/change' % (self.orga1.slug, self.event1.slug, c.id),
form_data) form_data)
assert Quota.objects.get(id=c.id).subevent == se2 with scopes_disabled():
assert Quota.objects.get(id=c.id).subevent == se2
def test_delete(self): def test_delete(self):
c = Quota.objects.create(event=self.event1, name="Full house", size=500) with scopes_disabled():
c = Quota.objects.create(event=self.event1, name="Full house", size=500)
doc = self.get_doc('/control/event/%s/%s/quotas/%s/delete' % (self.orga1.slug, self.event1.slug, c.id)) doc = self.get_doc('/control/event/%s/%s/quotas/%s/delete' % (self.orga1.slug, self.event1.slug, c.id))
form_data = extract_form_fields(doc.select('.container-fluid form')[0]) form_data = extract_form_fields(doc.select('.container-fluid form')[0])
doc = self.post_doc('/control/event/%s/%s/quotas/%s/delete' % (self.orga1.slug, self.event1.slug, c.id), doc = self.post_doc('/control/event/%s/%s/quotas/%s/delete' % (self.orga1.slug, self.event1.slug, c.id),
form_data) form_data)
assert doc.select(".alert-success") assert doc.select(".alert-success")
self.assertNotIn("Full house", doc.select("#page-wrapper")[0].text) self.assertNotIn("Full house", doc.select("#page-wrapper")[0].text)
assert not Quota.objects.filter(id=c.id).exists() with scopes_disabled():
assert not Quota.objects.filter(id=c.id).exists()
class ItemsTest(ItemFormTest): class ItemsTest(ItemFormTest):
@scopes_disabled()
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.item2 = Item.objects.create(event=self.event1, name="Business", default_price=0, position=2, self.item2 = Item.objects.create(event=self.event1, name="Business", default_price=0, position=2,
@@ -341,7 +369,7 @@ class ItemsTest(ItemFormTest):
'tax_rate': '19.00' 'tax_rate': '19.00'
}) })
resp = self.client.get('/control/event/%s/%s/items/' % (self.orga1.slug, self.event1.slug)) resp = self.client.get('/control/event/%s/%s/items/' % (self.orga1.slug, self.event1.slug))
assert 'T-Shirt' in resp.rendered_content assert 'T-Shirt' in resp.content.decode()
def test_update(self): def test_update(self):
self.client.post('/control/event/%s/%s/items/%d/' % (self.orga1.slug, self.event1.slug, self.item1.id), { self.client.post('/control/event/%s/%s/items/%d/' % (self.orga1.slug, self.event1.slug, self.item1.id), {
@@ -366,20 +394,23 @@ class ItemsTest(ItemFormTest):
'form-0-min_count': '1', 'form-0-min_count': '1',
'form-0-max_count': '2', 'form-0-max_count': '2',
}) })
assert self.item2.addons.exists() with scopes_disabled():
assert self.item2.addons.first().addon_category == self.addoncat assert self.item2.addons.exists()
assert self.item2.addons.first().addon_category == self.addoncat
a = self.item2.addons.first()
self.client.post('/control/event/%s/%s/items/%d/addons' % (self.orga1.slug, self.event1.slug, self.item2.id), { self.client.post('/control/event/%s/%s/items/%d/addons' % (self.orga1.slug, self.event1.slug, self.item2.id), {
'form-TOTAL_FORMS': '1', 'form-TOTAL_FORMS': '1',
'form-INITIAL_FORMS': '1', 'form-INITIAL_FORMS': '1',
'form-MIN_NUM_FORMS': '0', 'form-MIN_NUM_FORMS': '0',
'form-MAX_NUM_FORMS': '1000', 'form-MAX_NUM_FORMS': '1000',
'form-0-id': str(self.item2.addons.first().pk), 'form-0-id': str(a.pk),
'form-0-addon_category': str(self.addoncat.pk), 'form-0-addon_category': str(self.addoncat.pk),
'form-0-min_count': '1', 'form-0-min_count': '1',
'form-0-max_count': '2', 'form-0-max_count': '2',
'form-0-DELETE': 'on', 'form-0-DELETE': 'on',
}) })
assert not self.item2.addons.exists() with scopes_disabled():
assert not self.item2.addons.exists()
# Do not allow duplicates # Do not allow duplicates
self.client.post('/control/event/%s/%s/items/%d/addons' % (self.orga1.slug, self.event1.slug, self.item2.id), { self.client.post('/control/event/%s/%s/items/%d/addons' % (self.orga1.slug, self.event1.slug, self.item2.id), {
@@ -396,7 +427,8 @@ class ItemsTest(ItemFormTest):
'form-1-min_count': '1', 'form-1-min_count': '1',
'form-1-max_count': '2', 'form-1-max_count': '2',
}) })
assert not self.item2.addons.exists() with scopes_disabled():
assert not self.item2.addons.exists()
def test_manipulate_bundles(self): def test_manipulate_bundles(self):
self.client.post('/control/event/%s/%s/items/%d/bundles' % (self.orga1.slug, self.event1.slug, self.item2.id), { self.client.post('/control/event/%s/%s/items/%d/bundles' % (self.orga1.slug, self.event1.slug, self.item2.id), {
@@ -409,8 +441,9 @@ class ItemsTest(ItemFormTest):
'form-0-count': '2', 'form-0-count': '2',
'form-0-designated_price': '2.00', 'form-0-designated_price': '2.00',
}) })
assert self.item2.bundles.exists() with scopes_disabled():
assert self.item2.bundles.first().bundled_item == self.item1 assert self.item2.bundles.exists()
assert self.item2.bundles.first().bundled_item == self.item1
self.client.post('/control/event/%s/%s/items/%d/bundles' % (self.orga1.slug, self.event1.slug, self.item2.id), { self.client.post('/control/event/%s/%s/items/%d/bundles' % (self.orga1.slug, self.event1.slug, self.item2.id), {
'form-TOTAL_FORMS': '1', 'form-TOTAL_FORMS': '1',
'form-INITIAL_FORMS': '1', 'form-INITIAL_FORMS': '1',
@@ -422,7 +455,8 @@ class ItemsTest(ItemFormTest):
'form-0-designated_price': '2.00', 'form-0-designated_price': '2.00',
'form-0-DELETE': 'on', 'form-0-DELETE': 'on',
}) })
assert not self.item2.bundles.exists() with scopes_disabled():
assert not self.item2.bundles.exists()
# Do not allow self-reference # Do not allow self-reference
self.client.post('/control/event/%s/%s/items/%d/addons' % (self.orga1.slug, self.event1.slug, self.item2.id), { self.client.post('/control/event/%s/%s/items/%d/addons' % (self.orga1.slug, self.event1.slug, self.item2.id), {
@@ -435,10 +469,12 @@ class ItemsTest(ItemFormTest):
'form-0-count': '2', 'form-0-count': '2',
'form-0-designated_price': '2.00', 'form-0-designated_price': '2.00',
}) })
assert not self.item2.bundles.exists() with scopes_disabled():
assert not self.item2.bundles.exists()
# Do not allow multi-level bundles # Do not allow multi-level bundles
self.item1.bundles.create(bundled_item=self.item1, count=1, designated_price=0) with scopes_disabled():
self.item1.bundles.create(bundled_item=self.item1, count=1, designated_price=0)
self.client.post('/control/event/%s/%s/items/%d/bundles' % (self.orga1.slug, self.event1.slug, self.item2.id), { self.client.post('/control/event/%s/%s/items/%d/bundles' % (self.orga1.slug, self.event1.slug, self.item2.id), {
'form-TOTAL_FORMS': '1', 'form-TOTAL_FORMS': '1',
'form-INITIAL_FORMS': '0', 'form-INITIAL_FORMS': '0',
@@ -449,7 +485,8 @@ class ItemsTest(ItemFormTest):
'form-0-count': '2', 'form-0-count': '2',
'form-0-designated_price': '2.00', 'form-0-designated_price': '2.00',
}) })
assert not self.item2.bundles.exists() with scopes_disabled():
assert not self.item2.bundles.exists()
def test_update_variations(self): def test_update_variations(self):
self.client.post('/control/event/%s/%s/items/%d/variations' % (self.orga1.slug, self.event1.slug, self.item2.id), { self.client.post('/control/event/%s/%s/items/%d/variations' % (self.orga1.slug, self.event1.slug, self.item2.id), {
@@ -491,39 +528,45 @@ class ItemsTest(ItemFormTest):
'active': 'yes', 'active': 'yes',
'allow_cancel': 'yes' 'allow_cancel': 'yes'
}) })
assert not self.item2.variations.filter(pk=self.var2.pk).exists() with scopes_disabled():
assert not self.item2.variations.filter(pk=self.var2.pk).exists()
def test_delete(self): def test_delete(self):
self.client.post('/control/event/%s/%s/items/%d/delete' % (self.orga1.slug, self.event1.slug, self.item1.id), self.client.post('/control/event/%s/%s/items/%d/delete' % (self.orga1.slug, self.event1.slug, self.item1.id),
{}) {})
assert not self.event1.items.filter(pk=self.item1.pk).exists() with scopes_disabled():
assert not self.event1.items.filter(pk=self.item1.pk).exists()
self.client.post('/control/event/%s/%s/items/%d/delete' % (self.orga1.slug, self.event1.slug, self.item2.id), self.client.post('/control/event/%s/%s/items/%d/delete' % (self.orga1.slug, self.event1.slug, self.item2.id),
{}) {})
assert not self.event1.items.filter(pk=self.item2.pk).exists() with scopes_disabled():
assert not self.event1.items.filter(pk=self.item2.pk).exists()
def test_delete_ordered(self): def test_delete_ordered(self):
o = Order.objects.create( with scopes_disabled():
code='FOO', event=self.event1, email='dummy@dummy.test', o = Order.objects.create(
status=Order.STATUS_PENDING, code='FOO', event=self.event1, email='dummy@dummy.test',
datetime=now(), expires=now() + datetime.timedelta(days=10), status=Order.STATUS_PENDING,
total=14, locale='en' datetime=now(), expires=now() + datetime.timedelta(days=10),
) total=14, locale='en'
OrderPosition.objects.create( )
order=o, OrderPosition.objects.create(
item=self.item1, order=o,
variation=None, item=self.item1,
price=Decimal("14"), variation=None,
attendee_name_parts={'full_name': "Peter"} price=Decimal("14"),
) attendee_name_parts={'full_name': "Peter"}
)
self.client.post('/control/event/%s/%s/items/%d/delete' % (self.orga1.slug, self.event1.slug, self.item1.id), self.client.post('/control/event/%s/%s/items/%d/delete' % (self.orga1.slug, self.event1.slug, self.item1.id),
{}) {})
assert self.event1.items.filter(pk=self.item1.pk).exists() with scopes_disabled():
assert self.event1.items.filter(pk=self.item1.pk).exists()
self.item1.refresh_from_db() self.item1.refresh_from_db()
assert not self.item1.active assert not self.item1.active
def test_create_copy(self): def test_create_copy(self):
q = Question.objects.create(event=self.event1, question="Size", type="N") with scopes_disabled():
q.items.add(self.item2) q = Question.objects.create(event=self.event1, question="Size", type="N")
q.items.add(self.item2)
self.item2.sales_channels = ["web", "bar"] self.item2.sales_channels = ["web", "bar"]
self.client.post('/control/event/%s/%s/items/add' % (self.orga1.slug, self.event1.slug), { self.client.post('/control/event/%s/%s/items/add' % (self.orga1.slug, self.event1.slug), {
@@ -533,22 +576,24 @@ class ItemsTest(ItemFormTest):
'copy_from': str(self.item2.pk), 'copy_from': str(self.item2.pk),
'has_variations': '1' 'has_variations': '1'
}) })
i_old = Item.objects.get(name__icontains='Business') with scopes_disabled():
i_new = Item.objects.get(name__icontains='Intermediate') i_old = Item.objects.get(name__icontains='Business')
assert i_new.category == i_old.category i_new = Item.objects.get(name__icontains='Intermediate')
assert i_new.description == i_old.description assert i_new.category == i_old.category
assert i_new.active == i_old.active assert i_new.description == i_old.description
assert i_new.available_from == i_old.available_from assert i_new.active == i_old.active
assert i_new.available_until == i_old.available_until assert i_new.available_from == i_old.available_from
assert i_new.require_voucher == i_old.require_voucher assert i_new.available_until == i_old.available_until
assert i_new.hide_without_voucher == i_old.hide_without_voucher assert i_new.require_voucher == i_old.require_voucher
assert i_new.allow_cancel == i_old.allow_cancel assert i_new.hide_without_voucher == i_old.hide_without_voucher
assert i_new.sales_channels == i_old.sales_channels assert i_new.allow_cancel == i_old.allow_cancel
assert set(i_new.questions.all()) == set(i_old.questions.all()) assert i_new.sales_channels == i_old.sales_channels
assert set([str(v.value) for v in i_new.variations.all()]) == set([str(v.value) for v in i_old.variations.all()]) assert set(i_new.questions.all()) == set(i_old.questions.all())
assert set([str(v.value) for v in i_new.variations.all()]) == set([str(v.value) for v in i_old.variations.all()])
def test_add_to_existing_quota(self): def test_add_to_existing_quota(self):
q = Quota.objects.create(event=self.event1, name="New Test Quota", size=50) with scopes_disabled():
q = Quota.objects.create(event=self.event1, name="New Test Quota", size=50)
doc = self.get_doc('/control/event/%s/%s/items/add' % (self.orga1.slug, self.event1.slug)) doc = self.get_doc('/control/event/%s/%s/items/add' % (self.orga1.slug, self.event1.slug))
form_data = extract_form_fields(doc.select('.container-fluid form')[0]) form_data = extract_form_fields(doc.select('.container-fluid form')[0])
@@ -558,10 +603,11 @@ class ItemsTest(ItemFormTest):
form_data['quota_add_existing'] = str(q.pk) form_data['quota_add_existing'] = str(q.pk)
doc = self.post_doc('/control/event/%s/%s/items/add' % (self.orga1.slug, self.event1.slug), form_data) doc = self.post_doc('/control/event/%s/%s/items/add' % (self.orga1.slug, self.event1.slug), form_data)
i = Item.objects.get(name__icontains='Existing') with scopes_disabled():
i = Item.objects.get(name__icontains='Existing')
assert doc.select(".alert-success") assert doc.select(".alert-success")
assert q.items.filter(pk=i.pk).exists() assert q.items.filter(pk=i.pk).exists()
def test_add_to_new_quota(self): def test_add_to_new_quota(self):
doc = self.get_doc('/control/event/%s/%s/items/add' % (self.orga1.slug, self.event1.slug)) doc = self.get_doc('/control/event/%s/%s/items/add' % (self.orga1.slug, self.event1.slug))
@@ -574,8 +620,9 @@ class ItemsTest(ItemFormTest):
doc = self.post_doc('/control/event/%s/%s/items/add' % (self.orga1.slug, self.event1.slug), form_data) doc = self.post_doc('/control/event/%s/%s/items/add' % (self.orga1.slug, self.event1.slug), form_data)
assert doc.select(".alert-success") assert doc.select(".alert-success")
assert Quota.objects.filter(name__icontains='New Quota').exists() with scopes_disabled():
assert Item.objects.filter(name__icontains='New Item').exists() assert Quota.objects.filter(name__icontains='New Quota').exists()
i = Item.objects.get(name__icontains='New Item') assert Item.objects.filter(name__icontains='New Item').exists()
q = Quota.objects.get(name__icontains='New Quota') i = Item.objects.get(name__icontains='New Item')
assert q.items.filter(pk=i.pk).exists() q = Quota.objects.get(name__icontains='New Quota')
assert q.items.filter(pk=i.pk).exists()

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +1,13 @@
import datetime import datetime
from django_scopes import scopes_disabled
from tests.base import SoupTest, extract_form_fields from tests.base import SoupTest, extract_form_fields
from pretix.base.models import Event, Organizer, Team, User from pretix.base.models import Event, Organizer, Team, User
class OrganizerTest(SoupTest): class OrganizerTest(SoupTest):
@scopes_disabled()
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy') self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy')

View File

@@ -2,6 +2,7 @@ import datetime
from decimal import Decimal from decimal import Decimal
from django.utils.timezone import now from django.utils.timezone import now
from django_scopes import scopes_disabled
from tests.base import SoupTest from tests.base import SoupTest
from pretix.base.models import ( from pretix.base.models import (
@@ -10,6 +11,7 @@ from pretix.base.models import (
class OrderSearchTest(SoupTest): class OrderSearchTest(SoupTest):
@scopes_disabled()
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy') self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
@@ -67,21 +69,21 @@ class OrderSearchTest(SoupTest):
self.client.login(email='dummy@dummy.dummy', password='dummy') self.client.login(email='dummy@dummy.dummy', password='dummy')
def test_team_limit_event(self): def test_team_limit_event(self):
resp = self.client.get('/control/search/orders/').rendered_content resp = self.client.get('/control/search/orders/').content.decode()
assert 'FO1' in resp assert 'FO1' in resp
assert 'FO2' not in resp assert 'FO2' not in resp
def test_team_limit_event_wrong_permission(self): def test_team_limit_event_wrong_permission(self):
self.team.can_view_orders = False self.team.can_view_orders = False
self.team.save() self.team.save()
resp = self.client.get('/control/search/orders/').rendered_content resp = self.client.get('/control/search/orders/').content.decode()
assert 'FO1' not in resp assert 'FO1' not in resp
assert 'FO2' not in resp assert 'FO2' not in resp
def test_team_all_events(self): def test_team_all_events(self):
self.team.all_events = True self.team.all_events = True
self.team.save() self.team.save()
resp = self.client.get('/control/search/orders/').rendered_content resp = self.client.get('/control/search/orders/').content.decode()
assert 'FO1' in resp assert 'FO1' in resp
assert 'FO2' in resp assert 'FO2' in resp
@@ -89,13 +91,13 @@ class OrderSearchTest(SoupTest):
self.team.all_events = True self.team.all_events = True
self.team.can_view_orders = False self.team.can_view_orders = False
self.team.save() self.team.save()
resp = self.client.get('/control/search/orders/').rendered_content resp = self.client.get('/control/search/orders/').content.decode()
assert 'FO1' not in resp assert 'FO1' not in resp
assert 'FO2' not in resp assert 'FO2' not in resp
def test_team_none(self): def test_team_none(self):
self.team.members.clear() self.team.members.clear()
resp = self.client.get('/control/search/orders/').rendered_content resp = self.client.get('/control/search/orders/').content.decode()
assert 'FO1' not in resp assert 'FO1' not in resp
assert 'FO2' not in resp assert 'FO2' not in resp
@@ -104,44 +106,44 @@ class OrderSearchTest(SoupTest):
self.user.staffsession_set.create(date_start=now(), session_key=self.client.session.session_key) self.user.staffsession_set.create(date_start=now(), session_key=self.client.session.session_key)
self.user.save() self.user.save()
self.team.members.clear() self.team.members.clear()
resp = self.client.get('/control/search/orders/').rendered_content resp = self.client.get('/control/search/orders/').content.decode()
assert 'FO1' in resp assert 'FO1' in resp
assert 'FO2' in resp assert 'FO2' in resp
def test_filter_email(self): def test_filter_email(self):
resp = self.client.get('/control/search/orders/?query=dummy1@dummy').rendered_content resp = self.client.get('/control/search/orders/?query=dummy1@dummy').content.decode()
assert 'FO1' in resp assert 'FO1' in resp
resp = self.client.get('/control/search/orders/?query=dummynope').rendered_content resp = self.client.get('/control/search/orders/?query=dummynope').content.decode()
assert 'FO1' not in resp assert 'FO1' not in resp
def test_filter_attendee_name(self): def test_filter_attendee_name(self):
resp = self.client.get('/control/search/orders/?query=Pete').rendered_content resp = self.client.get('/control/search/orders/?query=Pete').content.decode()
assert 'FO1' in resp assert 'FO1' in resp
resp = self.client.get('/control/search/orders/?query=Mark').rendered_content resp = self.client.get('/control/search/orders/?query=Mark').content.decode()
assert 'FO1' not in resp assert 'FO1' not in resp
def test_filter_attendee_email(self): def test_filter_attendee_email(self):
resp = self.client.get('/control/search/orders/?query=att.com').rendered_content resp = self.client.get('/control/search/orders/?query=att.com').content.decode()
assert 'FO1' in resp assert 'FO1' in resp
resp = self.client.get('/control/search/orders/?query=nope.com').rendered_content resp = self.client.get('/control/search/orders/?query=nope.com').content.decode()
assert 'FO1' not in resp assert 'FO1' not in resp
def test_filter_invoice_address(self): def test_filter_invoice_address(self):
resp = self.client.get('/control/search/orders/?query=Ltd').rendered_content resp = self.client.get('/control/search/orders/?query=Ltd').content.decode()
assert 'FO1' in resp assert 'FO1' in resp
resp = self.client.get('/control/search/orders/?query=Miller').rendered_content resp = self.client.get('/control/search/orders/?query=Miller').content.decode()
assert 'FO1' in resp assert 'FO1' in resp
def test_filter_code(self): def test_filter_code(self):
resp = self.client.get('/control/search/orders/?query=FO1').rendered_content resp = self.client.get('/control/search/orders/?query=FO1').content.decode()
assert '30C3-FO1' in resp assert '30C3-FO1' in resp
resp = self.client.get('/control/search/orders/?query=30c3-FO1').rendered_content resp = self.client.get('/control/search/orders/?query=30c3-FO1').content.decode()
assert '30C3-FO1' in resp assert '30C3-FO1' in resp
resp = self.client.get('/control/search/orders/?query=30C3-fO1A').rendered_content resp = self.client.get('/control/search/orders/?query=30C3-fO1A').content.decode()
assert '30C3-FO1' in resp assert '30C3-FO1' in resp
resp = self.client.get('/control/search/orders/?query=30C3-fo14').rendered_content resp = self.client.get('/control/search/orders/?query=30C3-fo14').content.decode()
assert '30C3-FO1' in resp assert '30C3-FO1' in resp
resp = self.client.get('/control/search/orders/?query=31c3-FO1').rendered_content resp = self.client.get('/control/search/orders/?query=31c3-FO1').content.decode()
assert '30C3-FO1' not in resp assert '30C3-FO1' not in resp
resp = self.client.get('/control/search/orders/?query=FO2').rendered_content resp = self.client.get('/control/search/orders/?query=FO2').content.decode()
assert '30C3-FO1' not in resp assert '30C3-FO1' not in resp

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