forked from CGM_Public/pretix_original
Upgrade to Django 2.1 (#710)
* Upgrade to Django 2.0 * more models * i18n foo * Update setup.py * Fix Sentry exception PRETIXEU-JC * Enforce slug uniqueness * Import sorting * Upgrade to Django 2.1 * Travis config * Try to fix PostgreSQL failure * Smaller test matrix * staticfiles→static * Include request in all authenticate() calls
This commit is contained in:
@@ -39,7 +39,7 @@ class LoginForm(forms.Form):
|
||||
password = self.cleaned_data.get('password')
|
||||
|
||||
if email and password:
|
||||
self.user_cache = authenticate(email=email.lower(), password=password)
|
||||
self.user_cache = authenticate(request=self.request, email=email.lower(), password=password)
|
||||
if self.user_cache is None:
|
||||
raise forms.ValidationError(
|
||||
self.error_messages['invalid_login'],
|
||||
|
||||
@@ -3,8 +3,8 @@ from urllib.parse import urlsplit
|
||||
|
||||
import pytz
|
||||
from django.conf import settings
|
||||
from django.core.urlresolvers import get_script_prefix
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
from django.urls import get_script_prefix
|
||||
from django.utils import timezone, translation
|
||||
from django.utils.cache import patch_vary_headers
|
||||
from django.utils.deprecation import MiddlewareMixin
|
||||
|
||||
56
src/pretix/base/migrations/0098_auto_20180731_1243.py
Normal file
56
src/pretix/base/migrations/0098_auto_20180731_1243.py
Normal file
@@ -0,0 +1,56 @@
|
||||
# Generated by Django 2.0.7 on 2018-07-31 12:43
|
||||
|
||||
import django.core.validators
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
import pretix.base.validators
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('pretixbase', '0097_auto_20180722_0804'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='logentry',
|
||||
options={'ordering': ('-datetime', '-id')},
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='orderpayment',
|
||||
name='fee',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='payments', to='pretixbase.OrderFee'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='organizer',
|
||||
name='slug',
|
||||
field=models.SlugField(help_text='Should be short, only contain lowercase letters, numbers, dots, and dashes. Every slug can only be used once. This is being used in URLs to refer to your organizer accounts and your events.', unique=True, validators=[django.core.validators.RegexValidator(message='The slug may only contain letters, numbers, dots and dashes.', regex='^[a-zA-Z0-9.-]+$'), pretix.base.validators.OrganizerSlugBlacklistValidator()], verbose_name='Short form'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='staffsession',
|
||||
name='user',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='staffsessionauditlog',
|
||||
name='impersonating',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='staffsessionauditlog',
|
||||
name='session',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='logs', to='pretixbase.StaffSession'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='user',
|
||||
name='locale',
|
||||
field=models.CharField(choices=[('en', 'English'), ('de', 'German'), ('de-informal', 'German (informal)'), ('nl', 'Dutch'), ('da', 'Danish'), ('tr', 'Turkish'), ('pt-br', 'Portuguese (Brazil)')], default='en', max_length=50, verbose_name='Language'),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='event',
|
||||
unique_together={('organizer', 'slug')},
|
||||
),
|
||||
]
|
||||
@@ -340,7 +340,7 @@ class User(AbstractBaseUser, PermissionsMixin, LoggingMixin):
|
||||
|
||||
|
||||
class StaffSession(models.Model):
|
||||
user = models.ForeignKey('User')
|
||||
user = models.ForeignKey('User', on_delete=models.PROTECT)
|
||||
date_start = models.DateTimeField(auto_now_add=True)
|
||||
date_end = models.DateTimeField(null=True, blank=True)
|
||||
session_key = models.CharField(max_length=255)
|
||||
@@ -351,11 +351,11 @@ class StaffSession(models.Model):
|
||||
|
||||
|
||||
class StaffSessionAuditLog(models.Model):
|
||||
session = models.ForeignKey('StaffSession', related_name='logs')
|
||||
session = models.ForeignKey('StaffSession', related_name='logs', on_delete=models.PROTECT)
|
||||
datetime = models.DateTimeField(auto_now_add=True)
|
||||
url = models.CharField(max_length=255)
|
||||
method = models.CharField(max_length=255)
|
||||
impersonating = models.ForeignKey('User', null=True, blank=True)
|
||||
impersonating = models.ForeignKey('User', null=True, blank=True, on_delete=models.PROTECT)
|
||||
|
||||
class Meta:
|
||||
ordering = ('datetime',)
|
||||
|
||||
@@ -8,12 +8,12 @@ from pretix.base.models import LoggedModel
|
||||
|
||||
|
||||
class CheckinList(LoggedModel):
|
||||
event = models.ForeignKey('Event', related_name='checkin_lists')
|
||||
event = models.ForeignKey('Event', related_name='checkin_lists', on_delete=models.CASCADE)
|
||||
name = models.CharField(max_length=190)
|
||||
all_products = models.BooleanField(default=True, verbose_name=_("All products (including newly created ones)"))
|
||||
limit_products = models.ManyToManyField('Item', verbose_name=_("Limit to products"), blank=True)
|
||||
subevent = models.ForeignKey('SubEvent', null=True, blank=True,
|
||||
verbose_name=pgettext_lazy('subevent', 'Date'))
|
||||
verbose_name=pgettext_lazy('subevent', 'Date'), on_delete=models.CASCADE)
|
||||
include_pending = models.BooleanField(verbose_name=pgettext_lazy('checkin', 'Include pending orders'),
|
||||
default=False,
|
||||
help_text=_('With this option, people will be able to check in even if the '
|
||||
@@ -157,7 +157,7 @@ class Checkin(models.Model):
|
||||
"""
|
||||
A check-in object is created when a person enters the event.
|
||||
"""
|
||||
position = models.ForeignKey('pretixbase.OrderPosition', related_name='checkins')
|
||||
position = models.ForeignKey('pretixbase.OrderPosition', related_name='checkins', on_delete=models.CASCADE)
|
||||
datetime = models.DateTimeField(default=now)
|
||||
nonce = models.CharField(max_length=190, null=True, blank=True)
|
||||
list = models.ForeignKey(
|
||||
|
||||
@@ -265,6 +265,7 @@ class Event(EventMixin, LoggedModel):
|
||||
verbose_name = _("Event")
|
||||
verbose_name_plural = _("Events")
|
||||
ordering = ("date_from", "name")
|
||||
unique_together = (('organizer', 'slug'),)
|
||||
|
||||
def __str__(self):
|
||||
return str(self.name)
|
||||
|
||||
@@ -64,14 +64,14 @@ class Invoice(models.Model):
|
||||
:param file: The filename of the rendered invoice
|
||||
:type file: File
|
||||
"""
|
||||
order = models.ForeignKey('Order', related_name='invoices', db_index=True)
|
||||
order = models.ForeignKey('Order', related_name='invoices', db_index=True, on_delete=models.CASCADE)
|
||||
organizer = models.ForeignKey('Organizer', related_name='invoices', db_index=True, on_delete=models.PROTECT)
|
||||
event = models.ForeignKey('Event', related_name='invoices', db_index=True)
|
||||
event = models.ForeignKey('Event', related_name='invoices', db_index=True, on_delete=models.CASCADE)
|
||||
prefix = models.CharField(max_length=160, db_index=True)
|
||||
invoice_no = models.CharField(max_length=19, db_index=True)
|
||||
full_invoice_no = models.CharField(max_length=190, db_index=True)
|
||||
is_cancellation = models.BooleanField(default=False)
|
||||
refers = models.ForeignKey('Invoice', related_name='refered', null=True, blank=True)
|
||||
refers = models.ForeignKey('Invoice', related_name='refered', null=True, blank=True, on_delete=models.CASCADE)
|
||||
invoice_from = models.TextField()
|
||||
invoice_to = models.TextField()
|
||||
date = models.DateField(default=today)
|
||||
@@ -175,7 +175,7 @@ class InvoiceLine(models.Model):
|
||||
:param tax_name: The name of the applied tax rate
|
||||
:type tax_name: str
|
||||
"""
|
||||
invoice = models.ForeignKey('Invoice', related_name='lines')
|
||||
invoice = models.ForeignKey('Invoice', related_name='lines', on_delete=models.CASCADE)
|
||||
position = models.PositiveIntegerField(default=0)
|
||||
description = models.TextField()
|
||||
gross_value = models.DecimalField(max_digits=10, decimal_places=2)
|
||||
|
||||
@@ -447,7 +447,8 @@ class ItemVariation(models.Model):
|
||||
"""
|
||||
item = models.ForeignKey(
|
||||
Item,
|
||||
related_name='variations'
|
||||
related_name='variations',
|
||||
on_delete=models.CASCADE
|
||||
)
|
||||
value = I18nCharField(
|
||||
max_length=255,
|
||||
@@ -562,12 +563,14 @@ class ItemAddOn(models.Model):
|
||||
"""
|
||||
base_item = models.ForeignKey(
|
||||
Item,
|
||||
related_name='addons'
|
||||
related_name='addons',
|
||||
on_delete=models.CASCADE
|
||||
)
|
||||
addon_category = models.ForeignKey(
|
||||
ItemCategory,
|
||||
related_name='addon_to',
|
||||
verbose_name=_('Category')
|
||||
verbose_name=_('Category'),
|
||||
on_delete=models.CASCADE
|
||||
)
|
||||
min_count = models.PositiveIntegerField(
|
||||
default=0,
|
||||
@@ -679,7 +682,8 @@ class Question(LoggedModel):
|
||||
|
||||
event = models.ForeignKey(
|
||||
Event,
|
||||
related_name="questions"
|
||||
related_name="questions",
|
||||
on_delete=models.CASCADE
|
||||
)
|
||||
question = I18nTextField(
|
||||
verbose_name=_("Question")
|
||||
@@ -831,7 +835,7 @@ class Question(LoggedModel):
|
||||
|
||||
|
||||
class QuestionOption(models.Model):
|
||||
question = models.ForeignKey('Question', related_name='options')
|
||||
question = models.ForeignKey('Question', related_name='options', on_delete=models.CASCADE)
|
||||
identifier = models.CharField(max_length=190)
|
||||
answer = I18nCharField(verbose_name=_('Answer'))
|
||||
position = models.IntegerField(default=0)
|
||||
|
||||
@@ -119,7 +119,8 @@ class Order(LoggedModel):
|
||||
event = models.ForeignKey(
|
||||
Event,
|
||||
verbose_name=_("Event"),
|
||||
related_name="orders"
|
||||
related_name="orders",
|
||||
on_delete=models.CASCADE
|
||||
)
|
||||
email = models.EmailField(
|
||||
null=True, blank=True,
|
||||
@@ -226,11 +227,11 @@ class Order(LoggedModel):
|
||||
pending_sum_rc=-1 * F('payment_sum') + Coalesce(F('refund_sum'), 0),
|
||||
).annotate(
|
||||
is_overpaid=Case(
|
||||
When(~Q(status__in=[Order.STATUS_REFUNDED, Order.STATUS_CANCELED]) & Q(pending_sum_t__lt=0),
|
||||
When(~Q(status__in=(Order.STATUS_REFUNDED, Order.STATUS_CANCELED)) & Q(pending_sum_t__lt=0),
|
||||
then=Value('1')),
|
||||
When(Q(status__in=[Order.STATUS_REFUNDED, Order.STATUS_CANCELED]) & Q(pending_sum_rc__lt=0),
|
||||
When(Q(status__in=(Order.STATUS_REFUNDED, Order.STATUS_CANCELED)) & Q(pending_sum_rc__lt=0),
|
||||
then=Value('1')),
|
||||
When(Q(status__in=[Order.STATUS_EXPIRED, Order.STATUS_PENDING]) & Q(pending_sum_t__lte=0),
|
||||
When(Q(status__in=(Order.STATUS_EXPIRED, Order.STATUS_PENDING)) & Q(pending_sum_t__lte=0),
|
||||
then=Value('1')),
|
||||
default=Value('0'),
|
||||
output_field=models.IntegerField()
|
||||
@@ -544,14 +545,14 @@ class QuestionAnswer(models.Model):
|
||||
"""
|
||||
orderposition = models.ForeignKey(
|
||||
'OrderPosition', null=True, blank=True,
|
||||
related_name='answers'
|
||||
related_name='answers', on_delete=models.CASCADE
|
||||
)
|
||||
cartposition = models.ForeignKey(
|
||||
'CartPosition', null=True, blank=True,
|
||||
related_name='answers'
|
||||
related_name='answers', on_delete=models.CASCADE
|
||||
)
|
||||
question = models.ForeignKey(
|
||||
Question, related_name='answers'
|
||||
Question, related_name='answers', on_delete=models.CASCADE
|
||||
)
|
||||
options = models.ManyToManyField(
|
||||
QuestionOption, related_name='answers', blank=True
|
||||
@@ -699,7 +700,7 @@ class AbstractPosition(models.Model):
|
||||
help_text=_("Empty, if this product is not an admission ticket")
|
||||
)
|
||||
voucher = models.ForeignKey(
|
||||
'Voucher', null=True, blank=True
|
||||
'Voucher', null=True, blank=True, on_delete=models.CASCADE
|
||||
)
|
||||
addon_to = models.ForeignKey(
|
||||
'self', null=True, blank=True, on_delete=models.CASCADE, related_name='addons'
|
||||
@@ -829,7 +830,7 @@ class OrderPayment(models.Model):
|
||||
)
|
||||
fee = models.ForeignKey(
|
||||
'OrderFee',
|
||||
null=True, blank=True, related_name='payments'
|
||||
null=True, blank=True, related_name='payments', on_delete=models.SET_NULL
|
||||
)
|
||||
migrated = models.BooleanField(default=False)
|
||||
|
||||
@@ -1444,7 +1445,8 @@ class CartPosition(AbstractPosition):
|
||||
"""
|
||||
event = models.ForeignKey(
|
||||
Event,
|
||||
verbose_name=_("Event")
|
||||
verbose_name=_("Event"),
|
||||
on_delete=models.CASCADE
|
||||
)
|
||||
cart_id = models.CharField(
|
||||
max_length=255, null=True, blank=True, db_index=True,
|
||||
@@ -1488,7 +1490,7 @@ class CartPosition(AbstractPosition):
|
||||
|
||||
class InvoiceAddress(models.Model):
|
||||
last_modified = models.DateTimeField(auto_now=True)
|
||||
order = models.OneToOneField(Order, null=True, blank=True, related_name='invoice_address')
|
||||
order = models.OneToOneField(Order, null=True, blank=True, related_name='invoice_address', on_delete=models.CASCADE)
|
||||
is_business = models.BooleanField(default=False, verbose_name=_('Business customer'))
|
||||
company = models.CharField(max_length=255, blank=True, verbose_name=_('Company name'))
|
||||
name = models.CharField(max_length=255, verbose_name=_('Full name'), blank=True)
|
||||
|
||||
@@ -42,6 +42,7 @@ class Organizer(LoggedModel):
|
||||
OrganizerSlugBlacklistValidator()
|
||||
],
|
||||
verbose_name=_("Short form"),
|
||||
unique=True
|
||||
)
|
||||
|
||||
class Meta:
|
||||
|
||||
@@ -60,7 +60,7 @@ EU_CURRENCIES = {
|
||||
|
||||
|
||||
class TaxRule(LoggedModel):
|
||||
event = models.ForeignKey('Event', related_name='tax_rules')
|
||||
event = models.ForeignKey('Event', related_name='tax_rules', on_delete=models.CASCADE)
|
||||
name = I18nCharField(
|
||||
verbose_name=_('Name'),
|
||||
help_text=_('Should be short, e.g. "VAT"'),
|
||||
|
||||
@@ -137,14 +137,14 @@ class Voucher(LoggedModel):
|
||||
item = models.ForeignKey(
|
||||
Item, related_name='vouchers',
|
||||
verbose_name=_("Product"),
|
||||
null=True, blank=True,
|
||||
null=True, blank=True, on_delete=models.CASCADE,
|
||||
help_text=_(
|
||||
"This product is added to the user's cart if the voucher is redeemed."
|
||||
)
|
||||
)
|
||||
variation = models.ForeignKey(
|
||||
ItemVariation, related_name='vouchers',
|
||||
null=True, blank=True,
|
||||
null=True, blank=True, on_delete=models.CASCADE,
|
||||
verbose_name=_("Product variation"),
|
||||
help_text=_(
|
||||
"This variation of the product select above is being used."
|
||||
@@ -152,7 +152,7 @@ class Voucher(LoggedModel):
|
||||
)
|
||||
quota = models.ForeignKey(
|
||||
Quota, related_name='quota',
|
||||
null=True, blank=True,
|
||||
null=True, blank=True, on_delete=models.CASCADE,
|
||||
verbose_name=_("Quota"),
|
||||
help_text=_(
|
||||
"If enabled, the voucher is valid for any product affected by this quota."
|
||||
|
||||
@@ -43,10 +43,11 @@ class WaitingListEntry(LoggedModel):
|
||||
'Voucher',
|
||||
verbose_name=_("Assigned voucher"),
|
||||
null=True, blank=True,
|
||||
related_name='waitinglistentries'
|
||||
related_name='waitinglistentries',
|
||||
on_delete=models.CASCADE
|
||||
)
|
||||
item = models.ForeignKey(
|
||||
Item, related_name='waitinglistentries',
|
||||
Item, related_name='waitinglistentries', on_delete=models.CASCADE,
|
||||
verbose_name=_("Product"),
|
||||
help_text=_(
|
||||
"The product the user waits for."
|
||||
@@ -54,7 +55,7 @@ class WaitingListEntry(LoggedModel):
|
||||
)
|
||||
variation = models.ForeignKey(
|
||||
ItemVariation, related_name='waitinglistentries',
|
||||
null=True, blank=True,
|
||||
null=True, blank=True, on_delete=models.CASCADE,
|
||||
verbose_name=_("Product variation"),
|
||||
help_text=_(
|
||||
"The variation of the product selected above."
|
||||
|
||||
@@ -171,7 +171,7 @@ def build_cancellation(invoice: Invoice):
|
||||
|
||||
|
||||
def generate_cancellation(invoice: Invoice, trigger_pdf=True):
|
||||
cancellation = copy.copy(invoice)
|
||||
cancellation = copy.deepcopy(invoice)
|
||||
cancellation.pk = None
|
||||
cancellation.invoice_no = None
|
||||
cancellation.prefix = None
|
||||
|
||||
@@ -923,7 +923,7 @@ class OrderChangeManager:
|
||||
op.save()
|
||||
|
||||
try:
|
||||
ia = copy.copy(self.order.invoice_address)
|
||||
ia = copy.deepcopy(self.order.invoice_address)
|
||||
ia.pk = None
|
||||
ia.order = split_order
|
||||
ia.save()
|
||||
@@ -947,7 +947,7 @@ class OrderChangeManager:
|
||||
split_order.total += fee.value
|
||||
|
||||
for fee in self.order.fees.exclude(fee_type=OrderFee.FEE_TYPE_PAYMENT):
|
||||
new_fee = copy.copy(fee)
|
||||
new_fee = copy.deepcopy(fee)
|
||||
new_fee.pk = None
|
||||
new_fee.order = split_order
|
||||
split_order.total += new_fee.value
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{% load compress %}
|
||||
{% load i18n %}
|
||||
{% load staticfiles %}
|
||||
{% load static %}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{% load compress %}
|
||||
{% load i18n %}
|
||||
{% load staticfiles %}
|
||||
{% load static %}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
|
||||
@@ -63,7 +63,7 @@ ALLOWED_PROTOCOLS = ['http', 'https', 'mailto', 'tel']
|
||||
|
||||
def safelink_callback(attrs, new=False):
|
||||
url = attrs.get((None, 'href'), '/')
|
||||
if not is_safe_url(url) and not url.startswith('mailto:') and not url.startswith('tel:'):
|
||||
if not is_safe_url(url, allowed_hosts=None) and not url.startswith('mailto:') and not url.startswith('tel:'):
|
||||
signer = signing.Signer(salt='safe-redirect')
|
||||
attrs[None, 'href'] = reverse('redirect') + '?url=' + urllib.parse.quote(signer.sign(url))
|
||||
attrs[None, 'target'] = '_blank'
|
||||
|
||||
@@ -15,6 +15,6 @@ def url_replace(request, *pairs):
|
||||
if key in dict_:
|
||||
del dict_[key]
|
||||
else:
|
||||
dict_[key] = p
|
||||
dict_[key] = str(p)
|
||||
key = None
|
||||
return dict_.urlencode(safe='[]')
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
from django.utils import timezone
|
||||
from django.utils.translation.trans_real import DjangoTranslation
|
||||
from django.views.decorators.cache import cache_page
|
||||
from django.views.decorators.http import etag
|
||||
from django.views.i18n import get_javascript_catalog, render_javascript_catalog
|
||||
from django.views.i18n import JavaScriptCatalog, render_javascript_catalog
|
||||
|
||||
# Yes, we want to regenerate this every time the module has been imported to
|
||||
# refresh the cache at least at every code deployment
|
||||
@@ -18,6 +19,6 @@ js_info_dict = {
|
||||
@etag(lambda *s, **k: import_date)
|
||||
@cache_page(3600, key_prefix='js18n-%s' % import_date)
|
||||
def js_catalog(request, lang):
|
||||
packages = ['pretix']
|
||||
catalog, plural = get_javascript_catalog(lang, 'djangojs', packages)
|
||||
return render_javascript_catalog(catalog, plural)
|
||||
c = JavaScriptCatalog()
|
||||
c.translation = DjangoTranslation(lang, domain='djangojs')
|
||||
return render_javascript_catalog(c.get_catalog(), c.get_plural())
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import urllib.parse
|
||||
|
||||
from django.core import signing
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.http import HttpResponseBadRequest, HttpResponseRedirect
|
||||
from django.urls import reverse
|
||||
|
||||
|
||||
def redir_view(request):
|
||||
|
||||
Reference in New Issue
Block a user