Make all orders "guest orders"

This commit is contained in:
Raphael Michel
2015-10-05 11:24:00 +02:00
parent c47008cc18
commit 93d027cec6
40 changed files with 296 additions and 1264 deletions
+3 -3
View File
@@ -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
@@ -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',
),
]
+9 -28
View File
@@ -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")
+6 -4
View File
@@ -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
+18 -31
View File
@@ -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:
+3 -13
View File
@@ -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:
+8 -7
View File
@@ -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,
@@ -67,7 +67,7 @@
<dd>{{ order.expires }}</dd>
{% endif %}
<dt>{% trans "User" %}</dt>
<dd>{{ order.user|default:order.guest_email }}</dd>
<dd>{{ order.email }}</dd>
</dl>
</div>
</div>
@@ -52,7 +52,7 @@
<td><strong><a
href="{% url "control:event.order" event=request.event.slug organizer=request.event.organizer.slug code=o.code%}"
>{{ o.code }}</a></strong></td>
<td>{{ o.user.get_short_name }}</td>
<td>{{ o.email }}</td>
<td>{{ o.total|floatformat:2 }} {{ request.event.currency }}</td>
<td>{{ o.datetime|date:"SHORT_DATETIME_FORMAT" }}</td>
<td>{% include "pretixcontrol/orders/fragment_order_status.html" with order=o %}</td>
+2 -2
View File
@@ -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)
+5 -11
View File
@@ -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['_'] = '_'
@@ -1,58 +0,0 @@
{% extends "pretixpresale/event/base.html" %}
{% load i18n %}
{% block title %}{% trans "Your account" %}{% endblock %}
{% block content %}
<h2>{% trans "Welcome back!" %}</h2>
<div class="row">
<div class="col-md-6">
{% if orders %}
<a href="{% url "presale:event.orders" event=request.event.slug organizer=request.event.organizer.slug %}">
<div class="panel panel-primary">
<div class="panel-heading">
<div class="row">
<div class="col-xs-3">
<i class="fa fa-shopping-cart fa-5x"></i>
</div>
<div class="col-xs-9 text-right">
<div class="huge">{% trans "Your orders" %}</div>
</div>
</div>
</div>
</div>
</a>
{% else %}
<a href="{% url "presale:event.index" event=request.event.slug organizer=request.event.organizer.slug %}">
<div class="panel panel-primary">
<div class="panel-heading">
<div class="row">
<div class="col-xs-3">
<i class="fa fa-shopping-cart fa-5x"></i>
</div>
<div class="col-xs-9 text-right">
<div class="huge">{% trans "Place new order" %}</div>
</div>
</div>
</div>
</div>
</a>
{% endif %}
</div>
<div class="col-md-6">
<a href="{% url "presale:event.account.settings" event=request.event.slug organizer=request.event.organizer.slug %}">
<div class="panel panel-primary">
<div class="panel-heading">
<div class="row">
<div class="col-xs-3">
<i class="fa fa-wrench fa-5x"></i>
</div>
<div class="col-xs-9 text-right">
<div class="huge">{% trans "Your settings" %}</div>
</div>
</div>
</div>
</div>
</a>
</div>
</div>
{% endblock %}
@@ -1,33 +0,0 @@
{% extends "pretixpresale/event/base.html" %}
{% load i18n %}
{% load bootstrap3 %}
{% block title %}{% trans "Account settings" %}{% endblock %}
{% block content %}
<h2>{% trans "Account settings" %}</h2>
<form action="" method="post" class="form-horizontal">
{% csrf_token %}
{% bootstrap_form_errors form %}
<fieldset>
<legend>{% trans "General settings" %}</legend>
{% bootstrap_field form.givenname layout='horizontal' %}
{% bootstrap_field form.familyname layout='horizontal' %}
{% bootstrap_field form.locale layout='horizontal' %}
</fieldset>
<fieldset>
<legend>{% trans "Login settings" %}</legend>
{% 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' %}
</fieldset>
<div class="row checkout-button-row">
<div class="col-md-4 col-md-offset-8">
<button class="btn btn-block btn-primary btn-lg btn-save" type="submit">
{% trans "Save" %}
</button>
</div>
<div class="clearfix"></div>
</div>
</form>
{% endblock %}
@@ -36,18 +36,6 @@
{% endfor %}
</div> &middot;
{% endif %}
{% if request.user.is_authenticated %}
{% blocktrans trimmed with name=request.user.get_short_name %}
Hello, {{ name }}!
{% endblocktrans %} &middot;
<a href="{% url "presale:event.account" event=request.event.slug organizer=request.event.organizer.slug %}">
{% trans "Your account" %}</a> &middot;
<a href="{% url "presale:event.logout" event=request.event.slug organizer=request.event.organizer.slug %}">
{% trans "Logout" %}</a>
{% else %}
<a href="{% url "presale:event.checkout.login" event=request.event.slug organizer=request.event.organizer.slug %}">
{% trans "Login" %}</a>
{% endif %}
</div>
<div class="clearfix"></div>
</div>
@@ -1,20 +0,0 @@
{% extends "pretixpresale/event/base.html" %}
{% load i18n %}
{% load bootstrap3 %}
{% block title %}{% trans "Password recovery" %}{% endblock %}
{% block content %}
<h2>{% trans "Password recovery" %}</h2>
<form class="form-horizontal" method="post">
{% csrf_token %}
{% bootstrap_form_errors form type='all' layout='inline' %}
{% bootstrap_field form.email layout="horizontal" %}
<input type="hidden" name="form" value="login" />
<div class="form-group">
<div class="submit-group col-md-offset-3 col-md-4">
<button type="submit" class="btn btn-primary btn-save">
{% trans "Send recovery information" %}
</button>
</div>
</div>
</form>
{% endblock %}
@@ -1,99 +0,0 @@
{% extends "pretixpresale/event/base.html" %}
{% load i18n %}
{% load bootstrap3 %}
{% block title %}{% trans "Login" %}{% endblock %}
{% block content %}
<h2>{% trans "Login" %}</h2>
<p>{% trans "You need to login or register to continue" %}</p>
<div class="panel-group" id="login_accordion">
<div class="panel panel-default">
<div class="panel-heading" role="tab" id="headingOne">
<h4 class="panel-title">
<a data-toggle="collapse" href="#loginForm" data-parent="#login_accordion">
{% trans "I already have an account" %}
</a>
</h4>
</div>
<div id="loginForm" class="panel-collapse collapsed {% if request.POST.form == 'login' %}in{% endif %}">
<div class="panel-body">
<form class="form-horizontal" method="post">
{% csrf_token %}
{% bootstrap_form_errors login_form type='all' layout='inline' %}
{% bootstrap_field login_form.email layout="horizontal" %}
{% bootstrap_field login_form.password layout="horizontal" %}
<input type="hidden" name="form" value="login" />
<div class="form-group">
<div class="submit-group col-md-offset-3 col-md-4">
<button type="submit" class="btn btn-primary btn-save">
{% trans "Login" %}
</button>
<a href="{% url "presale:event.forgot" event=request.event.slug organizer=request.event.organizer.slug %}" class="btn btn-link">
{% trans "Lost password?" %}
</a>
</div>
</div>
</form>
</div>
</div>
</div>
{% if "guest" in request.GET %}
<div class="panel panel-default">
<div class="panel-heading" role="tab" id="headingOne">
<h4 class="panel-title">
<a data-toggle="collapse" href="#guestForm" data-parent="#login_accordion">
{% trans "I want to order as a guest" %}
</a>
</h4>
</div>
<div id="guestForm" class="panel-collapse collapsed {% if request.POST.form == 'guest' %}in{% endif %}">
<div class="panel-body">
<div class="panel-body">
<form class="form-horizontal" method="post">
{% csrf_token %}
{% bootstrap_form_errors guest_form type='all' layout='inline' %}
{% bootstrap_field guest_form.email layout="horizontal" %}
<input type="hidden" name="form" value="guest" />
<div class="form-group">
<div class="submit-group col-md-offset-3 col-md-4">
<button type="submit" class="btn btn-primary btn-save">
{% trans "Continue" %}
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
{% endif %}
<div class="panel panel-default">
<div class="panel-heading" role="tab" id="headingOne">
<h4 class="panel-title">
<a data-toggle="collapse" href="#registrationForm" data-parent="#login_accordion">
{% trans "I want to create a permanent account" %}
</a>
</h4>
</div>
<div id="registrationForm" class="panel-collapse collapsed
{% if request.POST.form == 'registration' %}in{% endif %}">
<div class="panel-body">
<form class="form-horizontal" method="post">
{% csrf_token %}
{% bootstrap_form_errors registration_form type='all' layout='inline' %}
{% bootstrap_field registration_form.email layout="horizontal" %}
{% bootstrap_field registration_form.password layout="horizontal" %}
{% bootstrap_field registration_form.password_repeat layout="horizontal" %}
<input type="hidden" name="form" value="registration" />
<div class="form-group">
<div class="submit-group col-md-offset-3 col-md-4">
<button type="submit" class="btn btn-primary btn-save">
{% trans "Register" %}
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
{% endblock %}
@@ -27,7 +27,7 @@
</div>
<div class="panel-body">
{% if can_retry %}
<a href="{% url "presale:event.order.pay" organizer=request.event.organizer.slug event=request.event.slug order=order.code %}"
<a href="{% url "presale:event.order.pay" organizer=request.event.organizer.slug event=request.event.slug secret=order.secret order=order.code %}"
class="btn btn-primary pull-right"><i class="fa fa-money"></i> {% trans "Complete payment" %}</a>
{% endif %}
{{ payment }}
@@ -52,7 +52,7 @@
{% endblocktrans %}
</p>
{% for b in download_buttons %}
<a href="{% url "presale:event.order.download" organizer=request.event.organizer.slug event=request.event.slug order=order.code output=b.identifier %}"
<a href="{% url "presale:event.order.download" organizer=request.event.organizer.slug event=request.event.slug secret=order.secret order=order.code output=b.identifier %}"
class="btn btn-primary">
<span class="fa {{ b.icon }}"></span> {{ b.text }}
</a>
@@ -69,7 +69,7 @@
<div class="panel-heading">
{% if order.can_modify_answers %}
<div class="pull-right">
<a href="{% url "presale:event.order.modify" organizer=request.event.organizer.slug event=request.event.slug order=order.code %}">
<a href="{% url "presale:event.order.modify" organizer=request.event.organizer.slug event=request.event.slug secret=order.secret order=order.code %}">
<span class="fa fa-edit"></span>
{% trans "Change details" %}
</a>
@@ -87,7 +87,7 @@
<div class="row">
<div class="col-md-12 text-right">
<p>
<a href="{% url 'presale:event.order.cancel' event=request.event.slug organizer=request.event.organizer.slug order=order.code %}"
<a href="{% url 'presale:event.order.cancel' event=request.event.slug organizer=request.event.organizer.slug secret=order.secret order=order.code %}"
class="btn btn-danger">
<span class="fa fa-remove"></span>
{% trans "Cancel order" %}
@@ -16,7 +16,7 @@
<div class="row checkout-button-row">
<div class="col-md-4">
<a class="btn btn-block btn-default btn-lg"
href="{% url "presale:event.order" event=request.event.slug organizer=request.event.organizer.slug order=order.code %}">
href="{% url "presale:event.order" event=request.event.slug organizer=request.event.organizer.slug secret=order.secret order=order.code %}">
{% trans "No, take me back" %}
</a>
</div>
@@ -16,7 +16,7 @@
<div class="row checkout-button-row">
<div class="col-md-4">
<a class="btn btn-block btn-default btn-lg"
href="{% url "presale:event.order" event=request.event.slug organizer=request.event.organizer.slug order=order.code %}">
href="{% url "presale:event.order" event=request.event.slug organizer=request.event.organizer.slug secret=order.secret order=order.code %}">
{% trans "Cancel" %}
</a>
</div>
@@ -27,7 +27,7 @@
<div class="row checkout-button-row">
<div class="col-md-4">
<a class="btn btn-block btn-default btn-lg"
href="{% url "presale:event.order" event=request.event.slug organizer=request.event.organizer.slug order=order.code %}">
href="{% url "presale:event.order" event=request.event.slug organizer=request.event.organizer.slug secret=order.secret order=order.code %}">
{% trans "Cancel" %}
</a>
</div>
@@ -1,43 +0,0 @@
{% extends "pretixpresale/event/base.html" %}
{% load i18n %}
{% block title %}{% trans "Your orders" %}{% endblock %}
{% block content %}
<h2>{% trans "Your orders" %}</h2>
<div class="table-responsive">
<table class="table">
<thead>
<th>{% trans "Order code" %}</th>
<th>{% trans "Date" %}</th>
<th>{% trans "Total" %}</th>
<th>{% trans "Status" %}</th>
<th></th>
</thead>
<tbody>
{% for order in orders %}
<tr>
<td><a href="{% url "presale:event.order" event=request.event.slug organizer=request.event.organizer.slug order=order.code %}">
<strong>{{ order.code }}</strong></td>
<td>{{ order.datetime|date:"SHORT_DATE_FORMAT" }}</td>
<td>{{ event.currency }} {{ order.total|floatformat:2 }}</td>
<td>{% include "pretixpresale/event/fragment_order_status.html" with order=order %}</td>
<td><a href="{% url "presale:event.order" event=request.event.slug organizer=request.event.organizer.slug order=order.code %}">
{% trans "View details" %}
</a></td>
</tr>
{% empty %}
<tr>
<td colspan="5">
<em>{% trans "You did not yet place any orders." %}</em>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<a href="{% url "presale:event.index" event=request.event.slug organizer=request.event.organizer.slug %}"
class="btn btn-primary btn-lg">
<span class="fa fa-plus"></span>
{% trans "Place new order" %}
</a>
{% endblock %}
@@ -1,21 +0,0 @@
{% extends "pretixpresale/event/base.html" %}
{% load i18n %}
{% load bootstrap3 %}
{% block title %}{% trans "Password recovery" %}{% endblock %}
{% block content %}
<h2>{% trans "Password recovery" %}</h2>
<form class="form-horizontal" method="post">
{% csrf_token %}
{% bootstrap_form_errors form type='all' layout='inline' %}
{% bootstrap_field form.password layout="horizontal" %}
{% bootstrap_field form.password_repeat layout="horizontal" %}
<input type="hidden" name="form" value="login" />
<div class="form-group">
<div class="submit-group col-md-offset-3 col-md-4">
<button type="submit" class="btn btn-primary btn-save">
{% trans "Set new password" %}
</button>
</div>
</div>
</form>
{% endblock %}
+10 -13
View File
@@ -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<order>[^/]+)/$', pretix.presale.views.order.OrderDetails.as_view(),
url(r'^order/(?P<order>[^/]+)/(?P<secret>[A-Za-z0-9]+)/$', pretix.presale.views.order.OrderDetails.as_view(),
name='event.order'),
url(r'^order/(?P<order>[^/]+)/cancel$', pretix.presale.views.order.OrderCancel.as_view(),
url(r'^order/(?P<order>[^/]+)/(?P<secret>[A-Za-z0-9]+)/cancel$',
pretix.presale.views.order.OrderCancel.as_view(),
name='event.order.cancel'),
url(r'^order/(?P<order>[^/]+)/modify$', pretix.presale.views.order.OrderModify.as_view(),
url(r'^order/(?P<order>[^/]+)/(?P<secret>[A-Za-z0-9]+)/modify$',
pretix.presale.views.order.OrderModify.as_view(),
name='event.order.modify'),
url(r'^order/(?P<order>[^/]+)/pay$', pretix.presale.views.order.OrderPay.as_view(),
url(r'^order/(?P<order>[^/]+)/(?P<secret>[A-Za-z0-9]+)/pay$', pretix.presale.views.order.OrderPay.as_view(),
name='event.order.pay'),
url(r'^order/(?P<order>[^/]+)/pay/confirm$', pretix.presale.views.order.OrderPayDo.as_view(),
url(r'^order/(?P<order>[^/]+)/(?P<secret>[A-Za-z0-9]+)/pay/confirm$',
pretix.presale.views.order.OrderPayDo.as_view(),
name='event.order.pay.confirm'),
url(r'^order/(?P<order>[^/]+)/download/(?P<output>[^/]+)$', pretix.presale.views.order.OrderDownload.as_view(),
url(r'^order/(?P<order>[^/]+)/(?P<secret>[A-Za-z0-9]+)/download/(?P<output>[^/]+)$',
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'),
]
+2 -29
View File
@@ -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']
+4 -26
View File
@@ -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:
+9 -12
View File
@@ -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":
+2 -261
View File
@@ -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,
})
+11 -10
View File
@@ -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())
+1 -1
View File
@@ -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)
+3 -3
View File
@@ -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
+2 -2
View File
@@ -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'
)
+1 -1
View File
@@ -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'
)
@@ -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'
)
+1 -2
View File
@@ -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'
)
-91
View File
@@ -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
+37 -99
View File
@@ -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)
+26 -25
View File
@@ -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')
-6
View File
@@ -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(
-215
View File
@@ -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'))
+90 -72
View File
@@ -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)