mirror of
https://github.com/pretix/pretix.git
synced 2026-09-13 16:14:40 +00:00
Added multi-domain capabilities
This commit is contained in:
@@ -27,8 +27,6 @@ Example::
|
|||||||
instance_name=pretix.de
|
instance_name=pretix.de
|
||||||
url=http://localhost
|
url=http://localhost
|
||||||
currency=EUR
|
currency=EUR
|
||||||
cookiedomain=.pretix.de
|
|
||||||
securecookie=on
|
|
||||||
datadir=/data
|
datadir=/data
|
||||||
plugins_default=pretix.plugins.sendmail,pretix.plugins.statistics
|
plugins_default=pretix.plugins.sendmail,pretix.plugins.statistics
|
||||||
|
|
||||||
@@ -41,13 +39,6 @@ Example::
|
|||||||
``currency``
|
``currency``
|
||||||
The default currency as a three-letter code. Defaults to ``EUR``.
|
The default currency as a three-letter code. Defaults to ``EUR``.
|
||||||
|
|
||||||
``cookiedomain``
|
|
||||||
The domain to be used for session cookies, csrf protection cookies and locale cookies.
|
|
||||||
Empty by default.
|
|
||||||
|
|
||||||
``securecookie``
|
|
||||||
Set the ``secure`` and ``httponly`` flags on session cookies. Off by default.
|
|
||||||
|
|
||||||
``datadir``
|
``datadir``
|
||||||
The local path to a data directory that will be used for storing user uploads and similar
|
The local path to a data directory that will be used for storing user uploads and similar
|
||||||
data. Defaults to thea value of the environment variable ``DATA_DIR`` or ``data``.
|
data. Defaults to thea value of the environment variable ``DATA_DIR`` or ``data``.
|
||||||
|
|||||||
@@ -9,12 +9,11 @@ from pretix.base.models import (
|
|||||||
CartPosition, Event, EventLock, Order, OrderPosition, Quota,
|
CartPosition, Event, EventLock, Order, OrderPosition, Quota,
|
||||||
)
|
)
|
||||||
from pretix.base.payment import BasePaymentProvider
|
from pretix.base.payment import BasePaymentProvider
|
||||||
from pretix.base.services.cart import CartError
|
|
||||||
from pretix.base.services.mail import mail
|
from pretix.base.services.mail import mail
|
||||||
from pretix.base.signals import (
|
from pretix.base.signals import (
|
||||||
order_paid, order_placed, register_payment_providers,
|
order_paid, order_placed, register_payment_providers,
|
||||||
)
|
)
|
||||||
from pretix.helpers.urls import build_absolute_uri
|
from pretix.multidomain.urlreverse import build_absolute_uri
|
||||||
|
|
||||||
error_messages = {
|
error_messages = {
|
||||||
'unavailable': _('Some of the products you selected were no longer available. '
|
'unavailable': _('Some of the products you selected were no longer available. '
|
||||||
@@ -68,9 +67,7 @@ def mark_order_paid(order: Order, provider: str=None, info: str=None, date: date
|
|||||||
{
|
{
|
||||||
'order': order,
|
'order': order,
|
||||||
'event': order.event,
|
'event': order.event,
|
||||||
'url': build_absolute_uri('presale:event.order', kwargs={
|
'url': build_absolute_uri(order.event, 'presale:event.order', kwargs={
|
||||||
'event': order.event.slug,
|
|
||||||
'organizer': order.event.organizer.slug,
|
|
||||||
'order': order.code,
|
'order': order.code,
|
||||||
'secret': order.secret
|
'secret': order.secret
|
||||||
}),
|
}),
|
||||||
@@ -189,9 +186,7 @@ def _perform_order(event: Event, payment_provider: BasePaymentProvider, position
|
|||||||
{
|
{
|
||||||
'order': order,
|
'order': order,
|
||||||
'event': event,
|
'event': event,
|
||||||
'url': build_absolute_uri('presale:event.order', kwargs={
|
'url': build_absolute_uri(event, 'presale:event.order', kwargs={
|
||||||
'event': event.slug,
|
|
||||||
'organizer': event.organizer.slug,
|
|
||||||
'order': order.code,
|
'order': order.code,
|
||||||
'secret': order.secret
|
'secret': order.secret
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
from urllib.parse import urlparse
|
from urllib.parse import urljoin, urlparse
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth import REDIRECT_FIELD_NAME
|
from django.contrib.auth import REDIRECT_FIELD_NAME
|
||||||
from django.core.urlresolvers import get_script_prefix, resolve
|
from django.core.urlresolvers import get_script_prefix, resolve
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
from django.shortcuts import resolve_url
|
from django.shortcuts import redirect, resolve_url
|
||||||
from django.utils.encoding import force_str
|
from django.utils.encoding import force_str
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
@@ -28,7 +28,13 @@ class PermissionMiddleware:
|
|||||||
def process_request(self, request):
|
def process_request(self, request):
|
||||||
url = resolve(request.path_info)
|
url = resolve(request.path_info)
|
||||||
url_name = url.url_name
|
url_name = url.url_name
|
||||||
if not request.path.startswith(get_script_prefix() + 'control') or url_name in self.EXCEPTIONS:
|
if not request.path.startswith(get_script_prefix() + 'control'):
|
||||||
|
# This middleware should only touch the /control subpath
|
||||||
|
return
|
||||||
|
if hasattr(request, 'domain'):
|
||||||
|
# If the user is on a organizer's subdomain, he sould be redirected to pretix
|
||||||
|
return redirect(urljoin(settings.SITE_URL, request.get_full_path()))
|
||||||
|
if url_name in self.EXCEPTIONS:
|
||||||
return
|
return
|
||||||
if not request.user.is_authenticated():
|
if not request.user.is_authenticated():
|
||||||
# Taken from django/contrib/auth/decorators.py
|
# Taken from django/contrib/auth/decorators.py
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class PretixMultidomainConfig(AppConfig):
|
||||||
|
name = 'pretix.multidomain'
|
||||||
|
label = 'pretixmultidomain'
|
||||||
|
|
||||||
|
default_app_config = 'pretix.multidomain.PretixMultidomainConfig'
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
import time
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.contrib.sessions.middleware import \
|
||||||
|
SessionMiddleware as BaseSessionMiddleware
|
||||||
|
from django.core.exceptions import DisallowedHost
|
||||||
|
from django.http.request import split_domain_port
|
||||||
|
from django.middleware.csrf import CsrfViewMiddleware as BaseCsrfMiddleware
|
||||||
|
from django.utils.cache import patch_vary_headers
|
||||||
|
from django.utils.http import cookie_date
|
||||||
|
|
||||||
|
from pretix.multidomain.models import KnownDomain
|
||||||
|
|
||||||
|
|
||||||
|
class MultiDomainMiddleware:
|
||||||
|
def process_request(self, request):
|
||||||
|
# We try three options, in order of decreasing preference.
|
||||||
|
if settings.USE_X_FORWARDED_HOST and ('HTTP_X_FORWARDED_HOST' in request.META):
|
||||||
|
host = request.META['HTTP_X_FORWARDED_HOST']
|
||||||
|
elif 'HTTP_HOST' in request.META:
|
||||||
|
host = request.META['HTTP_HOST']
|
||||||
|
else:
|
||||||
|
# Reconstruct the host using the algorithm from PEP 333.
|
||||||
|
host = request.META['SERVER_NAME']
|
||||||
|
server_port = str(request.META['SERVER_PORT'])
|
||||||
|
if server_port != ('443' if request.is_secure() else '80'):
|
||||||
|
host = '%s:%s' % (host, server_port)
|
||||||
|
|
||||||
|
domain, port = split_domain_port(host)
|
||||||
|
default_domain, default_port = split_domain_port(urlparse(settings.SITE_URL).netloc)
|
||||||
|
if domain:
|
||||||
|
request.host = domain
|
||||||
|
request.port = int(port) if port else None
|
||||||
|
try:
|
||||||
|
kd = KnownDomain.objects.get(domainname=domain) # noqa
|
||||||
|
request.domain = kd
|
||||||
|
except:
|
||||||
|
if settings.DEBUG or domain in ('testserver', 'localhost') or domain == default_domain:
|
||||||
|
return # TODO: Select main page
|
||||||
|
raise DisallowedHost("Unknown host: %r" % host)
|
||||||
|
else:
|
||||||
|
request.organizer = kd.organizer
|
||||||
|
else:
|
||||||
|
raise DisallowedHost("Invalid HTTP_HOST header: %r." % host)
|
||||||
|
|
||||||
|
|
||||||
|
class SessionMiddleware(BaseSessionMiddleware):
|
||||||
|
def process_response(self, request, response):
|
||||||
|
try:
|
||||||
|
accessed = request.session.accessed
|
||||||
|
modified = request.session.modified
|
||||||
|
empty = request.session.is_empty()
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
# First check if we need to delete this cookie.
|
||||||
|
# The session should be deleted only if the session is entirely empty
|
||||||
|
if settings.SESSION_COOKIE_NAME in request.COOKIES and empty:
|
||||||
|
response.delete_cookie(settings.SESSION_COOKIE_NAME)
|
||||||
|
else:
|
||||||
|
if accessed:
|
||||||
|
patch_vary_headers(response, ('Cookie',))
|
||||||
|
if modified or settings.SESSION_SAVE_EVERY_REQUEST:
|
||||||
|
if request.session.get_expire_at_browser_close():
|
||||||
|
max_age = None
|
||||||
|
expires = None
|
||||||
|
else:
|
||||||
|
max_age = request.session.get_expiry_age()
|
||||||
|
expires_time = time.time() + max_age
|
||||||
|
expires = cookie_date(expires_time)
|
||||||
|
# Save the session data and refresh the client cookie.
|
||||||
|
# Skip session save for 500 responses, refs #3881.
|
||||||
|
if response.status_code != 500:
|
||||||
|
request.session.save()
|
||||||
|
response.set_cookie(settings.SESSION_COOKIE_NAME,
|
||||||
|
request.session.session_key, max_age=max_age,
|
||||||
|
expires=expires, domain=request.host,
|
||||||
|
path=settings.SESSION_COOKIE_PATH,
|
||||||
|
secure=request.scheme == 'https',
|
||||||
|
httponly=settings.SESSION_COOKIE_HTTPONLY or None)
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
class CsrfViewMiddleware(BaseCsrfMiddleware):
|
||||||
|
def process_response(self, request, response):
|
||||||
|
if getattr(response, 'csrf_processing_done', False):
|
||||||
|
return response
|
||||||
|
|
||||||
|
# If CSRF_COOKIE is unset, then CsrfViewMiddleware.process_view was
|
||||||
|
# never called, probably because a request middleware returned a response
|
||||||
|
# (for example, contrib.auth redirecting to a login page).
|
||||||
|
if request.META.get("CSRF_COOKIE") is None:
|
||||||
|
return response
|
||||||
|
|
||||||
|
if not request.META.get("CSRF_COOKIE_USED", False):
|
||||||
|
return response
|
||||||
|
|
||||||
|
# Set the CSRF cookie even if it's already set, so we renew
|
||||||
|
# the expiry timer.
|
||||||
|
response.set_cookie(settings.CSRF_COOKIE_NAME,
|
||||||
|
request.META["CSRF_COOKIE"],
|
||||||
|
max_age=settings.CSRF_COOKIE_AGE,
|
||||||
|
domain=request.host,
|
||||||
|
path=settings.CSRF_COOKIE_PATH,
|
||||||
|
secure=request.scheme == 'https',
|
||||||
|
httponly=settings.CSRF_COOKIE_HTTPONLY
|
||||||
|
)
|
||||||
|
# Content varies with the CSRF cookie, so set the Vary header.
|
||||||
|
patch_vary_headers(response, ('Cookie',))
|
||||||
|
response.csrf_processing_done = True
|
||||||
|
return response
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import versions.models
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('pretixbase', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='KnownDomain',
|
||||||
|
fields=[
|
||||||
|
('domainname', models.CharField(serialize=False, max_length=255, primary_key=True)),
|
||||||
|
('organizer', versions.models.VersionedForeignKey(blank=True, to='pretixbase.Organizer', null=True)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import versions.models
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('pretixmultidomain', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='knowndomain',
|
||||||
|
options={'verbose_name': 'Known domain', 'verbose_name_plural': 'Known domains'},
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='knowndomain',
|
||||||
|
name='organizer',
|
||||||
|
field=versions.models.VersionedForeignKey(to='pretixbase.Organizer', null=True, related_name='domains', blank=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
from django.db import models
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from versions.models import VersionedForeignKey
|
||||||
|
|
||||||
|
from pretix.base.models import Organizer
|
||||||
|
|
||||||
|
|
||||||
|
class KnownDomain(models.Model):
|
||||||
|
domainname = models.CharField(max_length=255, primary_key=True)
|
||||||
|
organizer = VersionedForeignKey(Organizer, blank=True, null=True, related_name='domains')
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _("Known domain")
|
||||||
|
verbose_name_plural = _("Known domains")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.domainname
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
super().save(*args, **kwargs)
|
||||||
|
if self.organizer:
|
||||||
|
self.organizer.get_cache().clear()
|
||||||
|
|
||||||
|
def delete(self, *args, **kwargs):
|
||||||
|
if self.organizer:
|
||||||
|
self.organizer.get_cache().clear()
|
||||||
|
super().delete(*args, **kwargs)
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
from django import template
|
||||||
|
from django.core.urlresolvers import NoReverseMatch
|
||||||
|
from django.template import TemplateSyntaxError
|
||||||
|
from django.template.base import kwarg_re
|
||||||
|
from django.template.defaulttags import URLNode
|
||||||
|
from django.utils.encoding import smart_text
|
||||||
|
from django.utils.html import conditional_escape
|
||||||
|
|
||||||
|
register = template.Library()
|
||||||
|
|
||||||
|
|
||||||
|
class EventURLNode(URLNode):
|
||||||
|
def __init__(self, event, view_name, kwargs, asvar):
|
||||||
|
self.event = event
|
||||||
|
super().__init__(view_name, [], kwargs, asvar)
|
||||||
|
|
||||||
|
def render(self, context):
|
||||||
|
from pretix.multidomain.urlreverse import eventreverse
|
||||||
|
kwargs = {
|
||||||
|
smart_text(k, 'ascii'): v.resolve(context)
|
||||||
|
for k, v in self.kwargs.items()
|
||||||
|
}
|
||||||
|
view_name = self.view_name.resolve(context)
|
||||||
|
event = self.event.resolve(context)
|
||||||
|
url = ''
|
||||||
|
try:
|
||||||
|
url = eventreverse(event, view_name, kwargs=kwargs)
|
||||||
|
except NoReverseMatch:
|
||||||
|
if self.asvar is None:
|
||||||
|
raise
|
||||||
|
|
||||||
|
if self.asvar:
|
||||||
|
context[self.asvar] = url
|
||||||
|
return ''
|
||||||
|
else:
|
||||||
|
if context.autoescape:
|
||||||
|
url = conditional_escape(url)
|
||||||
|
return url
|
||||||
|
|
||||||
|
|
||||||
|
@register.tag
|
||||||
|
def eventurl(parser, token):
|
||||||
|
"""
|
||||||
|
Similar to {% url %} in the same way that eventreverse() is similar to reverse().
|
||||||
|
|
||||||
|
Takes an event object, an url name and optional keyword arguments
|
||||||
|
"""
|
||||||
|
bits = token.split_contents()
|
||||||
|
if len(bits) < 3:
|
||||||
|
raise TemplateSyntaxError("'%s' takes at least one argument, an event and the name of a url()." % bits[0])
|
||||||
|
viewname = parser.compile_filter(bits[2])
|
||||||
|
event = parser.compile_filter(bits[1])
|
||||||
|
kwargs = {}
|
||||||
|
asvar = None
|
||||||
|
bits = bits[3:]
|
||||||
|
if len(bits) >= 3 and bits[-2] == 'as':
|
||||||
|
asvar = bits[-1]
|
||||||
|
bits = bits[:-2]
|
||||||
|
|
||||||
|
if len(bits):
|
||||||
|
for bit in bits:
|
||||||
|
match = kwarg_re.match(bit)
|
||||||
|
if not match:
|
||||||
|
raise TemplateSyntaxError("Malformed arguments to eventurl tag")
|
||||||
|
name, value = match.groups()
|
||||||
|
if name:
|
||||||
|
kwargs[name] = parser.compile_filter(value)
|
||||||
|
else:
|
||||||
|
raise TemplateSyntaxError('Event urls only have keyword arguments.')
|
||||||
|
|
||||||
|
return EventURLNode(event, viewname, kwargs, asvar)
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
from urllib.parse import urljoin, urlsplit
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.core.urlresolvers import reverse
|
||||||
|
|
||||||
|
|
||||||
|
def get_domain(event):
|
||||||
|
c = event.organizer.get_cache()
|
||||||
|
domain = c.get('domain')
|
||||||
|
if domain is None:
|
||||||
|
domains = event.organizer.domains.all()
|
||||||
|
domain = domains[0].domainname if domains else None
|
||||||
|
c.set('domain', domain or 'none')
|
||||||
|
elif domain == 'none':
|
||||||
|
return None
|
||||||
|
return domain
|
||||||
|
|
||||||
|
|
||||||
|
def eventreverse(event, name, kwargs=None):
|
||||||
|
"""
|
||||||
|
Works similar to django.core.urlresolvers.reverse but takes into account that some
|
||||||
|
organizers might have their own (sub)domain instead of a subpath.
|
||||||
|
"""
|
||||||
|
kwargs = kwargs or {}
|
||||||
|
kwargs['event'] = event.slug
|
||||||
|
domain = get_domain(event)
|
||||||
|
if domain:
|
||||||
|
if 'organizer' in kwargs:
|
||||||
|
del kwargs['organizer']
|
||||||
|
path = reverse(name, kwargs=kwargs)
|
||||||
|
siteurlsplit = urlsplit(settings.SITE_URL)
|
||||||
|
if siteurlsplit.port and siteurlsplit.port not in (80, 443):
|
||||||
|
domain = '%s:%d' % (domain, siteurlsplit.port)
|
||||||
|
return urljoin('%s://%s' % (siteurlsplit.scheme, domain), path)
|
||||||
|
|
||||||
|
kwargs['organizer'] = event.organizer.slug
|
||||||
|
return reverse(name, kwargs=kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def build_absolute_uri(event, urlname, kwargs=None):
|
||||||
|
reversedurl = eventreverse(event, urlname, kwargs)
|
||||||
|
if '://' in reversedurl:
|
||||||
|
return reversedurl
|
||||||
|
return urljoin(settings.SITE_URL, reversedurl)
|
||||||
@@ -11,7 +11,7 @@ from django.utils.translation import ugettext as __, ugettext_lazy as _
|
|||||||
from pretix.base.models import Quota
|
from pretix.base.models import Quota
|
||||||
from pretix.base.payment import BasePaymentProvider
|
from pretix.base.payment import BasePaymentProvider
|
||||||
from pretix.base.services.orders import mark_order_paid
|
from pretix.base.services.orders import mark_order_paid
|
||||||
from pretix.helpers.urls import build_absolute_uri
|
from pretix.multidomain.urlreverse import build_absolute_uri
|
||||||
|
|
||||||
logger = logging.getLogger('pretix.plugins.paypal')
|
logger = logging.getLogger('pretix.plugins.paypal')
|
||||||
|
|
||||||
@@ -87,8 +87,8 @@ class Paypal(BasePaymentProvider):
|
|||||||
"payment_method": "paypal",
|
"payment_method": "paypal",
|
||||||
},
|
},
|
||||||
"redirect_urls": {
|
"redirect_urls": {
|
||||||
"return_url": build_absolute_uri('plugins:paypal:return'),
|
"return_url": build_absolute_uri(request.event, 'plugins:paypal:return'),
|
||||||
"cancel_url": build_absolute_uri('plugins:paypal:abort'),
|
"cancel_url": build_absolute_uri(request.event, 'plugins:paypal:abort'),
|
||||||
},
|
},
|
||||||
"transactions": [
|
"transactions": [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ from django.conf.urls import include, url
|
|||||||
from .views import abort, retry, success
|
from .views import abort, retry, success
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^paypal/', include([
|
url(r'^(?:(?P<organizer>[^/]+)/)?(?P<event>[^/]+)/paypal/', include([
|
||||||
url(r'^abort/$', abort, name='abort'),
|
url(r'^abort/$', abort, name='abort'),
|
||||||
url(r'^return/$', success, name='return'),
|
url(r'^return/$', success, name='return'),
|
||||||
url(r'^retry/(?P<order>[^/]+)/', retry, name='retry')
|
url(r'^retry/(?P<order>[^/]+)/', retry, name='retry')
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ from django.utils.translation import ugettext as __, ugettext_lazy as _
|
|||||||
|
|
||||||
from pretix.base.models import Event, Order
|
from pretix.base.models import Event, Order
|
||||||
from pretix.helpers.urls import build_absolute_uri
|
from pretix.helpers.urls import build_absolute_uri
|
||||||
|
from pretix.multidomain.urlreverse import eventreverse
|
||||||
from pretix.plugins.paypal.payment import Paypal
|
from pretix.plugins.paypal.payment import Paypal
|
||||||
|
|
||||||
logger = logging.getLogger('pretix.plugins.paypal')
|
logger = logging.getLogger('pretix.plugins.paypal')
|
||||||
@@ -23,10 +24,7 @@ def success(request):
|
|||||||
request.session['payment_paypal_payer'] = payer
|
request.session['payment_paypal_payer'] = payer
|
||||||
try:
|
try:
|
||||||
event = Event.objects.current.get(identity=request.session['payment_paypal_event'])
|
event = Event.objects.current.get(identity=request.session['payment_paypal_event'])
|
||||||
return redirect('presale:event.checkout',
|
return redirect(eventreverse(event, 'presale:event.checkout', kwargs={'step': 'confirm'}))
|
||||||
event=event.slug,
|
|
||||||
organizer=event.organizer.slug,
|
|
||||||
step='confirm')
|
|
||||||
except Event.DoesNotExist:
|
except Event.DoesNotExist:
|
||||||
pass # TODO: Handle this
|
pass # TODO: Handle this
|
||||||
else:
|
else:
|
||||||
@@ -38,10 +36,7 @@ def abort(request):
|
|||||||
messages.error(request, _('It looks like you cancelled the PayPal payment'))
|
messages.error(request, _('It looks like you cancelled the PayPal payment'))
|
||||||
try:
|
try:
|
||||||
event = Event.objects.current.get(identity=request.session['payment_paypal_event'])
|
event = Event.objects.current.get(identity=request.session['payment_paypal_event'])
|
||||||
return redirect('presale:event.checkout',
|
return redirect(eventreverse(event, 'presale:event.checkout', kwargs={'step': 'payment'}))
|
||||||
event=event.slug,
|
|
||||||
organizer=event.organizer.slug,
|
|
||||||
step='payment')
|
|
||||||
except Event.DoesNotExist:
|
except Event.DoesNotExist:
|
||||||
pass # TODO: Handle this
|
pass # TODO: Handle this
|
||||||
|
|
||||||
@@ -103,8 +98,7 @@ def retry(request, order):
|
|||||||
if resp:
|
if resp:
|
||||||
return redirect(resp)
|
return redirect(resp)
|
||||||
|
|
||||||
return redirect('presale:event.order',
|
return redirect(eventreverse(order.event, 'presale:event.order', kwargs={
|
||||||
event=order.event.slug,
|
'order': order.code,
|
||||||
organizer=order.event.organizer.slug,
|
'secret': order.secret
|
||||||
order=order.code,
|
}) + '?paid=yes')
|
||||||
secret=order.secret) + '?paid=yes'
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.core.validators import EmailValidator
|
from django.core.validators import EmailValidator
|
||||||
from django.db.models import Q, Sum
|
from django.db.models import Q, Sum
|
||||||
from django.http import HttpResponseNotAllowed
|
from django.http import HttpResponseNotAllowed
|
||||||
@@ -14,6 +13,7 @@ from django.views.generic.base import TemplateResponseMixin
|
|||||||
from pretix.base.models import CartPosition, Order
|
from pretix.base.models import CartPosition, Order
|
||||||
from pretix.base.services.orders import OrderError, perform_order
|
from pretix.base.services.orders import OrderError, perform_order
|
||||||
from pretix.base.signals import register_payment_providers
|
from pretix.base.signals import register_payment_providers
|
||||||
|
from pretix.multidomain.urlreverse import eventreverse
|
||||||
from pretix.presale.forms.checkout import ContactForm
|
from pretix.presale.forms.checkout import ContactForm
|
||||||
from pretix.presale.signals import checkout_flow_steps
|
from pretix.presale.signals import checkout_flow_steps
|
||||||
from pretix.presale.views import CartMixin
|
from pretix.presale.views import CartMixin
|
||||||
@@ -59,32 +59,19 @@ class BaseCheckoutFlowStep:
|
|||||||
return HttpResponseNotAllowed([])
|
return HttpResponseNotAllowed([])
|
||||||
|
|
||||||
def get_step_url(self):
|
def get_step_url(self):
|
||||||
return reverse(
|
return eventreverse(self.event, 'presale:event.checkout', kwargs={'step': self.identifier})
|
||||||
'presale:event.checkout',
|
|
||||||
kwargs={
|
|
||||||
'event': self.event.slug,
|
|
||||||
'organizer': self.event.organizer.slug,
|
|
||||||
'step': self.identifier
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_prev_url(self, request):
|
def get_prev_url(self, request):
|
||||||
prev = self.get_prev_applicable(request)
|
prev = self.get_prev_applicable(request)
|
||||||
if not prev:
|
if not prev:
|
||||||
return reverse('presale:event.index', kwargs={
|
return eventreverse(self.event, 'presale:event.index')
|
||||||
'event': self.request.event.slug,
|
|
||||||
'organizer': self.request.event.organizer.slug
|
|
||||||
})
|
|
||||||
else:
|
else:
|
||||||
return prev.get_step_url()
|
return prev.get_step_url()
|
||||||
|
|
||||||
def get_next_url(self, request):
|
def get_next_url(self, request):
|
||||||
n = self.get_next_applicable(request)
|
n = self.get_next_applicable(request)
|
||||||
if not n:
|
if not n:
|
||||||
return reverse('presale:event.checkout.confirm', kwargs={
|
return eventreverse(self.event, 'presale:event.checkout.confirm')
|
||||||
'event': self.request.event.slug,
|
|
||||||
'organizer': self.request.event.organizer.slug
|
|
||||||
})
|
|
||||||
else:
|
else:
|
||||||
return n.get_step_url()
|
return n.get_step_url()
|
||||||
|
|
||||||
@@ -342,9 +329,7 @@ class ConfirmStep(CartMixin, AsyncAction, TemplateFlowStep):
|
|||||||
return self.get_step_url()
|
return self.get_step_url()
|
||||||
|
|
||||||
def get_order_url(self, order):
|
def get_order_url(self, order):
|
||||||
return reverse('presale:event.order.pay.complete', kwargs={
|
return eventreverse(self.request.event, 'presale:event.order.pay.complete', kwargs={
|
||||||
'event': self.request.event.slug,
|
|
||||||
'organizer': self.request.event.organizer.slug,
|
|
||||||
'order': order.code,
|
'order': order.code,
|
||||||
'secret': order.secret
|
'secret': order.secret
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
|
from urllib.parse import urljoin
|
||||||
|
|
||||||
from django.core.urlresolvers import resolve
|
from django.core.urlresolvers import resolve
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
|
from django.shortcuts import redirect
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from pretix.base.models import Event
|
from pretix.base.models import Event
|
||||||
|
from pretix.multidomain.urlreverse import get_domain
|
||||||
|
|
||||||
|
|
||||||
class EventMiddleware:
|
class EventMiddleware:
|
||||||
@@ -15,10 +19,36 @@ class EventMiddleware:
|
|||||||
|
|
||||||
if 'event.' in url_name and 'event' in url.kwargs:
|
if 'event.' in url_name and 'event' in url.kwargs:
|
||||||
try:
|
try:
|
||||||
request.event = Event.objects.current.filter(
|
if hasattr(request, 'organizer'):
|
||||||
slug=url.kwargs['event'],
|
# We are on an organizer's custom domain
|
||||||
organizer__slug=url.kwargs['organizer'],
|
if 'organizer' in url.kwargs and url.kwargs['organizer']:
|
||||||
).select_related('organizer')[0]
|
if url.kwargs['organizer'] != request.organizer.slug:
|
||||||
|
raise Http404(_('The selected event was not found.'))
|
||||||
|
path = "/" + request.get_full_path().split("/", 2)[-1]
|
||||||
|
return redirect(path)
|
||||||
|
|
||||||
|
request.event = Event.objects.current.filter(
|
||||||
|
slug=url.kwargs['event'],
|
||||||
|
organizer=request.organizer,
|
||||||
|
).select_related('organizer')[0]
|
||||||
|
else:
|
||||||
|
# We are on our main domain
|
||||||
|
if 'organizer' not in url.kwargs:
|
||||||
|
raise Http404(_('The selected event was not found.'))
|
||||||
|
|
||||||
|
request.event = Event.objects.current.filter(
|
||||||
|
slug=url.kwargs['event'],
|
||||||
|
organizer__slug=url.kwargs['organizer']
|
||||||
|
).select_related('organizer')[0]
|
||||||
|
|
||||||
|
# If this organizer has a custom domain, send the user there
|
||||||
|
domain = get_domain(request.event)
|
||||||
|
if domain:
|
||||||
|
if request.port and request.port not in (80, 443):
|
||||||
|
domain = '%s:%d' % (domain, request.port)
|
||||||
|
path = request.get_full_path().split("/", 2)[-1]
|
||||||
|
return redirect(urljoin('%s://%s' % (request.scheme, domain), path))
|
||||||
|
|
||||||
except IndexError:
|
except IndexError:
|
||||||
raise Http404(_('The selected event was not found.'))
|
raise Http404(_('The selected event was not found.'))
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
{% load compress %}
|
{% load compress %}
|
||||||
{% load staticfiles %}
|
{% load staticfiles %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
{% load eventurl %}
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
@@ -22,7 +23,7 @@
|
|||||||
<div class="container event">
|
<div class="container event">
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<h1 class="pull-left">
|
<h1 class="pull-left">
|
||||||
<a href="{% url "presale:event.index" event=event.slug organizer=event.organizer.slug %}">{{ event.name }}</a>
|
<a href="{% eventurl event "presale:event.index" %}">{{ event.name }}</a>
|
||||||
<small>{{ event.date_from|date:"DATE_FORMAT" }}{% if event.settings.show_date_to %} – {{ event.date_to|date:"DATE_FORMAT" }}{% endif %}</small>
|
<small>{{ event.date_from|date:"DATE_FORMAT" }}{% if event.settings.show_date_to %} – {{ event.date_to|date:"DATE_FORMAT" }}{% endif %}</small>
|
||||||
</h1>
|
</h1>
|
||||||
<div class="pull-right loginbox">
|
<div class="pull-right loginbox">
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
{% extends "pretixpresale/event/base.html" %}
|
{% extends "pretixpresale/event/base.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load bootstrap3 %}
|
{% load bootstrap3 %}
|
||||||
|
{% load eventurl %}
|
||||||
{% block title %}{% trans "Confirm order" %}{% endblock %}
|
{% block title %}{% trans "Confirm order" %}{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h2>{% trans "Confirm order" %}</h2>
|
<h2>{% trans "Confirm order" %}</h2>
|
||||||
@@ -11,7 +12,7 @@
|
|||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<div class="pull-right">
|
<div class="pull-right">
|
||||||
<a href="
|
<a href="
|
||||||
{% url "presale:event.index" organizer=request.event.organizer.slug event=request.event.slug %}">
|
{% eventurl request.event "presale:event.index" %}">
|
||||||
<span class="fa fa-edit"></span>
|
<span class="fa fa-edit"></span>
|
||||||
{% trans "Modify" %}
|
{% trans "Modify" %}
|
||||||
</a>
|
</a>
|
||||||
@@ -41,7 +42,7 @@
|
|||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
{% if payment_provider.identifier != "free" %}
|
{% if payment_provider.identifier != "free" %}
|
||||||
<div class="pull-right">
|
<div class="pull-right">
|
||||||
<a href="{% url "presale:event.checkout" step="payment" organizer=request.event.organizer.slug event=request.event.slug %}">
|
<a href="{% eventurl request.event "presale:event.checkout" step="payment" %}">
|
||||||
<span class="fa fa-edit"></span>
|
<span class="fa fa-edit"></span>
|
||||||
{% trans "Modify" %}
|
{% trans "Modify" %}
|
||||||
</a>
|
</a>
|
||||||
@@ -59,7 +60,7 @@
|
|||||||
<div class="panel panel-primary panel-contact">
|
<div class="panel panel-primary panel-contact">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<div class="pull-right">
|
<div class="pull-right">
|
||||||
<a href="{% url "presale:event.checkout" step="questions" organizer=request.event.organizer.slug event=request.event.slug %}">
|
<a href="{% eventurl request.event "presale:event.checkout" step="questions" %}">
|
||||||
<span class="fa fa-edit"></span>
|
<span class="fa fa-edit"></span>
|
||||||
{% trans "Modify" %}
|
{% trans "Modify" %}
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
{% load eventurl %}
|
||||||
{% for line in cart.positions %}
|
{% for line in cart.positions %}
|
||||||
<div class="row-fluid cart-row">
|
<div class="row-fluid cart-row">
|
||||||
<div class="col-md-4 col-xs-6">
|
<div class="col-md-4 col-xs-6">
|
||||||
@@ -21,7 +22,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-md-2 col-xs-6 count">
|
<div class="col-md-2 col-xs-6 count">
|
||||||
{% if editable %}
|
{% if editable %}
|
||||||
<form action="{% url "presale:event.cart.remove" event=event.slug organizer=event.organizer.slug %}"
|
<form action="{% eventurl event "presale:event.cart.remove" %}"
|
||||||
method="post">
|
method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{% if line.variation %}
|
{% if line.variation %}
|
||||||
@@ -36,7 +37,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{{ line.count }}
|
{{ line.count }}
|
||||||
{% if editable %}
|
{% if editable %}
|
||||||
<form action="{% url "presale:event.cart.add" event=event.slug organizer=event.organizer.slug %}"
|
<form action="{% eventurl event "presale:event.cart.add" %}"
|
||||||
method="post" data-asynctask>
|
method="post" data-asynctask>
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{% if line.variation %}
|
{% if line.variation %}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{% extends "pretixpresale/event/base.html" %}
|
{% extends "pretixpresale/event/base.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
{% load eventurl %}
|
||||||
{% load thumbnail %}
|
{% load thumbnail %}
|
||||||
{% block title %}{% trans "Presale" %}{% endblock %}
|
{% block title %}{% trans "Presale" %}{% endblock %}
|
||||||
|
|
||||||
@@ -23,7 +24,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-md-4 col-md-offset-2 col-xs-12">
|
<div class="col-md-4 col-md-offset-2 col-xs-12">
|
||||||
<a class="btn btn-block btn-primary btn-lg"
|
<a class="btn btn-block btn-primary btn-lg"
|
||||||
href="{% url "presale:event.checkout.start" organizer=request.event.organizer.slug event=request.event.slug %}">
|
href="{% eventurl request.event "presale:event.checkout.start" %}">
|
||||||
<i class="fa fa-shopping-cart"></i> {% trans "Proceed with checkout" %}
|
<i class="fa fa-shopping-cart"></i> {% trans "Proceed with checkout" %}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -51,7 +52,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% if event.presale_is_running or event.settings.show_items_outside_presale_period %}
|
{% if event.presale_is_running or event.settings.show_items_outside_presale_period %}
|
||||||
<form method="post" data-asynctask
|
<form method="post" data-asynctask
|
||||||
action="{% url "presale:event.cart.add" organizer=request.event.organizer.slug event=request.event.slug %}?next={{ request.path|urlencode }}">
|
action="{% eventurl request.event "presale:event.cart.add" %}?next={{ request.path|urlencode }}">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{% for tup in items_by_category %}
|
{% for tup in items_by_category %}
|
||||||
<section>
|
<section>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
{% extends "pretixpresale/event/base.html" %}
|
{% extends "pretixpresale/event/base.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load bootstrap3 %}
|
{% load bootstrap3 %}
|
||||||
|
{% load eventurl %}
|
||||||
{% block title %}{% trans "Order details" %}{% endblock %}
|
{% block title %}{% trans "Order details" %}{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% if "thanks" in request.GET or "paid" in request.GET %}
|
{% if "thanks" in request.GET or "paid" in request.GET %}
|
||||||
@@ -32,7 +33,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
{% if can_retry %}
|
{% if can_retry %}
|
||||||
<a href="{% url "presale:event.order.pay" organizer=request.event.organizer.slug event=request.event.slug secret=order.secret order=order.code %}"
|
<a href="{% eventurl event "presale:event.order.pay" secret=order.secret order=order.code %}"
|
||||||
class="btn btn-primary pull-right"><i class="fa fa-money"></i> {% trans "Complete payment" %}
|
class="btn btn-primary pull-right"><i class="fa fa-money"></i> {% trans "Complete payment" %}
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -59,7 +60,7 @@
|
|||||||
{% endblocktrans %}
|
{% endblocktrans %}
|
||||||
</p>
|
</p>
|
||||||
{% for b in download_buttons %}
|
{% for b in download_buttons %}
|
||||||
<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 %}"
|
<a href="{% eventurl event "presale:event.order.download" secret=order.secret order=order.code output=b.identifier %}"
|
||||||
class="btn btn-primary">
|
class="btn btn-primary">
|
||||||
<span class="fa {{ b.icon }}"></span> {{ b.text }}
|
<span class="fa {{ b.icon }}"></span> {{ b.text }}
|
||||||
</a>
|
</a>
|
||||||
@@ -76,7 +77,7 @@
|
|||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
{% if order.can_modify_answers %}
|
{% if order.can_modify_answers %}
|
||||||
<div class="pull-right">
|
<div class="pull-right">
|
||||||
<a href="{% url "presale:event.order.modify" organizer=request.event.organizer.slug event=request.event.slug secret=order.secret order=order.code %}">
|
<a href="{% eventurl event "presale:event.order.modify" secret=order.secret order=order.code %}">
|
||||||
<span class="fa fa-edit"></span>
|
<span class="fa fa-edit"></span>
|
||||||
{% trans "Change details" %}
|
{% trans "Change details" %}
|
||||||
</a>
|
</a>
|
||||||
@@ -94,7 +95,7 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12 text-right">
|
<div class="col-md-12 text-right">
|
||||||
<p>
|
<p>
|
||||||
<a href="{% url 'presale:event.order.cancel' event=request.event.slug organizer=request.event.organizer.slug secret=order.secret order=order.code %}"
|
<a href="{% eventurl event 'presale:event.order.cancel' secret=order.secret order=order.code %}"
|
||||||
class="btn btn-danger">
|
class="btn btn-danger">
|
||||||
<span class="fa fa-remove"></span>
|
<span class="fa fa-remove"></span>
|
||||||
{% trans "Cancel order" %}
|
{% trans "Cancel order" %}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{% extends "pretixpresale/event/base.html" %}
|
{% extends "pretixpresale/event/base.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
{% load eventurl %}
|
||||||
{% block title %}{% trans "Cancel order" %}{% endblock %}
|
{% block title %}{% trans "Cancel order" %}{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h2>
|
<h2>
|
||||||
@@ -16,7 +17,7 @@
|
|||||||
<div class="row checkout-button-row">
|
<div class="row checkout-button-row">
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<a class="btn btn-block btn-default btn-lg"
|
<a class="btn btn-block btn-default btn-lg"
|
||||||
href="{% url "presale:event.order" event=request.event.slug organizer=request.event.organizer.slug secret=order.secret order=order.code %}">
|
href="{% eventurl request.event "presale:event.order" secret=order.secret order=order.code %}">
|
||||||
{% trans "No, take me back" %}
|
{% trans "No, take me back" %}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{% extends "pretixpresale/event/base.html" %}
|
{% extends "pretixpresale/event/base.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
{% load eventurl %}
|
||||||
{% block title %}{% trans "Pay order" %}{% endblock %}
|
{% block title %}{% trans "Pay order" %}{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h2>
|
<h2>
|
||||||
@@ -16,7 +17,7 @@
|
|||||||
<div class="row checkout-button-row">
|
<div class="row checkout-button-row">
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<a class="btn btn-block btn-default btn-lg"
|
<a class="btn btn-block btn-default btn-lg"
|
||||||
href="{% url "presale:event.order" event=request.event.slug organizer=request.event.organizer.slug secret=order.secret order=order.code %}">
|
href="{% eventurl request.event "presale:event.order" secret=order.secret order=order.code %}">
|
||||||
{% trans "Cancel" %}
|
{% trans "Cancel" %}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{% extends "pretixpresale/event/base.html" %}
|
{% extends "pretixpresale/event/base.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
{% load eventurl %}
|
||||||
{% block title %}{% trans "Pay order" %}{% endblock %}
|
{% block title %}{% trans "Pay order" %}{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h2>
|
<h2>
|
||||||
@@ -27,7 +28,7 @@
|
|||||||
<div class="row checkout-button-row">
|
<div class="row checkout-button-row">
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<a class="btn btn-block btn-default btn-lg"
|
<a class="btn btn-block btn-default btn-lg"
|
||||||
href="{% url "presale:event.order" event=request.event.slug organizer=request.event.organizer.slug secret=order.secret order=order.code %}">
|
href="{% eventurl request.event "presale:event.order" secret=order.secret order=order.code %}">
|
||||||
{% trans "Cancel" %}
|
{% trans "Cancel" %}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+30
-27
@@ -6,33 +6,36 @@ import pretix.presale.views.event
|
|||||||
import pretix.presale.views.locale
|
import pretix.presale.views.locale
|
||||||
import pretix.presale.views.order
|
import pretix.presale.views.order
|
||||||
|
|
||||||
|
eventurls = [
|
||||||
|
url(r'^cart/add$', pretix.presale.views.cart.CartAdd.as_view(), name='event.cart.add'),
|
||||||
|
url(r'^cart/remove$', pretix.presale.views.cart.CartRemove.as_view(), name='event.cart.remove'),
|
||||||
|
url(r'^checkout/start$', pretix.presale.views.checkout.CheckoutView.as_view(), name='event.checkout.start'),
|
||||||
|
url(r'^checkout/(?P<step>[^/]+)/$', pretix.presale.views.checkout.CheckoutView.as_view(),
|
||||||
|
name='event.checkout'),
|
||||||
|
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>[^/]+)/(?P<secret>[A-Za-z0-9]+)/cancel$',
|
||||||
|
pretix.presale.views.order.OrderCancel.as_view(),
|
||||||
|
name='event.order.cancel'),
|
||||||
|
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>[^/]+)/(?P<secret>[A-Za-z0-9]+)/pay$', pretix.presale.views.order.OrderPay.as_view(),
|
||||||
|
name='event.order.pay'),
|
||||||
|
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>[^/]+)/(?P<secret>[A-Za-z0-9]+)/pay/complete$',
|
||||||
|
pretix.presale.views.order.OrderPayComplete.as_view(),
|
||||||
|
name='event.order.pay.complete'),
|
||||||
|
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'^$', pretix.presale.views.event.EventIndex.as_view(), name='event.index'),
|
||||||
|
]
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^(?P<organizer>[^/]+)/(?P<event>[^/]+)/', include([
|
|
||||||
url(r'^$', pretix.presale.views.event.EventIndex.as_view(), name='event.index'),
|
|
||||||
url(r'^cart/add$', pretix.presale.views.cart.CartAdd.as_view(), name='event.cart.add'),
|
|
||||||
url(r'^cart/remove$', pretix.presale.views.cart.CartRemove.as_view(), name='event.cart.remove'),
|
|
||||||
url(r'^checkout/$', pretix.presale.views.checkout.CheckoutView.as_view(), name='event.checkout.start'),
|
|
||||||
url(r'^checkout/(?P<step>[^/]+)/$', pretix.presale.views.checkout.CheckoutView.as_view(),
|
|
||||||
name='event.checkout'),
|
|
||||||
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>[^/]+)/(?P<secret>[A-Za-z0-9]+)/cancel$',
|
|
||||||
pretix.presale.views.order.OrderCancel.as_view(),
|
|
||||||
name='event.order.cancel'),
|
|
||||||
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>[^/]+)/(?P<secret>[A-Za-z0-9]+)/pay$', pretix.presale.views.order.OrderPay.as_view(),
|
|
||||||
name='event.order.pay'),
|
|
||||||
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>[^/]+)/(?P<secret>[A-Za-z0-9]+)/pay/complete$',
|
|
||||||
pretix.presale.views.order.OrderPayComplete.as_view(),
|
|
||||||
name='event.order.pay.complete'),
|
|
||||||
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'^locale/set$', pretix.presale.views.locale.LocaleSet.as_view(), name='locale.set'),
|
url(r'^locale/set$', pretix.presale.views.locale.LocaleSet.as_view(), name='locale.set'),
|
||||||
|
url(r'^(?P<event>[^/]+)/', include(eventurls)),
|
||||||
|
url(r'^(?P<organizer>[^/]+)/(?P<event>[^/]+)/', include(eventurls)),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ from datetime import timedelta
|
|||||||
from itertools import groupby
|
from itertools import groupby
|
||||||
|
|
||||||
from django.contrib.auth.views import redirect_to_login
|
from django.contrib.auth.views import redirect_to_login
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
|
|
||||||
from pretix.base.models import CartPosition
|
from pretix.base.models import CartPosition
|
||||||
from pretix.base.signals import register_payment_providers
|
from pretix.base.signals import register_payment_providers
|
||||||
|
from pretix.multidomain.urlreverse import eventreverse
|
||||||
|
|
||||||
|
|
||||||
def login_required(view_func):
|
def login_required(view_func):
|
||||||
@@ -15,12 +15,7 @@ def login_required(view_func):
|
|||||||
if request.user.is_authenticated():
|
if request.user.is_authenticated():
|
||||||
return view_func(request, *args, **kwargs)
|
return view_func(request, *args, **kwargs)
|
||||||
path = request.path
|
path = request.path
|
||||||
return redirect_to_login(
|
return redirect_to_login(path, eventreverse(request.event, 'presale:event.checkout.login'), 'next')
|
||||||
path, reverse('presale:event.checkout.login', kwargs={
|
|
||||||
'organizer': request.event.organizer.slug,
|
|
||||||
'event': request.event.slug,
|
|
||||||
}), 'next'
|
|
||||||
)
|
|
||||||
|
|
||||||
return _wrapped_view
|
return _wrapped_view
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.http import JsonResponse
|
from django.http import JsonResponse
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
@@ -8,6 +7,7 @@ from django.views.generic import View
|
|||||||
from pretix.base.services.cart import (
|
from pretix.base.services.cart import (
|
||||||
CartError, add_items_to_cart, remove_items_from_cart,
|
CartError, add_items_to_cart, remove_items_from_cart,
|
||||||
)
|
)
|
||||||
|
from pretix.multidomain.urlreverse import eventreverse
|
||||||
from pretix.presale.views import EventViewMixin
|
from pretix.presale.views import EventViewMixin
|
||||||
from pretix.presale.views.async import AsyncAction
|
from pretix.presale.views.async import AsyncAction
|
||||||
|
|
||||||
@@ -18,10 +18,7 @@ class CartActionMixin:
|
|||||||
if "next" in self.request.GET and '://' not in self.request.GET:
|
if "next" in self.request.GET and '://' not in self.request.GET:
|
||||||
return self.request.GET.get('next')
|
return self.request.GET.get('next')
|
||||||
else:
|
else:
|
||||||
return reverse('presale:event.index', kwargs={
|
return eventreverse(self.request.event, 'presale:event.index')
|
||||||
'event': self.request.event.slug,
|
|
||||||
'organizer': self.request.event.organizer.slug,
|
|
||||||
})
|
|
||||||
|
|
||||||
def get_success_url(self, value=None):
|
def get_success_url(self, value=None):
|
||||||
return self.get_next_url()
|
return self.get_next_url()
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.views.generic import View
|
from django.views.generic import View
|
||||||
|
|
||||||
|
from pretix.multidomain.urlreverse import eventreverse
|
||||||
from pretix.presale.checkoutflow import get_checkout_flow
|
from pretix.presale.checkoutflow import get_checkout_flow
|
||||||
from pretix.presale.views import CartMixin
|
from pretix.presale.views import CartMixin
|
||||||
|
|
||||||
@@ -14,10 +14,7 @@ class CheckoutView(CartMixin, View):
|
|||||||
self.request = request
|
self.request = request
|
||||||
if not self.positions and "async_id" not in request.GET:
|
if not self.positions and "async_id" not in request.GET:
|
||||||
messages.error(request, _("Your cart is empty"))
|
messages.error(request, _("Your cart is empty"))
|
||||||
return redirect(reverse('presale:event.index', kwargs={
|
return redirect(eventreverse(self.request.event, 'presale:event.index'))
|
||||||
'organizer': self.request.event.organizer.slug,
|
|
||||||
'event': self.request.event.slug
|
|
||||||
}))
|
|
||||||
|
|
||||||
flow = get_checkout_flow(self.request.event)
|
flow = get_checkout_flow(self.request.event)
|
||||||
for step in flow:
|
for step in flow:
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ from pretix.base.services.tickets import generate
|
|||||||
from pretix.base.signals import (
|
from pretix.base.signals import (
|
||||||
register_payment_providers, register_ticket_outputs,
|
register_payment_providers, register_ticket_outputs,
|
||||||
)
|
)
|
||||||
|
from pretix.multidomain.urlreverse import eventreverse
|
||||||
from pretix.presale.views import CartMixin, EventViewMixin
|
from pretix.presale.views import CartMixin, EventViewMixin
|
||||||
from pretix.presale.views.questions import QuestionsViewMixin
|
from pretix.presale.views.questions import QuestionsViewMixin
|
||||||
|
|
||||||
@@ -36,9 +37,7 @@ class OrderDetailMixin:
|
|||||||
return provider
|
return provider
|
||||||
|
|
||||||
def get_order_url(self):
|
def get_order_url(self):
|
||||||
return reverse('presale:event.order', kwargs={
|
return eventreverse(self.request.event, 'presale:event.order', kwargs={
|
||||||
'event': self.request.event.slug,
|
|
||||||
'organizer': self.request.event.organizer.slug,
|
|
||||||
'order': self.order.code,
|
'order': self.order.code,
|
||||||
'secret': self.order.secret
|
'secret': self.order.secret
|
||||||
})
|
})
|
||||||
@@ -132,9 +131,7 @@ class OrderPay(EventViewMixin, OrderDetailMixin, TemplateView):
|
|||||||
return self.payment_provider.payment_form_render(self.request)
|
return self.payment_provider.payment_form_render(self.request)
|
||||||
|
|
||||||
def get_confirm_url(self):
|
def get_confirm_url(self):
|
||||||
return reverse('presale:event.order.pay.confirm', kwargs={
|
return eventreverse(self.request.event, 'presale:event.order.pay.confirm', kwargs={
|
||||||
'event': self.request.event.slug,
|
|
||||||
'organizer': self.request.event.organizer.slug,
|
|
||||||
'order': self.order.code,
|
'order': self.order.code,
|
||||||
'secret': self.order.secret
|
'secret': self.order.secret
|
||||||
})
|
})
|
||||||
@@ -169,9 +166,7 @@ class OrderPayDo(EventViewMixin, OrderDetailMixin, TemplateView):
|
|||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
def get_payment_url(self):
|
def get_payment_url(self):
|
||||||
return reverse('presale:event.order.pay', kwargs={
|
return eventreverse(self.request.event, 'presale:event.order.pay', kwargs={
|
||||||
'event': self.request.event.slug,
|
|
||||||
'organizer': self.request.event.organizer.slug,
|
|
||||||
'order': self.order.code,
|
'order': self.order.code,
|
||||||
'secret': self.order.secret
|
'secret': self.order.secret
|
||||||
})
|
})
|
||||||
@@ -194,9 +189,7 @@ class OrderPayComplete(EventViewMixin, OrderDetailMixin, View):
|
|||||||
return redirect(resp or self.get_order_url() + '?paid=yes')
|
return redirect(resp or self.get_order_url() + '?paid=yes')
|
||||||
|
|
||||||
def get_payment_url(self):
|
def get_payment_url(self):
|
||||||
return reverse('presale:event.order.pay', kwargs={
|
return eventreverse(self.request.event, 'presale:event.order.pay', kwargs={
|
||||||
'event': self.request.event.slug,
|
|
||||||
'organizer': self.request.event.organizer.slug,
|
|
||||||
'order': self.order.code,
|
'order': self.order.code,
|
||||||
'secret': self.order.secret
|
'secret': self.order.secret
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ PRETIX_PLUGINS_DEFAULT = config.get('pretix', 'plugins_default',
|
|||||||
|
|
||||||
DEFAULT_CURRENCY = config.get('pretix', 'currency', fallback='EUR')
|
DEFAULT_CURRENCY = config.get('pretix', 'currency', fallback='EUR')
|
||||||
|
|
||||||
ALLOWED_HOSTS = config.get('django', 'hosts', fallback='localhost').split(',')
|
ALLOWED_HOSTS = ['*']
|
||||||
|
|
||||||
LANGUAGE_CODE = config.get('locale', 'default', fallback='en')
|
LANGUAGE_CODE = config.get('locale', 'default', fallback='en')
|
||||||
TIME_ZONE = config.get('locale', 'timezone', fallback='UTC')
|
TIME_ZONE = config.get('locale', 'timezone', fallback='UTC')
|
||||||
@@ -79,11 +79,6 @@ EMAIL_HOST_PASSWORD = config.get('mail', 'password', fallback='')
|
|||||||
|
|
||||||
ADMINS = [('Admin', n) for n in config.get('mail', 'admins', fallback='').split(",") if n]
|
ADMINS = [('Admin', n) for n in config.get('mail', 'admins', fallback='').split(",") if n]
|
||||||
|
|
||||||
SESSION_COOKIE_SECURE = SESSION_COOKIE_HTTPONLY = config.getboolean(
|
|
||||||
'pretix', 'securecookie', fallback=False)
|
|
||||||
LANGUAGE_COOKIE_DOMAIN = SESSION_COOKIE_DOMAIN = CSRF_COOKIE_DOMAIN = config.get(
|
|
||||||
'pretix', 'cookiedomain', fallback=None)
|
|
||||||
|
|
||||||
CACHES = {
|
CACHES = {
|
||||||
'default': {
|
'default': {
|
||||||
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
|
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
|
||||||
@@ -98,6 +93,8 @@ if HAS_MEMCACHED:
|
|||||||
'LOCATION': config.get('memcached', 'location'),
|
'LOCATION': config.get('memcached', 'location'),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SESSION_ENGINE = "django.contrib.sessions.backends.cached_db"
|
||||||
|
|
||||||
HAS_REDIS = config.has_option('redis', 'location')
|
HAS_REDIS = config.has_option('redis', 'location')
|
||||||
if HAS_REDIS:
|
if HAS_REDIS:
|
||||||
CACHES['redis'] = {
|
CACHES['redis'] = {
|
||||||
@@ -126,6 +123,7 @@ STATIC_ROOT = '_static'
|
|||||||
SESSION_COOKIE_NAME = 'pretix_session'
|
SESSION_COOKIE_NAME = 'pretix_session'
|
||||||
LANGUAGE_COOKIE_NAME = 'pretix_language'
|
LANGUAGE_COOKIE_NAME = 'pretix_language'
|
||||||
CSRF_COOKIE_NAME = 'pretix_csrftoken'
|
CSRF_COOKIE_NAME = 'pretix_csrftoken'
|
||||||
|
SESSION_COOKIE_HTTPONLY = True
|
||||||
|
|
||||||
INSTALLED_APPS = (
|
INSTALLED_APPS = (
|
||||||
'django.contrib.auth',
|
'django.contrib.auth',
|
||||||
@@ -136,6 +134,7 @@ INSTALLED_APPS = (
|
|||||||
'pretix.base',
|
'pretix.base',
|
||||||
'pretix.control',
|
'pretix.control',
|
||||||
'pretix.presale',
|
'pretix.presale',
|
||||||
|
'pretix.multidomain',
|
||||||
'compressor',
|
'compressor',
|
||||||
'bootstrap3',
|
'bootstrap3',
|
||||||
'debug_toolbar.apps.DebugToolbarConfig',
|
'debug_toolbar.apps.DebugToolbarConfig',
|
||||||
@@ -153,9 +152,10 @@ INSTALLED_APPS = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
MIDDLEWARE_CLASSES = (
|
MIDDLEWARE_CLASSES = (
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
'pretix.multidomain.middlewares.MultiDomainMiddleware',
|
||||||
|
'pretix.multidomain.middlewares.SessionMiddleware',
|
||||||
'django.middleware.common.CommonMiddleware',
|
'django.middleware.common.CommonMiddleware',
|
||||||
'django.middleware.csrf.CsrfViewMiddleware',
|
'pretix.multidomain.middlewares.CsrfViewMiddleware',
|
||||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||||
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
|
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
|
||||||
'debug_toolbar.middleware.DebugToolbarMiddleware',
|
'debug_toolbar.middleware.DebugToolbarMiddleware',
|
||||||
@@ -272,6 +272,7 @@ MESSAGE_TAGS = {
|
|||||||
messages.WARNING: 'alert-warning',
|
messages.WARNING: 'alert-warning',
|
||||||
messages.SUCCESS: 'alert-success',
|
messages.SUCCESS: 'alert-success',
|
||||||
}
|
}
|
||||||
|
MESSAGE_STORAGE = 'django.contrib.messages.storage.session.SessionStorage'
|
||||||
|
|
||||||
THUMBNAIL_ALIASES = {
|
THUMBNAIL_ALIASES = {
|
||||||
'': {
|
'': {
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ for app in apps.get_app_configs():
|
|||||||
pluginpatterns.append(
|
pluginpatterns.append(
|
||||||
url(r'', include(urlmod, namespace=app.label))
|
url(r'', include(urlmod, namespace=app.label))
|
||||||
)
|
)
|
||||||
|
|
||||||
urlpatterns.append(
|
urlpatterns.append(
|
||||||
url(r'', include(pluginpatterns, namespace='plugins'))
|
url(r'', include(pluginpatterns, namespace='plugins'))
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
from django.db import DEFAULT_DB_ALIAS, connections
|
||||||
|
from django.test.utils import CaptureQueriesContext
|
||||||
|
|
||||||
|
|
||||||
|
# Inspired by /django/test/testcases.py
|
||||||
|
# but copied over to work without the unit test module
|
||||||
|
|
||||||
|
class _AssertNumQueriesContext(CaptureQueriesContext):
|
||||||
|
def __init__(self, num, connection):
|
||||||
|
self.num = num
|
||||||
|
super(_AssertNumQueriesContext, self).__init__(connection)
|
||||||
|
|
||||||
|
def __exit__(self, exc_type, exc_value, traceback):
|
||||||
|
super(_AssertNumQueriesContext, self).__exit__(exc_type, exc_value, traceback)
|
||||||
|
if exc_type is not None:
|
||||||
|
return
|
||||||
|
executed = len(self)
|
||||||
|
assert executed == self.num, "%d queries executed, %d expected\nCaptured queries were:\n%s" % (
|
||||||
|
executed, self.num,
|
||||||
|
'\n'.join(
|
||||||
|
query['sql'] for query in self.captured_queries
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def assert_num_queries(num, func=None, *args, **kwargs):
|
||||||
|
using = kwargs.pop("using", DEFAULT_DB_ALIAS)
|
||||||
|
conn = connections[using]
|
||||||
|
|
||||||
|
context = _AssertNumQueriesContext(num, conn)
|
||||||
|
if func is None:
|
||||||
|
return context
|
||||||
|
|
||||||
|
with context:
|
||||||
|
func(*args, **kwargs)
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
import pytest
|
||||||
|
from django.conf import settings
|
||||||
|
from django.template import Context, Template
|
||||||
|
from django.utils.timezone import now
|
||||||
|
|
||||||
|
from pretix.base.models import Event, Organizer
|
||||||
|
from pretix.multidomain.models import KnownDomain
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def env():
|
||||||
|
o = Organizer.objects.create(name='MRMCD', slug='mrmcd')
|
||||||
|
event = Event.objects.create(
|
||||||
|
organizer=o, name='MRMCD2015', slug='2015',
|
||||||
|
date_from=now()
|
||||||
|
)
|
||||||
|
settings.SITE_URL = 'http://example.com'
|
||||||
|
return o, event
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_control_only_on_main_domain(env, client):
|
||||||
|
KnownDomain.objects.create(domainname='foobar', organizer=env[0])
|
||||||
|
r = client.get('/control/login', HTTP_HOST='foobar')
|
||||||
|
assert r.status_code == 302
|
||||||
|
assert r['Location'] == 'http://example.com/control/login'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_unknown_domain(env, client):
|
||||||
|
r = client.get('/control/login', HTTP_HOST='foobar')
|
||||||
|
assert r.status_code == 400
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_event_on_custom_domain(env, client):
|
||||||
|
KnownDomain.objects.create(domainname='foobar', organizer=env[0])
|
||||||
|
r = client.get('/2015/', HTTP_HOST='foobar')
|
||||||
|
assert r.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_event_with_custom_domain_on_main_domain(env, client):
|
||||||
|
KnownDomain.objects.create(domainname='foobar', organizer=env[0])
|
||||||
|
r = client.get('/mrmcd/2015/', HTTP_HOST='example.com')
|
||||||
|
assert r.status_code == 302
|
||||||
|
assert r['Location'] == 'http://foobar/2015/'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_event_on_custom_domain_only_with_wrong_organizer(env, client):
|
||||||
|
organizer2 = Organizer.objects.create(name='Dummy', slug='dummy')
|
||||||
|
Event.objects.create(
|
||||||
|
organizer=organizer2, name='D1234', slug='1234',
|
||||||
|
date_from=now()
|
||||||
|
)
|
||||||
|
KnownDomain.objects.create(domainname='foobar', organizer=env[0])
|
||||||
|
r = client.get('/dummy/1234/', HTTP_HOST='foobar')
|
||||||
|
assert r.status_code == 404
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_unknown_event_on_custom_domain(env, client):
|
||||||
|
organizer2 = Organizer.objects.create(name='Dummy', slug='dummy')
|
||||||
|
Event.objects.create(
|
||||||
|
organizer=organizer2, name='D1234', slug='1234',
|
||||||
|
date_from=now()
|
||||||
|
)
|
||||||
|
KnownDomain.objects.create(domainname='foobar', organizer=env[0])
|
||||||
|
r = client.get('/1234/', HTTP_HOST='foobar')
|
||||||
|
assert r.status_code == 404
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_cookie_domain_on_custom_domain(env, client):
|
||||||
|
KnownDomain.objects.create(domainname='foobar', organizer=env[0])
|
||||||
|
r = client.get('/2015/', HTTP_HOST='foobar')
|
||||||
|
assert r.status_code == 200
|
||||||
|
assert r.client.cookies['pretix_csrftoken']['domain'] == 'foobar'
|
||||||
|
assert r.client.cookies['pretix_session']['domain'] == 'foobar'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_cookie_domain_on_main_domain(env, client):
|
||||||
|
r = client.get('/mrmcd/2015/', HTTP_HOST='example.com')
|
||||||
|
assert r.status_code == 200
|
||||||
|
assert r.client.cookies['pretix_csrftoken']['domain'] == 'example.com'
|
||||||
|
assert r.client.cookies['pretix_session']['domain'] == 'example.com'
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import pytest
|
||||||
|
from django.conf import settings
|
||||||
|
from django.template import Context, Template
|
||||||
|
from django.utils.timezone import now
|
||||||
|
|
||||||
|
from pretix.base.models import Event, Organizer
|
||||||
|
from pretix.multidomain.models import KnownDomain
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def env():
|
||||||
|
o = Organizer.objects.create(name='MRMCD', slug='mrmcd')
|
||||||
|
event = Event.objects.create(
|
||||||
|
organizer=o, name='MRMCD2015', slug='2015',
|
||||||
|
date_from=now()
|
||||||
|
)
|
||||||
|
settings.SITE_URL = 'http://example.com'
|
||||||
|
return o, event
|
||||||
|
|
||||||
|
|
||||||
|
TEMPLATE_FRONT_PAGE = Template("{% load eventurl %} {% eventurl event 'presale:event.index' %}")
|
||||||
|
TEMPLATE_KWARGS = Template("{% load eventurl %} {% eventurl event 'presale:event.checkout' step='payment' %}")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_event_main_domain_front_page(env):
|
||||||
|
rendered = TEMPLATE_FRONT_PAGE.render(Context({
|
||||||
|
'event': env[1]
|
||||||
|
})).strip()
|
||||||
|
assert rendered == '/mrmcd/2015/'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_event_custom_domain_front_page(env):
|
||||||
|
KnownDomain.objects.create(domainname='foobar', organizer=env[0])
|
||||||
|
rendered = TEMPLATE_FRONT_PAGE.render(Context({
|
||||||
|
'event': env[1]
|
||||||
|
})).strip()
|
||||||
|
assert rendered == 'http://foobar/2015/'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_event_main_domain_kwargs(env):
|
||||||
|
rendered = TEMPLATE_KWARGS.render(Context({
|
||||||
|
'event': env[1]
|
||||||
|
})).strip()
|
||||||
|
assert rendered == '/mrmcd/2015/checkout/payment/'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_event_custom_domain_kwargs(env):
|
||||||
|
KnownDomain.objects.create(domainname='foobar', organizer=env[0])
|
||||||
|
rendered = TEMPLATE_KWARGS.render(Context({
|
||||||
|
'event': env[1]
|
||||||
|
})).strip()
|
||||||
|
assert rendered == 'http://foobar/2015/checkout/payment/'
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
import pytest
|
||||||
|
from django.conf import settings
|
||||||
|
from django.utils.timezone import now
|
||||||
|
from tests import assert_num_queries
|
||||||
|
|
||||||
|
from pretix.base.models import Event, Organizer
|
||||||
|
from pretix.multidomain.models import KnownDomain
|
||||||
|
from pretix.multidomain.urlreverse import build_absolute_uri, eventreverse
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def env():
|
||||||
|
o = Organizer.objects.create(name='MRMCD', slug='mrmcd')
|
||||||
|
event = Event.objects.create(
|
||||||
|
organizer=o, name='MRMCD2015', slug='2015',
|
||||||
|
date_from=now()
|
||||||
|
)
|
||||||
|
settings.SITE_URL = 'http://example.com'
|
||||||
|
return o, event
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_event_main_domain_front_page(env):
|
||||||
|
assert eventreverse(env[1], 'presale:event.index') == '/mrmcd/2015/'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_event_custom_domain_kwargs(env):
|
||||||
|
KnownDomain.objects.create(domainname='foobar', organizer=env[0])
|
||||||
|
assert eventreverse(env[1], 'presale:event.checkout', {'step': 'payment'}) == 'http://foobar/2015/checkout/payment/'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_event_main_domain_kwargs(env):
|
||||||
|
assert eventreverse(env[1], 'presale:event.checkout', {'step': 'payment'}) == '/mrmcd/2015/checkout/payment/'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_event_custom_domain_front_page(env):
|
||||||
|
KnownDomain.objects.create(domainname='foobar', organizer=env[0])
|
||||||
|
assert eventreverse(env[1], 'presale:event.index') == 'http://foobar/2015/'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_event_custom_domain_keep_port(env):
|
||||||
|
settings.SITE_URL = 'http://example.com:8081'
|
||||||
|
KnownDomain.objects.create(domainname='foobar', organizer=env[0])
|
||||||
|
assert eventreverse(env[1], 'presale:event.index') == 'http://foobar:8081/2015/'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_event_custom_domain_keep_scheme(env):
|
||||||
|
settings.SITE_URL = 'https://example.com'
|
||||||
|
KnownDomain.objects.create(domainname='foobar', organizer=env[0])
|
||||||
|
assert eventreverse(env[1], 'presale:event.index') == 'https://foobar/2015/'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_event_main_domain_cache(env):
|
||||||
|
env[0].get_cache().clear()
|
||||||
|
with assert_num_queries(1):
|
||||||
|
eventreverse(env[1], 'presale:event.index')
|
||||||
|
with assert_num_queries(0):
|
||||||
|
eventreverse(env[1], 'presale:event.index')
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_event_custom_domain_cache(env):
|
||||||
|
KnownDomain.objects.create(domainname='foobar', organizer=env[0])
|
||||||
|
env[0].get_cache().clear()
|
||||||
|
with assert_num_queries(1):
|
||||||
|
eventreverse(env[1], 'presale:event.index')
|
||||||
|
with assert_num_queries(0):
|
||||||
|
eventreverse(env[1], 'presale:event.index')
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_event_custom_domain_cache_clear(env):
|
||||||
|
kd = KnownDomain.objects.create(domainname='foobar', organizer=env[0])
|
||||||
|
env[0].get_cache().clear()
|
||||||
|
with assert_num_queries(1):
|
||||||
|
eventreverse(env[1], 'presale:event.index')
|
||||||
|
kd.delete()
|
||||||
|
with assert_num_queries(1):
|
||||||
|
eventreverse(env[1], 'presale:event.index')
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_event_main_domain_absolute(env):
|
||||||
|
assert build_absolute_uri(env[1], 'presale:event.index') == 'http://example.com/mrmcd/2015/'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_event_custom_domain_absolute(env):
|
||||||
|
KnownDomain.objects.create(domainname='foobar', organizer=env[0])
|
||||||
|
assert build_absolute_uri(env[1], 'presale:event.index') == 'http://foobar/2015/'
|
||||||
@@ -34,7 +34,7 @@ class CheckoutTestCase(TestCase):
|
|||||||
self._set_session('email', 'admin@localhost')
|
self._set_session('email', 'admin@localhost')
|
||||||
|
|
||||||
def test_empty_cart(self):
|
def test_empty_cart(self):
|
||||||
response = self.client.get('/%s/%s/checkout/' % (self.orga.slug, self.event.slug), follow=True)
|
response = self.client.get('/%s/%s/checkout/start' % (self.orga.slug, self.event.slug), follow=True)
|
||||||
self.assertRedirects(response, '/%s/%s/' % (self.orga.slug, self.event.slug),
|
self.assertRedirects(response, '/%s/%s/' % (self.orga.slug, self.event.slug),
|
||||||
target_status_code=200)
|
target_status_code=200)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user