diff --git a/doc/development/concepts.rst b/doc/development/concepts.rst index 1baf608229..ca3548b7dc 100644 --- a/doc/development/concepts.rst +++ b/doc/development/concepts.rst @@ -28,9 +28,9 @@ Users and events Pretix is all about **events**, which are defined as something happening somewhere. Every event is managed by the **organizer**, an abstract entity running the event. -Pretix is used by **users**. We want to enable global users who can just login into -pretix and buy tickets for as many events as they like but at the same time it -should be possible to order products **without** needing an user account. +Pretix has a concept of **users** that is used for all the people who have to log +in to the control panel to manage one or more events. No user is required to place an +order. Items and variations diff --git a/src/pretix/base/migrations/0019_auto_20151004_1233.py b/src/pretix/base/migrations/0019_auto_20151004_1233.py new file mode 100644 index 0000000000..c4cc680df2 --- /dev/null +++ b/src/pretix/base/migrations/0019_auto_20151004_1233.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('pretixbase', '0018_eventlock_token'), + ] + + operations = [ + migrations.RenameField( + model_name='order', + old_name='guest_email', + new_name='email', + ), + migrations.RenameField( + model_name='order', + old_name='guest_locale', + new_name='locale', + ), + migrations.RemoveField( + model_name='cartposition', + name='user', + ), + migrations.RemoveField( + model_name='order', + name='user', + ), + ] diff --git a/src/pretix/base/models.py b/src/pretix/base/models.py index 5093742d35..a606f94047 100644 --- a/src/pretix/base/models.py +++ b/src/pretix/base/models.py @@ -1366,7 +1366,7 @@ class Quota(Versionable): def generate_secret(): - return ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(32)) + return ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(16)) class Order(Versionable): @@ -1393,8 +1393,10 @@ class Order(Versionable): :param event: The event this belongs to :type event: Event - :param user: The user who ordered this - :type user: User + :param email: The email of the person who ordered this + :type email: str + :param locale: The locale of this order + :type locale: str :param datetime: The datetime of the order placement :type datetime: datetime :param expires: The date until this order has to be paid to guarantee the @@ -1438,16 +1440,11 @@ class Order(Versionable): verbose_name=_("Event"), related_name="orders" ) - user = models.ForeignKey( - User, null=True, blank=True, - verbose_name=_("User"), - related_name="orders" - ) - guest_email = models.EmailField( + email = models.EmailField( null=True, blank=True, verbose_name=_('E-mail') ) - guest_locale = models.CharField( + locale = models.CharField( null=True, blank=True, max_length=32, verbose_name=_('Locale') ) @@ -1592,18 +1589,6 @@ class Order(Versionable): return str(e) return True - @property - def locale(self): - if self.user: - return self.user.locale - return self.guest_locale - - @property - def email(self): - if self.user: - return self.user.email - return self.guest_email - class CachedTicket(models.Model): order = VersionedForeignKey(Order, on_delete=models.CASCADE) @@ -1736,8 +1721,8 @@ class CartPosition(ObjectWithAnswers, Versionable): :type event: Evnt :param item: The selected item :type item: Item - :param user: The user who has this in his cart - :type user: User + :param session: The user session that contains this cart position + :type session: str :param variation: The selected ItemVariation or null, if the item has no properties :type variation: ItemVariation :param datetime: The datetime this item was put into the cart @@ -1753,10 +1738,6 @@ class CartPosition(ObjectWithAnswers, Versionable): Event, verbose_name=_("Event") ) - user = models.ForeignKey( - User, null=True, blank=True, - verbose_name=_("User") - ) session = models.CharField( max_length=255, null=True, blank=True, verbose_name=_("Session") diff --git a/src/pretix/base/payment.py b/src/pretix/base/payment.py index d8c410aa95..7477b42264 100644 --- a/src/pretix/base/payment.py +++ b/src/pretix/base/payment.py @@ -10,10 +10,9 @@ from django.http import HttpRequest from django.template.loader import get_template from django.utils.translation import ugettext_lazy as _ -from pretix.base.models import CartPosition, Order +from pretix.base.models import CartPosition, Order, Quota from pretix.base.settings import SettingsSandbox from pretix.base.signals import register_payment_providers -from pretix.presale.views import user_cart_q class BasePaymentProvider: @@ -411,7 +410,10 @@ class FreeOrderProvider(BasePaymentProvider): def payment_perform(self, request: HttpRequest, order: Order): from pretix.base.services.orders import mark_order_paid - mark_order_paid(order, 'free') + try: + mark_order_paid(order, 'free') + except Quota.QuotaExceededException as e: + messages.error(request, str(e)) @property def settings_form_fields(self) -> dict: @@ -442,7 +444,7 @@ class FreeOrderProvider(BasePaymentProvider): def is_allowed(self, request: HttpRequest) -> bool: return CartPosition.objects.current.filter( - user_cart_q(request) & Q(event=request.event) + session=request.session.session_key, event=request.event ).aggregate(sum=Sum('price'))['sum'] == 0 diff --git a/src/pretix/base/services/cart.py b/src/pretix/base/services/cart.py index a42947a503..bd854e55ec 100644 --- a/src/pretix/base/services/cart.py +++ b/src/pretix/base/services/cart.py @@ -5,7 +5,7 @@ from django.utils.timezone import now from django.utils.translation import ugettext_lazy as _ from pretix.base.models import ( - CartPosition, Event, EventLock, Item, ItemVariation, Quota, User, + CartPosition, Event, EventLock, Item, ItemVariation, Quota, ) @@ -28,27 +28,21 @@ error_messages = { } -def _user_cart_q(user=None, guest_session=None): - if user and user.is_authenticated(): - return Q(Q(user=user) | Q(session=guest_session)) - return Q(Q(user__isnull=True) & Q(session=guest_session)) - - -def _extend_existing(event, user, guest_session, expiry): +def _extend_existing(event, session, expiry): # Extend this user's cart session to 30 minutes from now to ensure all items in the # cart expire at the same time # We can extend the reservation of items which are not yet expired without risk CartPosition.objects.current.filter( - _user_cart_q(user, guest_session) & Q(event=event) & Q(expires__gt=now()) + Q(session=session) & Q(event=event) & Q(expires__gt=now()) ).update(expires=expiry) -def _re_add_expired_positions(items, event, user, guest_session): +def _re_add_expired_positions(items, event, session): positions = set() # For items that are already expired, we have to delete and re-add them, as they might # be no longer available or prices might have changed. Sorry! expired = CartPosition.objects.current.filter( - _user_cart_q(user, guest_session) & Q(event=event) & Q(expires__lte=now()) + Q(session=session) & Q(event=event) & Q(expires__lte=now()) ) for cp in expired: items.insert(0, (cp.item_id, cp.variation_id, 1, cp)) @@ -69,7 +63,7 @@ def _check_date(event): raise CartError(error_messages['ended']) -def _add_items(event, items, user, guest_session, expiry): +def _add_items(event, items, session, expiry): err = None # Fetch items from the database @@ -129,40 +123,36 @@ def _add_items(event, items, user, guest_session, expiry): else: CartPosition.objects.create( event=event, item=item, variation=variation, price=price, expires=expiry, - user=user if user and user.is_authenticated() else None, - session=guest_session if not user or not user.is_authenticated() else None + session=session ) return err -def add_items_to_cart(event: str, items: list, user: int=None, guest_session: str=None): +def add_items_to_cart(event: str, items: list, session: str=None): """ - Adds a list of items to a user's or a guest's cart. + Adds a list of items to a user's cart. :param event: The event ID in question :param items: A list of tuple of the form (item id, variation id or None, number) - :param user: User ID - :param guest_session: Session ID of a guest + :param session: Session ID of a guest :raises CartError: On any error that occured """ - if user: - user = User.objects.get(id=user) event = Event.objects.current.get(identity=event) try: with event.lock(): _check_date(event) - existing = CartPosition.objects.current.filter(_user_cart_q(user, guest_session) & Q(event=event)).count() + existing = CartPosition.objects.current.filter(Q(session=session) & Q(event=event)).count() if sum(i[2] for i in items) + existing > int(event.settings.max_items_per_order): # TODO: i18n plurals raise CartError(error_messages['max_items'] % event.settings.max_items_per_order) expiry = now() + timedelta(minutes=event.settings.get('reservation_time', as_type=int)) - _extend_existing(event, user, guest_session, expiry) + _extend_existing(event, session, expiry) - expired = _re_add_expired_positions(items, event, user, guest_session) + expired = _re_add_expired_positions(items, event, session) if not items: raise CartError(error_messages['empty']) - err = _add_items(event, items, user, guest_session, expiry) + err = _add_items(event, items, session, expiry) _delete_expired(expired) if err: raise CartError(err) @@ -170,20 +160,17 @@ def add_items_to_cart(event: str, items: list, user: int=None, guest_session: st raise CartError(error_messages['busy']) -def remove_items_from_cart(event: str, items: list, user: int=None, guest_session: str=None): +def remove_items_from_cart(event: str, items: list, session: str=None): """ - Removes a list of items from a user's or a guest's cart. + Removes a list of items from a user's cart. :param event: The event ID in question :param items: A list of tuple of the form (item id, variation id or None, number) - :param user: User ID - :param guest_session: Session ID of a guest + :param session: Session ID of a guest """ - if user: - user = User.objects.get(id=user) event = Event.objects.current.get(identity=event) for item, variation, cnt in items: - cw = _user_cart_q(user, guest_session) & Q(item_id=item) & Q(event=event) + cw = Q(session=session) & Q(item_id=item) & Q(event=event) if variation: cw &= Q(variation_id=variation) else: diff --git a/src/pretix/base/services/mail.py b/src/pretix/base/services/mail.py index b5337df535..a91471279b 100644 --- a/src/pretix/base/services/mail.py +++ b/src/pretix/base/services/mail.py @@ -17,7 +17,7 @@ def mail(email: str, subject: str, template: str, context: dict=None, event: Eve """ Sends out an email to a user. - :param user: The user this should be sent to. + :param email: The e-mail this should be sent to. :param subject: The e-mail subject. Should be localized. :param template: The filename of a template to be used. It will be rendered with the recipient's locale. Alternatively, you @@ -31,7 +31,8 @@ def mail(email: str, subject: str, template: str, context: dict=None, event: Eve backend. """ _lng = translation.get_language() - translation.activate(locale or settings.LANGUAGE_CODE) + if locale: + translation.activate(locale or settings.LANGUAGE_CODE) if isinstance(template, LazyI18nString): body = str(template) @@ -52,17 +53,6 @@ def mail(email: str, subject: str, template: str, context: dict=None, event: Eve "You are receiving this e-mail because you placed an order for %s." % event.name ) body += "\r\n" - body += _( - "You can view all of your orders at the following URL:" - ) - body += "\r\n" - body += build_absolute_uri( - 'presale:event.orders', kwargs={ - 'event': event.slug, - 'organizer': event.organizer.slug - } - ) - body += "\r\n" try: return mail_send([email], subject, body, sender) finally: diff --git a/src/pretix/base/services/orders.py b/src/pretix/base/services/orders.py index c4838f5107..011da66025 100644 --- a/src/pretix/base/services/orders.py +++ b/src/pretix/base/services/orders.py @@ -67,7 +67,8 @@ def mark_order_paid(order: Order, provider: str=None, info: str=None, date: date 'event': order.event.slug, 'organizer': order.event.organizer.slug, 'order': order.code, - }) + '?order_secret=' + order.secret, + 'secret': order.secret + }), 'downloads': order.event.settings.get('ticket_download', as_type=bool) }, order.event, locale=order.locale @@ -131,14 +132,14 @@ def check_positions(event: Event, dt: datetime, positions: list): raise OrderError(err) -def perform_order(event: Event, payment_provider: BasePaymentProvider, positions: list, user: User=None, +def perform_order(event: Event, payment_provider: BasePaymentProvider, positions: list, email: str=None, locale: str=None): dt = now() try: with event.lock(): check_positions(event, dt, positions) - order = place_order(event, user, email if user is None else None, positions, dt, payment_provider, + order = place_order(event, email, positions, dt, payment_provider, locale=locale) mail( order.email, _('Your order: %(code)s') % {'code': order.code}, @@ -150,7 +151,8 @@ def perform_order(event: Event, payment_provider: BasePaymentProvider, positions 'event': event.slug, 'organizer': event.organizer.slug, 'order': order.code, - }) + '?order_secret=' + order.secret, + 'secret': order.secret + }), 'payment': payment_provider.order_pending_mail_render(order) }, event, locale=order.locale @@ -163,7 +165,7 @@ def perform_order(event: Event, payment_provider: BasePaymentProvider, positions @transaction.atomic() -def place_order(event: Event, user: User, email: str, positions: list, dt: datetime, +def place_order(event: Event, email: str, positions: list, dt: datetime, payment_provider: BasePaymentProvider, locale: str=None): total = sum([c.price for c in positions]) payment_fee = payment_provider.calculate_fee(total) @@ -174,8 +176,7 @@ def place_order(event: Event, user: User, email: str, positions: list, dt: datet order = Order.objects.create( status=Order.STATUS_PENDING, event=event, - user=user, - guest_email=email, + email=email, datetime=dt, expires=min(expires), locale=locale, diff --git a/src/pretix/control/templates/pretixcontrol/order/index.html b/src/pretix/control/templates/pretixcontrol/order/index.html index b36f78a8df..f8abebc276 100644 --- a/src/pretix/control/templates/pretixcontrol/order/index.html +++ b/src/pretix/control/templates/pretixcontrol/order/index.html @@ -67,7 +67,7 @@
{{ order.expires }}
{% endif %}
{% trans "User" %}
-
{{ order.user|default:order.guest_email }}
+
{{ order.email }}
diff --git a/src/pretix/control/templates/pretixcontrol/orders/index.html b/src/pretix/control/templates/pretixcontrol/orders/index.html index 468e69077c..f619bbbe4d 100644 --- a/src/pretix/control/templates/pretixcontrol/orders/index.html +++ b/src/pretix/control/templates/pretixcontrol/orders/index.html @@ -52,7 +52,7 @@ {{ o.code }} - {{ o.user.get_short_name }} + {{ o.email }} {{ o.total|floatformat:2 }} {{ request.event.currency }} {{ o.datetime|date:"SHORT_DATETIME_FORMAT" }} {% include "pretixcontrol/orders/fragment_order_status.html" with order=o %} diff --git a/src/pretix/control/views/orders.py b/src/pretix/control/views/orders.py index d9f97e917e..8e92cd145c 100644 --- a/src/pretix/control/views/orders.py +++ b/src/pretix/control/views/orders.py @@ -41,7 +41,7 @@ class OrderList(EventPermissionRequiredMixin, ListView): if self.request.GET.get("user", "") != "": u = self.request.GET.get("user", "") qs = qs.filter( - Q(user__email__icontains=u) | Q(user__givenname__icontains=u) | Q(user__familyname__icontains=u) + Q(email__icontains=u) ) if self.request.GET.get("status", "") != "": s = self.request.GET.get("status", "") @@ -49,7 +49,7 @@ class OrderList(EventPermissionRequiredMixin, ListView): if self.request.GET.get("item", "") != "": i = self.request.GET.get("item", "") qs = qs.filter(positions__item_id__in=(i,)).distinct() - return qs.select_related("user") + return qs def get_context_data(self, **kwargs): ctx = super().get_context_data(**kwargs) diff --git a/src/pretix/presale/middleware.py b/src/pretix/presale/middleware.py index 219c9f6146..02576b54df 100644 --- a/src/pretix/presale/middleware.py +++ b/src/pretix/presale/middleware.py @@ -13,17 +13,6 @@ class EventMiddleware: if url_namespace != 'presale': return - if 'order_secrets' not in request.session: - request.session['order_secrets'] = [] - if 'order_secret' in request.GET and request.GET.get('order_secret') not in request.session['order_secrets']: - # We can't use append here, because this would not trigger __setitem__ - # on the session store and would not be saved - request.session['order_secrets'] = request.session['order_secrets'] + [request.GET.get('order_secret')] - # Removal of the secret from the URL has been disabled so people can bookmark it - # g = request.GET.copy() - # del g['order_secret'] - # return redirect(request.path + '?' + g.urlencode()) - if 'event.' in url_name and 'event' in url.kwargs: try: request.event = Event.objects.current.filter( @@ -32,3 +21,8 @@ class EventMiddleware: ).select_related('organizer')[0] except IndexError: raise Http404(_('The selected event was not found.')) + + if '_' not in request.session: + # We need to create session even if we do not yet store something there, because we need the session + # key for e.g. saving the user's cart + request.session['_'] = '_' diff --git a/src/pretix/presale/templates/pretixpresale/event/account.html b/src/pretix/presale/templates/pretixpresale/event/account.html deleted file mode 100644 index 85e9c41bb9..0000000000 --- a/src/pretix/presale/templates/pretixpresale/event/account.html +++ /dev/null @@ -1,58 +0,0 @@ -{% extends "pretixpresale/event/base.html" %} -{% load i18n %} -{% block title %}{% trans "Your account" %}{% endblock %} - -{% block content %} -

{% trans "Welcome back!" %}

-
-
- {% if orders %} - -
-
-
-
- -
-
-
{% trans "Your orders" %}
-
-
-
-
-
- {% else %} - -
-
-
-
- -
-
-
{% trans "Place new order" %}
-
-
-
-
-
- {% endif %} -
-
- -
-
-
-
- -
-
-
{% trans "Your settings" %}
-
-
-
-
-
-
-
-{% endblock %} \ No newline at end of file diff --git a/src/pretix/presale/templates/pretixpresale/event/account_settings.html b/src/pretix/presale/templates/pretixpresale/event/account_settings.html deleted file mode 100644 index d7107f17da..0000000000 --- a/src/pretix/presale/templates/pretixpresale/event/account_settings.html +++ /dev/null @@ -1,33 +0,0 @@ -{% extends "pretixpresale/event/base.html" %} -{% load i18n %} -{% load bootstrap3 %} -{% block title %}{% trans "Account settings" %}{% endblock %} - -{% block content %} -

{% trans "Account settings" %}

-
- {% csrf_token %} - {% bootstrap_form_errors form %} -
- {% trans "General settings" %} - {% bootstrap_field form.givenname layout='horizontal' %} - {% bootstrap_field form.familyname layout='horizontal' %} - {% bootstrap_field form.locale layout='horizontal' %} -
-
- {% trans "Login settings" %} - {% bootstrap_field form.old_pw layout='horizontal' %} - {% bootstrap_field form.email layout='horizontal' %} - {% bootstrap_field form.new_pw layout='horizontal' %} - {% bootstrap_field form.new_pw_repeat layout='horizontal' %} -
-
-
- -
-
-
-
-{% endblock %} diff --git a/src/pretix/presale/templates/pretixpresale/event/base.html b/src/pretix/presale/templates/pretixpresale/event/base.html index a9e1b00dbc..a14e060d67 100644 --- a/src/pretix/presale/templates/pretixpresale/event/base.html +++ b/src/pretix/presale/templates/pretixpresale/event/base.html @@ -36,18 +36,6 @@ {% endfor %} · {% endif %} - {% if request.user.is_authenticated %} - {% blocktrans trimmed with name=request.user.get_short_name %} - Hello, {{ name }}! - {% endblocktrans %} · - - {% trans "Your account" %} · - - {% trans "Logout" %} - {% else %} - - {% trans "Login" %} - {% endif %}
diff --git a/src/pretix/presale/templates/pretixpresale/event/forgot.html b/src/pretix/presale/templates/pretixpresale/event/forgot.html deleted file mode 100644 index 87d0ac24d9..0000000000 --- a/src/pretix/presale/templates/pretixpresale/event/forgot.html +++ /dev/null @@ -1,20 +0,0 @@ -{% extends "pretixpresale/event/base.html" %} -{% load i18n %} -{% load bootstrap3 %} -{% block title %}{% trans "Password recovery" %}{% endblock %} -{% block content %} -

{% trans "Password recovery" %}

-
- {% csrf_token %} - {% bootstrap_form_errors form type='all' layout='inline' %} - {% bootstrap_field form.email layout="horizontal" %} - -
-
- -
-
-
-{% endblock %} diff --git a/src/pretix/presale/templates/pretixpresale/event/login.html b/src/pretix/presale/templates/pretixpresale/event/login.html deleted file mode 100644 index bc2115e67b..0000000000 --- a/src/pretix/presale/templates/pretixpresale/event/login.html +++ /dev/null @@ -1,99 +0,0 @@ -{% extends "pretixpresale/event/base.html" %} -{% load i18n %} -{% load bootstrap3 %} -{% block title %}{% trans "Login" %}{% endblock %} -{% block content %} -

{% trans "Login" %}

-

{% trans "You need to login or register to continue" %}

-
-
- - -
- {% if "guest" in request.GET %} -
- - -
- {% endif %} -
- - -
-
-{% endblock %} diff --git a/src/pretix/presale/templates/pretixpresale/event/order.html b/src/pretix/presale/templates/pretixpresale/event/order.html index 25f80f2b6b..08bd7e0ebd 100644 --- a/src/pretix/presale/templates/pretixpresale/event/order.html +++ b/src/pretix/presale/templates/pretixpresale/event/order.html @@ -27,7 +27,7 @@
{% if can_retry %} - {% trans "Complete payment" %} {% endif %} {{ payment }} @@ -52,7 +52,7 @@ {% endblocktrans %}

{% for b in download_buttons %} - {{ b.text }} @@ -69,7 +69,7 @@
{% if order.can_modify_answers %}
- + {% trans "Change details" %} @@ -87,7 +87,7 @@

- {% trans "Cancel order" %} diff --git a/src/pretix/presale/templates/pretixpresale/event/order_cancel.html b/src/pretix/presale/templates/pretixpresale/event/order_cancel.html index 8a0aafc38a..08ef4fb956 100644 --- a/src/pretix/presale/templates/pretixpresale/event/order_cancel.html +++ b/src/pretix/presale/templates/pretixpresale/event/order_cancel.html @@ -16,7 +16,7 @@

diff --git a/src/pretix/presale/templates/pretixpresale/event/order_pay.html b/src/pretix/presale/templates/pretixpresale/event/order_pay.html index dccb519dd8..c489f2ed32 100644 --- a/src/pretix/presale/templates/pretixpresale/event/order_pay.html +++ b/src/pretix/presale/templates/pretixpresale/event/order_pay.html @@ -16,7 +16,7 @@
diff --git a/src/pretix/presale/templates/pretixpresale/event/order_pay_confirm.html b/src/pretix/presale/templates/pretixpresale/event/order_pay_confirm.html index c5427ebbd3..8992bf2abd 100644 --- a/src/pretix/presale/templates/pretixpresale/event/order_pay_confirm.html +++ b/src/pretix/presale/templates/pretixpresale/event/order_pay_confirm.html @@ -27,7 +27,7 @@
diff --git a/src/pretix/presale/templates/pretixpresale/event/orders.html b/src/pretix/presale/templates/pretixpresale/event/orders.html deleted file mode 100644 index 4fc0ac4a5f..0000000000 --- a/src/pretix/presale/templates/pretixpresale/event/orders.html +++ /dev/null @@ -1,43 +0,0 @@ -{% extends "pretixpresale/event/base.html" %} -{% load i18n %} -{% block title %}{% trans "Your orders" %}{% endblock %} - -{% block content %} -

{% trans "Your orders" %}

-
- - - - - - - - - - {% for order in orders %} - - - - - - - - {% empty %} - - - - {% endfor %} - -
{% trans "Order code" %}{% trans "Date" %}{% trans "Total" %}{% trans "Status" %}
- {{ order.code }}{{ order.datetime|date:"SHORT_DATE_FORMAT" }}{{ event.currency }} {{ order.total|floatformat:2 }}{% include "pretixpresale/event/fragment_order_status.html" with order=order %} - {% trans "View details" %} -
- {% trans "You did not yet place any orders." %} -
-
- - - {% trans "Place new order" %} - -{% endblock %} \ No newline at end of file diff --git a/src/pretix/presale/templates/pretixpresale/event/recover.html b/src/pretix/presale/templates/pretixpresale/event/recover.html deleted file mode 100644 index 8749c21b09..0000000000 --- a/src/pretix/presale/templates/pretixpresale/event/recover.html +++ /dev/null @@ -1,21 +0,0 @@ -{% extends "pretixpresale/event/base.html" %} -{% load i18n %} -{% load bootstrap3 %} -{% block title %}{% trans "Password recovery" %}{% endblock %} -{% block content %} -

{% trans "Password recovery" %}

-
- {% csrf_token %} - {% bootstrap_form_errors form type='all' layout='inline' %} - {% bootstrap_field form.password layout="horizontal" %} - {% bootstrap_field form.password_repeat layout="horizontal" %} - -
-
- -
-
-
-{% endblock %} diff --git a/src/pretix/presale/urls.py b/src/pretix/presale/urls.py index dbc6481169..73dc43e18a 100644 --- a/src/pretix/presale/urls.py +++ b/src/pretix/presale/urls.py @@ -16,25 +16,22 @@ urlpatterns = [ name='event.checkout.payment'), url(r'^checkout/confirm$', pretix.presale.views.checkout.OrderConfirm.as_view(), name='event.checkout.confirm'), - url(r'^order/(?P[^/]+)/$', pretix.presale.views.order.OrderDetails.as_view(), + url(r'^order/(?P[^/]+)/(?P[A-Za-z0-9]+)/$', pretix.presale.views.order.OrderDetails.as_view(), name='event.order'), - url(r'^order/(?P[^/]+)/cancel$', pretix.presale.views.order.OrderCancel.as_view(), + url(r'^order/(?P[^/]+)/(?P[A-Za-z0-9]+)/cancel$', + pretix.presale.views.order.OrderCancel.as_view(), name='event.order.cancel'), - url(r'^order/(?P[^/]+)/modify$', pretix.presale.views.order.OrderModify.as_view(), + url(r'^order/(?P[^/]+)/(?P[A-Za-z0-9]+)/modify$', + pretix.presale.views.order.OrderModify.as_view(), name='event.order.modify'), - url(r'^order/(?P[^/]+)/pay$', pretix.presale.views.order.OrderPay.as_view(), + url(r'^order/(?P[^/]+)/(?P[A-Za-z0-9]+)/pay$', pretix.presale.views.order.OrderPay.as_view(), name='event.order.pay'), - url(r'^order/(?P[^/]+)/pay/confirm$', pretix.presale.views.order.OrderPayDo.as_view(), + url(r'^order/(?P[^/]+)/(?P[A-Za-z0-9]+)/pay/confirm$', + pretix.presale.views.order.OrderPayDo.as_view(), name='event.order.pay.confirm'), - url(r'^order/(?P[^/]+)/download/(?P[^/]+)$', pretix.presale.views.order.OrderDownload.as_view(), + url(r'^order/(?P[^/]+)/(?P[A-Za-z0-9]+)/download/(?P[^/]+)$', + pretix.presale.views.order.OrderDownload.as_view(), name='event.order.download'), - url(r'^login$', pretix.presale.views.event.EventLogin.as_view(), name='event.checkout.login'), - url(r'^forgot$', pretix.presale.views.event.EventForgot.as_view(), name='event.forgot'), - url(r'^forgot/recover$', pretix.presale.views.event.EventRecover.as_view(), name='event.forgot.recover'), - url(r'^logout$', pretix.presale.views.event.EventLogout.as_view(), name='event.logout'), - url(r'^orders$', pretix.presale.views.event.EventOrders.as_view(), name='event.orders'), - url(r'^account$', pretix.presale.views.event.EventAccount.as_view(), name='event.account'), - url(r'^account/settings$', pretix.presale.views.event.EventAccountSettings.as_view(), name='event.account.settings'), ])), url(r'^locale/set$', pretix.presale.views.locale.LocaleSet.as_view(), name='locale.set'), ] diff --git a/src/pretix/presale/views/__init__.py b/src/pretix/presale/views/__init__.py index d4c3a7e89f..b9d24d0e75 100644 --- a/src/pretix/presale/views/__init__.py +++ b/src/pretix/presale/views/__init__.py @@ -22,20 +22,7 @@ def login_required(view_func): 'event': request.event.slug, }), 'next' ) - return _wrapped_view - -def login_or_guest_required(view_func): - def _wrapped_view(request, *args, **kwargs): - if request.user.is_authenticated() or 'guest_email' in request.session: - return view_func(request, *args, **kwargs) - path = request.path - return redirect_to_login( - path, reverse('presale:event.checkout.login', kwargs={ - 'organizer': request.event.organizer.slug, - 'event': request.event.slug, - }) + '?guest=1', 'next' - ) return _wrapped_view @@ -46,28 +33,14 @@ class LoginRequiredMixin: return login_required(view) -class LoginOrGuestRequiredMixin: - @classmethod - def as_view(cls, **initkwargs): - view = super().as_view(**initkwargs) - return login_or_guest_required(view) - - -def user_cart_q(request): - if request.user.is_authenticated(): - return Q(Q(user=request.user) | Q(session=request.session.session_key)) - return Q(Q(user__isnull=True) & Q(session=request.session.session_key)) - - class CartDisplayMixin: - @cached_property def positions(self): """ A list of this users cart position """ return list(CartPosition.objects.current.filter( - user_cart_q(self.request) & Q(event=self.request.event) + session=self.request.session.session_key, event=self.request.event ).order_by( 'item', 'variation' ).select_related( @@ -79,7 +52,7 @@ class CartDisplayMixin: def get_cart(self, answers=False, queryset=None, payment_fee=None): queryset = queryset or CartPosition.objects.current.filter( - user_cart_q(self.request) & Q(event=self.request.event) + session=self.request.session.session_key, event=self.request.event ) prefetch = ['variation__values', 'variation__values__prop'] diff --git a/src/pretix/presale/views/cart.py b/src/pretix/presale/views/cart.py index 56b325b027..cd9f40d30c 100644 --- a/src/pretix/presale/views/cart.py +++ b/src/pretix/presale/views/cart.py @@ -1,24 +1,16 @@ import json -from datetime import timedelta from django.contrib import messages from django.contrib.auth.views import redirect_to_login from django.core.urlresolvers import reverse -from django.db.models import Q from django.shortcuts import redirect -from django.utils.timezone import now from django.utils.translation import ugettext_lazy as _ from django.views.generic import View -from pretix.base.models import ( - CartPosition, EventLock, Item, ItemVariation, Quota, -) from pretix.base.services.cart import ( CartError, add_items_to_cart, remove_items_from_cart, ) -from pretix.presale.views import ( - EventViewMixin, LoginOrGuestRequiredMixin, user_cart_q, -) +from pretix.presale.views import EventViewMixin class CartActionMixin: @@ -67,15 +59,14 @@ class CartActionMixin: return items -class CartRemove(EventViewMixin, CartActionMixin, LoginOrGuestRequiredMixin, View): +class CartRemove(EventViewMixin, CartActionMixin, View): def post(self, *args, **kwargs): items = self._items_from_post_data() if not items: return redirect(self.get_failure_url()) - remove_items_from_cart(self.request.event.identity, items, self.request.user.id, - self.request.session.session_key) + remove_items_from_cart(self.request.event.identity, items, self.request.session.session_key) messages.success(self.request, _('Your cart has been updated.')) return redirect(self.get_success_url()) @@ -87,24 +78,11 @@ class CartAdd(EventViewMixin, CartActionMixin, View): def post(self, request, *args, **kwargs): items = self._items_from_post_data() - - # We do not use LoginRequiredMixin here, as we want to store stuff into the - # session before redirecting to login - if not request.user.is_authenticated() and 'guest_email' not in request.session: - request.session['cart_tmp'] = json.dumps(items) - return redirect_to_login( - self.get_success_url(), reverse('presale:event.checkout.login', kwargs={ - 'organizer': request.event.organizer.slug, - 'event': request.event.slug, - }) + '?guest=1', 'next' - ) - return self.process(items) def process(self, items): try: - add_items_to_cart(self.request.event.identity, items, self.request.user.id, - self.request.session.session_key) + add_items_to_cart(self.request.event.identity, items, self.request.session.session_key) messages.success(self.request, _('The products have been successfully added to your cart.')) return redirect(self.get_success_url()) except CartError as e: diff --git a/src/pretix/presale/views/checkout.py b/src/pretix/presale/views/checkout.py index ef0aaa2dc5..db842c7f0c 100644 --- a/src/pretix/presale/views/checkout.py +++ b/src/pretix/presale/views/checkout.py @@ -12,9 +12,7 @@ from pretix.base.models import CartPosition, OrderPosition, QuestionAnswer from pretix.base.services.orders import OrderError, perform_order from pretix.base.signals import register_payment_providers from pretix.presale.forms.checkout import QuestionsForm -from pretix.presale.views import ( - CartDisplayMixin, EventViewMixin, LoginOrGuestRequiredMixin, user_cart_q, -) +from pretix.presale.views import CartDisplayMixin, EventViewMixin class CheckoutView(TemplateView): @@ -43,12 +41,13 @@ class CheckoutView(TemplateView): 'organizer': self.request.event.organizer.slug }) - def get_order_url(self, order, add_secret): + def get_order_url(self, order): return reverse('presale:event.order', kwargs={ 'event': self.request.event.slug, 'organizer': self.request.event.organizer.slug, 'order': order.code, - }) + '?thanks=yes' + ('&order_secret=' + order.secret if add_secret else '') + 'secret': order.secret + }) + '?thanks=yes' class QuestionsViewMixin: @@ -108,8 +107,7 @@ class QuestionsViewMixin: return not failed -class CheckoutStart(EventViewMixin, CartDisplayMixin, LoginOrGuestRequiredMixin, - QuestionsViewMixin, CheckoutView): +class CheckoutStart(EventViewMixin, CartDisplayMixin, QuestionsViewMixin, CheckoutView): template_name = "pretixpresale/event/checkout_questions.html" def post(self, *args, **kwargs): @@ -140,13 +138,13 @@ class CheckoutStart(EventViewMixin, CartDisplayMixin, LoginOrGuestRequiredMixin, return ctx -class PaymentDetails(EventViewMixin, CartDisplayMixin, LoginOrGuestRequiredMixin, CheckoutView): +class PaymentDetails(EventViewMixin, CartDisplayMixin, CheckoutView): template_name = "pretixpresale/event/checkout_payment.html" @cached_property def _total_order_value(self): return CartPosition.objects.current.filter( - user_cart_q(self.request) & Q(event=self.request.event) + Q(session=self.request.session.session_key) & Q(event=self.request.event) ).aggregate(sum=Sum('price'))['sum'] @cached_property @@ -196,7 +194,7 @@ class PaymentDetails(EventViewMixin, CartDisplayMixin, LoginOrGuestRequiredMixin return self.get_questions_url() + "?back=true" -class OrderConfirm(EventViewMixin, CartDisplayMixin, LoginOrGuestRequiredMixin, CheckoutView): +class OrderConfirm(EventViewMixin, CartDisplayMixin, CheckoutView): template_name = "pretixpresale/event/checkout_confirm.html" def __init__(self, *args, **kwargs): @@ -259,7 +257,6 @@ class OrderConfirm(EventViewMixin, CartDisplayMixin, LoginOrGuestRequiredMixin, def perform_order(self, request: HttpRequest): try: order = perform_order(self.request.event, self.payment_provider, self.positions, - user=request.user if request.user.is_authenticated() else None, email=request.session.get('guest_email', None), locale=translation.get_language()) except OrderError as e: @@ -269,7 +266,7 @@ class OrderConfirm(EventViewMixin, CartDisplayMixin, LoginOrGuestRequiredMixin, # Message is delivered via GET parameter # messages.success(request, _('Your order has been placed.')) resp = self.payment_provider.payment_perform(request, order) - return redirect(resp or self.get_order_url(order, not request.user.is_authenticated())) + return redirect(resp or self.get_order_url(order)) def get_previous_url(self): if self.payment_provider.identifier != "free": diff --git a/src/pretix/presale/views/event.py b/src/pretix/presale/views/event.py index cc45cab43f..8649b2535f 100644 --- a/src/pretix/presale/views/event.py +++ b/src/pretix/presale/views/event.py @@ -1,30 +1,7 @@ -import json - -from django.conf import settings -from django.contrib import messages -from django.contrib.auth import ( - authenticate, login, logout, update_session_auth_hash, -) -from django.contrib.auth.tokens import default_token_generator -from django.core.urlresolvers import reverse from django.db.models import Count -from django.shortcuts import redirect -from django.utils.functional import cached_property -from django.utils.translation import ugettext_lazy as _ -from django.views.generic import TemplateView, UpdateView, View +from django.views.generic import TemplateView -from pretix.base.forms.auth import ( - LoginForm, PasswordForgotForm, PasswordRecoverForm, RegistrationForm, -) -from pretix.base.forms.user import UserSettingsForm -from pretix.base.models import User -from pretix.base.services.cart import CartError, add_items_to_cart -from pretix.base.services.mail import mail -from pretix.helpers.urls import build_absolute_uri -from pretix.presale.forms.checkout import GuestForm -from pretix.presale.views import ( - CartDisplayMixin, EventViewMixin, LoginRequiredMixin, -) +from pretix.presale.views import CartDisplayMixin, EventViewMixin class EventIndex(EventViewMixin, CartDisplayMixin, TemplateView): @@ -80,239 +57,3 @@ class EventIndex(EventViewMixin, CartDisplayMixin, TemplateView): context['cart'] = self.get_cart() return context - - -class EventLogin(EventViewMixin, TemplateView): - template_name = 'pretixpresale/event/login.html' - - def redirect_to_next(self): - if 'cart_tmp' in self.request.session: - items = json.loads(self.request.session['cart_tmp']) - del self.request.session['cart_tmp'] - try: - add_items_to_cart(self.request.event.identity, items, self.request.user.id, - self.request.session.session_key) - messages.success(self.request, _('The products have been successfully added to your cart.')) - except CartError as e: - messages.error(self.request, str(e)) - if 'next' in self.request.GET: - return redirect(self.request.GET.get('next')) - else: - return redirect('presale:event.account', - organizer=self.request.event.organizer.slug, - event=self.request.event.slug) - - def get(self, request, *args, **kwargs): - if request.user.is_authenticated(): - return self.redirect_to_next() - return super().get(request, *args, **kwargs) - - def post(self, request, *args, **kwargs): - if request.POST.get('form') == 'login': - form = self.login_form - if form.is_valid() and form.user_cache: - login(request, form.user_cache) - return self.redirect_to_next() - elif request.POST.get('form') == 'guest': - form = self.guest_form - if form.is_valid(): - request.session['guest_email'] = form.cleaned_data['email'] - return self.redirect_to_next() - elif request.POST.get('form') == 'registration': - form = self.registration_form - if form.is_valid(): - user = User.objects.create_user( - form.cleaned_data['email'], form.cleaned_data['password'], - locale=request.LANGUAGE_CODE, - timezone=request.timezone if hasattr(request, 'timezone') else settings.TIME_ZONE - ) - user = authenticate(email=user.email, password=form.cleaned_data['password']) - login(request, user) - return self.redirect_to_next() - return super().get(request, *args, **kwargs) - - @cached_property - def login_form(self): - return LoginForm( - self.request, - data=self.request.POST if self.request.POST.get('form', '') == 'login' else None - ) - - @cached_property - def guest_form(self): - return GuestForm( - data=self.request.POST if self.request.POST.get('form', '') == 'guest' else None - ) - - @cached_property - def registration_form(self): - return RegistrationForm( - data=self.request.POST if self.request.POST.get('form', '') == 'registration' else None - ) - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - context['login_form'] = self.login_form - context['registration_form'] = self.registration_form - context['guest_form'] = self.guest_form - return context - - -class EventForgot(EventViewMixin, TemplateView): - template_name = 'pretixpresale/event/forgot.html' - - def get(self, request, *args, **kwargs): - if request.user.is_authenticated(): - return redirect('presale:event.orders', - organizer=self.request.event.organizer.slug, - event=self.request.event.slug) - return super().get(request, *args, **kwargs) - - def post(self, request, *args, **kwargs): - if self.form.is_valid(): - user = self.form.cleaned_data['user'] - mail( - user.email, _('Password recovery'), 'pretixpresale/email/forgot.txt', - { - 'user': user, - 'event': self.request.event, - 'url': build_absolute_uri('presale:event.forgot.recover', kwargs={ - 'event': self.request.event.slug, - 'organizer': self.request.event.organizer.slug, - }) + '?id=%d&token=%s' % (user.id, default_token_generator.make_token(user)), - }, - self.request.event, locale=user.locale - ) - messages.success(request, _('We sent you an e-mail containing further instructions.')) - return redirect('presale:event.forgot', - organizer=self.request.event.organizer.slug, - event=self.request.event.slug) - else: - return self.get(request, *args, **kwargs) - - @cached_property - def form(self): - return PasswordForgotForm( - event=self.request.event, - data=self.request.POST if self.request.method == 'POST' else None - ) - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - context['form'] = self.form - return context - - -class EventRecover(EventViewMixin, TemplateView): - template_name = 'pretixpresale/event/recover.html' - - error_messages = { - 'invalid': _('You clicked on an invalid link. Please check that you copied the full ' - 'web address into your address bar. Please note that the link is only valid ' - 'for three days and that the link can only be used once.'), - 'unknownuser': _('We were unable to find the user you requested a new password for.') - } - - def get(self, request, *args, **kwargs): - if request.user.is_authenticated(): - return redirect('presale:event.orders', - organizer=self.request.event.organizer.slug, - event=self.request.event.slug) - try: - user = User.objects.get(id=self.request.GET.get('id')) - except User.DoesNotExist: - return self.invalid('unknownuser') - if not default_token_generator.check_token(user, self.request.GET.get('token')): - return self.invalid('invalid') - return super().get(request, *args, **kwargs) - - def invalid(self, msg): - messages.error(self.request, self.error_messages[msg]) - return redirect('presale:event.forgot', - organizer=self.request.event.organizer.slug, - event=self.request.event.slug) - - def post(self, request, *args, **kwargs): - if self.form.is_valid(): - try: - user = User.objects.get(id=self.request.GET.get('id')) - except User.DoesNotExist: - return self.invalid('unknownuser') - if not default_token_generator.check_token(user, self.request.GET.get('token')): - return self.invalid('invalid') - user.set_password(self.form.cleaned_data['password']) - user.save() - messages.success(request, _('You can now login using your new password.')) - return redirect('presale:event.checkout.login', - organizer=self.request.event.organizer.slug, - event=self.request.event.slug) - else: - return self.get(request, *args, **kwargs) - - @cached_property - def form(self): - return PasswordRecoverForm( - data=self.request.POST if self.request.method == 'POST' else None - ) - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - context['form'] = self.form - return context - - -class EventLogout(EventViewMixin, View): - def get(self, request, *args, **kwargs): - logout(request) - return redirect('presale:event.index', - organizer=self.request.event.organizer.slug, - event=self.request.event.slug) - - -class EventAccount(LoginRequiredMixin, EventViewMixin, TemplateView): - template_name = 'pretixpresale/event/account.html' - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - context['orders'] = self.request.user.orders.current.count() - return context - - -class EventOrders(LoginRequiredMixin, EventViewMixin, TemplateView): - template_name = 'pretixpresale/event/orders.html' - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - context['orders'] = self.request.user.orders.current.all() - return context - - -class EventAccountSettings(LoginRequiredMixin, EventViewMixin, UpdateView): - model = User - form_class = UserSettingsForm - template_name = 'pretixpresale/event/account_settings.html' - - def get_object(self, queryset=None): - return self.request.user - - def get_form_kwargs(self): - kwargs = super().get_form_kwargs() - kwargs['user'] = self.request.user - return kwargs - - def form_invalid(self, form): - messages.error(self.request, _('Your changes could not be saved. See below for details.')) - return super().form_invalid(form) - - def form_valid(self, form): - messages.success(self.request, _('Your changes have been saved.')) - sup = super().form_valid(form) - update_session_auth_hash(self.request, self.request.user) - return sup - - def get_success_url(self): - return reverse('presale:event.account.settings', - kwargs={ - 'event': self.request.event.slug, - 'organizer': self.request.event.organizer.slug, - }) diff --git a/src/pretix/presale/views/order.py b/src/pretix/presale/views/order.py index 31c1f1f5f5..d6026f9fb8 100644 --- a/src/pretix/presale/views/order.py +++ b/src/pretix/presale/views/order.py @@ -23,10 +23,8 @@ class OrderDetailMixin: @cached_property def order(self): try: - q = Q(Q(secret__isnull=False) & Q(secret__in=self.request.session['order_secrets'])) - if self.request.user.is_authenticated(): - q |= Q(user=self.request.user) - return Order.objects.current.get(q & Q(event=self.request.event) & Q(code=self.kwargs['order'])) + return Order.objects.current.get(secret=self.kwargs['secret'], + event=self.request.event, code=self.kwargs['order']) except Order.DoesNotExist: return None @@ -43,6 +41,7 @@ class OrderDetailMixin: 'event': self.request.event.slug, 'organizer': self.request.event.organizer.slug, 'order': self.order.code, + 'secret': self.order.secret }) @@ -52,7 +51,7 @@ class OrderDetails(EventViewMixin, OrderDetailMixin, CartDisplayMixin, TemplateV def get(self, request, *args, **kwargs): self.kwargs = kwargs if not self.order: - raise Http404(_('Unknown order code or order does belong to another user.')) + raise Http404(_('Unknown order code or not authorized to access this order.')) return super().get(request, *args, **kwargs) @cached_property @@ -104,7 +103,7 @@ class OrderPay(EventViewMixin, OrderDetailMixin, TemplateView): def dispatch(self, request, *args, **kwargs): self.request = request if not self.order: - raise Http404(_('Unknown order code or order does belong to another user.')) + raise Http404(_('Unknown order code or not authorized to access this order.')) if (self.order.status not in (Order.STATUS_PENDING, Order.STATUS_EXPIRED) or not self.payment_provider.order_can_retry(self.order) or not self.payment_provider.is_enabled): @@ -138,6 +137,7 @@ class OrderPay(EventViewMixin, OrderDetailMixin, TemplateView): 'event': self.request.event.slug, 'organizer': self.request.event.organizer.slug, 'order': self.order.code, + 'secret': self.order.secret }) @@ -147,7 +147,7 @@ class OrderPayDo(EventViewMixin, OrderDetailMixin, TemplateView): def dispatch(self, request, *args, **kwargs): self.request = request if not self.order: - raise Http404(_('Unknown order code or order does belong to another user.')) + raise Http404(_('Unknown order code or not authorized to access this order.')) if not self.payment_provider.order_can_retry(self.order) or not self.payment_provider.is_enabled: messages.error(request, _('The payment for this order cannot be continued.')) return redirect(self.get_order_url()) @@ -178,6 +178,7 @@ class OrderPayDo(EventViewMixin, OrderDetailMixin, TemplateView): 'event': self.request.event.slug, 'organizer': self.request.event.organizer.slug, 'order': self.order.code, + 'secret': self.order.secret }) @@ -210,7 +211,7 @@ class OrderModify(EventViewMixin, OrderDetailMixin, QuestionsViewMixin, Template self.request = request self.kwargs = kwargs if not self.order: - raise Http404(request, _('Unknown order code or order does belong to another user.')) + raise Http404(_('Unknown order code or not authorized to access this order.')) if not self.order.can_modify_answers: messages.error(request, _('You cannot modify this order')) return redirect(self.get_order_url()) @@ -230,7 +231,7 @@ class OrderCancel(EventViewMixin, OrderDetailMixin, TemplateView): self.request = request self.kwargs = kwargs if not self.order: - raise Http404(_('Unknown order code or order does belong to another user.')) + raise Http404(_('Unknown order code or not authorized to access this order.')) if self.order.status not in (Order.STATUS_PENDING, Order.STATUS_EXPIRED): messages.error(request, _('You cannot cancel this order')) return redirect(self.get_order_url()) @@ -265,7 +266,7 @@ class OrderDownload(EventViewMixin, OrderDetailMixin, View): messages.error(request, _('You requested an invalid ticket output type.')) return redirect(self.get_order_url()) if not self.order: - raise Http404(_('Unknown order code or order does belong to another user.')) + raise Http404(_('Unknown order code or not authorized to access this order.')) if self.order.status != Order.STATUS_PAID: messages.error(request, _('Order is not paid.')) return redirect(self.get_order_url()) diff --git a/src/tests/base/test_models.py b/src/tests/base/test_models.py index e9fffafc84..ec66f30fec 100644 --- a/src/tests/base/test_models.py +++ b/src/tests/base/test_models.py @@ -308,7 +308,7 @@ class OrderTestCase(BaseQuotaTestCase): self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy') self.order = Order.objects.create( status=Order.STATUS_PENDING, event=self.event, - user=self.user, datetime=now() - timedelta(days=5), + datetime=now() - timedelta(days=5), expires=now() + timedelta(days=5), total=46 ) self.quota.items.add(self.item1) diff --git a/src/tests/base/test_orders.py b/src/tests/base/test_orders.py index 9d01cb0468..78e0cd4704 100644 --- a/src/tests/base/test_orders.py +++ b/src/tests/base/test_orders.py @@ -22,7 +22,7 @@ def event(): def test_expiry_days(event): today = now() event.settings.set('payment_term_days', 5) - order = place_order(event, user=None, email='dummy@example.org', positions=[], + order = place_order(event, email='dummy@example.org', positions=[], dt=today, payment_provider=FreeOrderProvider(event), locale='de') assert (order.expires - today).days == 5 @@ -33,12 +33,12 @@ def test_expiry_last(event): today = now() event.settings.set('payment_term_days', 5) event.settings.set('payment_term_last', now() + timedelta(days=3)) - order = place_order(event, user=None, email='dummy@example.org', positions=[], + order = place_order(event, email='dummy@example.org', positions=[], dt=today, payment_provider=FreeOrderProvider(event), locale='de') assert (order.expires - today).days == 3 event.settings.set('payment_term_last', now() + timedelta(days=7)) - order = place_order(event, user=None, email='dummy@example.org', positions=[], + order = place_order(event, email='dummy@example.org', positions=[], dt=today, payment_provider=FreeOrderProvider(event), locale='de') assert (order.expires - today).days == 5 diff --git a/src/tests/control/test_orders.py b/src/tests/control/test_orders.py index 0c5fa32a96..93797ea917 100644 --- a/src/tests/control/test_orders.py +++ b/src/tests/control/test_orders.py @@ -25,8 +25,8 @@ def env(): can_change_orders=True ) o = Order.objects.create( - code='FOO', event=event, - user=user, status=Order.STATUS_PENDING, + code='FOO', event=event, email='dummy@dummy.test', + status=Order.STATUS_PENDING, datetime=now(), expires=now() + timedelta(days=10), total=0, payment_provider='banktransfer' ) diff --git a/src/tests/control/test_permissions.py b/src/tests/control/test_permissions.py index d65e31f62e..ad46626579 100644 --- a/src/tests/control/test_permissions.py +++ b/src/tests/control/test_permissions.py @@ -18,7 +18,7 @@ def env(): user = User.objects.create_user('dummy@dummy.dummy', 'dummy') Order.objects.create( code='FOO', event=event, - user=user, status=Order.STATUS_PENDING, + status=Order.STATUS_PENDING, datetime=now(), expires=now() + timedelta(days=10), total=0, payment_provider='banktransfer' ) diff --git a/src/tests/plugins/banktransfer/test_import.py b/src/tests/plugins/banktransfer/test_import.py index bf4eb8f9cc..23a750d20a 100644 --- a/src/tests/plugins/banktransfer/test_import.py +++ b/src/tests/plugins/banktransfer/test_import.py @@ -21,13 +21,13 @@ def env(): EventPermission.objects.create(user=user, event=event) o1 = Order.objects.create( code='1234S', event=event, - user=user, status=Order.STATUS_PENDING, + status=Order.STATUS_PENDING, datetime=now(), expires=now() + timedelta(days=10), total=23, payment_provider='banktransfer' ) o2 = Order.objects.create( code='6789Z', event=event, - user=user, status=Order.STATUS_CANCELLED, + status=Order.STATUS_CANCELLED, datetime=now(), expires=now() + timedelta(days=10), total=23, payment_provider='banktransfer' ) diff --git a/src/tests/plugins/test_pretixdroid.py b/src/tests/plugins/test_pretixdroid.py index 4621412fc2..4ba742bf01 100644 --- a/src/tests/plugins/test_pretixdroid.py +++ b/src/tests/plugins/test_pretixdroid.py @@ -30,8 +30,7 @@ def env(): var2.values.add(val2) ticket = Item.objects.create(event=event, name='Ticket', default_price=23) o1 = Order.objects.create( - code='FOO', event=event, - user=user, status=Order.STATUS_PENDING, + code='FOO', event=event, status=Order.STATUS_PENDING, datetime=now(), expires=now() + timedelta(days=10), total=0, payment_provider='banktransfer' ) diff --git a/src/tests/presale/test_account.py b/src/tests/presale/test_account.py deleted file mode 100644 index 93f135375b..0000000000 --- a/src/tests/presale/test_account.py +++ /dev/null @@ -1,91 +0,0 @@ -import time - -from tests.base import BrowserTest -from tests.presale.test_event import EventTestMixin - -from pretix.base.models import User - - -class UserSettingsTest(EventTestMixin, BrowserTest): - def setUp(self): - super().setUp() - self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy') - self.driver.implicitly_wait(10) - self.driver.get('%s/%s/%s/login' % (self.live_server_url, self.orga.slug, self.event.slug)) - # open the login accordion - self.scroll_and_click(self.driver.find_element_by_css_selector('a[href*=loginForm]')) - time.sleep(1) - # enter login details - self.driver.find_element_by_css_selector('#loginForm input[name=email]').send_keys('dummy@dummy.dummy') - self.driver.find_element_by_css_selector('#loginForm input[name=password]').send_keys('dummy') - self.scroll_and_click(self.driver.find_element_by_css_selector('#loginForm button.btn-primary')) - self.driver.find_element_by_partial_link_text('Your account') - self.driver.get('%s/%s/%s/account/settings' % (self.live_server_url, self.orga.slug, self.event.slug)) - - def test_set_name(self): - self.driver.find_element_by_name("givenname").clear() - self.driver.find_element_by_name("familyname").clear() - self.driver.find_element_by_name("givenname").send_keys("Peter") - self.driver.find_element_by_name("familyname").send_keys("Miller") - self.scroll_and_click(self.driver.find_element_by_class_name('btn-save')) - self.driver.find_element_by_class_name("alert-success") - self.user = User.objects.get(pk=self.user.pk) - assert self.user.givenname == 'Peter' - assert self.user.familyname == 'Miller' - - def test_change_email_require_password(self): - self.driver.find_element_by_name("email").clear() - self.driver.find_element_by_name("email").send_keys("foo@example.com") - self.scroll_and_click(self.driver.find_element_by_class_name('btn-save')) - self.driver.find_element_by_class_name("alert-danger") - self.user = User.objects.get(pk=self.user.pk) - assert self.user.email == 'dummy@dummy.dummy' - - def test_change_email_success(self): - self.driver.find_element_by_name("email").clear() - self.driver.find_element_by_name("email").send_keys("foo@example.com") - self.driver.find_element_by_name("old_pw").clear() - self.driver.find_element_by_name("old_pw").send_keys("dummy") - self.scroll_and_click(self.driver.find_element_by_class_name('btn-save')) - self.driver.find_element_by_class_name("alert-success") - self.user = User.objects.get(pk=self.user.pk) - assert self.user.email == 'foo@example.com' - - def test_change_email_no_duplicates(self): - User.objects.create_user('foo@example.com', 'foo') - self.driver.find_element_by_name("email").clear() - self.driver.find_element_by_name("email").send_keys("foo@example.com") - self.driver.find_element_by_name("old_pw").clear() - self.driver.find_element_by_name("old_pw").send_keys("dummy") - self.scroll_and_click(self.driver.find_element_by_class_name('btn-save')) - self.driver.find_element_by_class_name("alert-danger") - self.user = User.objects.get(pk=self.user.pk) - assert self.user.email == 'dummy@dummy.dummy' - - def test_change_password_require_password(self): - self.driver.find_element_by_name("new_pw").send_keys("foo") - self.driver.find_element_by_name("new_pw_repeat").send_keys("foo") - self.scroll_and_click(self.driver.find_element_by_class_name('btn-save')) - self.driver.find_element_by_class_name("alert-danger") - pw = self.user.password - self.user = User.objects.get(pk=self.user.pk) - assert self.user.password == pw - - def test_change_password_success(self): - self.driver.find_element_by_name("new_pw").send_keys("foo") - self.driver.find_element_by_name("new_pw_repeat").send_keys("foo") - self.driver.find_element_by_name("old_pw").send_keys("dummy") - self.scroll_and_click(self.driver.find_element_by_class_name('btn-save')) - self.driver.find_element_by_class_name("alert-success") - self.user = User.objects.get(pk=self.user.pk) - assert self.user.check_password("foo") - - def test_change_password_require_repeat(self): - self.driver.find_element_by_name("new_pw").send_keys("foo") - self.driver.find_element_by_name("new_pw_repeat").send_keys("bar") - self.driver.find_element_by_name("old_pw").send_keys("dummy") - self.scroll_and_click(self.driver.find_element_by_class_name('btn-save')) - self.driver.find_element_by_class_name("alert-danger") - pw = self.user.password - self.user = User.objects.get(pk=self.user.pk) - assert self.user.password == pw diff --git a/src/tests/presale/test_cart.py b/src/tests/presale/test_cart.py index f75ca7aa05..ec37dd287f 100644 --- a/src/tests/presale/test_cart.py +++ b/src/tests/presale/test_cart.py @@ -3,6 +3,7 @@ import time from datetime import timedelta from bs4 import BeautifulSoup +from django.conf import settings from django.test import TestCase from django.utils.timezone import now from tests.base import BrowserTest @@ -14,7 +15,6 @@ from pretix.base.models import ( class CartTestMixin: - def setUp(self): super().setUp() self.orga = Organizer.objects.create(name='CCC', slug='ccc') @@ -22,7 +22,6 @@ class CartTestMixin: organizer=self.orga, name='30C3', slug='30c3', date_from=datetime.datetime(2013, 12, 26, tzinfo=datetime.timezone.utc) ) - self.user = User.objects.create_user('dummy@dummy.dummy', 'demo') self.category = ItemCategory.objects.create(event=self.event, name="Everything", position=0) self.quota_shirts = Quota.objects.create(event=self.event, name='Shirts', size=2) self.shirt = Item.objects.create(event=self.event, name='T-Shirt', category=self.category, default_price=12) @@ -42,72 +41,11 @@ class CartTestMixin: category=self.category, default_price=23) self.quota_tickets.items.add(self.ticket) - -class CartBrowserTest(CartTestMixin, BrowserTest): - - def test_not_logged_in(self): - self.driver.get('%s/%s/%s/' % (self.live_server_url, self.orga.slug, self.event.slug)) - # add the entry ticket to cart - self.driver.find_element_by_css_selector('input[type=number][name=item_%s]' % self.ticket.identity).send_keys('1') - self.scroll_and_click(self.driver.find_element_by_css_selector('.checkout-button-row button')) - # should redirect to login page - self.driver.find_element_by_name('email') - - def test_simple_login(self): - self.driver.get('%s/%s/%s/' % (self.live_server_url, self.orga.slug, self.event.slug)) - # add the entry ticket to cart - self.driver.find_element_by_css_selector('input[type=number][name=item_%s]' % self.ticket.identity).send_keys('1') - self.scroll_and_click(self.driver.find_element_by_css_selector('.checkout-button-row button')) - # should redirect to login page - # open the login accordion - self.scroll_and_click(self.driver.find_element_by_css_selector('a[href*=loginForm]')) - time.sleep(1) - # enter login details - self.driver.find_element_by_css_selector('#loginForm input[name=email]').send_keys('dummy@dummy.dummy') - self.driver.find_element_by_css_selector('#loginForm input[name=password]').send_keys('demo') - self.scroll_and_click(self.driver.find_element_by_css_selector('#loginForm button.btn-primary')) - # should display our ticket - self.assertIn('Early-bird', self.driver.find_element_by_css_selector('.cart-row:first-child').text) - - def test_simple_login_as_guest(self): - self.driver.get('%s/%s/%s/' % (self.live_server_url, self.orga.slug, self.event.slug)) - # add the entry ticket to cart - self.driver.find_element_by_css_selector('input[type=number][name=item_%s]' % self.ticket.identity).send_keys('1') - self.scroll_and_click(self.driver.find_element_by_css_selector('.checkout-button-row button')) - # should redirect to login page - # open the login accordion - self.scroll_and_click(self.driver.find_element_by_css_selector('a[href*=guestForm]')) - time.sleep(1) - # enter login details - self.driver.find_element_by_css_selector('#guestForm input[name=email]').send_keys('dummy@dummy.dummy') - self.scroll_and_click(self.driver.find_element_by_css_selector('#guestForm button.btn-primary')) - # should display our ticket - self.assertIn('Early-bird', self.driver.find_element_by_css_selector('.cart-row:first-child').text) - - def test_registration(self): - self.driver.get('%s/%s/%s/' % (self.live_server_url, self.orga.slug, self.event.slug)) - # add the entry ticket to cart - self.driver.find_element_by_css_selector('input[type=number][name=item_%s]' % self.ticket.identity).send_keys('1') - self.scroll_and_click(self.driver.find_element_by_css_selector('.checkout-button-row button')) - # should redirect to login page - # open the login accordion - self.scroll_and_click(self.driver.find_element_by_css_selector('a[href*=registrationForm]')) - time.sleep(1) - # enter login details - self.driver.find_element_by_css_selector('#registrationForm input[name=email]').send_keys('demo@example.com') - self.driver.find_element_by_css_selector('#registrationForm input[name=password]').send_keys('demo') - self.driver.find_element_by_css_selector('#registrationForm input[name=password_repeat]').send_keys('demo') - self.scroll_and_click(self.driver.find_element_by_css_selector('#registrationForm button.btn-primary')) - # should display our ticket - self.assertIn('Early-bird', self.driver.find_element_by_css_selector('.cart-row:first-child').text) + self.client.get('/%s/%s/' % (self.orga.slug, self.event.slug)) + self.session_key = self.client.cookies.get(settings.SESSION_COOKIE_NAME).value class CartTest(CartTestMixin, TestCase): - - def setUp(self): - super().setUp() - self.assertTrue(self.client.login(email='dummy@dummy.dummy', password='demo')) - def test_simple(self): response = self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), { 'item_' + self.ticket.identity: '1' @@ -119,7 +57,7 @@ class CartTest(CartTestMixin, TestCase): self.assertIn('1', doc.select('.cart .cart-row')[0].select('.count')[0].text) self.assertIn('23', doc.select('.cart .cart-row')[0].select('.price')[0].text) self.assertIn('23', doc.select('.cart .cart-row')[0].select('.price')[1].text) - objs = list(CartPosition.objects.filter(user=self.user, event=self.event)) + objs = list(CartPosition.objects.filter(session=self.session_key, event=self.event)) self.assertEqual(len(objs), 1) self.assertEqual(objs[0].item, self.ticket) self.assertIsNone(objs[0].variation) @@ -137,7 +75,7 @@ class CartTest(CartTestMixin, TestCase): self.assertIn('1', doc.select('.cart .cart-row')[0].select('.count')[0].text) self.assertIn('14', doc.select('.cart .cart-row')[0].select('.price')[0].text) self.assertIn('14', doc.select('.cart .cart-row')[0].select('.price')[1].text) - objs = list(CartPosition.objects.filter(user=self.user, event=self.event)) + objs = list(CartPosition.objects.filter(session=self.session_key, event=self.event)) self.assertEqual(len(objs), 1) self.assertEqual(objs[0].item, self.shirt) self.assertEqual(objs[0].variation, self.shirt_red) @@ -154,7 +92,7 @@ class CartTest(CartTestMixin, TestCase): self.assertIn('2', doc.select('.cart .cart-row')[0].select('.count')[0].text) self.assertIn('23', doc.select('.cart .cart-row')[0].select('.price')[0].text) self.assertIn('46', doc.select('.cart .cart-row')[0].select('.price')[1].text) - objs = list(CartPosition.objects.filter(user=self.user, event=self.event)) + objs = list(CartPosition.objects.filter(session=self.session_key, event=self.event)) self.assertEqual(len(objs), 2) for obj in objs: self.assertEqual(obj.item, self.ticket) @@ -171,7 +109,7 @@ class CartTest(CartTestMixin, TestCase): doc = BeautifulSoup(response.rendered_content) self.assertIn('Early-bird', doc.select('.cart')[0].text) self.assertIn('Shirt', doc.select('.cart')[0].text) - objs = list(CartPosition.objects.filter(user=self.user, event=self.event)) + objs = list(CartPosition.objects.filter(session=self.session_key, event=self.event)) self.assertEqual(len(objs), 3) self.assertIn(self.shirt, [obj.item for obj in objs]) self.assertIn(self.shirt_red, [obj.variation for obj in objs]) @@ -185,7 +123,7 @@ class CartTest(CartTestMixin, TestCase): target_status_code=200) doc = BeautifulSoup(response.rendered_content) self.assertIn('numbers only', doc.select('.alert-danger')[0].text) - self.assertFalse(CartPosition.objects.filter(user=self.user, event=self.event).exists()) + self.assertFalse(CartPosition.objects.filter(session=self.session_key, event=self.event).exists()) response = self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), { }, follow=True) @@ -193,7 +131,7 @@ class CartTest(CartTestMixin, TestCase): target_status_code=200) doc = BeautifulSoup(response.rendered_content) self.assertIn('did not select any products', doc.select('.alert-warning')[0].text) - self.assertFalse(CartPosition.objects.filter(user=self.user, event=self.event).exists()) + self.assertFalse(CartPosition.objects.filter(session=self.session_key, event=self.event).exists()) def test_wrong_event(self): event2 = Event.objects.create( @@ -208,7 +146,7 @@ class CartTest(CartTestMixin, TestCase): target_status_code=200) doc = BeautifulSoup(response.rendered_content) self.assertIn('not available', doc.select('.alert-danger')[0].text) - self.assertFalse(CartPosition.objects.filter(user=self.user, event=self.event).exists()) + self.assertFalse(CartPosition.objects.filter(session=self.session_key, event=self.event).exists()) def test_no_quota(self): shirt2 = Item.objects.create(event=self.event, name='T-Shirt', default_price=12) @@ -219,11 +157,11 @@ class CartTest(CartTestMixin, TestCase): target_status_code=200) doc = BeautifulSoup(response.rendered_content) self.assertIn('no longer available', doc.select('.alert-danger')[0].text) - self.assertFalse(CartPosition.objects.filter(user=self.user, event=self.event).exists()) + self.assertFalse(CartPosition.objects.filter(session=self.session_key, event=self.event).exists()) def test_max_items(self): CartPosition.objects.create( - event=self.event, user=self.user, item=self.ticket, + event=self.event, session=self.session_key, item=self.ticket, price=23, expires=now() + timedelta(minutes=10) ) self.event.settings.max_items_per_order = 5 @@ -234,7 +172,7 @@ class CartTest(CartTestMixin, TestCase): target_status_code=200) doc = BeautifulSoup(response.rendered_content) self.assertIn('more than', doc.select('.alert-danger')[0].text) - self.assertEqual(CartPosition.objects.filter(user=self.user, event=self.event).count(), 1) + self.assertEqual(CartPosition.objects.filter(session=self.session_key, event=self.event).count(), 1) def test_quota_full(self): self.quota_tickets.size = 0 @@ -246,7 +184,7 @@ class CartTest(CartTestMixin, TestCase): target_status_code=200) doc = BeautifulSoup(response.rendered_content) self.assertIn('no longer available', doc.select('.alert-danger')[0].text) - self.assertFalse(CartPosition.objects.filter(user=self.user, event=self.event).exists()) + self.assertFalse(CartPosition.objects.filter(session=self.session_key, event=self.event).exists()) def test_quota_partly(self): self.quota_tickets.size = 1 @@ -262,7 +200,7 @@ class CartTest(CartTestMixin, TestCase): self.assertIn('1', doc.select('.cart .cart-row')[0].select('.count')[0].text) self.assertIn('23', doc.select('.cart .cart-row')[0].select('.price')[0].text) self.assertIn('23', doc.select('.cart .cart-row')[0].select('.price')[1].text) - objs = list(CartPosition.objects.filter(user=self.user, event=self.event)) + objs = list(CartPosition.objects.filter(session=self.session_key, event=self.event)) self.assertEqual(len(objs), 1) self.assertEqual(objs[0].item, self.ticket) self.assertIsNone(objs[0].variation) @@ -270,7 +208,7 @@ class CartTest(CartTestMixin, TestCase): def test_renew_in_time(self): cp = CartPosition.objects.create( - event=self.event, user=self.user, item=self.ticket, + event=self.event, session=self.session_key, item=self.ticket, price=23, expires=now() + timedelta(minutes=10) ) self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), { @@ -280,12 +218,12 @@ class CartTest(CartTestMixin, TestCase): def test_renew_expired_successfully(self): CartPosition.objects.create( - event=self.event, user=self.user, item=self.ticket, + event=self.event, session=self.session_key, item=self.ticket, price=23, expires=now() - timedelta(minutes=10) ) self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), { }, follow=True) - objs = list(CartPosition.objects.current.filter(user=self.user, event=self.event)) + objs = list(CartPosition.objects.current.filter(session=self.session_key, event=self.event)) self.assertEqual(len(objs), 1) self.assertEqual(objs[0].item, self.ticket) self.assertIsNone(objs[0].variation) @@ -297,7 +235,7 @@ class CartTest(CartTestMixin, TestCase): Currently fails. See: https://github.com/pretix/pretix/issues/20 """ cr1 = CartPosition.objects.create( - event=self.event, user=self.user, item=self.ticket, + event=self.event, session=self.session_key, item=self.ticket, price=23, expires=now() - timedelta(minutes=10) ) q1 = Question.objects.create( @@ -310,7 +248,7 @@ class CartTest(CartTestMixin, TestCase): )) self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), { }, follow=True) - objs = list(CartPosition.objects.current.filter(user=self.user, event=self.event)) + objs = list(CartPosition.objects.current.filter(session=self.session_key, event=self.event)) self.assertEqual(len(objs), 1) self.assertEqual(objs[0].answers.get(question=q1).answer, '23') @@ -318,14 +256,14 @@ class CartTest(CartTestMixin, TestCase): self.quota_tickets.size = 0 self.quota_tickets.save() CartPosition.objects.create( - event=self.event, user=self.user, item=self.ticket, + event=self.event, session=self.session_key, item=self.ticket, price=23, expires=now() - timedelta(minutes=10) ) response = self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), { }, follow=True) doc = BeautifulSoup(response.rendered_content) self.assertIn('no longer available', doc.select('.alert-danger')[0].text) - self.assertFalse(CartPosition.objects.current.filter(user=self.user, event=self.event).exists()) + self.assertFalse(CartPosition.objects.current.filter(session=self.session_key, event=self.event).exists()) def test_restriction_ok(self): self.event.plugins = 'tests.testdummy' @@ -336,7 +274,7 @@ class CartTest(CartTestMixin, TestCase): }, follow=True) self.assertRedirects(response, '/%s/%s/' % (self.orga.slug, self.event.slug), target_status_code=200) - objs = list(CartPosition.objects.current.filter(user=self.user, event=self.event)) + objs = list(CartPosition.objects.current.filter(session=self.session_key, event=self.event)) self.assertEqual(len(objs), 1) self.assertEqual(objs[0].item, self.ticket) self.assertIsNone(objs[0].variation) @@ -353,11 +291,11 @@ class CartTest(CartTestMixin, TestCase): target_status_code=200) doc = BeautifulSoup(response.rendered_content) self.assertIn('no longer available', doc.select('.alert-danger')[0].text) - self.assertFalse(CartPosition.objects.filter(user=self.user, event=self.event).exists()) + self.assertFalse(CartPosition.objects.filter(session=self.session_key, event=self.event).exists()) def test_remove_simple(self): CartPosition.objects.create( - event=self.event, user=self.user, item=self.ticket, + event=self.event, session=self.session_key, item=self.ticket, price=23, expires=now() + timedelta(minutes=10) ) response = self.client.post('/%s/%s/cart/remove' % (self.orga.slug, self.event.slug), { @@ -365,11 +303,11 @@ class CartTest(CartTestMixin, TestCase): }, follow=True) doc = BeautifulSoup(response.rendered_content) self.assertIn('updated', doc.select('.alert-success')[0].text) - self.assertFalse(CartPosition.objects.current.filter(user=self.user, event=self.event).exists()) + self.assertFalse(CartPosition.objects.current.filter(session=self.session_key, event=self.event).exists()) def test_remove_variation(self): CartPosition.objects.create( - event=self.event, user=self.user, item=self.shirt, variation=self.shirt_red, + event=self.event, session=self.session_key, item=self.shirt, variation=self.shirt_red, price=14, expires=now() + timedelta(minutes=10) ) response = self.client.post('/%s/%s/cart/remove' % (self.orga.slug, self.event.slug), { @@ -377,15 +315,15 @@ class CartTest(CartTestMixin, TestCase): }, follow=True) doc = BeautifulSoup(response.rendered_content) self.assertIn('updated', doc.select('.alert-success')[0].text) - self.assertFalse(CartPosition.objects.current.filter(user=self.user, event=self.event).exists()) + self.assertFalse(CartPosition.objects.current.filter(session=self.session_key, event=self.event).exists()) def test_remove_one_of_multiple(self): CartPosition.objects.create( - event=self.event, user=self.user, item=self.ticket, + event=self.event, session=self.session_key, item=self.ticket, price=23, expires=now() + timedelta(minutes=10) ) CartPosition.objects.create( - event=self.event, user=self.user, item=self.ticket, + event=self.event, session=self.session_key, item=self.ticket, price=23, expires=now() + timedelta(minutes=10) ) response = self.client.post('/%s/%s/cart/remove' % (self.orga.slug, self.event.slug), { @@ -393,15 +331,15 @@ class CartTest(CartTestMixin, TestCase): }, follow=True) doc = BeautifulSoup(response.rendered_content) self.assertIn('updated', doc.select('.alert-success')[0].text) - self.assertEqual(CartPosition.objects.current.filter(user=self.user, event=self.event).count(), 1) + self.assertEqual(CartPosition.objects.current.filter(session=self.session_key, event=self.event).count(), 1) def test_remove_multiple(self): CartPosition.objects.create( - event=self.event, user=self.user, item=self.ticket, + event=self.event, session=self.session_key, item=self.ticket, price=23, expires=now() + timedelta(minutes=10) ) CartPosition.objects.create( - event=self.event, user=self.user, item=self.ticket, + event=self.event, session=self.session_key, item=self.ticket, price=23, expires=now() + timedelta(minutes=10) ) response = self.client.post('/%s/%s/cart/remove' % (self.orga.slug, self.event.slug), { @@ -409,15 +347,15 @@ class CartTest(CartTestMixin, TestCase): }, follow=True) doc = BeautifulSoup(response.rendered_content) self.assertIn('updated', doc.select('.alert-success')[0].text) - self.assertFalse(CartPosition.objects.current.filter(user=self.user, event=self.event).exists()) + self.assertFalse(CartPosition.objects.current.filter(session=self.session_key, event=self.event).exists()) def test_remove_most_expensive(self): CartPosition.objects.create( - event=self.event, user=self.user, item=self.ticket, + event=self.event, session=self.session_key, item=self.ticket, price=23, expires=now() + timedelta(minutes=10) ) CartPosition.objects.create( - event=self.event, user=self.user, item=self.ticket, + event=self.event, session=self.session_key, item=self.ticket, price=20, expires=now() + timedelta(minutes=10) ) response = self.client.post('/%s/%s/cart/remove' % (self.orga.slug, self.event.slug), { @@ -425,7 +363,7 @@ class CartTest(CartTestMixin, TestCase): }, follow=True) doc = BeautifulSoup(response.rendered_content) self.assertIn('updated', doc.select('.alert-success')[0].text) - objs = list(CartPosition.objects.current.filter(user=self.user, event=self.event)) + objs = list(CartPosition.objects.current.filter(session=self.session_key, event=self.event)) self.assertEqual(len(objs), 1) self.assertEqual(objs[0].item, self.ticket) self.assertIsNone(objs[0].variation) diff --git a/src/tests/presale/test_checkout.py b/src/tests/presale/test_checkout.py index 4ffe34d636..15a99b42f7 100644 --- a/src/tests/presale/test_checkout.py +++ b/src/tests/presale/test_checkout.py @@ -2,17 +2,17 @@ import datetime from datetime import timedelta from bs4 import BeautifulSoup +from django.conf import settings from django.test import TestCase from django.utils.timezone import now from pretix.base.models import ( CartPosition, Event, Item, ItemCategory, Order, OrderPosition, Organizer, - Question, Quota, User, + Question, Quota, ) class CheckoutTestCase(TestCase): - def setUp(self): super().setUp() self.orga = Organizer.objects.create(name='CCC', slug='ccc') @@ -21,16 +21,17 @@ class CheckoutTestCase(TestCase): date_from=datetime.datetime(2013, 12, 26, tzinfo=datetime.timezone.utc), plugins='pretix.plugins.stripe,pretix.plugins.banktransfer' ) - self.user = User.objects.create_user('dummy@dummy.dummy', 'demo') self.category = ItemCategory.objects.create(event=self.event, name="Everything", position=0) self.quota_tickets = Quota.objects.create(event=self.event, name='Tickets', size=5) self.ticket = Item.objects.create(event=self.event, name='Early-bird ticket', category=self.category, default_price=23, admission=True) self.quota_tickets.items.add(self.ticket) - self.assertTrue(self.client.login(email='dummy@dummy.dummy', password='demo')) self.event.settings.set('attendee_names_asked', False) self.event.settings.set('payment_banktransfer__enabled', True) + self.client.get('/%s/%s/' % (self.orga.slug, self.event.slug)) + self.session_key = self.client.cookies.get(settings.SESSION_COOKIE_NAME).value + def test_empty_cart(self): response = self.client.get('/%s/%s/checkout' % (self.orga.slug, self.event.slug), follow=True) self.assertRedirects(response, '/%s/%s/' % (self.orga.slug, self.event.slug), @@ -38,11 +39,11 @@ class CheckoutTestCase(TestCase): def test_no_questions(self): CartPosition.objects.create( - event=self.event, user=self.user, item=self.ticket, + event=self.event, session=self.session_key, item=self.ticket, price=23, expires=now() + timedelta(minutes=10) ) CartPosition.objects.create( - event=self.event, user=self.user, item=self.ticket, + event=self.event, session=self.session_key, item=self.ticket, price=20, expires=now() + timedelta(minutes=10) ) response = self.client.get('/%s/%s/checkout' % (self.orga.slug, self.event.slug), follow=True) @@ -61,11 +62,11 @@ class CheckoutTestCase(TestCase): self.ticket.questions.add(q1) self.ticket.questions.add(q2) cr1 = CartPosition.objects.create( - event=self.event, user=self.user, item=self.ticket, + event=self.event, session=self.session_key, item=self.ticket, price=23, expires=now() + timedelta(minutes=10) ) cr2 = CartPosition.objects.create( - event=self.event, user=self.user, item=self.ticket, + event=self.event, session=self.session_key, item=self.ticket, price=20, expires=now() + timedelta(minutes=10) ) response = self.client.get('/%s/%s/checkout' % (self.orga.slug, self.event.slug), follow=True) @@ -107,7 +108,7 @@ class CheckoutTestCase(TestCase): self.event.settings.set('attendee_names_asked', True) self.event.settings.set('attendee_names_required', True) cr1 = CartPosition.objects.create( - event=self.event, user=self.user, item=self.ticket, + event=self.event, session=self.session_key, item=self.ticket, price=23, expires=now() + timedelta(minutes=10) ) response = self.client.get('/%s/%s/checkout' % (self.orga.slug, self.event.slug), follow=True) @@ -135,7 +136,7 @@ class CheckoutTestCase(TestCase): self.event.settings.set('attendee_names_asked', True) self.event.settings.set('attendee_names_required', False) cr1 = CartPosition.objects.create( - event=self.event, user=self.user, item=self.ticket, + event=self.event, session=self.session_key, item=self.ticket, price=23, expires=now() + timedelta(minutes=10) ) response = self.client.get('/%s/%s/checkout' % (self.orga.slug, self.event.slug), follow=True) @@ -157,7 +158,7 @@ class CheckoutTestCase(TestCase): self.event.settings.set('payment_stripe__enabled', True) self.event.settings.set('payment_banktransfer__enabled', True) CartPosition.objects.create( - event=self.event, user=self.user, item=self.ticket, + event=self.event, session=self.session_key, item=self.ticket, price=23, expires=now() + timedelta(minutes=10) ) response = self.client.get('/%s/%s/checkout/payment' % (self.orga.slug, self.event.slug), follow=True) @@ -177,7 +178,7 @@ class CheckoutTestCase(TestCase): self.event.settings.set('payment_stripe__enabled', True) self.event.settings.set('payment_banktransfer__enabled', True) cr1 = CartPosition.objects.create( - event=self.event, user=self.user, item=self.ticket, + event=self.event, session=self.session_key, item=self.ticket, price=23, expires=now() + timedelta(minutes=10) ) @@ -220,7 +221,7 @@ class CheckoutTestCase(TestCase): def test_confirm_in_time(self): cr1 = CartPosition.objects.create( - event=self.event, user=self.user, item=self.ticket, + event=self.event, session=self.session_key, item=self.ticket, price=23, expires=now() + timedelta(minutes=10) ) self._set_session('payment', 'banktransfer') @@ -229,12 +230,12 @@ class CheckoutTestCase(TestCase): doc = BeautifulSoup(response.rendered_content) self.assertEqual(len(doc.select(".thank-you")), 1) self.assertFalse(CartPosition.objects.current.filter(identity=cr1.identity).exists()) - self.assertEqual(len(Order.objects.current.filter(user=self.user)), 1) - self.assertEqual(len(OrderPosition.objects.current.filter(order__user=self.user)), 1) + self.assertEqual(Order.objects.current.count(), 1) + self.assertEqual(OrderPosition.objects.current.count(), 1) def test_confirm_expired_available(self): cr1 = CartPosition.objects.create( - event=self.event, user=self.user, item=self.ticket, + event=self.event, session=self.session_key, item=self.ticket, price=23, expires=now() - timedelta(minutes=10) ) self._set_session('payment', 'banktransfer') @@ -243,15 +244,15 @@ class CheckoutTestCase(TestCase): doc = BeautifulSoup(response.rendered_content) self.assertEqual(len(doc.select(".thank-you")), 1) self.assertFalse(CartPosition.objects.current.filter(identity=cr1.identity).exists()) - self.assertEqual(len(Order.objects.current.filter(user=self.user)), 1) - self.assertEqual(len(OrderPosition.objects.current.filter(order__user=self.user)), 1) + self.assertEqual(Order.objects.current.count(), 1) + self.assertEqual(OrderPosition.objects.current.count(), 1) def test_confirm_price_changed(self): self.ticket = self.ticket.clone() self.ticket.default_price = 24 self.ticket.save() cr1 = CartPosition.objects.create( - event=self.event, user=self.user, item=self.ticket, + event=self.event, session=self.session_key, item=self.ticket, price=23, expires=now() - timedelta(minutes=10) ) self._set_session('payment', 'banktransfer') @@ -266,11 +267,11 @@ class CheckoutTestCase(TestCase): self.quota_tickets.size = 1 self.quota_tickets.save() CartPosition.objects.create( - event=self.event, user=self.user, item=self.ticket, + event=self.event, session=self.session_key, item=self.ticket, price=23, expires=now() - timedelta(minutes=10) ) CartPosition.objects.create( - event=self.event, user=self.user, item=self.ticket, + event=self.event, session=self.session_key, item=self.ticket, price=23, expires=now() - timedelta(minutes=10) ) self._set_session('payment', 'banktransfer') @@ -278,14 +279,14 @@ class CheckoutTestCase(TestCase): response = self.client.post('/%s/%s/checkout/confirm' % (self.orga.slug, self.event.slug), follow=True) doc = BeautifulSoup(response.rendered_content) self.assertEqual(len(doc.select(".alert-danger")), 1) - self.assertEqual(CartPosition.objects.current.filter(user=self.user).count(), 1) + self.assertEqual(CartPosition.objects.current.filter(session=self.session_key).count(), 1) def test_confirm_inactive(self): self.ticket = self.ticket.clone() self.ticket.active = False self.ticket.save() cr1 = CartPosition.objects.create( - event=self.event, user=self.user, item=self.ticket, + event=self.event, session=self.session_key, item=self.ticket, price=23, expires=now() - timedelta(minutes=10) ) self._set_session('payment', 'banktransfer') @@ -299,7 +300,7 @@ class CheckoutTestCase(TestCase): self.quota_tickets.size = 0 self.quota_tickets.save() cr1 = CartPosition.objects.create( - event=self.event, user=self.user, item=self.ticket, + event=self.event, session=self.session_key, item=self.ticket, price=23, expires=now() - timedelta(minutes=10) ) self._set_session('payment', 'banktransfer') @@ -312,7 +313,7 @@ class CheckoutTestCase(TestCase): def test_confirm_completely_unavailable(self): self.quota_tickets.items.remove(self.ticket) CartPosition.objects.create( - event=self.event, user=self.user, item=self.ticket, + event=self.event, session=self.session_key, item=self.ticket, price=23, expires=now() - timedelta(minutes=10) ) self._set_session('payment', 'banktransfer') diff --git a/src/tests/presale/test_event.py b/src/tests/presale/test_event.py index d424bd1495..34858d0962 100644 --- a/src/tests/presale/test_event.py +++ b/src/tests/presale/test_event.py @@ -142,12 +142,7 @@ class ItemDisplayTest(EventTestMixin, BrowserTest): class DeadlineTest(EventTestMixin, TestCase): - def setUp(self): - super().setUp() - self.user = User.objects.create_user('demo@demo.dummy', 'demo') - def test_not_yet_started(self): - self.assertTrue(self.client.login(email='demo@demo.dummy', password='demo')) self.event.presale_start = now() + datetime.timedelta(days=1) self.event.save() response = self.client.get( @@ -164,7 +159,6 @@ class DeadlineTest(EventTestMixin, TestCase): self.assertIn('not yet started', response.rendered_content) def test_over(self): - self.assertTrue(self.client.login(email='demo@demo.dummy', password='demo')) self.event.presale_end = now() - datetime.timedelta(days=1) self.event.save() response = self.client.get( diff --git a/src/tests/presale/test_event_auth.py b/src/tests/presale/test_event_auth.py deleted file mode 100644 index 3f363eb30f..0000000000 --- a/src/tests/presale/test_event_auth.py +++ /dev/null @@ -1,215 +0,0 @@ -from datetime import date, timedelta - -from django.conf import settings -from django.contrib.auth.tokens import ( - PasswordResetTokenGenerator, default_token_generator, -) -from django.core import mail as djmail -from django.test import TestCase -from tests.presale.test_event import EventTestMixin - -from pretix.base.models import User - - -class LoginTest(EventTestMixin, TestCase): - def setUp(self): - super().setUp() - self.user = User.objects.create_user('demo@demo.dummy', 'demo') - - def test_login_invalid(self): - response = self.client.post( - '/%s/%s/login' % (self.orga.slug, self.event.slug), - { - 'form': 'login', - 'email': 'demo@demo.foo', - 'password': 'bar' - } - ) - self.assertEqual(response.status_code, 200) - self.assertIn('alert-danger', response.rendered_content) - - def test_login_valid(self): - response = self.client.post( - '/%s/%s/login' % (self.orga.slug, self.event.slug), - { - 'form': 'login', - 'email': 'demo@demo.dummy', - 'password': 'demo' - } - ) - self.assertEqual(response.status_code, 302) - - def test_login_already_logged_in(self): - self.assertTrue(self.client.login(email='demo@demo.dummy', password='demo')) - response = self.client.get( - '/%s/%s/login' % (self.orga.slug, self.event.slug), - ) - self.assertEqual(response.status_code, 302) - - def test_logout(self): - self.assertTrue(self.client.login(email='demo@demo.dummy', password='demo')) - response = self.client.get( - '/%s/%s/logout' % (self.orga.slug, self.event.slug), - ) - self.assertEqual(response.status_code, 302) - response = self.client.get( - '/%s/%s/login' % (self.orga.slug, self.event.slug), - ) - self.assertEqual(response.status_code, 200) - - -class RegistrationFormTest(EventTestMixin, TestCase): - def test_different_passwords(self): - response = self.client.post('/%s/%s/login' % (self.orga.slug, self.event.slug), { - 'form': 'registration', - 'email': 'dummy@dummy.dummy', - 'password': 'foo', - 'password_repeat': 'foobar' - }) - self.assertEqual(response.status_code, 200) - - def test_email_duplicate(self): - self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy') - response = self.client.post('/%s/%s/login' % (self.orga.slug, self.event.slug), { - 'form': 'registration', - 'email': 'dummy@dummy.dummy', - 'password': 'foo', - 'password_repeat': 'foo' - }) - self.assertEqual(response.status_code, 200) - - def test_success(self): - response = self.client.post('/%s/%s/login' % (self.orga.slug, self.event.slug), { - 'form': 'registration', - 'email': 'dummy@dummy.dummy', - 'password': 'foo', - 'password_repeat': 'foo' - }) - self.assertEqual(response.status_code, 302) - - -class PasswordRecoveryFormTest(EventTestMixin, TestCase): - def setUp(self): - super().setUp() - self.user = User.objects.create_user('demo@demo.dummy', 'demo') - - def test_unknown(self): - response = self.client.post('/%s/%s/forgot' % (self.orga.slug, self.event.slug), { - 'email': 'dummy@dummy.dummy', - }) - self.assertEqual(response.status_code, 200) - - def test_email_sent(self): - djmail.outbox = [] - - response = self.client.post('/%s/%s/forgot' % (self.orga.slug, self.event.slug), { - 'email': 'demo@demo.dummy', - }) - self.assertEqual(response.status_code, 302) - - assert len(djmail.outbox) == 1 - assert djmail.outbox[0].to == [self.user.email] - assert "recover?id=%d&token=" % self.user.id in djmail.outbox[0].body - - def test_recovery_unknown_user(self): - response = self.client.get('/%s/%s/forgot/recover?id=0&token=foo' % (self.orga.slug, self.event.slug)) - self.assertEqual(response.status_code, 302) - response = self.client.post( - '/%s/%s/forgot/recover?id=0&token=foo' % (self.orga.slug, self.event.slug), - { - 'password': 'foobar', - 'password_repeat': 'foobar' - } - ) - self.assertEqual(response.status_code, 302) - self.user = User.objects.get(id=self.user.id) - self.assertTrue(self.user.check_password('demo')) - - def test_recovery_invalid_token(self): - response = self.client.get( - '/%s/%s/forgot/recover?id=%d&token=foo' % (self.orga.slug, self.event.slug, self.user.id) - ) - self.assertEqual(response.status_code, 302) - response = self.client.post( - '/%s/%s/forgot/recover?id=%d&token=foo' % (self.orga.slug, self.event.slug, self.user.id), - { - 'password': 'foobar', - 'password_repeat': 'foobar' - } - ) - self.assertEqual(response.status_code, 302) - self.user = User.objects.get(id=self.user.id) - self.assertTrue(self.user.check_password('demo')) - - def test_recovery_expired_token(self): - class Mocked(PasswordResetTokenGenerator): - def _today(self): - return date.today() - timedelta(settings.PASSWORD_RESET_TIMEOUT_DAYS + 1) - - generator = Mocked() - token = generator.make_token(self.user) - response = self.client.get( - '/%s/%s/forgot/recover?id=%d&token=%s' % (self.orga.slug, self.event.slug, self.user.id, token) - ) - self.assertEqual(response.status_code, 302) - response = self.client.post( - '/%s/%s/forgot/recover?id=%d&token=%s' % (self.orga.slug, self.event.slug, self.user.id, token), - { - 'password': 'foobar', - 'password_repeat': 'foobar' - } - ) - self.assertEqual(response.status_code, 302) - self.user = User.objects.get(id=self.user.id) - self.assertTrue(self.user.check_password('demo')) - - def test_recovery_valid_token_success(self): - token = default_token_generator.make_token(self.user) - response = self.client.get( - '/%s/%s/forgot/recover?id=%d&token=%s' % (self.orga.slug, self.event.slug, self.user.id, token) - ) - self.assertEqual(response.status_code, 200) - response = self.client.post( - '/%s/%s/forgot/recover?id=%d&token=%s' % (self.orga.slug, self.event.slug, self.user.id, token), - { - 'password': 'foobar', - 'password_repeat': 'foobar' - } - ) - self.assertEqual(response.status_code, 302) - self.user = User.objects.get(id=self.user.id) - self.assertTrue(self.user.check_password('foobar')) - - def test_recovery_valid_token_empty_passwords(self): - token = default_token_generator.make_token(self.user) - response = self.client.get( - '/%s/%s/forgot/recover?id=%d&token=%s' % (self.orga.slug, self.event.slug, self.user.id, token) - ) - self.assertEqual(response.status_code, 200) - response = self.client.post( - '/%s/%s/forgot/recover?id=%d&token=%s' % (self.orga.slug, self.event.slug, self.user.id, token), - { - 'password': '', - 'password_repeat': 'foobar' - } - ) - self.assertEqual(response.status_code, 200) - self.user = User.objects.get(id=self.user.id) - self.assertTrue(self.user.check_password('demo')) - - def test_recovery_valid_token_different_passwords(self): - token = default_token_generator.make_token(self.user) - response = self.client.get( - '/%s/%s/forgot/recover?id=%d&token=%s' % (self.orga.slug, self.event.slug, self.user.id, token) - ) - self.assertEqual(response.status_code, 200) - response = self.client.post( - '/%s/%s/forgot/recover?id=%d&token=%s' % (self.orga.slug, self.event.slug, self.user.id, token), - { - 'password': 'foo', - 'password_repeat': 'foobar' - } - ) - self.assertEqual(response.status_code, 200) - self.user = User.objects.get(id=self.user.id) - self.assertTrue(self.user.check_password('demo')) diff --git a/src/tests/presale/test_orders.py b/src/tests/presale/test_orders.py index a5554bb71a..b55bc91d96 100644 --- a/src/tests/presale/test_orders.py +++ b/src/tests/presale/test_orders.py @@ -12,7 +12,6 @@ from pretix.base.models import ( class OrdersTest(TestCase): - def setUp(self): super().setUp() self.orga = Organizer.objects.create(name='CCC', slug='ccc') @@ -23,9 +22,6 @@ class OrdersTest(TestCase): ) self.event.settings.set('payment_banktransfer__enabled', True) self.event.settings.set('ticketoutput_testdummy__enabled', True) - self.user = User.objects.create_user('dummy@dummy.dummy', 'foo') - self.user2 = User.objects.create_user('bar@dummy.dummy', 'foo') - self.assertTrue(self.client.login(email='dummy@dummy.dummy', password='foo')) self.category = ItemCategory.objects.create(event=self.event, name="Everything", position=0) self.quota_shirts = Quota.objects.create(event=self.event, name='Shirts', size=2) @@ -54,7 +50,7 @@ class OrdersTest(TestCase): self.order = Order.objects.create( status=Order.STATUS_PENDING, event=self.event, - user=self.user, + email='admin@localhost', datetime=now() - datetime.timedelta(days=3), expires=now() + datetime.timedelta(days=11), total=Decimal("23"), @@ -70,68 +66,57 @@ class OrdersTest(TestCase): self.not_my_order = Order.objects.create( status=Order.STATUS_PENDING, event=self.event, - user=self.user2, + email='user@localhost', datetime=now() - datetime.timedelta(days=3), expires=now() + datetime.timedelta(days=11), total=Decimal("23") ) - def test_orders_list(self): - response = self.client.get( - '/%s/%s/orders' % (self.orga.slug, self.event.slug) - ) - doc = BeautifulSoup(response.rendered_content) - rows = doc.select("table tbody tr") - self.assertEqual(len(rows), 1) - row = rows[0] - self.assertIn(self.order.code, row.text) - self.assertIn(str(self.order.total), row.text) - def test_unknown_order(self): response = self.client.get( - '/%s/%s/order/ABCDE/' % (self.orga.slug, self.event.slug) + '/%s/%s/order/ABCDE/123/' % (self.orga.slug, self.event.slug) ) assert response.status_code == 404 response = self.client.get( - '/%s/%s/order/%s/' % (self.orga.slug, self.event.slug, self.not_my_order.code) + '/%s/%s/order/%s/123/' % (self.orga.slug, self.event.slug, self.not_my_order.code) ) assert response.status_code == 404 response = self.client.get( - '/%s/%s/order/ABCDE/pay' % (self.orga.slug, self.event.slug) + '/%s/%s/order/ABCDE/123/pay' % (self.orga.slug, self.event.slug) ) assert response.status_code == 404 response = self.client.get( - '/%s/%s/order/%s/pay' % (self.orga.slug, self.event.slug, self.not_my_order.code) + '/%s/%s/order/%s/123/pay' % (self.orga.slug, self.event.slug, self.not_my_order.code) ) assert response.status_code == 404 response = self.client.get( - '/%s/%s/order/ABCDE/pay/confirm' % (self.orga.slug, self.event.slug) + '/%s/%s/order/ABCDE/123/pay/confirm' % (self.orga.slug, self.event.slug) ) assert response.status_code == 404 response = self.client.get( - '/%s/%s/order/%s/pay/confirm' % (self.orga.slug, self.event.slug, self.not_my_order.code) + '/%s/%s/order/%s/123/pay/confirm' % (self.orga.slug, self.event.slug, self.not_my_order.code) ) assert response.status_code == 404 response = self.client.get( - '/%s/%s/order/ABCDE/modify' % (self.orga.slug, self.event.slug) + '/%s/%s/order/ABCDE/123/modify' % (self.orga.slug, self.event.slug) ) assert response.status_code == 404 response = self.client.get( - '/%s/%s/order/%s/modify' % (self.orga.slug, self.event.slug, self.not_my_order.code) + '/%s/%s/order/%s/123/modify' % (self.orga.slug, self.event.slug, self.not_my_order.code) ) assert response.status_code == 404 response = self.client.get( - '/%s/%s/order/ABCDE/cancel' % (self.orga.slug, self.event.slug) + '/%s/%s/order/ABCDE/123/cancel' % (self.orga.slug, self.event.slug) ) assert response.status_code == 404 response = self.client.get( - '/%s/%s/order/%s/cancel' % (self.orga.slug, self.event.slug, self.not_my_order.code) + '/%s/%s/order/%s/123/cancel' % (self.orga.slug, self.event.slug, self.not_my_order.code) ) assert response.status_code == 404 def test_orders_detail(self): response = self.client.get( - '/%s/%s/order/%s/' % (self.orga.slug, self.event.slug, self.order.code) + '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret) ) assert response.status_code == 200 doc = BeautifulSoup(response.rendered_content) @@ -142,7 +127,7 @@ class OrdersTest(TestCase): self.order.status = Order.STATUS_REFUNDED self.order.save() self.client.get( - '/%s/%s/order/%s/modify' % (self.orga.slug, self.event.slug, self.order.code) + '/%s/%s/order/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret) ) self.order = Order.objects.current.get(identity=self.order.identity) assert self.order.status == Order.STATUS_REFUNDED @@ -151,15 +136,19 @@ class OrdersTest(TestCase): self.event.settings.set('attendee_names_asked', True) self.event.settings.set('attendee_names_required', False) - response = self.client.get('/%s/%s/order/%s/modify' % (self.orga.slug, self.event.slug, self.order.code)) + response = self.client.get( + '/%s/%s/order/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)) doc = BeautifulSoup(response.rendered_content) self.assertEqual(len(doc.select('input[name=%s-attendee_name]' % self.ticket_pos.identity)), 1) # Not all fields filled out, expect success - response = self.client.post('/%s/%s/order/%s/modify' % (self.orga.slug, self.event.slug, self.order.code), { - '%s-attendee_name' % self.ticket_pos.identity: '', - }, follow=True) - self.assertRedirects(response, '/%s/%s/order/%s/' % (self.orga.slug, self.event.slug, self.order.code), + response = self.client.post( + '/%s/%s/order/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { + '%s-attendee_name' % self.ticket_pos.identity: '', + }, follow=True) + self.assertRedirects(response, + '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, + self.order.secret), target_status_code=200) self.ticket_pos = OrderPosition.objects.current.get(identity=self.ticket_pos.identity) assert self.ticket_pos.attendee_name in (None, '') @@ -168,21 +157,25 @@ class OrdersTest(TestCase): self.event.settings.set('attendee_names_asked', True) self.event.settings.set('attendee_names_required', True) - response = self.client.get('/%s/%s/order/%s/modify' % (self.orga.slug, self.event.slug, self.order.code)) + response = self.client.get( + '/%s/%s/order/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)) doc = BeautifulSoup(response.rendered_content) self.assertEqual(len(doc.select('input[name=%s-attendee_name]' % self.ticket_pos.identity)), 1) # Not all required fields filled out, expect failure - response = self.client.post('/%s/%s/order/%s/modify' % (self.orga.slug, self.event.slug, self.order.code), { - '%s-attendee_name' % self.ticket_pos.identity: '', - }, follow=True) + response = self.client.post( + '/%s/%s/order/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { + '%s-attendee_name' % self.ticket_pos.identity: '', + }, follow=True) doc = BeautifulSoup(response.rendered_content) self.assertGreaterEqual(len(doc.select('.has-error')), 1) - response = self.client.post('/%s/%s/order/%s/modify' % (self.orga.slug, self.event.slug, self.order.code), { - '%s-attendee_name' % self.ticket_pos.identity: 'Peter', - }, follow=True) - self.assertRedirects(response, '/%s/%s/order/%s/' % (self.orga.slug, self.event.slug, self.order.code), + response = self.client.post( + '/%s/%s/order/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { + '%s-attendee_name' % self.ticket_pos.identity: 'Peter', + }, follow=True) + self.assertRedirects(response, '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, + self.order.secret), target_status_code=200) self.ticket_pos = OrderPosition.objects.current.get(identity=self.ticket_pos.identity) assert self.ticket_pos.attendee_name == 'Peter' @@ -191,16 +184,20 @@ class OrdersTest(TestCase): self.event.settings.set('attendee_names_asked', False) self.event.settings.set('attendee_names_required', False) - response = self.client.get('/%s/%s/order/%s/modify' % (self.orga.slug, self.event.slug, self.order.code)) + response = self.client.get( + '/%s/%s/order/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)) doc = BeautifulSoup(response.rendered_content) self.assertEqual(len(doc.select('input[name=%s-question_%s]' % ( self.ticket_pos.identity, self.question.identity))), 1) # Not all fields filled out, expect success - response = self.client.post('/%s/%s/order/%s/modify' % (self.orga.slug, self.event.slug, self.order.code), { - '%s-question_%s' % (self.ticket_pos.identity, self.question.identity): '', - }, follow=True) - self.assertRedirects(response, '/%s/%s/order/%s/' % (self.orga.slug, self.event.slug, self.order.code), + response = self.client.post( + '/%s/%s/order/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { + '%s-question_%s' % (self.ticket_pos.identity, self.question.identity): '', + }, follow=True) + self.assertRedirects(response, + '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, + self.order.secret), target_status_code=200) assert not self.ticket_pos.answers.filter(question=self.question).exists() @@ -210,22 +207,27 @@ class OrdersTest(TestCase): self.question.required = True self.question.save() - response = self.client.get('/%s/%s/order/%s/modify' % (self.orga.slug, self.event.slug, self.order.code)) + response = self.client.get('/%s/%s/order/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, + self.order.secret)) doc = BeautifulSoup(response.rendered_content) self.assertEqual(len(doc.select('input[name=%s-question_%s]' % ( self.ticket_pos.identity, self.question.identity))), 1) # Not all required fields filled out, expect failure - response = self.client.post('/%s/%s/order/%s/modify' % (self.orga.slug, self.event.slug, self.order.code), { - '%s-question_%s' % (self.ticket_pos.identity, self.question.identity): '', - }, follow=True) + response = self.client.post( + '/%s/%s/order/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { + '%s-question_%s' % (self.ticket_pos.identity, self.question.identity): '', + }, follow=True) doc = BeautifulSoup(response.rendered_content) self.assertGreaterEqual(len(doc.select('.has-error')), 1) - response = self.client.post('/%s/%s/order/%s/modify' % (self.orga.slug, self.event.slug, self.order.code), { - '%s-question_%s' % (self.ticket_pos.identity, self.question.identity): 'ABC', - }, follow=True) - self.assertRedirects(response, '/%s/%s/order/%s/' % (self.orga.slug, self.event.slug, self.order.code), + response = self.client.post( + '/%s/%s/order/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { + '%s-question_%s' % (self.ticket_pos.identity, self.question.identity): 'ABC', + }, follow=True) + self.assertRedirects(response, + '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, + self.order.secret), target_status_code=200) assert self.ticket_pos.answers.get(question=self.question).answer == 'ABC' @@ -233,67 +235,83 @@ class OrdersTest(TestCase): self.order.status = Order.STATUS_PAID self.order.save() self.client.get( - '/%s/%s/order/%s/cancel' % (self.orga.slug, self.event.slug, self.order.code) + '/%s/%s/order/%s/%s/cancel' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret) ) self.order = Order.objects.current.get(identity=self.order.identity) assert self.order.status == Order.STATUS_PAID def test_orders_cancel(self): response = self.client.get( - '/%s/%s/order/%s/cancel' % (self.orga.slug, self.event.slug, self.order.code) + '/%s/%s/order/%s/%s/cancel' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret) ) assert response.status_code == 200 - response = self.client.post('/%s/%s/order/%s/cancel' % (self.orga.slug, self.event.slug, self.order.code), { - }, follow=True) - self.assertRedirects(response, '/%s/%s/order/%s/' % (self.orga.slug, self.event.slug, self.order.code), + response = self.client.post( + '/%s/%s/order/%s/%s/cancel' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { + }, follow=True) + self.assertRedirects(response, + '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, + self.order.secret), target_status_code=200) assert Order.objects.current.get(identity=self.order.identity).status == Order.STATUS_CANCELLED def test_orders_download(self): self.event.settings.set('ticket_download', True) del self.event.settings['ticket_download_date'] - response = self.client.get('/%s/%s/order/%s/download/pdf' % (self.orga.slug, self.event.slug, self.order.code), - follow=True) - self.assertRedirects(response, '/%s/%s/order/%s/' % (self.orga.slug, self.event.slug, self.order.code), + response = self.client.get( + '/%s/%s/order/%s/%s/download/pdf' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), + follow=True) + self.assertRedirects(response, + '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, + self.order.secret), target_status_code=200) response = self.client.get( - '/%s/%s/order/ABC/download/testdummy' % (self.orga.slug, self.event.slug) + '/%s/%s/order/ABC/123/download/testdummy' % (self.orga.slug, self.event.slug) ) assert response.status_code == 404 response = self.client.get( - '/%s/%s/order/%s/download/testdummy' % (self.orga.slug, self.event.slug, self.order.code), + '/%s/%s/order/%s/%s/download/testdummy' % (self.orga.slug, self.event.slug, self.order.code, + self.order.secret), follow=True ) - self.assertRedirects(response, '/%s/%s/order/%s/' % (self.orga.slug, self.event.slug, self.order.code), + self.assertRedirects(response, + '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, + self.order.secret), target_status_code=200) self.order.status = Order.STATUS_PAID self.order.save() response = self.client.get( - '/%s/%s/order/%s/download/testdummy' % (self.orga.slug, self.event.slug, self.order.code), + '/%s/%s/order/%s/%s/download/testdummy' % (self.orga.slug, self.event.slug, self.order.code, + self.order.secret), ) assert response.status_code == 302 self.event.settings.set('ticket_download_date', now() + datetime.timedelta(days=1)) response = self.client.get( - '/%s/%s/order/%s/download/testdummy' % (self.orga.slug, self.event.slug, self.order.code), + '/%s/%s/order/%s/%s/download/testdummy' % (self.orga.slug, self.event.slug, self.order.code, + self.order.secret), follow=True ) - self.assertRedirects(response, '/%s/%s/order/%s/' % (self.orga.slug, self.event.slug, self.order.code), + self.assertRedirects(response, + '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, + self.order.secret), target_status_code=200) del self.event.settings['ticket_download_date'] response = self.client.get( - '/%s/%s/order/%s/download/testdummy' % (self.orga.slug, self.event.slug, self.order.code), + '/%s/%s/order/%s/%s/download/testdummy' % (self.orga.slug, self.event.slug, self.order.code, + self.order.secret), ) assert response.status_code == 302 self.event.settings.set('ticket_download', False) response = self.client.get( - '/%s/%s/order/%s/download/testdummy' % (self.orga.slug, self.event.slug, self.order.code), + '/%s/%s/order/%s/%s/download/testdummy' % (self.orga.slug, self.event.slug, self.order.code, + self.order.secret), follow=True ) - self.assertRedirects(response, '/%s/%s/order/%s/' % (self.orga.slug, self.event.slug, self.order.code), + self.assertRedirects(response, '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, + self.order.secret), target_status_code=200)