Compare commits

..

1 Commits

Author SHA1 Message Date
Raphael Michel
db67959abf Add a custom manager 2017-05-19 10:31:02 +02:00
82 changed files with 914 additions and 1323 deletions

View File

@@ -5,6 +5,7 @@ tests:
- virtualenv env
- source env/bin/activate
- pip install -U pip wheel setuptools
- XDG_CACHE_HOME=/cache bash .travis.sh style
- XDG_CACHE_HOME=/cache bash .travis.sh tests
tags:
- python3

View File

@@ -51,7 +51,7 @@ If there is a problem, a status code in the ``5xx`` range will be returned.
Performance monitoring
----------------------
If you want to generate detailed performance statistics of your pretix installation, there is an
If you to generate detailled performance statistics of your pretix installation, there is an
endpoint at ``https://pretix.mydomain.com/metrics`` (no slash at the end) which returns a
number of values in the text format understood by monitoring tools like Prometheus_. This data
is only collected and exposed if you enable it in the :ref:`metrics-settings` section of your

View File

@@ -25,7 +25,7 @@ Frontend
--------
.. automodule:: pretix.presale.signals
:members: html_head, html_footer, footer_links, front_page_top, front_page_bottom, contact_form_fields, checkout_confirm_messages
:members: html_head, html_footer, footer_links, front_page_top, front_page_bottom, checkout_confirm_messages
.. automodule:: pretix.presale.signals

View File

@@ -40,7 +40,7 @@ automatically). If you are working on Ubuntu or Debian, we strongly recommend up
your pip and setuptools installation inside the virtual environment, otherwise some of
the dependencies might fail::
pip3 install -U pip setuptools
pip3 install -U pip setuptools==28.6.1
Working with the code
---------------------
@@ -81,7 +81,7 @@ and head to http://localhost:8000/
As we did not implement an overall front page yet, you need to go directly to
http://localhost:8000/control/ for the admin view or, if you imported the test
data as suggested above, to the event page at http://localhost:8000/bigevents/2018/
data as suggested above, to the event page at http://localhost:8000/bigevents/2017/
.. note:: If you want the development server to listen on a different interface or
port (for example because you develop on `pretixdroid`_), you can check

View File

@@ -15,8 +15,7 @@ ways that pretix itself is:
* PDF ticket output
The following plugins are not shipped with pretix but are maintained by the
same team. We update them regularly to make them compatible with the latest
pretix releases:
same team:
* `SEPA direct debit`_
* `Pages`_
@@ -24,17 +23,8 @@ pretix releases:
* `Cartshare`_
* `Fontpack Free fonts`_
The following closed-source plugins are available to customers of the hosted pretix.eu platform.
Please get in touch with the pretix team if you want to have them for your self-hosted
pretix installation:
* Campaign tracking
* Integration with Google Analytics and Facebook Pixel
* Integration with Slack
* Integration with MailChimp
The following plugins are from independent third-party authors, so we can make
no statements about their stability or compatibility:
no statements about their stability:
* `esPass ticket output`_
* `IcePay integration`_

View File

@@ -36,11 +36,11 @@ t = Team.objects.get_or_create(
can_change_organizer_settings=True, can_change_event_settings=True, can_change_items=True,
can_view_orders=True, can_change_orders=True, can_view_vouchers=True, can_change_vouchers=True
)
t[0].members.add(user)
cat_tickets = ItemCategory.objects.create(
t.members.add(user)
cat_tickets = ItemCategory.all.create(
event=event, name='Tickets'
)
cat_merch = ItemCategory.objects.create(
cat_merch = ItemCategory.all.create(
event=event, name='Merchandise'
)
question = Question.objects.create(

View File

@@ -1 +1 @@
__version__ = "1.4.1"
__version__ = "1.4.0-dev0"

View File

@@ -1,9 +1,9 @@
import csv
import io
from collections import OrderedDict
from decimal import Decimal
import pytz
from defusedcsv import csv
from django import forms
from django.db.models import Sum
from django.dispatch import receiver

View File

@@ -1,27 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2017-05-21 09:42
from __future__ import unicode_literals
from django.core.cache import cache
from django.db import migrations
def rename_placeholder(app, schema_editor):
EventSettingsStore = app.get_model('pretixbase', 'Event_SettingsStore')
for setting in EventSettingsStore.objects.all():
if setting.key == 'mail_text_order_placed':
new_value = setting.value.replace('{paymentinfo}', '{payment_info}')
setting.value = new_value
cache.delete('hierarkey_{}_{}'.format('event', setting.object_id))
setting.save()
class Migration(migrations.Migration):
dependencies = [
('pretixbase', '0060_auto_20170510_1027'),
]
operations = [
migrations.RunPython(rename_placeholder, migrations.RunPython.noop)
]

View File

@@ -2,6 +2,7 @@ import json
import uuid
from django.contrib.contenttypes.models import ContentType
from django.core import checks
from django.db import models
from django.db.models.signals import post_delete
from django.dispatch import receiver
@@ -34,7 +35,6 @@ def cached_file_delete(sender, instance, **kwargs):
class LoggingMixin:
def log_action(self, action, data=None, user=None):
"""
Create a LogEntry object that is related to this object.
@@ -59,7 +59,6 @@ class LoggingMixin:
class LoggedModel(models.Model, LoggingMixin):
class Meta:
abstract = True
@@ -74,3 +73,38 @@ class LoggedModel(models.Model, LoggingMixin):
return LogEntry.objects.filter(
content_type=ContentType.objects.get_for_model(type(self)), object_id=self.pk
).select_related('user', 'event')
class EventBoundModelMixin:
event_lookup = 'event'
@classmethod
def for_event(cls, event):
return cls.all.filter(**{
cls.event_lookup: event
})
@classmethod
def check(cls, **kwargs):
try:
errors = super(cls).check(**kwargs)
except AttributeError:
errors = []
if hasattr(cls, 'objects'):
errors.append(
checks.Error(
'Default model manager "objects" defined.',
hint='Replace the objects manager by a manager called "all".',
obj=cls,
id='pretixbase.E001',
)
)
if not hasattr(cls, 'all'):
errors.append(
checks.Error(
'Model manager "all" not defined.',
obj=cls,
id='pretixbase.E002',
)
)
return errors

View File

@@ -234,14 +234,14 @@ class Event(LoggedModel):
), tz)
def copy_data_from(self, other):
from . import ItemAddOn, ItemCategory, Item, Question, Quota
from . import ItemAddOn, Item, Question, Quota
from ..signals import event_copy_data
self.plugins = other.plugins
self.save()
category_map = {}
for c in ItemCategory.objects.filter(event=other):
for c in other.categories.all():
category_map[c.pk] = c
c.pk = None
c.event = self

View File

@@ -14,12 +14,12 @@ from django.utils.translation import ugettext_lazy as _
from i18nfield.fields import I18nCharField, I18nTextField
from pretix.base.decimal import round_decimal
from pretix.base.models.base import LoggedModel
from pretix.base.models.base import EventBoundModelMixin, LoggedModel
from .event import Event
class ItemCategory(LoggedModel):
class ItemCategory(EventBoundModelMixin, LoggedModel):
"""
Items can be sorted into these categories.
@@ -53,6 +53,8 @@ class ItemCategory(LoggedModel):
'source for add-ons.')
)
all = models.Manager()
class Meta:
verbose_name = _("Product category")
verbose_name_plural = _("Product categories")

View File

@@ -5,7 +5,6 @@ from django.contrib.contenttypes.models import ContentType
from django.db import models
from django.urls import reverse
from django.utils.functional import cached_property
from django.utils.html import escape
from django.utils.translation import ugettext_lazy as _
@@ -67,7 +66,7 @@ class LogEntry(models.Model):
'organizer': self.event.organizer.slug,
'code': co.code
}),
'val': escape(co.code),
'val': co.code,
}
elif isinstance(co, Voucher):
a_text = _('Voucher {val}')
@@ -77,7 +76,7 @@ class LogEntry(models.Model):
'organizer': self.event.organizer.slug,
'voucher': co.id
}),
'val': escape(co.code[:6]),
'val': co.code[:6],
}
elif isinstance(co, Item):
a_text = _('Product {val}')
@@ -87,7 +86,7 @@ class LogEntry(models.Model):
'organizer': self.event.organizer.slug,
'item': co.id
}),
'val': escape(co.name),
'val': co.name,
}
elif isinstance(co, Quota):
a_text = _('Quota {val}')
@@ -97,7 +96,7 @@ class LogEntry(models.Model):
'organizer': self.event.organizer.slug,
'quota': co.id
}),
'val': escape(co.name),
'val': co.name,
}
elif isinstance(co, ItemCategory):
a_text = _('Category {val}')
@@ -107,7 +106,7 @@ class LogEntry(models.Model):
'organizer': self.event.organizer.slug,
'category': co.id
}),
'val': escape(co.name),
'val': co.name,
}
elif isinstance(co, Question):
a_text = _('Question {val}')
@@ -117,7 +116,7 @@ class LogEntry(models.Model):
'organizer': self.event.organizer.slug,
'question': co.id
}),
'val': escape(co.question),
'val': co.question,
}
if a_text and a_map:

View File

@@ -1,5 +1,4 @@
import copy
import json
import os
import string
from datetime import datetime
@@ -184,10 +183,6 @@ class Order(LoggedModel):
def __str__(self):
return self.full_code
@cached_property
def meta_info_data(self):
return json.loads(self.meta_info)
@property
def full_code(self):
"""

View File

@@ -414,7 +414,7 @@ def _perform_order(event: str, payment_provider: str, position_ids: List[str],
'order': order.code,
'secret': order.secret
}),
'payment_info': str(pprov.order_pending_mail_render(order)),
'paymentinfo': str(pprov.order_pending_mail_render(order)),
'invoice_name': invoice_name,
'invoice_company': invoice_company,
},
@@ -512,7 +512,7 @@ class OrderChangeManager:
if (not variation and item.has_variations) or (variation and variation.item_id != item.pk):
raise OrderError(self.error_messages['product_without_variation'])
price = item.default_price if variation is None else variation.price
if price is None:
if not price:
raise OrderError(self.error_messages['product_invalid'])
self._totaldiff = price - position.price
self._quotadiff.update(variation.quotas.all() if variation else item.quotas.all())

View File

@@ -240,7 +240,7 @@ Your {event} team"""))
we successfully received your order for {event} with a total value
of {total} {currency}. Please complete your payment before {date}.
{payment_info}
{paymentinfo}
You can change your order details and view the status of your order at
{url}

View File

@@ -1,13 +0,0 @@
from django import template
from django.template.defaultfilters import stringfilter
from pretix.helpers.escapejson import escapejson
register = template.Library()
@register.filter("escapejson")
@stringfilter
def escapejs_filter(value):
"""Hex encodes characters for use in a application/json type script."""
return escapejson(value)

View File

@@ -1,12 +1,6 @@
import urllib.parse
import bleach
import markdown
from bleach import DEFAULT_CALLBACKS
from django import template
from django.core import signing
from django.urls import reverse
from django.utils.http import is_safe_url
from django.utils.safestring import mark_safe
register = template.Library()
@@ -48,15 +42,6 @@ ALLOWED_ATTRIBUTES = {
}
def safelink_callback(attrs, new=False):
url = attrs.get((None, 'href'), '/')
if not is_safe_url(url):
signer = signing.Signer(salt='safe-redirect')
attrs[None, 'href'] = reverse('redirect') + '?url=' + urllib.parse.quote(signer.sign(url))
attrs[None, 'target'] = '_blank'
return attrs
@register.filter
def rich_text(text: str, **kwargs):
"""
@@ -67,5 +52,5 @@ def rich_text(text: str, **kwargs):
markdown.markdown(text),
tags=ALLOWED_TAGS,
attributes=ALLOWED_ATTRIBUTES,
), callbacks=DEFAULT_CALLBACKS + [safelink_callback])
))
return mark_safe(body_md)

View File

@@ -33,7 +33,7 @@ def contextprocessor(request):
_js_payment_weekdays_disabled = '[]'
_nav_event = []
if getattr(request, 'event', None) and hasattr(request, 'organizer'):
if hasattr(request, 'event'):
for receiver, response in nav_event.send(request.event, request=request):
_nav_event += response
if request.event.settings.get('payment_term_weekdays'):

View File

@@ -259,12 +259,10 @@ class EventSettingsForm(SettingsForm):
)
attendee_emails_asked = forms.BooleanField(
label=_("Ask for email addresses per ticket"),
help_text=_("Normally, pretix asks for one email address per order and the order confirmation will be sent "
"only to that email address. If you enable this option, the system will additionally ask for "
help_text=_("Normally, pretix asks for one email address per order and the order confirmation will be send "
"to that email address. If you enable this option, the system will additionally ask for "
"individual email addresses for every admission ticket. This might be useful if you want to "
"obtain individual addresses for every attendee even in case of group orders. However, "
"pretix will send the order confirmation only to the one primary email address, not to the "
"per-attendee addresses."),
"obtain individual addresses for every attendee even in case of group orders."),
required=False
)
attendee_emails_required = forms.BooleanField(
@@ -492,9 +490,9 @@ class MailSettingsForm(SettingsForm):
label=_("Text"),
required=False,
widget=I18nTextarea,
help_text=_("Available placeholders: {event}, {total}, {currency}, {date}, {payment_info}, {url}, "
help_text=_("Available placeholders: {event}, {total}, {currency}, {date}, {paymentinfo}, {url}, "
"{invoice_name}, {invoice_company}"),
validators=[PlaceholderValidator(['{event}', '{total}', '{currency}', '{date}', '{payment_info}',
validators=[PlaceholderValidator(['{event}', '{total}', '{currency}', '{date}', '{paymentinfo}',
'{url}', '{invoice_name}', '{invoice_company}'])]
)
mail_text_order_paid = I18nFormField(
@@ -612,7 +610,7 @@ class DisplaySettingsForm(SettingsForm):
)
logo_image = ExtFileField(
label=_('Logo image'),
ext_whitelist=(".png", ".jpg", ".gif", ".jpeg"),
ext_whitelist=(".png", ".jpg", ".svg", ".gif", ".jpeg"),
required=False,
help_text=_('If you provide a logo image, we will by default not show your events name and date '
'in the page header. We will show your logo with a maximal height of 120 pixels.')

View File

@@ -121,7 +121,7 @@ class OrganizerSettingsForm(SettingsForm):
organizer_logo_image = ExtFileField(
label=_('Logo image'),
ext_whitelist=(".png", ".jpg", ".gif", ".jpeg"),
ext_whitelist=(".png", ".jpg", ".svg", ".gif", ".jpeg"),
required=False,
help_text=_('If you provide a logo image, we will by default not show your organization name '
'in the page header. We will show your logo with a maximal height of 120 pixels.')

View File

@@ -1,6 +1,5 @@
{% extends "pretixcontrol/base.html" %}
{% load i18n %}
{% load staticfiles %}
{% block title %}{{ request.event.name }}{% endblock %}
{% block nav %}
@@ -113,9 +112,7 @@
<li>
<a href="{{ nav.url }}" {% if nav.active %}class="active"{% endif %}
{% if nav.children %}class="has-children"{% endif %}>
{% if nav.icon and "." in nav.icon %}
<img src="{% static nav.icon %}" class="fa-img">
{% elif nav.icon %}
{% if nav.icon %}
<i class="fa fa-{{ nav.icon }} fa-fw"></i>
{% endif %}
{{ nav.label }}

View File

@@ -1,7 +1,6 @@
{% extends "pretixcontrol/items/base.html" %}
{% load i18n %}
{% load bootstrap3 %}
{% load escapejson %}
{% load formset_tags %}
{% block title %}{% blocktrans with name=question.question %}Question: {{ name }}{% endblocktrans %}{% endblock %}
{% block inside %}
@@ -59,7 +58,7 @@
<div class="chart" id="question_chart" data-type="{{ question.type }}">
</div>
<script type="application/json" id="question-chart-data">{{ stats_json|escapejson }}</script>
<script type="application/json" id="question-chart-data">{{ stats_json|safe }}</script>
</div>
<div class="col-md-5 col-xs-12">
<table class="table table-bordered table-hover">

View File

@@ -1,7 +1,6 @@
{% extends "pretixcontrol/items/base.html" %}
{% load i18n %}
{% load bootstrap3 %}
{% load escapejson %}
{% load eventsignal %}
{% block title %}{% blocktrans with name=quota.name %}Quota: {{ name }}{% endblocktrans %}{% endblock %}
{% block inside %}
@@ -21,7 +20,7 @@
<div class="chart" id="quota_chart">
</div>
<script type="application/json" id="quota-chart-data">{{ quota_chart_data|escapejson }}</script>
<script type="application/json" id="quota-chart-data">{{ quota_chart_data|safe }}</script>
</div>
<div class="col-md-5 col-xs-12">
<legend>{% trans "Availability calculation" %}</legend>

View File

@@ -1,4 +1,4 @@
from django.db.models import F, Prefetch, Q
from django.db.models import Prefetch, Q
from django.db.models.functions import Coalesce
from django.views.generic import ListView
@@ -68,15 +68,12 @@ class CheckInView(EventPermissionRequiredMixin, ListView):
'-code': '-order__code',
'email': 'order__email',
'-email': '-order__email',
# Set nulls_first to be consistent over databases
'status': F('checkins__id').asc(nulls_first=True),
'-status': F('checkins__id').desc(nulls_last=True),
'timestamp': F('checkins__datetime').asc(nulls_first=True),
'-timestamp': F('checkins__datetime').desc(nulls_last=True),
'status': 'checkins__id',
'-status': '-checkins__id',
'timestamp': 'checkins__datetime',
'-timestamp': '-checkins__datetime',
'item': 'item__name',
'-item': '-item__name',
'name': (F('display_name').asc(nulls_first=True),
{'display_name': Coalesce('attendee_name', 'addon_to__attendee_name')}),
'-name': (F('display_name').desc(nulls_last=True),
{'display_name': Coalesce('attendee_name', 'addon_to__attendee_name')}),
'name': ('display_name', {'display_name': Coalesce('attendee_name', 'addon_to__attendee_name')}),
'-name': ('-display_name', {'display_name': Coalesce('attendee_name', 'addon_to__attendee_name')}),
}

View File

@@ -10,7 +10,6 @@ from django.shortcuts import render
from django.template.loader import get_template
from django.utils import formats
from django.utils.formats import date_format
from django.utils.html import escape
from django.utils.translation import ugettext_lazy as _
from pretix.base.models import (
@@ -139,7 +138,7 @@ def quota_widgets(sender, **kwargs):
status, left = q.availability()
widgets.append({
'content': NUM_WIDGET.format(num='{}/{}'.format(left, q.size) if q.size is not None else '\u221e',
text=_('{quota} left').format(quota=escape(q.name))),
text=_('{quota} left').format(quota=q.name)),
'display_size': 'small',
'priority': 50,
'url': reverse('control:event.items.quotas.show', kwargs={
@@ -270,8 +269,7 @@ def user_event_widgets(**kwargs):
for event in events:
widgets.append({
'content': '<div class="event">{event}<span class="from">{df}</span><span class="to">{dt}</span></div>'.format(
event=escape(event.name),
df=date_format(event.date_from, 'SHORT_DATE_FORMAT') if event.date_from else '',
event=event.name, df=date_format(event.date_from, 'SHORT_DATE_FORMAT') if event.date_from else '',
dt=date_format(event.date_to, 'SHORT_DATE_FORMAT') if event.date_to else ''
),
'display_size': 'small',

View File

@@ -316,7 +316,8 @@ class InvoicePreview(EventPermissionRequiredMixin, View):
def get(self, request, *args, **kwargs):
pdf = build_preview_invoice_pdf(request.event)
resp = HttpResponse(pdf, content_type='application/pdf')
resp['Content-Disposition'] = 'attachment; filename="invoice-preview.pdf"'
resp['Content-Security-Policy'] = "style-src 'unsafe-inline'; script-src 'unsafe-inline'; object-src 'self'"
resp['Content-Disposition'] = 'inline; filename="invoice-preview.pdf"'
return resp
@@ -436,7 +437,7 @@ class MailSettingsPreview(EventPermissionRequiredMixin, View):
def items(self):
return {
'mail_text_order_placed': ['total', 'currency', 'date', 'invoice_company',
'event', 'payment_info', 'url', 'invoice_name'],
'event', 'paymentinfo', 'url', 'invoice_name'],
'mail_text_order_paid': ['event', 'url', 'invoice_name', 'invoice_company', 'payment_info'],
'mail_text_order_free': ['event', 'url', 'invoice_name', 'invoice_company'],
'mail_text_resend_link': ['event', 'url', 'invoice_name', 'invoice_company'],
@@ -467,7 +468,7 @@ class MailSettingsPreview(EventPermissionRequiredMixin, View):
'code': '68CYU2H6ZTP3WLK5',
'invoice_name': _('John Doe'),
'invoice_company': _('Sample Corporation'),
'payment_info': _('Please transfer money to this bank account: 9999-9999-9999-9999')
'paymentinfo': _('Please transfer money to this bank account: 9999-9999-9999-9999')
}
def generate_order_url(self, code, secret):
@@ -527,7 +528,11 @@ class TicketSettingsPreview(EventPermissionRequiredMixin, View):
fname, mimet, data = tickets.preview(self.request.event.pk, self.output.identifier)
resp = HttpResponse(data, content_type=mimet)
ftype = fname.split(".")[-1]
resp['Content-Disposition'] = 'attachment; filename="ticket-preview.{}"'.format(ftype)
if mimet == "application/pdf":
resp['Content-Security-Policy'] = "style-src 'unsafe-inline'; script-src 'unsafe-inline'; object-src 'self'"
resp['Content-Disposition'] = 'inline; filename="ticket-preview.{}"'.format(ftype)
else:
resp['Content-Disposition'] = 'attachment; filename="ticket-preview.{}"'.format(ftype)
return resp
def get_error_url(self) -> str:

View File

@@ -674,7 +674,7 @@ class ExportDoView(EventPermissionRequiredMixin, ExportMixin, AsyncAction, View)
if not self.exporter.form.is_valid():
messages.error(self.request, _('There was a problem processing your input. See below for error details.'))
return self.get(request, *args, **kwargs)
return self.get(*args, **kwargs)
cf = CachedFile()
cf.date = now()

View File

@@ -1,6 +1,6 @@
import csv
import io
from defusedcsv import csv
from django.conf import settings
from django.contrib import messages
from django.core.urlresolvers import resolve, reverse

View File

@@ -0,0 +1,6 @@
from debug_toolbar.middleware import DebugToolbarMiddleware
from django.utils.deprecation import MiddlewareMixin
class DebugMiddlewareCompatibilityShim(MiddlewareMixin, DebugToolbarMiddleware):
pass

View File

@@ -1,16 +0,0 @@
from django.utils import six
from django.utils.encoding import force_text
from django.utils.functional import keep_lazy
from django.utils.safestring import SafeText, mark_safe
_json_escapes = {
ord('>'): '\\u003E',
ord('<'): '\\u003C',
ord('&'): '\\u0026',
}
@keep_lazy(six.text_type, SafeText)
def escapejson(value):
"""Hex encodes characters for use in a application/json type script."""
return mark_safe(force_text(value).translate(_json_escapes))

File diff suppressed because it is too large Load Diff

View File

@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-06-01 10:54+0000\n"
"PO-Revision-Date: 2017-06-01 12:56+0200\n"
"POT-Creation-Date: 2017-05-18 09:17+0000\n"
"PO-Revision-Date: 2017-05-11 12:13+0200\n"
"Last-Translator: Raphael Michel <michel@rami.io>\n"
"Language-Team: \n"
"Language: de\n"
@@ -79,71 +79,59 @@ msgid "May 31st, 2017"
msgstr "31. Mai 2017"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:164
msgid "May 31st June 4th, 2017"
msgstr "31. Mai 4. Juni 2017"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:165
msgid "20:00"
msgstr "20:00"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:166
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:165
msgid "19:00"
msgstr "19:00"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:167
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:166
msgid "2017-05-31 20:00"
msgstr "31.05.2016 20:00"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:168
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:167
msgid "2017-05-31 19:00"
msgstr "31.05.2016 19:00"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:169
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:168
msgid "Random City"
msgstr "Musterstadt"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:170
msgid ""
"Addon 1\n"
"Addon 2"
msgstr ""
"Workshop 1\n"
"Workshop 2"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:215
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:213
msgid "The PDF background file could not be loaded for the following reason:"
msgstr "Die Hintergrund-PDF-Datei konnte nicht geladen werden:"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:364
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:362
msgid "Group of objects"
msgstr "Gruppe von Objekten"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:370
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:368
msgid "Text object"
msgstr "Text-Objekt"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:372
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:370
msgid "Barcode area"
msgstr "QR-Code-Bereich"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:374
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:372
msgid "Object"
msgstr "Objekt"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:378
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:376
msgid "Ticket design"
msgstr "Ticket-Design"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:614
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:612
msgid "Saving failed."
msgstr "Speichern fehlgeschlagen."
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:646
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:644
msgid "Do you really want to leave the editor without saving your changes?"
msgstr ""
"Möchten Sie den Editor wirklich schließen ohne Ihre Änderungen zu speichern?"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:659
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:657
msgid "Error while uploading your PDF file, please try again."
msgstr ""
"Es gab ein Problem beim Hochladen der PDF-Datei, bitte erneut versuchen."

File diff suppressed because it is too large Load Diff

View File

@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-06-01 10:54+0000\n"
"PO-Revision-Date: 2017-06-01 12:56+0200\n"
"POT-Creation-Date: 2017-05-18 09:17+0000\n"
"PO-Revision-Date: 2017-05-11 12:13+0200\n"
"Last-Translator: Raphael Michel <michel@rami.io>\n"
"Language-Team: \n"
"Language: de\n"
@@ -79,71 +79,59 @@ msgid "May 31st, 2017"
msgstr "31. Mai 2017"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:164
msgid "May 31st June 4th, 2017"
msgstr "31. Mai 4. Juni 2017"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:165
msgid "20:00"
msgstr "20:00"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:166
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:165
msgid "19:00"
msgstr "19:00"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:167
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:166
msgid "2017-05-31 20:00"
msgstr "31.05.2016 20:00"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:168
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:167
msgid "2017-05-31 19:00"
msgstr "31.05.2016 19:00"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:169
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:168
msgid "Random City"
msgstr "Musterstadt"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:170
msgid ""
"Addon 1\n"
"Addon 2"
msgstr ""
"Workshop 1\n"
"Workshop 2"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:215
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:213
msgid "The PDF background file could not be loaded for the following reason:"
msgstr "Die Hintergrund-PDF-Datei konnte nicht geladen werden:"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:364
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:362
msgid "Group of objects"
msgstr "Gruppe von Objekten"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:370
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:368
msgid "Text object"
msgstr "Text-Objekt"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:372
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:370
msgid "Barcode area"
msgstr "QR-Code-Bereich"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:374
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:372
msgid "Object"
msgstr "Objekt"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:378
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:376
msgid "Ticket design"
msgstr "Ticket-Design"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:614
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:612
msgid "Saving failed."
msgstr "Speichern fehlgeschlagen."
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:646
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:644
msgid "Do you really want to leave the editor without saving your changes?"
msgstr ""
"Möchtest du den Editor wirklich schließen ohne Ihre Änderungen zu speichern?"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:659
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:657
msgid "Error while uploading your PDF file, please try again."
msgstr ""
"Es gab ein Problem beim Hochladen der PDF-Datei, bitte erneut versuchen."

View File

@@ -2,9 +2,8 @@ import time
from urllib.parse import urlparse
from django.conf import settings
from django.contrib.sessions.middleware import (
SessionMiddleware as BaseSessionMiddleware,
)
from django.contrib.sessions.middleware import \
SessionMiddleware as BaseSessionMiddleware
from django.core.cache import cache
from django.core.exceptions import DisallowedHost
from django.core.urlresolvers import set_urlconf

View File

@@ -13,7 +13,6 @@ def parse(data, hint):
raise HintMismatchError('Invalid hint')
if len(data[0]) != hint['cols']:
raise HintMismatchError('Wrong column count')
good_hint = False
for row in data:
resrow = {}
if None in row or len(row) != hint['cols']:
@@ -32,10 +31,8 @@ def parse(data, hint):
or len(resrow['reference']) == 0 or resrow['date'] == '':
# This is probably a headline or something other special.
continue
if resrow['reference'] or resrow['payer']:
good_hint = True
result.append(resrow)
return result, good_hint
return result
def get_rows_from_file(file):

View File

@@ -20,7 +20,7 @@ def parse(file):
result.append({
'reference': "\n".join([
t.data.get(f) for f in ('transaction_details', 'customer_reference', 'bank_reference',
'extra_details', 'non_swift_text') if t.data.get(f, '')]),
'extra_details') if t.data.get(f, '')]),
'amount': str(round_decimal(t.data['amount'].amount)),
'date': t.data['date'].isoformat()
})

View File

@@ -84,7 +84,7 @@ def _get_unknown_transactions(event: Event, job: BankImportJob, data: list):
amount = Decimal("0.00")
trans = BankTransaction(event=event, import_job=job,
payer=row.get('payer', ''),
payer=row['payer'],
reference=row['reference'],
amount=amount,
date=row['date'])

View File

@@ -14,15 +14,9 @@
<dd>{{ payment_info.reference }}</dd>
</dl>
{% else %}
{% if order.status == "p" %}
<p>{% blocktrans trimmed %}
This order has been marked as paid via bank transfer manually.
{% endblocktrans %}</p>
{% else %}
<p>{% blocktrans trimmed %}
This order has been planned to be paid via bank transfer, but no payment has been received yet.
{% endblocktrans %}</p>
{% endif %}
<p>{% blocktrans trimmed %}
This order has been planned to be paid via bank transfer, but no payment has been received yet.
{% endblocktrans %}</p>
<dl class="dl-horizontal">
<dt>{% trans "Reference code" %}</dt>
<dd>{{ order.full_code }}</dd>

View File

@@ -275,14 +275,12 @@ class ImportView(EventPermissionRequiredMixin, ListView):
if self.request.event.settings.get('banktransfer_csvhint') is not None:
hint = self.request.event.settings.get('banktransfer_csvhint', as_type=dict)
try:
parsed, good = csvimport.parse(data, hint)
parsed = csvimport.parse(data, hint)
except csvimport.HintMismatchError: # TODO: narrow down
logger.exception('Import using stored hint failed')
else:
if good:
return self.start_processing(parsed)
return self.start_processing(parsed)
return self.assign_view(data)
@@ -310,7 +308,7 @@ class ImportView(EventPermissionRequiredMixin, ListView):
logger.error('Import using stored hint failed: ' + str(e))
pass
else:
parsed, __ = csvimport.parse(data, hint)
parsed = csvimport.parse(data, hint)
return self.start_processing(parsed)
def process_csv(self):

View File

@@ -1,7 +1,7 @@
import csv
import io
from collections import OrderedDict
from defusedcsv import csv
from django import forms
from django.db.models.functions import Coalesce
from django.utils.translation import ugettext as _, ugettext_lazy
@@ -110,7 +110,7 @@ class CSVCheckinList(BaseCheckinList):
if form_data['secrets']:
row.append(op.secret)
if self.event.settings.attendee_emails_asked:
row.append(op.attendee_email or (op.addon_to.attendee_email if op.addon_to else ''))
row.append(op.attendee_email or (op.addon_to.attendee_name if op.addon_to else ''))
acache = {}
for a in op.answers.all():
acache[a.question_id] = str(a)

View File

@@ -17,9 +17,8 @@ from django.views.generic import TemplateView, View
from pretix.base.models import Checkin, Event, Order, OrderPosition
from pretix.control.permissions import EventPermissionRequiredMixin
from pretix.helpers.urls import build_absolute_uri
from pretix.multidomain.urlreverse import (
build_absolute_uri as event_absolute_uri,
)
from pretix.multidomain.urlreverse import \
build_absolute_uri as event_absolute_uri
logger = logging.getLogger('pretix.plugins.pretixdroid')
API_VERSION = 3

View File

@@ -2,7 +2,6 @@
{% load i18n %}
{% load compress %}
{% load staticfiles %}
{% load escapejson %}
{% block title %}{% trans "Statistics" %}{% endblock %}
{% block content %}
<h1>{% trans "Statistics" %}</h1>
@@ -31,9 +30,9 @@
<div id="obp_chart" class="chart"></div>
</div>
</div>
<script type="application/json" id="obd-data">{{ obd_data|escapejson }}</script>
<script type="application/json" id="rev-data">{{ rev_data|escapejson }}</script>
<script type="application/json" id="obp-data">{{ obp_data|escapejson }}</script>
<script type="application/json" id="obd-data">{{ obd_data|safe }}</script>
<script type="application/json" id="rev-data">{{ rev_data|safe }}</script>
<script type="application/json" id="obp-data">{{ obp_data|safe }}</script>
<script type="application/text" id="currency">{{ request.event.currency }}</script>
<script type="application/javascript" src="{% static "pretixplugins/statistics/statistics.js" %}"></script>
{% else %}

View File

@@ -161,13 +161,11 @@ var editor = {
"attendee_name": gettext("John Doe"),
"event_name": gettext("Sample event name"),
"event_date": gettext("May 31st, 2017"),
"event_date_range": gettext("May 31st June 4th, 2017"),
"event_begin_time": gettext("20:00"),
"event_admission_time": gettext("19:00"),
"event_begin": gettext("2017-05-31 20:00"),
"event_admission": gettext("2017-05-31 19:00"),
"event_location": gettext("Random City"),
"addons": gettext("Addon 1\nAddon 2"),
"event_location": gettext("Random City")
},
_load_pdf: function (dump) {

View File

@@ -267,13 +267,11 @@
<option value="attendee_name">{% trans "Attendee name" %}</option>
<option value="event_name">{% trans "Event name" %}</option>
<option value="event_date">{% trans "Event date" %}</option>
<option value="event_date_range">{% trans "Event date range" %}</option>
<option value="event_begin">{% trans "Event begin date and time" %}</option>
<option value="event_begin_time">{% trans "Event begin time" %}</option>
<option value="event_admission">{% trans "Event admission date and time" %}</option>
<option value="event_admission_time">{% trans "Event admission time" %}</option>
<option value="event_location">{% trans "Event location" %}</option>
<option value="addons">{% trans "List of Add-Ons" %}</option>
<option value="other">{% trans "Other…" %}</option>
</select>
<textarea type="text" value="" class="input-block-level form-control"

View File

@@ -85,8 +85,6 @@ class PdfTicketOutput(BaseTicketOutput):
return str(order.event.location).replace("\n", "<br/>\n")
elif o['content'] == 'event_date':
return order.event.get_date_from_display(show_times=False)
elif o['content'] == 'event_date_range':
return order.event.get_date_range_display()
elif o['content'] == 'event_begin':
return order.event.get_date_from_display(show_times=True)
elif o['content'] == 'event_begin_time':
@@ -99,11 +97,6 @@ class PdfTicketOutput(BaseTicketOutput):
if order.event.date_admission:
tz = timezone(order.event.settings.timezone)
return date_format(order.event.date_admission.astimezone(tz), "TIME_FORMAT")
elif o['content'] == 'addons':
return "<br/>".join([
'{} - {}'.format(p.item, p.variation) if p.variation else str(p.item)
for p in op.addons.select_related('item', 'variation')
])
return ''
def _draw_textarea(self, canvas: Canvas, op: OrderPosition, order: Order, o: dict):
@@ -233,9 +226,9 @@ class PdfTicketOutput(BaseTicketOutput):
"fontfamily": "Open Sans", "bold": False, "italic": False, "width": "110.00", "content": "attendee_name",
"text": "John Doe", "align": "left"},
{"type": "textarea", "left": "17.50", "bottom": "242.10", "fontsize": "13.0", "color": [0, 0, 0, 1],
"fontfamily": "Open Sans", "bold": False, "italic": False, "width": "110.00",
"content": "event_date_range", "text": "May 31st, 2017", "align": "left"},
{"type": "textarea", "left": "17.50", "bottom": "204.80", "fontsize": "13.0", "color": [0, 0, 0, 1],
"fontfamily": "Open Sans", "bold": False, "italic": False, "width": "110.00", "content": "event_date",
"text": "May 31st, 2017", "align": "left"},
{"type": "textarea", "left": "17.50", "bottom": "234.30", "fontsize": "13.0", "color": [0, 0, 0, 1],
"fontfamily": "Open Sans", "bold": False, "italic": False, "width": "110.00", "content": "event_location",
"text": "Random City", "align": "left"},
{"type": "textarea", "left": "17.50", "bottom": "194.50", "fontsize": "13.0", "color": [0, 0, 0, 1],

View File

@@ -86,7 +86,6 @@ class EditorView(EventPermissionRequiredMixin, ChartContainingView, TemplateView
if "preview" in request.POST:
with rolledback_transaction(), language(request.event.settings.locale):
item = request.event.items.create(name=_("Sample product"), default_price=42.23)
item2 = request.event.items.create(name=_("Sample workshop"), default_price=23.40)
from pretix.base.models import Order
order = request.event.orders.create(status=Order.STATUS_PENDING, datetime=now(),
@@ -94,8 +93,6 @@ class EditorView(EventPermissionRequiredMixin, ChartContainingView, TemplateView
expires=now(), code="PREVIEW1234", total=119)
p = order.positions.create(item=item, attendee_name=_("John Doe"), price=item.default_price)
order.positions.create(item=item2, attendee_name=_("John Doe"), price=item.default_price, addon_to=p)
order.positions.create(item=item2, attendee_name=_("John Doe"), price=item.default_price, addon_to=p)
prov = PdfTicketOutput(request.event,
override_layout=(json.loads(request.POST.get("data"))
@@ -105,7 +102,8 @@ class EditorView(EventPermissionRequiredMixin, ChartContainingView, TemplateView
resp = HttpResponse(data, content_type=mimet)
ftype = fname.split(".")[-1]
resp['Content-Disposition'] = 'attachment; filename="ticket-preview.{}"'.format(ftype)
resp['Content-Security-Policy'] = "style-src 'unsafe-inline'; script-src 'unsafe-inline'; object-src 'self'"
resp['Content-Disposition'] = 'inline; filename="ticket-preview.{}"'.format(ftype)
return resp
elif "data" in request.POST:
if cf:

View File

@@ -19,8 +19,7 @@ from pretix.presale.forms.checkout import (
AddOnsForm, ContactForm, InvoiceAddressForm,
)
from pretix.presale.signals import (
checkout_confirm_messages, checkout_flow_steps, contact_form_fields,
order_meta_from_request,
checkout_confirm_messages, checkout_flow_steps, order_meta_from_request,
)
from pretix.presale.views import CartMixin, get_cart, get_cart_total
from pretix.presale.views.async import AsyncAction
@@ -256,13 +255,10 @@ class QuestionsStep(QuestionsViewMixin, CartMixin, TemplateFlowStep):
@cached_property
def contact_form(self):
initial = {
'email': self.request.session.get('email', '')
}
initial.update(self.request.session.get('contact_form_data', {}))
return ContactForm(data=self.request.POST if self.request.method == "POST" else None,
event=self.request.event,
initial=initial)
initial={
'email': self.request.session.get('email', '')
})
@cached_property
def invoice_address(self):
@@ -294,7 +290,6 @@ class QuestionsStep(QuestionsViewMixin, CartMixin, TemplateFlowStep):
if request.event.settings.invoice_address_asked:
addr = self.invoice_form.save()
request.session['invoice_address'] = addr.pk
request.session['contact_form_data'] = self.contact_form.cleaned_data
return redirect(self.get_next_url(request))
@@ -440,18 +435,6 @@ class ConfirmStep(CartMixin, AsyncAction, TemplateFlowStep):
ctx['payment_provider'] = self.payment_provider
ctx['addr'] = self.invoice_address
ctx['confirm_messages'] = self.confirm_messages
ctx['contact_info'] = []
responses = contact_form_fields.send(self.event)
for r, response in sorted(responses, key=lambda r: str(r[0])):
for key, value in response.items():
v = self.request.session.get('contact_form_data', {}).get(key)
if v is True:
v = _('Yes')
elif v is False:
v = _('No')
ctx['contact_info'].append((value.label, v))
return ctx
@cached_property
@@ -502,12 +485,9 @@ class ConfirmStep(CartMixin, AsyncAction, TemplateFlowStep):
})
return redirect(self.get_error_url())
meta_info = {
'contact_form_data': self.request.session.get('contact_form_data', {})
}
meta_info = {}
for receiver, response in order_meta_from_request.send(sender=request.event, request=request):
meta_info.update(response)
return self.do(self.request.event.id, self.payment_provider.identifier,
[p.id for p in self.positions], request.session.get('email'),
translation.get_language(), self.invoice_address.pk, meta_info)

View File

@@ -1,18 +1,19 @@
from decimal import Decimal
from itertools import chain
from django import forms
from django.core.exceptions import ValidationError
from django.db.models import Count, Prefetch, Q
from django.forms.widgets import RadioChoiceInput, RadioFieldRenderer
from django.utils.encoding import force_text
from django.utils.formats import number_format
from django.utils.html import format_html
from django.utils.safestring import mark_safe
from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _
from pretix.base.models import ItemVariation, Question
from pretix.base.models.orders import InvoiceAddress
from pretix.base.templatetags.rich_text import rich_text
from pretix.presale.signals import contact_form_fields
class ContactForm(forms.Form):
@@ -22,16 +23,6 @@ class ContactForm(forms.Form):
'modifications to your order or download your ticket later.'),
widget=forms.EmailInput(attrs={'data-typocheck-target': '1'}))
def __init__(self, *args, **kwargs):
self.event = kwargs.pop('event')
super().__init__(*args, **kwargs)
responses = contact_form_fields.send(self.event)
for r, response in sorted(responses, key=lambda r: str(r[0])):
for key, value in response.items():
# We need to be this explicit, since OrderedDict.update does not retain ordering
self.fields[key] = value
class InvoiceAddressForm(forms.ModelForm):
@@ -164,35 +155,51 @@ class QuestionsForm(forms.Form):
self.fields['question_%s' % q.id] = field
class AddOnRadioSelect(forms.RadioSelect):
option_template_name = 'pretixpresale/forms/addon_choice_option.html'
# The following will get totally different once Django 1.11 is integrated
class AddOnVariationSelectInput(RadioChoiceInput):
def optgroups(self, name, value, attrs=None):
attrs = attrs or {}
groups = []
has_selected = False
for index, (option_value, option_label, option_desc) in enumerate(chain(self.choices)):
if option_value is None:
option_value = ''
if isinstance(option_label, (list, tuple)):
raise TypeError('Choice groups are not supported here')
group_name = None
subgroup = []
groups.append((group_name, subgroup, index))
def __init__(self, name, value, attrs, choice, index):
super().__init__(name, value, attrs, choice, index)
self.description = force_text(choice[2])
selected = (
force_text(option_value) in value and
(has_selected is False or self.allow_multiple_selected)
def render(self, name=None, value=None, attrs=None):
if self.id_for_label:
label_for = format_html(' for="{}"', self.id_for_label)
else:
label_for = ''
attrs = dict(self.attrs, **attrs) if attrs else self.attrs
if self.description:
return format_html(
'<label{}>{} {}</label> <span class="fa fa-info-circle toggle-variation-description"></span>'
'<div class="variation-description addon-variation-description">{}</div>',
label_for, self.tag(attrs), self.choice_label,
rich_text(str(self.description))
)
else:
return format_html(
'<label{}>{} {}</label>',
label_for, self.tag(attrs), self.choice_label,
)
if selected is True and has_selected is False:
has_selected = True
attrs['description'] = option_desc
subgroup.append(self.create_option(
name, option_value, option_label, selected, index,
subindex=None, attrs=attrs,
))
return groups
class AddOnVariationSelectRenderer(RadioFieldRenderer):
choice_input_class = AddOnVariationSelectInput
def render(self):
id_ = self.attrs.get('id')
output = []
for i, choice in enumerate(self.choices):
w = self.choice_input_class(self.name, self.value, self.attrs.copy(), choice, i)
output.append(format_html(self.inner_html, choice_value=force_text(w), sub_widgets=''))
return format_html(
self.outer_html,
id_attr=format_html(' id="{}"', id_) if id_ else '',
content=mark_safe('\n'.join(output)),
)
class AddOnVariationSelect(forms.RadioSelect):
renderer = AddOnVariationSelectRenderer
class AddOnVariationField(forms.ChoiceField):
@@ -300,7 +307,7 @@ class AddOnsForm(forms.Form):
choices=choices,
label=i.name,
required=False,
widget=AddOnRadioSelect,
widget=AddOnVariationSelect,
help_text=rich_text(str(i.description)),
initial=current_addons.get(i.pk),
)

View File

@@ -69,18 +69,6 @@ You will recieve the request triggering the order creation as the ``request`` ke
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""
contact_form_fields = EventPluginSignal(
providing_args=[]
)
"""
This signals allows you to add form fields to the contact form that is presented during checkout
and by default only asks for the email address. You are supposed to return a dictionary of
form fields with globally unique keys. The validated form results will be saved into the
``contact_form_data`` entry of the order metadata dictionary.
As with all plugin signals, the ``sender`` keyword argument will contain the event.
"""
order_info = EventPluginSignal(
providing_args=["order"]
)

View File

@@ -8,7 +8,7 @@
<head>
<title>{% block thetitle %}{% endblock %}</title>
{% compress css %}
<link rel="stylesheet" type="text/x-scss" href="{% static "lightbox/css/lightbox.scss" %}" />
<link rel="stylesheet" type="text/css" href="{% static "lightbox/css/lightbox.css" %}" />
{% endcompress %}
{% if css_file %}
<link rel="stylesheet" type="text/css" href="{{ css_file }}"/>

View File

@@ -111,12 +111,6 @@
<dt>{% trans "E-mail address" %}</dt>
<dd>{{ request.session.email }}</dd>
</dl>
{% for l, v in contact_info %}
<dl class="dl-horizontal">
<dt>{{ l }}</dt>
<dd>{{ v }}</dd>
</dl>
{% endfor %}
</div>
</div>
</div>

View File

@@ -132,8 +132,7 @@
<div class="col-md-8 col-xs-12">
{% if item.picture %}
<a href="{{ item.picture.url }}" class="productpicture"
data-title="{{ item.name|force_escape|force_escape }}"
{# Yes, double-escape to prevent XSS in lightbox #}
data-title="{{ item.name }}"
data-lightbox="{{ item.id }}">
<img src="{{ item.picture|thumbnail_url:'productlist' }}"
alt="{{ item.name }}"/>
@@ -244,7 +243,7 @@
<div class="col-md-8 col-xs-12">
{% if item.picture %}
<a href="{{ item.picture.url }}" class="productpicture"
data-title="{{ item.name|force_escape|force_escape }}"
data-title="{{ item.name }}"
data-lightbox="{{ item.id }}">
<img src="{{ item.picture|thumbnail_url:'productlist' }}"
alt="{{ item.name }}"/>

View File

@@ -29,8 +29,7 @@
<div class="col-md-8 col-xs-12">
{% if item.picture %}
<a href="{{ item.picture.url }}" class="productpicture"
data-title="{{ item.name|force_escape|force_escape }}"
{# Yes, double-escape to prevent XSS in lightbox #}
data-title="{{ item.name }}"
data-lightbox="{{ item.id }}">
<img src="{{ item.picture|thumbnail_url:'productlist' }}"
alt="{{ item.name }}"/>
@@ -117,8 +116,7 @@
<div class="col-md-8 col-xs-12">
{% if item.picture %}
<a href="{{ item.picture.url }}" class="productpicture"
data-title="{{ item.name|force_escape|force_escape }}"
{# Yes, double-escape to prevent XSS in lightbox #}
data-title="{{ item.name }}"
data-lightbox="{{ item.id }}">
<img src="{{ item.picture|thumbnail_url:'productlist' }}"
alt="{{ item.name }}"/>

View File

@@ -1,3 +0,0 @@
{% load rich_text %}
<label{% if widget.attrs.id %} for="{{ widget.attrs.id }}"{% endif %}>{% include "django/forms/widgets/input.html" %} {{ widget.label }}</label> {% if widget.attrs.description %}<span class="fa fa-info-circle toggle-variation-description"></span>
<div class="variation-description addon-variation-description">{{ widget.attrs.description|rich_text }}</div>{% endif %}

View File

@@ -581,9 +581,15 @@ class OrderDownload(EventViewMixin, OrderDetailMixin, View):
return render(self.request, "pretixbase/cachedfiles/pending.html", {})
else:
resp = FileResponse(ct.file.file, content_type=ct.type)
resp['Content-Disposition'] = 'attachment; filename="{}-{}-{}{}"'.format(
self.request.event.slug.upper(), self.order.code, self.output.identifier, ct.extension
)
if ct.type == "application/pdf":
resp['Content-Security-Policy'] = "style-src 'unsafe-inline'; script-src 'unsafe-inline'; object-src 'self'"
resp['Content-Disposition'] = 'inline; filename="{}-{}-{}{}"'.format(
self.request.event.slug.upper(), self.order.code, self.output.identifier, ct.extension
)
else:
resp['Content-Disposition'] = 'attachment; filename="{}-{}-{}{}"'.format(
self.request.event.slug.upper(), self.order.code, self.output.identifier, ct.extension
)
return resp
def _download_position(self):
@@ -614,10 +620,17 @@ class OrderDownload(EventViewMixin, OrderDetailMixin, View):
return render(self.request, "pretixbase/cachedfiles/pending.html", {})
else:
resp = FileResponse(ct.file.file, content_type=ct.type)
resp['Content-Disposition'] = 'attachment; filename="{}-{}-{}-{}{}"'.format(
self.request.event.slug.upper(), self.order.code, self.order_position.positionid,
self.output.identifier, ct.extension
)
if ct.type == "application/pdf":
resp['Content-Security-Policy'] = "style-src 'unsafe-inline'; script-src 'unsafe-inline'; object-src 'self'"
resp['Content-Disposition'] = 'inline; filename="{}-{}-{}-{}{}"'.format(
self.request.event.slug.upper(), self.order.code, self.order_position.positionid,
self.output.identifier, ct.extension
)
else:
resp['Content-Disposition'] = 'attachment; filename="{}-{}-{}-{}{}"'.format(
self.request.event.slug.upper(), self.order.code, self.order_position.positionid,
self.output.identifier, ct.extension
)
return resp
@@ -647,5 +660,6 @@ class InvoiceDownload(EventViewMixin, OrderDetailMixin, View):
return redirect(self.get_order_url())
resp = FileResponse(invoice.file.file, content_type='application/pdf')
resp['Content-Disposition'] = 'attachment; filename="{}.pdf"'.format(invoice.number)
resp['Content-Security-Policy'] = "style-src 'unsafe-inline'; script-src 'unsafe-inline'; object-src 'self'"
resp['Content-Disposition'] = 'inline; filename="{}.pdf"'.format(invoice.number)
return resp

View File

@@ -83,7 +83,7 @@ PRETIX_PASSWORD_RESET = config.getboolean('pretix', 'password_reset', fallback=T
SITE_URL = config.get('pretix', 'url', fallback='http://localhost')
PRETIX_PLUGINS_DEFAULT = config.get('pretix', 'plugins_default',
fallback='pretix.plugins.sendmail,pretix.plugins.statistics,pretix.plugins.checkinlists')
fallback='pretix.plugins.sendmail,pretix.plugins.statistics')
DEFAULT_CURRENCY = config.get('pretix', 'currency', fallback='EUR')
CURRENCIES = list(currencies)
@@ -258,7 +258,7 @@ try:
import debug_toolbar # noqa
if DEBUG:
INSTALLED_APPS.append('debug_toolbar.apps.DebugToolbarConfig')
MIDDLEWARE.insert(0, 'debug_toolbar.middleware.DebugToolbarMiddleware')
MIDDLEWARE.insert(0, 'pretix.helpers.debug.DebugMiddlewareCompatibilityShim')
except ImportError:
pass
@@ -376,9 +376,7 @@ COMPRESS_PRECOMPILERS = (
COMPRESS_ENABLED = COMPRESS_OFFLINE = not debug_fallback
COMPRESS_CSS_FILTERS = (
# CssAbsoluteFilter is incredibly slow, especially when dealing with our _flags.scss
# However, we don't need it if we consequently use the static() function in Sass
# 'compressor.filters.css_default.CssAbsoluteFilter',
'compressor.filters.css_default.CssAbsoluteFilter',
'compressor.filters.cssmin.CSSCompressorFilter',
)

View File

@@ -1,5 +1,5 @@
/* @license
morris.js v0.5.1
morris.js v0.5.0
Copyright 2014 Olly Smith All rights reserved.
Licensed under the BSD-2-Clause License.
*/
@@ -74,7 +74,6 @@ Licensed under the BSD-2-Clause License.
__extends(Grid, _super);
function Grid(options) {
this.hasToShow = __bind(this.hasToShow, this);
this.resizeHandler = __bind(this.resizeHandler, this);
var _this = this;
if (typeof options.element === 'string') {
@@ -198,7 +197,7 @@ Licensed under the BSD-2-Clause License.
};
Grid.prototype.setData = function(data, redraw) {
var e, flatEvents, from, idx, index, maxGoal, minGoal, ret, row, step, to, total, y, ykey, ymax, ymin, yval, _i, _len, _ref, _ref1;
var e, idx, index, maxGoal, minGoal, ret, row, step, total, y, ykey, ymax, ymin, yval, _ref;
if (redraw == null) {
redraw = true;
}
@@ -255,7 +254,7 @@ Licensed under the BSD-2-Clause License.
if ((yval != null) && typeof yval !== 'number') {
yval = null;
}
if ((yval != null) && this.hasToShow(idx)) {
if (yval != null) {
if (this.cumulative) {
total += yval;
} else {
@@ -289,24 +288,21 @@ Licensed under the BSD-2-Clause License.
this.events = [];
if (this.options.events.length > 0) {
if (this.options.parseTime) {
_ref = this.options.events;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
e = _ref[_i];
if (e instanceof Array) {
from = e[0], to = e[1];
this.events.push([Morris.parseDate(from), Morris.parseDate(to)]);
} else {
this.events.push(Morris.parseDate(e));
this.events = (function() {
var _i, _len, _ref, _results;
_ref = this.options.events;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
e = _ref[_i];
_results.push(Morris.parseDate(e));
}
}
return _results;
}).call(this);
} else {
this.events = this.options.events;
}
flatEvents = $.map(this.events, function(e) {
return e;
});
this.xmax = Math.max(this.xmax, Math.max.apply(Math, flatEvents));
this.xmin = Math.min(this.xmin, Math.min.apply(Math, flatEvents));
this.xmax = Math.max(this.xmax, Math.max.apply(Math, this.events));
this.xmin = Math.min(this.xmin, Math.min.apply(Math, this.events));
}
if (this.xmin === this.xmax) {
this.xmin -= 1;
@@ -320,7 +316,7 @@ Licensed under the BSD-2-Clause License.
}
this.ymax += 1;
}
if (((_ref1 = this.options.axes) === true || _ref1 === 'both' || _ref1 === 'y') || this.options.grid === true) {
if (((_ref = this.options.axes) === true || _ref === 'both' || _ref === 'y') || this.options.grid === true) {
if (this.options.ymax === this.gridDefaults.ymax && this.options.ymin === this.gridDefaults.ymin) {
this.grid = this.autoGridLines(this.ymin, this.ymax, this.options.numLines);
this.ymin = Math.min(this.ymin, this.grid[0]);
@@ -328,9 +324,9 @@ Licensed under the BSD-2-Clause License.
} else {
step = (this.ymax - this.ymin) / (this.options.numLines - 1);
this.grid = (function() {
var _j, _ref2, _ref3, _results;
var _i, _ref1, _ref2, _results;
_results = [];
for (y = _j = _ref2 = this.ymin, _ref3 = this.ymax; step > 0 ? _j <= _ref3 : _j >= _ref3; y = _j += step) {
for (y = _i = _ref1 = this.ymin, _ref2 = this.ymax; step > 0 ? _i <= _ref2 : _i >= _ref2; y = _i += step) {
_results.push(y);
}
return _results;
@@ -409,7 +405,7 @@ Licensed under the BSD-2-Clause License.
};
Grid.prototype._calc = function() {
var angle, bottomOffsets, gridLine, h, i, w, yLabelWidths, _ref, _ref1;
var bottomOffsets, gridLine, h, i, w, yLabelWidths, _ref, _ref1;
w = this.el.width();
h = this.el.height();
if (this.elementWidth !== w || this.elementHeight !== h || this.dirty) {
@@ -431,53 +427,23 @@ Licensed under the BSD-2-Clause License.
}
return _results;
}).call(this);
if (!this.options.horizontal) {
this.left += Math.max.apply(Math, yLabelWidths);
} else {
this.bottom -= Math.max.apply(Math, yLabelWidths);
}
this.left += Math.max.apply(Math, yLabelWidths);
}
if ((_ref1 = this.options.axes) === true || _ref1 === 'both' || _ref1 === 'x') {
if (!this.options.horizontal) {
angle = -this.options.xLabelAngle;
} else {
angle = -90;
}
bottomOffsets = (function() {
var _i, _ref2, _results;
_results = [];
for (i = _i = 0, _ref2 = this.data.length; 0 <= _ref2 ? _i < _ref2 : _i > _ref2; i = 0 <= _ref2 ? ++_i : --_i) {
_results.push(this.measureText(this.data[i].label, angle).height);
_results.push(this.measureText(this.data[i].text, -this.options.xLabelAngle).height);
}
return _results;
}).call(this);
if (!this.options.horizontal) {
this.bottom -= Math.max.apply(Math, bottomOffsets);
} else {
this.left += Math.max.apply(Math, bottomOffsets);
}
this.bottom -= Math.max.apply(Math, bottomOffsets);
}
this.width = Math.max(1, this.right - this.left);
this.height = Math.max(1, this.bottom - this.top);
if (!this.options.horizontal) {
this.dx = this.width / (this.xmax - this.xmin);
this.dy = this.height / (this.ymax - this.ymin);
this.yStart = this.bottom;
this.yEnd = this.top;
this.xStart = this.left;
this.xEnd = this.right;
this.xSize = this.width;
this.ySize = this.height;
} else {
this.dx = this.height / (this.xmax - this.xmin);
this.dy = this.width / (this.ymax - this.ymin);
this.yStart = this.left;
this.yEnd = this.right;
this.xStart = this.top;
this.xEnd = this.bottom;
this.xSize = this.height;
this.ySize = this.width;
}
this.dx = this.width / (this.xmax - this.xmin);
this.dy = this.height / (this.ymax - this.ymin);
if (this.calc) {
return this.calc();
}
@@ -485,18 +451,14 @@ Licensed under the BSD-2-Clause License.
};
Grid.prototype.transY = function(y) {
if (!this.options.horizontal) {
return this.bottom - (y - this.ymin) * this.dy;
} else {
return this.left + (y - this.ymin) * this.dy;
}
return this.bottom - (y - this.ymin) * this.dy;
};
Grid.prototype.transX = function(x) {
if (this.data.length === 1) {
return (this.xStart + this.xEnd) / 2;
return (this.left + this.right) / 2;
} else {
return this.xStart + (x - this.xmin) * this.dx;
return this.left + (x - this.xmin) * this.dx;
}
};
@@ -523,50 +485,32 @@ Licensed under the BSD-2-Clause License.
};
Grid.prototype.yAxisFormat = function(label) {
return this.yLabelFormat(label, 0);
return this.yLabelFormat(label);
};
Grid.prototype.yLabelFormat = function(label, i) {
Grid.prototype.yLabelFormat = function(label) {
if (typeof this.options.yLabelFormat === 'function') {
return this.options.yLabelFormat(label, i);
return this.options.yLabelFormat(label);
} else {
return "" + this.options.preUnits + (Morris.commas(label)) + this.options.postUnits;
}
};
Grid.prototype.getYAxisLabelX = function() {
return this.left - this.options.padding / 2;
};
Grid.prototype.drawGrid = function() {
var basePos, lineY, pos, _i, _len, _ref, _ref1, _ref2, _results;
var lineY, y, _i, _len, _ref, _ref1, _ref2, _results;
if (this.options.grid === false && ((_ref = this.options.axes) !== true && _ref !== 'both' && _ref !== 'y')) {
return;
}
if (!this.options.horizontal) {
basePos = this.getYAxisLabelX();
} else {
basePos = this.getXAxisLabelY();
}
_ref1 = this.grid;
_results = [];
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
lineY = _ref1[_i];
pos = this.transY(lineY);
y = this.transY(lineY);
if ((_ref2 = this.options.axes) === true || _ref2 === 'both' || _ref2 === 'y') {
if (!this.options.horizontal) {
this.drawYAxisLabel(basePos, pos, this.yAxisFormat(lineY));
} else {
this.drawXAxisLabel(pos, basePos, this.yAxisFormat(lineY));
}
this.drawYAxisLabel(this.left - this.options.padding / 2, y, this.yAxisFormat(lineY));
}
if (this.options.grid) {
pos = Math.floor(pos) + 0.5;
if (!this.options.horizontal) {
_results.push(this.drawGridLine("M" + this.xStart + "," + pos + "H" + this.xEnd));
} else {
_results.push(this.drawGridLine("M" + pos + "," + this.xStart + "V" + this.xEnd));
}
_results.push(this.drawGridLine("M" + this.left + "," + y + "H" + (this.left + this.width)));
} else {
_results.push(void 0);
}
@@ -599,42 +543,11 @@ Licensed under the BSD-2-Clause License.
};
Grid.prototype.drawGoal = function(goal, color) {
var path, y;
y = Math.floor(this.transY(goal)) + 0.5;
if (!this.options.horizontal) {
path = "M" + this.xStart + "," + y + "H" + this.xEnd;
} else {
path = "M" + y + "," + this.xStart + "V" + this.xEnd;
}
return this.raphael.path(path).attr('stroke', color).attr('stroke-width', this.options.goalStrokeWidth);
return this.raphael.path("M" + this.left + "," + (this.transY(goal)) + "H" + this.right).attr('stroke', color).attr('stroke-width', this.options.goalStrokeWidth);
};
Grid.prototype.drawEvent = function(event, color) {
var from, path, to, x;
if (event instanceof Array) {
from = event[0], to = event[1];
from = Math.floor(this.transX(from)) + 0.5;
to = Math.floor(this.transX(to)) + 0.5;
if (!this.options.horizontal) {
return this.raphael.rect(from, this.yEnd, to - from, this.yStart - this.yEnd).attr({
fill: color,
stroke: false
}).toBack();
} else {
return this.raphael.rect(this.yStart, from, this.yEnd - this.yStart, to - from).attr({
fill: color,
stroke: false
}).toBack();
}
} else {
x = Math.floor(this.transX(event)) + 0.5;
if (!this.options.horizontal) {
path = "M" + x + "," + this.yStart + "V" + this.yEnd;
} else {
path = "M" + this.yStart + "," + x + "H" + this.yEnd;
}
return this.raphael.path(path).attr('stroke', color).attr('stroke-width', this.options.eventStrokeWidth);
}
return this.raphael.path("M" + (this.transX(event)) + "," + this.bottom + "V" + this.top).attr('stroke', color).attr('stroke-width', this.options.eventStrokeWidth);
};
Grid.prototype.drawYAxisLabel = function(xPos, yPos, text) {
@@ -673,10 +586,6 @@ Licensed under the BSD-2-Clause License.
return this.redraw();
};
Grid.prototype.hasToShow = function(i) {
return this.options.shown === true || this.options.shown[i] === true;
};
return Grid;
})(Morris.EventEmitter);
@@ -753,13 +662,13 @@ Licensed under the BSD-2-Clause License.
this.options.parent.append(this.el);
}
Hover.prototype.update = function(html, x, y, centre_y) {
Hover.prototype.update = function(html, x, y) {
if (!html) {
return this.hide();
} else {
this.html(html);
this.show();
return this.moveTo(x, y, centre_y);
return this.moveTo(x, y);
}
};
@@ -767,7 +676,7 @@ Licensed under the BSD-2-Clause License.
return this.el.html(content);
};
Hover.prototype.moveTo = function(x, y, centre_y) {
Hover.prototype.moveTo = function(x, y) {
var hoverHeight, hoverWidth, left, parentHeight, parentWidth, top;
parentWidth = this.options.parent.innerWidth();
parentHeight = this.options.parent.innerHeight();
@@ -775,18 +684,11 @@ Licensed under the BSD-2-Clause License.
hoverHeight = this.el.outerHeight();
left = Math.min(Math.max(0, x - hoverWidth / 2), parentWidth - hoverWidth);
if (y != null) {
if (centre_y === true) {
top = y - hoverHeight / 2;
if (top < 0) {
top = 0;
}
} else {
top = y - hoverHeight - 10;
if (top < 0) {
top = y + 10;
if (top + hoverHeight > parentHeight) {
top = parentHeight / 2 - hoverHeight / 2;
}
top = y - hoverHeight - 10;
if (top < 0) {
top = y + 10;
if (top + hoverHeight > parentHeight) {
top = parentHeight / 2 - hoverHeight / 2;
}
}
} else {
@@ -843,14 +745,10 @@ Licensed under the BSD-2-Clause License.
pointStrokeColors: ['#ffffff'],
pointFillColors: [],
smooth: true,
shown: true,
xLabels: 'auto',
xLabelFormat: null,
xLabelMargin: 24,
hideHover: false,
trendLine: false,
trendLineWidth: 2,
trendLineColors: ['#689bc3', '#a2b3bf', '#64b764']
hideHover: false
};
Line.prototype.calc = function() {
@@ -942,15 +840,11 @@ Licensed under the BSD-2-Clause License.
Line.prototype.hoverContentForRow = function(index) {
var content, j, row, y, _i, _len, _ref;
row = this.data[index];
content = $("<div class='morris-hover-row-label'>").text(row.label);
content = content.prop('outerHTML');
content = "<div class='morris-hover-row-label'>" + row.label + "</div>";
_ref = row.y;
for (j = _i = 0, _len = _ref.length; _i < _len; j = ++_i) {
y = _ref[j];
if (this.options.labels[j] === false) {
continue;
}
content += "<div class='morris-hover-point' style='color: " + (this.colorFor(row, j, 'label')) + "'>\n " + this.options.labels[j] + ":\n " + (this.yLabelFormat(y, j)) + "\n</div>";
content += "<div class='morris-hover-point' style='color: " + (this.colorFor(row, j, 'label')) + "'>\n " + this.options.labels[j] + ":\n " + (this.yLabelFormat(y)) + "\n</div>";
}
if (typeof this.options.hoverCallback === 'function') {
content = this.options.hoverCallback(index, this.options, content, row.src);
@@ -1060,20 +954,11 @@ Licensed under the BSD-2-Clause License.
var i, _i, _j, _ref, _ref1, _results;
this.seriesPoints = [];
for (i = _i = _ref = this.options.ykeys.length - 1; _ref <= 0 ? _i <= 0 : _i >= 0; i = _ref <= 0 ? ++_i : --_i) {
if (this.hasToShow(i)) {
if (this.options.trendLine !== false && this.options.trendLine === true || this.options.trendLine[i] === true) {
this._drawTrendLine(i);
}
this._drawLineFor(i);
}
this._drawLineFor(i);
}
_results = [];
for (i = _j = _ref1 = this.options.ykeys.length - 1; _ref1 <= 0 ? _j <= 0 : _j >= 0; i = _ref1 <= 0 ? ++_j : --_j) {
if (this.hasToShow(i)) {
_results.push(this._drawPointFor(i));
} else {
_results.push(void 0);
}
_results.push(this._drawPointFor(i));
}
return _results;
};
@@ -1102,38 +987,6 @@ Licensed under the BSD-2-Clause License.
}
};
Line.prototype._drawTrendLine = function(index) {
var a, b, data, datapoints, path, sum_x, sum_xx, sum_xy, sum_y, val, x, y, _i, _len, _ref;
sum_x = 0;
sum_y = 0;
sum_xx = 0;
sum_xy = 0;
datapoints = 0;
_ref = this.data;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
val = _ref[_i];
x = val.x;
y = val.y[index];
if (y === void 0) {
continue;
}
datapoints += 1;
sum_x += x;
sum_y += y;
sum_xx += x * x;
sum_xy += x * y;
}
a = (datapoints * sum_xy - sum_x * sum_y) / (datapoints * sum_xx - sum_x * sum_x);
b = (sum_y / datapoints) - ((a * sum_x) / datapoints);
data = [{}, {}];
data[0].x = this.transX(this.data[0].x);
data[0].y = this.transY(this.data[0].x * a + b);
data[1].x = this.transX(this.data[this.data.length - 1].x);
data[1].y = this.transY(this.data[this.data.length - 1].x * a + b);
path = Morris.Line.createPath(data, false, this.bottom);
return path = this.raphael.path(path).attr('stroke', this.colorFor(null, index, 'trendLine')).attr('stroke-width', this.options.trendLineWidth);
};
Line.createPath = function(coords, smooth, bottom) {
var coord, g, grads, i, ix, lg, path, prevCoord, x1, x2, y1, y2, _i, _len;
path = "";
@@ -1225,10 +1078,8 @@ Licensed under the BSD-2-Clause License.
return this.options.lineColors.call(this, row, sidx, type);
} else if (type === 'point') {
return this.options.pointFillColors[sidx % this.options.pointFillColors.length] || this.options.lineColors[sidx % this.options.lineColors.length];
} else if (type === 'line') {
return this.options.lineColors[sidx % this.options.lineColors.length];
} else {
return this.options.trendLineColors[sidx % this.options.trendLineColors.length];
return this.options.lineColors[sidx % this.options.lineColors.length];
}
};
@@ -1269,9 +1120,6 @@ Licensed under the BSD-2-Clause License.
};
Line.prototype.pointGrowSeries = function(index) {
if (this.pointSizeForSeries(index) === 0) {
return;
}
return Raphael.animation({
r: this.pointSizeForSeries(index) + 3
}, 25, 'linear');
@@ -1561,9 +1409,7 @@ Licensed under the BSD-2-Clause License.
barColors: ['#0b62a4', '#7a92a3', '#4da74d', '#afd8f8', '#edc240', '#cb4b4b', '#9440ed'],
barOpacity: 1.0,
barRadius: [0, 0, 0, 0],
xLabelMargin: 50,
horizontal: false,
shown: true
xLabelMargin: 50
};
Bar.prototype.calc = function() {
@@ -1580,7 +1426,7 @@ Licensed under the BSD-2-Clause License.
_results = [];
for (idx = _i = 0, _len = _ref.length; _i < _len; idx = ++_i) {
row = _ref[idx];
row._x = this.xStart + this.xSize * (idx + 0.5) / this.data.length;
row._x = this.left + this.width * (idx + 0.5) / this.data.length;
_results.push(row._y = (function() {
var _j, _len1, _ref1, _results1;
_ref1 = row.y;
@@ -1608,54 +1454,28 @@ Licensed under the BSD-2-Clause License.
};
Bar.prototype.drawXAxis = function() {
var angle, basePos, i, label, labelBox, margin, maxSize, offset, prevAngleMargin, prevLabelMargin, row, size, startPos, textBox, _i, _ref, _results;
if (!this.options.horizontal) {
basePos = this.getXAxisLabelY();
} else {
basePos = this.getYAxisLabelX();
}
var i, label, labelBox, margin, offset, prevAngleMargin, prevLabelMargin, row, textBox, ypos, _i, _ref, _results;
ypos = this.bottom + (this.options.xAxisLabelTopPadding || this.options.padding / 2);
prevLabelMargin = null;
prevAngleMargin = null;
_results = [];
for (i = _i = 0, _ref = this.data.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
row = this.data[this.data.length - 1 - i];
if (!this.options.horizontal) {
label = this.drawXAxisLabel(row._x, basePos, row.label);
} else {
label = this.drawYAxisLabel(basePos, row._x - 0.5 * this.options.gridTextSize, row.label);
}
if (!this.options.horizontal) {
angle = this.options.xLabelAngle;
} else {
angle = 0;
}
label = this.drawXAxisLabel(row._x, ypos, row.label);
textBox = label.getBBox();
label.transform("r" + (-angle));
label.transform("r" + (-this.options.xLabelAngle));
labelBox = label.getBBox();
label.transform("t0," + (labelBox.height / 2) + "...");
if (angle !== 0) {
offset = -0.5 * textBox.width * Math.cos(angle * Math.PI / 180.0);
if (this.options.xLabelAngle !== 0) {
offset = -0.5 * textBox.width * Math.cos(this.options.xLabelAngle * Math.PI / 180.0);
label.transform("t" + offset + ",0...");
}
if (!this.options.horizontal) {
startPos = labelBox.x;
size = labelBox.width;
maxSize = this.el.width();
} else {
startPos = labelBox.y;
size = labelBox.height;
maxSize = this.el.height();
}
if (((prevLabelMargin == null) || prevLabelMargin >= startPos + size || (prevAngleMargin != null) && prevAngleMargin >= startPos) && startPos >= 0 && (startPos + size) < maxSize) {
if (angle !== 0) {
margin = 1.25 * this.options.gridTextSize / Math.sin(angle * Math.PI / 180.0);
prevAngleMargin = startPos - margin;
}
if (!this.options.horizontal) {
_results.push(prevLabelMargin = startPos - this.options.xLabelMargin);
} else {
_results.push(prevLabelMargin = startPos);
if (((prevLabelMargin == null) || prevLabelMargin >= labelBox.x + labelBox.width || (prevAngleMargin != null) && prevAngleMargin >= labelBox.x) && labelBox.x >= 0 && (labelBox.x + labelBox.width) < this.el.width()) {
if (this.options.xLabelAngle !== 0) {
margin = 1.25 * this.options.gridTextSize / Math.sin(this.options.xLabelAngle * Math.PI / 180.0);
prevAngleMargin = labelBox.x - margin;
}
_results.push(prevLabelMargin = labelBox.x - this.options.xLabelMargin);
} else {
_results.push(label.remove());
}
@@ -1663,23 +1483,10 @@ Licensed under the BSD-2-Clause License.
return _results;
};
Bar.prototype.getXAxisLabelY = function() {
return this.bottom + (this.options.xAxisLabelTopPadding || this.options.padding / 2);
};
Bar.prototype.drawSeries = function() {
var barWidth, bottom, groupWidth, i, idx, lastTop, left, leftPadding, numBars, row, sidx, size, spaceLeft, top, ypos, zeroPos, _i, _ref;
groupWidth = this.xSize / this.options.data.length;
if (this.options.stacked) {
numBars = 1;
} else {
numBars = 0;
for (i = _i = 0, _ref = this.options.ykeys.length - 1; 0 <= _ref ? _i <= _ref : _i >= _ref; i = 0 <= _ref ? ++_i : --_i) {
if (this.hasToShow(i)) {
numBars += 1;
}
}
}
var barWidth, bottom, groupWidth, idx, lastTop, left, leftPadding, numBars, row, sidx, size, spaceLeft, top, ypos, zeroPos;
groupWidth = this.width / this.options.data.length;
numBars = this.options.stacked ? 1 : this.options.ykeys.length;
barWidth = (groupWidth * this.options.barSizeRatio - this.options.barGap * (numBars - 1)) / numBars;
if (this.options.barSize) {
barWidth = Math.min(barWidth, this.options.barSize);
@@ -1688,21 +1495,18 @@ Licensed under the BSD-2-Clause License.
leftPadding = spaceLeft / 2;
zeroPos = this.ymin <= 0 && this.ymax >= 0 ? this.transY(0) : null;
return this.bars = (function() {
var _j, _len, _ref1, _results;
_ref1 = this.data;
var _i, _len, _ref, _results;
_ref = this.data;
_results = [];
for (idx = _j = 0, _len = _ref1.length; _j < _len; idx = ++_j) {
row = _ref1[idx];
for (idx = _i = 0, _len = _ref.length; _i < _len; idx = ++_i) {
row = _ref[idx];
lastTop = 0;
_results.push((function() {
var _k, _len1, _ref2, _results1;
_ref2 = row._y;
var _j, _len1, _ref1, _results1;
_ref1 = row._y;
_results1 = [];
for (sidx = _k = 0, _len1 = _ref2.length; _k < _len1; sidx = ++_k) {
ypos = _ref2[sidx];
if (!this.hasToShow(sidx)) {
continue;
}
for (sidx = _j = 0, _len1 = _ref1.length; _j < _len1; sidx = ++_j) {
ypos = _ref1[sidx];
if (ypos !== null) {
if (zeroPos) {
top = Math.min(ypos, zeroPos);
@@ -1711,28 +1515,19 @@ Licensed under the BSD-2-Clause License.
top = ypos;
bottom = this.bottom;
}
left = this.xStart + idx * groupWidth + leftPadding;
left = this.left + idx * groupWidth + leftPadding;
if (!this.options.stacked) {
left += sidx * (barWidth + this.options.barGap);
}
size = bottom - top;
if (this.options.verticalGridCondition && this.options.verticalGridCondition(row.x)) {
if (!this.options.horizontal) {
this.drawBar(this.xStart + idx * groupWidth, this.yEnd, groupWidth, this.ySize, this.options.verticalGridColor, this.options.verticalGridOpacity, this.options.barRadius);
} else {
this.drawBar(this.yStart, this.xStart + idx * groupWidth, this.ySize, groupWidth, this.options.verticalGridColor, this.options.verticalGridOpacity, this.options.barRadius);
}
this.drawBar(this.left + idx * groupWidth, this.top, groupWidth, Math.abs(this.top - this.bottom), this.options.verticalGridColor, this.options.verticalGridOpacity, this.options.barRadius);
}
if (this.options.stacked) {
top -= lastTop;
}
if (!this.options.horizontal) {
this.drawBar(left, top, barWidth, size, this.colorFor(row, sidx, 'bar'), this.options.barOpacity, this.options.barRadius);
_results1.push(lastTop += size);
} else {
this.drawBar(top, left, size, barWidth, this.colorFor(row, sidx, 'bar'), this.options.barOpacity, this.options.barRadius);
_results1.push(lastTop -= size);
}
this.drawBar(left, top, barWidth, size, this.colorFor(row, sidx, 'bar'), this.options.barOpacity, this.options.barRadius);
_results1.push(lastTop += size);
} else {
_results1.push(null);
}
@@ -1763,29 +1558,23 @@ Licensed under the BSD-2-Clause License.
}
};
Bar.prototype.hitTest = function(x, y) {
var pos;
Bar.prototype.hitTest = function(x) {
if (this.data.length === 0) {
return null;
}
if (!this.options.horizontal) {
pos = x;
} else {
pos = y;
}
pos = Math.max(Math.min(pos, this.xEnd), this.xStart);
return Math.min(this.data.length - 1, Math.floor((pos - this.xStart) / (this.xSize / this.data.length)));
x = Math.max(Math.min(x, this.right), this.left);
return Math.min(this.data.length - 1, Math.floor((x - this.left) / (this.width / this.data.length)));
};
Bar.prototype.onGridClick = function(x, y) {
var index;
index = this.hitTest(x, y);
index = this.hitTest(x);
return this.fire('click', index, this.data[index].src, x, y);
};
Bar.prototype.onHoverMove = function(x, y) {
var index, _ref;
index = this.hitTest(x, y);
index = this.hitTest(x);
return (_ref = this.hover).update.apply(_ref, this.hoverContentForRow(index));
};
@@ -1798,27 +1587,17 @@ Licensed under the BSD-2-Clause License.
Bar.prototype.hoverContentForRow = function(index) {
var content, j, row, x, y, _i, _len, _ref;
row = this.data[index];
content = $("<div class='morris-hover-row-label'>").text(row.label);
content = content.prop('outerHTML');
content = "<div class='morris-hover-row-label'>" + row.label + "</div>";
_ref = row.y;
for (j = _i = 0, _len = _ref.length; _i < _len; j = ++_i) {
y = _ref[j];
if (this.options.labels[j] === false) {
continue;
}
content += "<div class='morris-hover-point' style='color: " + (this.colorFor(row, j, 'label')) + "'>\n " + this.options.labels[j] + ":\n " + (this.yLabelFormat(y, j)) + "\n</div>";
content += "<div class='morris-hover-point' style='color: " + (this.colorFor(row, j, 'label')) + "'>\n " + this.options.labels[j] + ":\n " + (this.yLabelFormat(y)) + "\n</div>";
}
if (typeof this.options.hoverCallback === 'function') {
content = this.options.hoverCallback(index, this.options, content, row.src);
}
if (!this.options.horizontal) {
x = this.left + (index + 0.5) * this.width / this.data.length;
return [content, x];
} else {
x = this.left + 0.5 * this.width;
y = this.top + (index + 0.5) * this.height / this.data.length;
return [content, x, y, true];
}
x = this.left + (index + 0.5) * this.width / this.data.length;
return [content, x];
};
Bar.prototype.drawXAxisLabel = function(xPos, yPos, text) {

View File

@@ -1,6 +1,6 @@
/* Preload images */
body:after {
content: url(static('lightbox/images/close.png')) url(static('lightbox/images/loading.gif')) url(static('lightbox/images/prev.png')) url(static('lightbox/images/next.png'));
content: url(../images/close.png) url(../images/loading.gif) url(../images/prev.png) url(../images/next.png);
display: none;
}
@@ -79,7 +79,7 @@ body:after {
width: 32px;
height: 32px;
margin: 0 auto;
background: url(static('lightbox/images/loading.gif')) no-repeat;
background: url(../images/loading.gif) no-repeat;
}
.lb-nav {
@@ -110,7 +110,7 @@ body:after {
width: 34%;
left: 0;
float: left;
background: url(static('lightbox/images/prev.png')) left 48% no-repeat;
background: url(../images/prev.png) left 48% no-repeat;
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=0);
opacity: 0;
-webkit-transition: opacity 0.6s;
@@ -128,7 +128,7 @@ body:after {
width: 64%;
right: 0;
float: right;
background: url(static('lightbox/images/next.png')) right 48% no-repeat;
background: url(../images/next.png) right 48% no-repeat;
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=0);
opacity: 0;
-webkit-transition: opacity 0.6s;
@@ -192,7 +192,7 @@ body:after {
float: right;
width: 30px;
height: 30px;
background: url(static('lightbox/images/close.png')) top right no-repeat;
background: url(../images/close.png) top right no-repeat;
text-align: right;
outline: none;
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=70);

View File

@@ -29,11 +29,6 @@ nav.navbar {
display: inline;
}
#side-menu img.fa-img {
height: auto;
width: 1.28571em;
}
nav.navbar .danger, nav.navbar .danger:hover, nav.navbar .danger:active {
background: $brand-danger !important;
}

View File

@@ -12,7 +12,7 @@ function typocheck() {
$sources.each(function () {
$.each($(this).val().toLowerCase().replace('-', '').split(' '), function (i, w) {
if (w && w.length > 5) {
if (w) {
words.push(w);
}
});

View File

@@ -1,4 +1,4 @@
django-debug-toolbar==1.8
django-debug-toolbar==1.5
sqlparse==0.2.1 # pinned due to difficulties with django-debug-toolbar
# Testing requirements
pep8==1.5.7 # exact requirement by flake8 2.4.0

View File

@@ -1,19 +1,19 @@
# Functional requirements
Django>=1.11.*
Django>=1.10.7,<1.11
python-dateutil
pytz
django-bootstrap3==8.2.*
django-bootstrap3==8.0.*
django-formset-js-improved==0.5.0.1
django-compressor==2.1.1
django-compressor==2.1
django-hierarkey==1.0.*
reportlab==3.2.*
PyPDF2==1.26.*
easy-thumbnails==2.4.*
easy-thumbnails==2.*
django-libsass
libsass
django-otp==0.3.*
python-u2flib-server==4.*
django-formtools==2.0
django-formtools==1.0
celery==4.0.2
kombu==4.0.2
django-statici18n==1.3.*
@@ -28,15 +28,14 @@ django-markup
markdown
bleach==2.*
raven
django-i18nfield>=1.0.1
django-i18nfield
# Stripe
stripe==1.22.*
# PayPal
paypalrestsdk==1.12.*
pycparser==2.13 # https://github.com/eliben/pycparser/issues/147
# Banktransfer
chardet<3.1.0,>=3.0.2
chardet>=2.3,<3
mt-940==3.2
vobject==0.9.*
pycountry
defusedcsv>=1.0.1

View File

@@ -1,2 +1,2 @@
django-redis==4.8.*
django-redis==4.1.*
redis==2.10.5

View File

@@ -62,21 +62,21 @@ setup(
keywords='tickets web shop ecommerce',
install_requires=[
'Django==1.11.*',
'Django==1.10.*',
'python-dateutil==2.4.*',
'pytz',
'django-bootstrap3==8.2.*',
'django-bootstrap3==7.1.*',
'django-formset-js-improved==0.5.0.1',
'django-compressor==2.1',
'django-hierarkey==1.0.*',
'reportlab==3.2.*',
'easy-thumbnails==2.4.*',
'easy-thumbnails==2.*',
'PyPDF2==1.26.*',
'django-libsass',
'libsass',
'django-otp==0.3.*',
'python-u2flib-server==4.*',
'django-formtools==2.0',
'django-formtools==1.0',
'celery==4.0.2',
'kombu==4.0.2',
'django-statici18n==1.3.*',
@@ -93,19 +93,18 @@ setup(
'raven',
'paypalrestsdk==1.12.*',
'pycparser==2.13',
'django-redis==4.7.*',
'django-redis==4.1.*',
'redis==2.10.5',
'stripe==1.22.*',
'chardet<3.1.0,>=3.0.2',
'mt-940==4.7',
'django-i18nfield>=1.0.1',
'chardet>=2.3,<3',
'mt-940==3.2',
'django-i18nfield',
'vobject==0.9.*',
'pycountry',
'defusedcsv'
'pycountry'
],
extras_require={
'dev': [
'django-debug-toolbar==1.7',
'django-debug-toolbar==1.5',
'sqlparse==0.2.1',
'pep8==1.5.7',
'pyflakes==1.1.0',

View File

@@ -2,9 +2,10 @@ 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):
# Inspired by /django/test/testcases.py
# but copied over to work without the unit test module
def __init__(self, num, connection):
self.num = num
super(_AssertNumQueriesContext, self).__init__(connection)

View File

@@ -92,6 +92,7 @@ class I18nFieldTest(TestCase):
"""
This test case tests the I18n*Field classes
"""
@classmethod
def setUpTestData(cls):
o = Organizer.objects.create(name='Dummy', slug='dummy')
@@ -101,8 +102,8 @@ class I18nFieldTest(TestCase):
)
def test_save_load_cycle_plain_string(self):
obj = ItemCategory.objects.create(event=self.event, name="Hello")
obj = ItemCategory.objects.get(id=obj.id)
obj = ItemCategory.all.create(event=self.event, name="Hello")
obj = ItemCategory.all.get(id=obj.id)
self.assertIsInstance(obj.name, LazyI18nString)
translation.activate('en')
self.assertEqual(str(obj.name), "Hello")
@@ -110,14 +111,14 @@ class I18nFieldTest(TestCase):
self.assertEqual(str(obj.name), "Hello")
def test_save_load_cycle_i18n_string(self):
obj = ItemCategory.objects.create(event=self.event,
name=LazyI18nString(
{
'de': 'Hallo',
'en': 'Hello'
}
))
obj = ItemCategory.objects.get(id=obj.id)
obj = ItemCategory.all.create(event=self.event,
name=LazyI18nString(
{
'de': 'Hallo',
'en': 'Hello'
}
))
obj = ItemCategory.all.get(id=obj.id)
self.assertIsInstance(obj.name, LazyI18nString)
translation.activate('en')
self.assertEqual(str(obj.name), "Hello")

View File

@@ -687,8 +687,8 @@ class ItemCategoryTest(TestCase):
)
def test_sorting(self):
c1 = ItemCategory.objects.create(event=self.event)
c2 = ItemCategory.objects.create(event=self.event)
c1 = ItemCategory.all.create(event=self.event)
c2 = ItemCategory.all.create(event=self.event)
assert c1 < c2
c1.position = 2
c2.position = 1

View File

@@ -210,12 +210,12 @@ def checkin_list_env():
('code', ['A1Ticket', 'A1Mascot', 'A2Ticket', 'A3Ticket']),
('-email', ['A3Ticket', 'A2Ticket', 'A1Ticket', 'A1Mascot']),
('email', ['A1Ticket', 'A1Mascot', 'A2Ticket', 'A3Ticket']),
('-status', ['A3Ticket', 'A1Ticket', 'A1Mascot', 'A2Ticket']),
('status', ['A1Mascot', 'A2Ticket', 'A1Ticket', 'A3Ticket']),
('-timestamp', ['A1Ticket', 'A3Ticket', 'A1Mascot', 'A2Ticket']), # A1 checkin date > A3 checkin date
('timestamp', ['A1Mascot', 'A2Ticket', 'A3Ticket', 'A1Ticket']),
('-name', ['A3Ticket', 'A2Ticket', 'A1Ticket', 'A1Mascot']),
('name', ['A1Mascot', 'A1Ticket', 'A2Ticket', 'A3Ticket']), # mascot doesn't include attendee name
# ('-status', ['A3Ticket', 'A1Ticket', 'A1Mascot', 'A2Ticket']),
# ('status', ['A1Mascot', 'A2Ticket', 'A1Ticket', 'A3Ticket']),
# ('-timestamp', ['A1Ticket', 'A3Ticket', 'A1Mascot', 'A2Ticket']), # A1 checkin date > A3 checkin date
# ('timestamp', ['A1Mascot', 'A2Ticket', 'A3Ticket', 'A1Ticket']),
# ('-name', ['A3Ticket', 'A2Ticket', 'A1Ticket', 'A1Mascot']),
# ('name', ['A1Mascot', 'A1Ticket', 'A2Ticket', 'A3Ticket']), # mascot doesn't include attendee name
('-item', ['A1Ticket', 'A2Ticket', 'A3Ticket', 'A1Mascot']),
('item', ['A1Mascot', 'A1Ticket', 'A2Ticket', 'A3Ticket']),
])
@@ -259,7 +259,8 @@ def test_checkins_item_filter(client, checkin_list_env):
@pytest.mark.parametrize("query, expected", [
('status=&item=&user=&ordering=', ['A1Ticket', 'A1Mascot', 'A2Ticket', 'A3Ticket']),
('status=1&item=&user=&ordering=timestamp', ['A3Ticket', 'A1Ticket']),
('status=0&item=&user=&ordering=-name', ['A2Ticket', 'A1Mascot']),
# ('status=0&item=&user=&ordering=-name', ['A2Ticket', 'A1Mascot']),
# ('status=&item=Ticket&user=&ordering=checkins__datetime', ['A2Ticket', 'A3Ticket', 'A1Ticket']),
])
def test_checkins_list_mixed(client, checkin_list_env, query, expected):
client.login(email='dummy@dummy.dummy', password='dummy')
@@ -288,8 +289,8 @@ def checkin_list_with_addon_env():
team.limit_events.add(event)
# item
cat_adm = ItemCategory.objects.create(event=event, name="Admission")
cat_workshop = ItemCategory.objects.create(event=event, name="Admission", is_addon=True)
cat_adm = ItemCategory.all.create(event=event, name="Admission")
cat_workshop = ItemCategory.all.create(event=event, name="Admission", is_addon=True)
item_ticket = Item.objects.create(event=event, name="Ticket", default_price=23, admission=True, category=cat_adm)
item_workshop = Item.objects.create(event=event, name="Workshop", default_price=10, admission=False,
category=cat_workshop)

View File

@@ -68,7 +68,7 @@ class EventsTest(SoupTest):
assert len(doc.select(".alert-success")) > 0
# date_to should not be changed even though the timezone is changed
assert doc.select("[name=date_to]")[0]['value'] == "2013-12-30 17:00:00"
assert 'selected' in doc.find('option', {"value": "Asia/Tokyo"}).attrs
assert doc.find('option', {"value": "Asia/Tokyo"})['selected'] == "selected"
assert doc.select("[name=settings-max_items_per_order]")[0]['value'] == "12"
self.event1.refresh_from_db()

View File

@@ -37,7 +37,7 @@ class CategoriesTest(ItemFormTest):
self.assertIn("Entry tickets", doc.select("#page-wrapper table")[0].text)
def test_update(self):
c = ItemCategory.objects.create(event=self.event1, name="Entry tickets")
c = ItemCategory.all.create(event=self.event1, name="Entry tickets")
doc = self.get_doc('/control/event/%s/%s/categories/%s/' % (self.orga1.slug, self.event1.slug, c.id))
form_data = extract_form_fields(doc.select('.container-fluid form')[0])
form_data['name_0'] = 'T-Shirts'
@@ -46,11 +46,11 @@ class CategoriesTest(ItemFormTest):
assert doc.select(".alert-success")
self.assertIn("T-Shirts", doc.select("#page-wrapper table")[0].text)
self.assertNotIn("Entry tickets", doc.select("#page-wrapper table")[0].text)
assert str(ItemCategory.objects.get(id=c.id).name) == 'T-Shirts'
assert str(ItemCategory.all.get(id=c.id).name) == 'T-Shirts'
def test_sort(self):
c1 = ItemCategory.objects.create(event=self.event1, name="Entry tickets", position=0)
ItemCategory.objects.create(event=self.event1, name="T-Shirts", position=1)
c1 = ItemCategory.all.create(event=self.event1, name="Entry tickets", position=0)
ItemCategory.all.create(event=self.event1, name="T-Shirts", position=1)
doc = self.get_doc('/control/event/%s/%s/categories/' % (self.orga1.slug, self.event1.slug))
self.assertIn("Entry tickets", doc.select("table > tbody > tr")[0].text)
self.assertIn("T-Shirts", doc.select("table > tbody > tr")[1].text)
@@ -66,14 +66,14 @@ class CategoriesTest(ItemFormTest):
self.assertIn("T-Shirts", doc.select("table > tbody > tr")[1].text)
def test_delete(self):
c = ItemCategory.objects.create(event=self.event1, name="Entry tickets")
c = ItemCategory.all.create(event=self.event1, name="Entry tickets")
doc = self.get_doc('/control/event/%s/%s/categories/%s/delete' % (self.orga1.slug, self.event1.slug, c.id))
form_data = extract_form_fields(doc.select('.container-fluid form')[0])
doc = self.post_doc('/control/event/%s/%s/categories/%s/delete' % (self.orga1.slug, self.event1.slug, c.id),
form_data)
assert doc.select(".alert-success")
self.assertNotIn("Entry tickets", doc.select("#page-wrapper")[0].text)
assert not ItemCategory.objects.filter(id=c.id).exists()
assert not ItemCategory.all.filter(id=c.id).exists()
class QuestionsTest(ItemFormTest):
@@ -264,7 +264,7 @@ class ItemsTest(ItemFormTest):
require_voucher=True, allow_cancel=False)
self.var1 = ItemVariation.objects.create(item=self.item2, value="Silver")
self.var2 = ItemVariation.objects.create(item=self.item2, value="Gold")
self.addoncat = ItemCategory.objects.create(event=self.event1, name="Item category")
self.addoncat = ItemCategory.all.create(event=self.event1, name="Item category")
def test_move(self):
self.client.post('/control/event/%s/%s/items/%s/down' % (self.orga1.slug, self.event1.slug, self.item1.id),)

View File

@@ -141,7 +141,7 @@ class MailSettingPreviewTest(SoupTest):
assert res['msgs']['en'] == self.locale_event.name['en']
def test_mail_text_order_placed(self):
text = '{event}{total}{currency}{date}{payment_info}{url}{invoice_name}{invoice_company}'
text = '{event}{total}{currency}{date}{paymentinfo}{url}{invoice_name}{invoice_company}'
response = self.client.post(self.target.format(
self.orga1.slug, self.event1.slug), {
'item': 'mail_text_order_placed',

View File

@@ -26,7 +26,7 @@ def item(event):
@pytest.fixture
def item_category(event):
return ItemCategory.objects.create(event=event)
return ItemCategory.all.create(event=event)
@pytest.fixture

View File

@@ -15,7 +15,7 @@ class CsvImportTest(TestCase):
with open(os.path.join(DATA_DIR, filename), 'rb') as f:
data = csvimport.get_rows_from_file(f)
self.assertEqual(data, expected)
parsed, good = csvimport.parse(data, hint)
parsed = csvimport.parse(data, hint)
self.assertEqual(parsed, expected_parsed)
def test_sample_file_bbbank(self):
@@ -125,7 +125,7 @@ class CsvImportTest(TestCase):
def test_sample_file_postbank(self):
expected = [
['Buchungstag', 'Wertstellung', 'Umsatzart', 'Buchungsdetails', 'Auftraggeber', 'Empfänger',
'Betrag ()', 'Saldo ()'],
'Betrag (\x80)', 'Saldo (\x80)'],
['07.08.2016', '01.08.2016', 'Gutschrift', 'Verwendungszweck 2015ABCDE', 'Karla Kundin',
'Fiktive Veranstaltungsgesellschaft mbH', '\xA4 42,00', '\xA4 1.337,42'],
['29.07.2016', '29.07.2016', 'Gutschrift', 'Referenz NOTPROVIDED', 'Lars Lieferant',

View File

@@ -18,7 +18,7 @@ def env(client):
plugins='pretix.plugins.paypal',
live=True
)
category = ItemCategory.objects.create(event=event, name="Everything", position=0)
category = ItemCategory.all.create(event=event, name="Everything", position=0)
quota_tickets = Quota.objects.create(event=event, name='Tickets', size=5)
ticket = Item.objects.create(event=event, name='Early-bird ticket',
category=category, default_price=23, admission=True)

View File

@@ -27,7 +27,7 @@ def env(client):
plugins='pretix.plugins.stripe',
live=True
)
category = ItemCategory.objects.create(event=event, name="Everything", position=0)
category = ItemCategory.all.create(event=event, name="Everything", position=0)
quota_tickets = Quota.objects.create(event=event, name='Tickets', size=5)
ticket = Item.objects.create(event=event, name='Early-bird ticket',
category=category, default_price=23, admission=True)

View File

@@ -30,7 +30,7 @@ def item(event):
@pytest.fixture
def item_category(event):
"""Returns an item category instance"""
return ItemCategory.objects.create(event=event)
return ItemCategory.all.create(event=event)
@pytest.fixture

View File

@@ -24,7 +24,7 @@ class CartTestMixin:
date_from=datetime.datetime(2013, 12, 26, tzinfo=datetime.timezone.utc),
live=True
)
self.category = ItemCategory.objects.create(event=self.event, name="Everything", position=0)
self.category = ItemCategory.all.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)
self.quota_shirts.items.add(self.shirt)
@@ -1013,7 +1013,7 @@ class CartTest(CartTestMixin, TestCase):
class CartAddonTest(CartTestMixin, TestCase):
def setUp(self):
super().setUp()
self.workshopcat = ItemCategory.objects.create(name="Workshops", is_addon=True, event=self.event)
self.workshopcat = ItemCategory.all.create(name="Workshops", is_addon=True, event=self.event)
self.workshopquota = Quota.objects.create(event=self.event, name='Workshop 1', size=5)
self.workshop1 = Item.objects.create(event=self.event, name='Workshop 1',
category=self.workshopcat, default_price=12)

View File

@@ -24,7 +24,7 @@ class CheckoutTestCase(TestCase):
plugins='pretix.plugins.stripe,pretix.plugins.banktransfer',
live=True
)
self.category = ItemCategory.objects.create(event=self.event, name="Everything", position=0)
self.category = ItemCategory.all.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)
@@ -36,7 +36,7 @@ class CheckoutTestCase(TestCase):
self.session_key = self.client.cookies.get(settings.SESSION_COOKIE_NAME).value
self._set_session('email', 'admin@localhost')
self.workshopcat = ItemCategory.objects.create(name="Workshops", is_addon=True, event=self.event)
self.workshopcat = ItemCategory.all.create(name="Workshops", is_addon=True, event=self.event)
self.workshopquota = Quota.objects.create(event=self.event, name='Workshop 1', size=5)
self.workshop1 = Item.objects.create(event=self.event, name='Workshop 1',
category=self.workshopcat, default_price=12)

View File

@@ -66,18 +66,6 @@ class EventMiddlewareTest(EventTestMixin, SoupTest):
class ItemDisplayTest(EventTestMixin, SoupTest):
def test_link_rewrite(self):
q = Quota.objects.create(event=self.event, name='Quota', size=2)
item = Item.objects.create(event=self.event, name='Early-bird ticket', default_price=0, active=True,
description="http://example.org [Sample](http://example.net)")
q.items.add(item)
html = self.client.get('/%s/%s/' % (self.orga.slug, self.event.slug)).rendered_content
self.assertNotIn('href="http://example.org', html)
self.assertNotIn('href="http://example.net', html)
self.assertIn('href="/redirect/?url=http%3A//example.org%3A', html)
self.assertIn('href="/redirect/?url=http%3A//example.net%3A', html)
def test_not_active(self):
q = Quota.objects.create(event=self.event, name='Quota', size=2)
item = Item.objects.create(event=self.event, name='Early-bird ticket', default_price=0, active=False)
@@ -128,7 +116,7 @@ class ItemDisplayTest(EventTestMixin, SoupTest):
self.assertNotIn("Early-bird", html)
def test_simple_with_category(self):
c = ItemCategory.objects.create(event=self.event, name="Entry tickets", position=0)
c = ItemCategory.all.create(event=self.event, name="Entry tickets", position=0)
q = Quota.objects.create(event=self.event, name='Quota', size=2)
item = Item.objects.create(event=self.event, name='Early-bird ticket', category=c, default_price=0)
q.items.add(item)
@@ -137,13 +125,13 @@ class ItemDisplayTest(EventTestMixin, SoupTest):
self.assertIn("Early-bird", doc.select("section:nth-of-type(1) div:nth-of-type(1)")[0].text)
def test_simple_without_quota(self):
c = ItemCategory.objects.create(event=self.event, name="Entry tickets", position=0)
c = ItemCategory.all.create(event=self.event, name="Entry tickets", position=0)
Item.objects.create(event=self.event, name='Early-bird ticket', category=c, default_price=0)
resp = self.client.get('/%s/%s/' % (self.orga.slug, self.event.slug))
self.assertNotIn("Early-bird", resp.rendered_content)
def test_no_variations_in_quota(self):
c = ItemCategory.objects.create(event=self.event, name="Entry tickets", position=0)
c = ItemCategory.all.create(event=self.event, name="Entry tickets", position=0)
q = Quota.objects.create(event=self.event, name='Quota', size=2)
item = Item.objects.create(event=self.event, name='Early-bird ticket', category=c, default_price=0)
ItemVariation.objects.create(item=item, value='Blue')
@@ -152,7 +140,7 @@ class ItemDisplayTest(EventTestMixin, SoupTest):
self.assertNotIn("Early-bird", resp.rendered_content)
def test_one_variation_in_quota(self):
c = ItemCategory.objects.create(event=self.event, name="Entry tickets", position=0)
c = ItemCategory.all.create(event=self.event, name="Entry tickets", position=0)
q = Quota.objects.create(event=self.event, name='Quota', size=2)
item = Item.objects.create(event=self.event, name='Early-bird ticket', category=c, default_price=0)
var1 = ItemVariation.objects.create(item=item, value='Red')
@@ -162,7 +150,7 @@ class ItemDisplayTest(EventTestMixin, SoupTest):
self._assert_variation_found()
def test_one_variation_in_unlimited_quota(self):
c = ItemCategory.objects.create(event=self.event, name="Entry tickets", position=0)
c = ItemCategory.all.create(event=self.event, name="Entry tickets", position=0)
q = Quota.objects.create(event=self.event, name='Quota', size=None)
item = Item.objects.create(event=self.event, name='Early-bird ticket', category=c, default_price=0)
var1 = ItemVariation.objects.create(item=item, value='Red')
@@ -178,7 +166,7 @@ class ItemDisplayTest(EventTestMixin, SoupTest):
self.assertNotIn("Black", doc.select("section:nth-of-type(1)")[0].text)
def test_variation_prices_in_quota(self):
c = ItemCategory.objects.create(event=self.event, name="Entry tickets", position=0)
c = ItemCategory.all.create(event=self.event, name="Entry tickets", position=0)
q = Quota.objects.create(event=self.event, name='Quota', size=2)
item = Item.objects.create(event=self.event, name='Early-bird ticket', category=c, default_price=12)
var1 = ItemVariation.objects.create(item=item, value='Red', default_price=14, position=1)

View File

@@ -25,7 +25,7 @@ class OrdersTest(TestCase):
self.event.settings.set('payment_banktransfer__enabled', True)
self.event.settings.set('ticketoutput_testdummy__enabled', True)
self.category = ItemCategory.objects.create(event=self.event, name="Everything", position=0)
self.category = ItemCategory.all.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)
self.quota_shirts.items.add(self.shirt)