New pretixdroid configuration system

This commit is contained in:
Raphael Michel
2017-08-29 23:10:59 +02:00
parent 43b5140754
commit 631cded0d6
13 changed files with 658 additions and 190 deletions

View File

@@ -4,8 +4,8 @@ msgid ""
msgstr ""
"Project-Id-Version: 1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-08-27 07:30+0000\n"
"PO-Revision-Date: 2017-08-27 09:33+0200\n"
"POT-Creation-Date: 2017-08-29 21:12+0000\n"
"PO-Revision-Date: 2017-08-29 23:16+0200\n"
"Last-Translator: Raphael Michel <michel@rami.io>\n"
"Language-Team: Raphael Michel <michel@rami.io>\n"
"Language: de\n"
@@ -13,7 +13,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 2.0.3\n"
"X-Generator: Poedit 2.0.2\n"
"X-Poedit-Bookmarks: -1,-1,904,-1,-1,-1,-1,-1,-1,-1\n"
#: pretix/base/exporters/answers.py:18
@@ -1034,6 +1034,8 @@ msgstr "Antwort"
#: pretix/control/templates/pretixcontrol/waitinglist/index.html:119
#: pretix/plugins/checkinlists/exporters.py:69
#: pretix/plugins/checkinlists/exporters.py:109
#: pretix/plugins/pretixdroid/models.py:15
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:46
#: pretix/plugins/reports/exporters.py:248
msgctxt "subevent"
msgid "Date"
@@ -1227,6 +1229,8 @@ msgstr "Das Produkt \"{item}\" ist nicht mehr verfügbar."
#: pretix/base/models/orders.py:549 pretix/control/views/item.py:436
#: pretix/control/views/vouchers.py:81 pretix/control/views/vouchers.py:82
#: pretix/plugins/checkinlists/exporters.py:124
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:71
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:72
#: pretix/presale/checkoutflow.py:477
msgid "Yes"
msgstr "Ja"
@@ -1236,6 +1240,8 @@ msgstr "Ja"
#: pretix/control/views/vouchers.py:82
#: pretix/plugins/checkinlists/exporters.py:124
#: pretix/plugins/paypal/templates/pretixplugins/paypal/action_refund.html:14
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:71
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:72
#: pretix/plugins/stripe/templates/pretixplugins/stripe/action_refund.html:14
#: pretix/presale/checkoutflow.py:479
msgid "No"
@@ -3769,6 +3775,8 @@ msgstr "Alle Veranstalter"
#: pretix/control/forms/filter.py:195
#: pretix/control/templates/pretixcontrol/organizers/teams.html:39
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:59
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:63
msgid "All"
msgstr "Alle"
@@ -6063,6 +6071,7 @@ msgid "The following products might be no longer available for sale:"
msgstr "Die folgenden Produkte stehen möglicherweise nicht mehr zum Verkauf:"
#: pretix/control/templates/pretixcontrol/items/quota_edit.html:27
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:48
msgid "Items"
msgstr "Produkte"
@@ -8786,6 +8795,43 @@ msgid ""
"This plugin allows you to use the pretixdroid Android app for your event."
msgstr "Dieses Plugin erlaubt, die pretixdroid-Android-App zu verwenden."
#: pretix/plugins/pretixdroid/models.py:11
msgid "Can scan all products"
msgstr "Kann alle Produkte scannen"
#: pretix/plugins/pretixdroid/models.py:12
msgid "Can scan these products"
msgstr "Nur diese Produkte"
#: pretix/plugins/pretixdroid/models.py:13
msgid "pretixdroid 1.6 or newer only"
msgstr "pretixdroid 1.6 oder neuer"
#: pretix/plugins/pretixdroid/models.py:16
msgid "Show information"
msgstr "Informationen anzeigen"
#: pretix/plugins/pretixdroid/models.py:17
msgid ""
"If disabled, the device can not see how many tickets exist and how many are "
"already scanned. pretixdroid 1.6 or newer only."
msgstr ""
"Wenn diese Option deaktiviert ist, kann das Gerät nicht sehen wie viele "
"Tickets existieren und wie viele bereits gescannt wurden (ab pretixdroid "
"1.6)."
#: pretix/plugins/pretixdroid/models.py:19
msgid "Search allowed"
msgstr "Suche erlaubt"
#: pretix/plugins/pretixdroid/models.py:20
msgid ""
"If disabled, the device can not search for attendees by name. pretixdroid "
"1.6 or newer only."
msgstr ""
"Wenn diese Option deaktiviert ist, kann mit dem Gerät nicht nach Namen "
"gesucht werden (ab pretixdroid 1.6)."
#: pretix/plugins/pretixdroid/signals.py:21
msgid "pretixdroid"
msgstr "pretixdroid"
@@ -8820,6 +8866,8 @@ msgstr ""
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:5
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:7
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration_code.html:5
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration_code.html:8
msgid "pretixdroid configuration"
msgstr "pretixdroid-Konfiguration"
@@ -8832,45 +8880,76 @@ msgstr ""
"die Tickets scannen und überprüfen können."
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:11
msgid "App download"
msgstr "App-Download"
msgid "Create app configuration"
msgstr "App-Konfiguration erstellen"
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:15
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:13
msgid ""
"To start scanning tickets with our Android app, first create a configuration "
"code here:"
msgstr ""
"Um mit unserer Android-App Tickets zu scannen, erstellen Sie hier erst einen "
"Konfigurations-Code:"
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:30
msgid "Create"
msgstr "Erstellen"
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:38
msgid "Existing app configurations"
msgstr "Bestehende App-Konfigurationen"
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:44
msgid "ID"
msgstr "ID"
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:49
msgid "Show info"
msgstr "Infos anzeigen"
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:50
msgid "Allow search"
msgstr "Sucher erlauben"
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:75
msgid "Show QR code"
msgstr "QR-Code anzeigen"
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration_code.html:10
msgid "Back to overview"
msgstr "Zurück zur Übersicht"
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration_code.html:13
msgid "1. Download app"
msgstr "1. App herunterladen"
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration_code.html:17
msgid "Download the app from the Google Play Store"
msgstr "Laden Sie die App aus dem Play Store herunter"
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:20
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration_code.html:22
msgid ""
"Android, Google Play and the Google Play logo are trademarks of Google Inc."
msgstr ""
"Android, Google Play und das Google Play-Logo sind eingetragene Marken von "
"Google Inc."
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:25
msgid "App configuration"
msgstr "App-Konfiguration"
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration_code.html:27
msgid "2. Scan code"
msgstr "2. Code scannen"
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:27
msgid ""
"If you start the app for the first time, it will request that you scan the "
"following code. The code tells the app all it needs about your event."
msgstr ""
"Wenn Sie die App das erste Mal starten wird sie darum bitten, den folgenden "
"Code einzuscannen. Der Code enthält alle nötigen Informationen über die "
"Veranstaltung."
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration_code.html:33
msgid "3. Start scanning tickets"
msgstr "3. Los geht's Tickets scannen"
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:37
msgctxt "subevent"
msgid "Choose date"
msgstr "Termin wählen"
#: pretix/plugins/pretixdroid/views.py:42
#: pretix/plugins/pretixdroid/views.py:102
msgid "The selected configuration does not exist."
msgstr "Die ausgewählte Konfiguration existiert nicht."
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:46
msgid "Show configuration"
msgstr "Konfiguration anzeigen"
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:52
msgid "Reset authentication token"
msgstr "Authentifizierungstoken zurücksetzen"
#: pretix/plugins/pretixdroid/views.py:100
msgid "The selected configuration has been deleted."
msgstr "Die ausgewählte Konfiguration wurde gelöscht."
#: pretix/plugins/reports/__init__.py:10 pretix/plugins/reports/__init__.py:13
msgid "Report exporter"
@@ -10670,6 +10749,24 @@ msgstr "Deutsch"
msgid "German (informal)"
msgstr "Deutsch (Du)"
#~ msgid "App download"
#~ msgstr "App-Download"
#~ msgid ""
#~ "If you start the app for the first time, it will request that you scan "
#~ "the following code. The code tells the app all it needs about your event."
#~ msgstr ""
#~ "Wenn Sie die App das erste Mal starten wird sie darum bitten, den "
#~ "folgenden Code einzuscannen. Der Code enthält alle nötigen Informationen "
#~ "über die Veranstaltung."
#~ msgctxt "subevent"
#~ msgid "Choose date"
#~ msgstr "Termin wählen"
#~ msgid "Reset authentication token"
#~ msgstr "Authentifizierungstoken zurücksetzen"
#~ msgid "Download calendar as iCal file"
#~ msgstr "Kalender als iCal herunterladen"

View File

@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-08-27 07:31+0000\n"
"POT-Creation-Date: 2017-08-29 21:12+0000\n"
"PO-Revision-Date: 2017-08-27 09:35+0200\n"
"Last-Translator: Raphael Michel <michel@rami.io>\n"
"Language-Team: \n"

View File

@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: 1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-08-27 07:30+0000\n"
"PO-Revision-Date: 2017-08-27 09:35+0200\n"
"POT-Creation-Date: 2017-08-29 21:12+0000\n"
"PO-Revision-Date: 2017-08-29 23:17+0200\n"
"Last-Translator: Raphael Michel <michel@rami.io>\n"
"Language-Team: Raphael Michel <michel@rami.io>\n"
"Language: de\n"
@@ -16,7 +16,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 2.0.3\n"
"X-Generator: Poedit 2.0.2\n"
#: pretix/base/exporters/answers.py:18
msgid "Answers to file upload questions"
@@ -1036,6 +1036,8 @@ msgstr "Antwort"
#: pretix/control/templates/pretixcontrol/waitinglist/index.html:119
#: pretix/plugins/checkinlists/exporters.py:69
#: pretix/plugins/checkinlists/exporters.py:109
#: pretix/plugins/pretixdroid/models.py:15
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:46
#: pretix/plugins/reports/exporters.py:248
msgctxt "subevent"
msgid "Date"
@@ -1229,6 +1231,8 @@ msgstr "Das Produkt \"{item}\" ist nicht mehr verfügbar."
#: pretix/base/models/orders.py:549 pretix/control/views/item.py:436
#: pretix/control/views/vouchers.py:81 pretix/control/views/vouchers.py:82
#: pretix/plugins/checkinlists/exporters.py:124
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:71
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:72
#: pretix/presale/checkoutflow.py:477
msgid "Yes"
msgstr "Ja"
@@ -1238,6 +1242,8 @@ msgstr "Ja"
#: pretix/control/views/vouchers.py:82
#: pretix/plugins/checkinlists/exporters.py:124
#: pretix/plugins/paypal/templates/pretixplugins/paypal/action_refund.html:14
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:71
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:72
#: pretix/plugins/stripe/templates/pretixplugins/stripe/action_refund.html:14
#: pretix/presale/checkoutflow.py:479
msgid "No"
@@ -3766,6 +3772,8 @@ msgstr "Alle Veranstalter"
#: pretix/control/forms/filter.py:195
#: pretix/control/templates/pretixcontrol/organizers/teams.html:39
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:59
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:63
msgid "All"
msgstr "Alle"
@@ -6051,6 +6059,7 @@ msgid "The following products might be no longer available for sale:"
msgstr "Die folgenden Produkte stehen möglicherweise nicht mehr zum Verkauf:"
#: pretix/control/templates/pretixcontrol/items/quota_edit.html:27
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:48
msgid "Items"
msgstr "Produkte"
@@ -8765,6 +8774,45 @@ msgid ""
"This plugin allows you to use the pretixdroid Android app for your event."
msgstr "Dieses Plugin erlaubt, die pretixdroid-Android-App zu verwenden."
#: pretix/plugins/pretixdroid/models.py:11
msgid "Can scan all products"
msgstr "Kann alle Produkte scannen"
#: pretix/plugins/pretixdroid/models.py:12
msgid "Can scan these products"
msgstr "Nur diese Produkte"
#: pretix/plugins/pretixdroid/models.py:13
msgid "pretixdroid 1.6 or newer only"
msgstr "pretixdroid 1.6 oder neuer"
#: pretix/plugins/pretixdroid/models.py:16
#, fuzzy
#| msgid "Show configuration"
msgid "Show information"
msgstr "Informationen anzeigen"
#: pretix/plugins/pretixdroid/models.py:17
msgid ""
"If disabled, the device can not see how many tickets exist and how many are "
"already scanned. pretixdroid 1.6 or newer only."
msgstr ""
"Wenn diese Option deaktiviert ist, kann das Gerät nicht sehen wie viele "
"Tickets existieren und wie viele bereits gescannt wurden (ab pretixdroid "
"1.6)."
#: pretix/plugins/pretixdroid/models.py:19
msgid "Search allowed"
msgstr "Sucher erlaubt"
#: pretix/plugins/pretixdroid/models.py:20
msgid ""
"If disabled, the device can not search for attendees by name. pretixdroid "
"1.6 or newer only."
msgstr ""
"Wenn diese Option deaktiviert ist, kann mit dem Gerät nicht nach Namen "
"gesucht werden (ab pretixdroid 1.6)."
#: pretix/plugins/pretixdroid/signals.py:21
msgid "pretixdroid"
msgstr "pretixdroid"
@@ -8799,6 +8847,8 @@ msgstr ""
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:5
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:7
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration_code.html:5
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration_code.html:8
msgid "pretixdroid configuration"
msgstr "pretixdroid-Konfiguration"
@@ -8811,45 +8861,76 @@ msgstr ""
"die Tickets scannen und überprüfen kannst."
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:11
msgid "App download"
msgstr "App-Download"
msgid "Create app configuration"
msgstr "App-Konfiguration erstellen"
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:15
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:13
msgid ""
"To start scanning tickets with our Android app, first create a configuration "
"code here:"
msgstr ""
"Um mit unserer Android-App Tickets zu scannen, erstelle hier erst einen "
"Konfigurations-Code:"
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:30
msgid "Create"
msgstr "Erstellen"
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:38
msgid "Existing app configurations"
msgstr "Bestehende App-Konfigurationen"
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:44
msgid "ID"
msgstr "ID"
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:49
msgid "Show info"
msgstr "Infos anzeigen"
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:50
msgid "Allow search"
msgstr "Suche erlauben"
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:75
msgid "Show QR code"
msgstr "QR-Code anzeigen"
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration_code.html:10
msgid "Back to overview"
msgstr "Zurück zur Übersicht"
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration_code.html:13
msgid "1. Download app"
msgstr "1. App herunterladen"
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration_code.html:17
msgid "Download the app from the Google Play Store"
msgstr "Lade die App aus dem App Store herunter"
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:20
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration_code.html:22
msgid ""
"Android, Google Play and the Google Play logo are trademarks of Google Inc."
msgstr ""
"Android, Google Play und das Google Play-Logo sind eingetragene Marken von "
"Google Inc."
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:25
msgid "App configuration"
msgstr "App-Konfiguration"
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration_code.html:27
msgid "2. Scan code"
msgstr "2. Code scannen"
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:27
msgid ""
"If you start the app for the first time, it will request that you scan the "
"following code. The code tells the app all it needs about your event."
msgstr ""
"Wenn du die App das erste Mal startest wird sie dich bitten, den folgenden "
"Code einzuscannen. Der Code enthält alle nötigen Informationen über die "
"Veranstaltung."
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration_code.html:33
msgid "3. Start scanning tickets"
msgstr "3. Los geht's Tickets scannen"
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:37
msgctxt "subevent"
msgid "Choose date"
msgstr "Termin wählen"
#: pretix/plugins/pretixdroid/views.py:42
#: pretix/plugins/pretixdroid/views.py:102
msgid "The selected configuration does not exist."
msgstr "Die ausgewählte Konfiguration existiert nicht."
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:46
msgid "Show configuration"
msgstr "Konfiguration anzeigen"
#: pretix/plugins/pretixdroid/templates/pretixplugins/pretixdroid/configuration.html:52
msgid "Reset authentication token"
msgstr "Authentifizierungstoken zurücksetzen"
#: pretix/plugins/pretixdroid/views.py:100
msgid "The selected configuration has been deleted."
msgstr "Die ausgewählte Konfiguration wurde gelöscht."
#: pretix/plugins/reports/__init__.py:10 pretix/plugins/reports/__init__.py:13
msgid "Report exporter"
@@ -10641,6 +10722,24 @@ msgstr "Deutsch"
msgid "German (informal)"
msgstr "Deutsch (Du)"
#~ msgid "App download"
#~ msgstr "App-Download"
#~ msgid ""
#~ "If you start the app for the first time, it will request that you scan "
#~ "the following code. The code tells the app all it needs about your event."
#~ msgstr ""
#~ "Wenn du die App das erste Mal startest wird sie dich bitten, den "
#~ "folgenden Code einzuscannen. Der Code enthält alle nötigen Informationen "
#~ "über die Veranstaltung."
#~ msgctxt "subevent"
#~ msgid "Choose date"
#~ msgstr "Termin wählen"
#~ msgid "Reset authentication token"
#~ msgstr "Authentifizierungstoken zurücksetzen"
#~ msgid "Download calendar as iCal file"
#~ msgstr "Kalender als iCal herunterladen"

View File

@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-08-27 07:31+0000\n"
"POT-Creation-Date: 2017-08-29 21:12+0000\n"
"PO-Revision-Date: 2017-08-27 09:35+0200\n"
"Last-Translator: Raphael Michel <michel@rami.io>\n"
"Language-Team: \n"

View File

@@ -0,0 +1,23 @@
from django import forms
from pretix.plugins.pretixdroid.models import AppConfiguration
class AppConfigurationForm(forms.ModelForm):
class Meta:
model = AppConfiguration
fields = ('all_items', 'items', 'subevent', 'show_info', 'allow_search')
widgets = {
'items': forms.CheckboxSelectMultiple(attrs={
'data-inverse-dependency': '#id_all_items'
}),
}
def __init__(self, **kwargs):
self.event = kwargs.pop('event')
super().__init__(**kwargs)
self.fields['items'].queryset = self.event.items.all()
if self.event.has_subevents:
self.fields['subevent'].queryset = self.event.subevents.all()
else:
del self.fields['subevent']

View File

@@ -0,0 +1,48 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.4 on 2017-08-29 13:08
from __future__ import unicode_literals
import django.db.models.deletion
from django.db import migrations, models
def runfwd(app, schema_editor):
EventSettingsStore = app.get_model('pretixbase', 'Event_SettingsStore')
AppConfiguration = app.get_model('pretixdroid', 'AppConfiguration')
for setting in EventSettingsStore.objects.filter(key='pretixdroid_key'):
AppConfiguration.objects.create(
event=setting.object,
key=setting.value,
all_items=True
)
setting.delete()
class Migration(migrations.Migration):
initial = True
dependencies = [
('pretixbase', '0074_auto_20170825_1258'),
('pretixdroid', '0002_auto_20161208_1644'),
]
operations = [
migrations.CreateModel(
name='AppConfiguration',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('key', models.CharField(db_index=True, max_length=190, unique=True)),
('all_items', models.BooleanField(default=True)),
('allow_search', models.BooleanField(default=True)),
('show_info', models.BooleanField(default=True)),
('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='pretixbase.Event')),
('items', models.ManyToManyField(blank=True, to='pretixbase.Item')),
('subevent', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='pretixbase.SubEvent')),
],
),
migrations.RunPython(
runfwd, migrations.RunPython.noop
)
]

View File

@@ -0,0 +1,27 @@
import string
from django.db import models
from django.utils.crypto import get_random_string
from django.utils.translation import pgettext_lazy, ugettext_lazy as _
class AppConfiguration(models.Model):
event = models.ForeignKey('pretixbase.Event')
key = models.CharField(max_length=190, unique=True, db_index=True)
all_items = models.BooleanField(default=True, verbose_name=_('Can scan all products'))
items = models.ManyToManyField('pretixbase.Item', blank=True, verbose_name=_('Can scan these products'))
subevent = models.ForeignKey('pretixbase.SubEvent', null=True, blank=True,
verbose_name=pgettext_lazy('subevent', 'Date'))
show_info = models.BooleanField(default=True, verbose_name=_('Show information'),
help_text=_('If disabled, the device can not see how many tickets exist and how '
'many are already scanned. pretixdroid 1.6 or newer only.'))
allow_search = models.BooleanField(default=True, verbose_name=_('Search allowed'),
help_text=_('If disabled, the device can not search for attendees by name. '
'pretixdroid 1.6 or newer only.'))
def save(self, **kwargs):
if not self.key:
self.key = get_random_string(
length=32, allowed_chars=string.ascii_uppercase + string.ascii_lowercase + string.digits
)
return super().save(**kwargs)

View File

@@ -8,53 +8,81 @@
<p>{% blocktrans trimmed %}
pretixdroid is an Android app that you can use to control tickets at the entrance of your event.
{% endblocktrans %}</p>
<h2>{% trans "App download" %}</h2>
<p>
<a href="http://play.google.com/store/apps/details?id=eu.pretix.pretixdroid">
<img src="{% static "pretixplugins/pretixdroid/play_store_en.png" %}" alt="
{% trans "Download the app from the Google Play Store" %}" height="70">
</a>
</p>
<p>
<small>
{% blocktrans trimmed %}
Android, Google Play and the Google Play logo are trademarks of Google Inc.
{% endblocktrans %}
</small>
</p>
<h2>{% trans "App configuration" %}</h2>
<h2>{% trans "Create app configuration" %}</h2>
<p>
{% blocktrans trimmed %}
If you start the app for the first time, it will request that you scan the following code.
The code tells the app all it needs about your event.
To start scanning tickets with our Android app, first create a configuration code here:
{% endblocktrans %}
</p>
{% if request.event.has_subevents %}
<form class="form-inline helper-display-inline" action="" method="get">
<p>
{% if request.event.has_subevents %}
<select name="subevent" class="form-control">
<option value="">{% trans "Choose date" context "subevent" %}</option>
{% for se in request.event.subevents.all %}
<option value="{{ se.id }}"
{% if request.GET.subevent|add:0 == se.id %}selected="selected"{% endif %}>
{{ se.name }} {{ se.get_date_range_display }}
</option>
{% endfor %}
</select>
{% endif %}
<button class="btn btn-primary" type="submit">{% trans "Show configuration" %}</button>
</p>
<form action="" method="post" class="form-horizontal">
{% csrf_token %}
{% bootstrap_form_errors add_form %}
{% bootstrap_field add_form.all_items layout="horizontal" %}
{% bootstrap_field add_form.items layout="horizontal" %}
{% bootstrap_field add_form.show_info layout="horizontal" %}
{% bootstrap_field add_form.allow_search layout="horizontal" %}
{% if add_form.subevent %}
{% bootstrap_field add_form.subevent layout="horizontal" %}
{% endif %}
<div class="form-group">
<div class="col-md-offset-3 col-md-9">
<button type="submit" class="btn btn-primary btn-save" name="add" value="1">
{% trans "Create" %}
</button>
</div>
</div>
</form>
{% if configs %}
<h2>{% trans "Existing app configurations" %}</h2>
<form action="" method="post" class="form-horizontal">
{% csrf_token %}
<table class="table">
<thead>
<tr>
<th>{% trans "ID" %}</th>
{% if request.event.has_subevents %}
<th>{% trans "Date" context "subevent" %}</th>
{% endif %}
<th>{% trans "Items" %}</th>
<th>{% trans "Show info" %}</th>
<th>{% trans "Allow search" %}</th>
<th></th>
</tr>
</thead>
<tbody>
{% for ac in configs %}
<tr>
<td>{{ ac.key|slice:"0:8" }}…</td>
{% if request.event.has_subevents %}
<td>{% if ac.subevent %}{{ ac.subevent }}{% else %}{% trans "All" %}{% endif %}</td>
{% endif %}
<td>
{% if ac.all_items %}
{% trans "All" %}
{% else %}
{% for item in ac.items.all %}
<a href="{% url "control:event.item" organizer=request.event.organizer.slug event=request.event.slug item=item.id %}">{{ item.name }}</a>
{% if loop.revindex0 > 0 %}<br>{% endif %}
{% endfor %}
{% endif %}
</td>
<td>{% if ac.show_info %}{% trans "Yes" %}{% else %}{% trans "No" %}{% endif %}</td>
<td>{% if ac.allow_search %}{% trans "Yes" %}{% else %}{% trans "No" %}{% endif %}</td>
<td class="text-right">
<a href="{% url "plugins:pretixdroid:config.code" organizer=request.event.organizer.slug event=request.event.slug config=ac.pk %}" class="btn btn-default">
<span class="fa fa-qrcode"></span> {% trans "Show QR code" %}
</a>
<button class="btn btn-danger" name="delete" value="{{ ac.pk }}">
<span class="fa fa-trash"></span>
</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</form>
{% endif %}
{% if not request.event.has_subevents or subevent %}
<div id="qrcodeCanvas"></div>
<a href="?flush_key=1" class="btn btn-default">{% trans "Reset authentication token" %}</a>
<script type="text/json" id="qrdata">
{{ qrdata|safe }}
</script>
{% endif %}
<script type="text/javascript" src="{% static "pretixplugins/pretixdroid/pretixdroid.js" %}"></script>
{% endblock %}

View File

@@ -0,0 +1,36 @@
{% extends "pretixcontrol/event/base.html" %}
{% load i18n %}
{% load bootstrap3 %}
{% load staticfiles %}
{% block title %}{% trans "pretixdroid configuration" %}{% endblock %}
{% block content %}
<h1>
{% trans "pretixdroid configuration" %}
<a href="{% url "plugins:pretixdroid:config" organizer=request.event.organizer.slug event=request.event.slug %}" class="btn btn-default">
{% trans "Back to overview" %}
</a>
</h1>
<h2>{% trans "1. Download app" %}</h2>
<p>
<a href="http://play.google.com/store/apps/details?id=eu.pretix.pretixdroid">
<img src="{% static "pretixplugins/pretixdroid/play_store_en.png" %}" alt="
{% trans "Download the app from the Google Play Store" %}" height="70">
</a>
</p>
<p>
<small>
{% blocktrans trimmed %}
Android, Google Play and the Google Play logo are trademarks of Google Inc.
{% endblocktrans %}
</small>
</p>
<h2>{% trans "2. Scan code" %}</h2>
<div id="qrcodeCanvas"></div>
<script type="text/json" id="qrdata">
{{ qrdata|safe }}
</script>
<h2>{% trans "3. Start scanning tickets" %}</h2>
<script type="text/javascript" src="{% static "pretixplugins/pretixdroid/pretixdroid.js" %}"></script>
{% endblock %}

View File

@@ -14,8 +14,10 @@ pretixdroid_api_patterns = [
]
urlpatterns = [
url(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/pretixdroid/', views.ConfigView.as_view(),
url(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/pretixdroid/$', views.ConfigView.as_view(),
name='config'),
url(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/pretixdroid/(?P<config>\d+)/$',
views.ConfigCodeView.as_view(), name='config.code'),
url(r'^pretixdroid/api/(?P<organizer>[^/]+)/(?P<event>[^/]+)/(?P<subevent>\d+)/',
include(pretixdroid_api_patterns)),
url(r'^pretixdroid/api/(?P<organizer>[^/]+)/(?P<event>[^/]+)/', include(pretixdroid_api_patterns)),

View File

@@ -1,17 +1,19 @@
import json
import logging
import string
import dateutil.parser
from django.contrib import messages
from django.db import transaction
from django.db.models import Count, Q
from django.http import (
HttpResponseForbidden, HttpResponseNotFound, JsonResponse,
)
from django.shortcuts import get_object_or_404
from django.utils.crypto import get_random_string
from django.shortcuts import get_object_or_404, redirect
from django.urls import reverse
from django.utils.decorators import method_decorator
from django.utils.functional import cached_property
from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _
from django.views.decorators.csrf import csrf_exempt
from django.views.generic import TemplateView, View
@@ -22,44 +24,93 @@ from pretix.helpers.urls import build_absolute_uri
from pretix.multidomain.urlreverse import (
build_absolute_uri as event_absolute_uri,
)
from pretix.plugins.pretixdroid.forms import AppConfigurationForm
from pretix.plugins.pretixdroid.models import AppConfiguration
logger = logging.getLogger('pretix.plugins.pretixdroid')
API_VERSION = 3
class ConfigCodeView(EventPermissionRequiredMixin, TemplateView):
template_name = 'pretixplugins/pretixdroid/configuration_code.html'
permission = 'can_change_orders'
def get(self, request, **kwargs):
try:
self.object = self.request.event.appconfiguration_set.get(pk=kwargs.get("config"))
except AppConfiguration.DoesNotExist:
messages.error(request, _('The selected configuration does not exist.'))
return redirect(reverse('plugins:pretixdroid:config', kwargs={
'organizer': self.request.event.organizer.slug,
'event': self.request.event.slug,
}))
return super().get(request, **kwargs)
def get_context_data(self, **kwargs):
ctx = super().get_context_data()
url = build_absolute_uri('plugins:pretixdroid:api.redeem', kwargs={
'organizer': self.request.event.organizer.slug,
'event': self.request.event.slug
})
if self.object.subevent:
url = build_absolute_uri('plugins:pretixdroid:api.redeem', kwargs={
'organizer': self.request.event.organizer.slug,
'event': self.request.event.slug,
'subevent': self.object.subevent.pk
})
ctx['qrdata'] = json.dumps({
'version': API_VERSION,
'url': url[:-7], # the slice removes the redeem/ part at the end
'key': self.object.key,
'allow_search': self.object.allow_search,
'show_info': self.object.show_info
})
return ctx
class ConfigView(EventPermissionRequiredMixin, TemplateView):
template_name = 'pretixplugins/pretixdroid/configuration.html'
permission = 'can_change_orders'
@cached_property
def add_form(self):
return AppConfigurationForm(
event=self.request.event,
instance=AppConfiguration(event=self.request.event),
data=self.request.POST if self.request.method == "POST" and "add" in self.request.POST else None
)
def post(self, request, *args, **kwargs):
if "add" in self.request.POST and self.add_form.is_valid():
self.add_form.save()
self.request.event.log_action('pretix.plugins.pretixdroid.config.added', user=self.request.user,
data=dict(self.add_form.cleaned_data))
return redirect(reverse('plugins:pretixdroid:config.code', kwargs={
'organizer': self.request.event.organizer.slug,
'event': self.request.event.slug,
'config': self.add_form.instance.pk
}))
elif "delete" in self.request.POST:
try:
ac = self.request.event.appconfiguration_set.get(pk=request.POST.get("delete"))
self.request.event.log_action('pretix.plugins.pretixdroid.config.deleted', user=self.request.user,
data={'id': ac.pk})
ac.delete()
messages.success(request, _('The selected configuration has been deleted.'))
except AppConfiguration.DoesNotExist:
messages.error(request, _('The selected configuration does not exist.'))
return redirect(reverse('plugins:pretixdroid:config', kwargs={
'organizer': self.request.event.organizer.slug,
'event': self.request.event.slug,
}))
else:
return self.get(request, *args, **kwargs)
def get_context_data(self, **kwargs):
ctx = super().get_context_data()
key = self.request.event.settings.get('pretixdroid_key')
if not key or 'flush_key' in self.request.GET:
key = get_random_string(length=32,
allowed_chars=string.ascii_uppercase + string.ascii_lowercase + string.digits)
self.request.event.settings.set('pretixdroid_key', key)
subevent = None
url = build_absolute_uri('plugins:pretixdroid:api.redeem', kwargs={
'organizer': self.request.event.organizer.slug,
'event': self.request.event.slug
})
if self.request.event.has_subevents:
if self.request.GET.get('subevent'):
subevent = get_object_or_404(SubEvent, event=self.request.event, pk=self.request.GET['subevent'])
url = build_absolute_uri('plugins:pretixdroid:api.redeem', kwargs={
'organizer': self.request.event.organizer.slug,
'event': self.request.event.slug,
'subevent': subevent.pk
})
ctx['subevent'] = subevent
ctx['qrdata'] = json.dumps({
'version': API_VERSION,
'url': url[:-7], # the slice removes the redeem/ part at the end
'key': key,
})
ctx['add_form'] = self.add_form
ctx['configs'] = self.request.event.appconfiguration_set.prefetch_related('items')
return ctx
@@ -75,13 +126,16 @@ class ApiView(View):
except Event.DoesNotExist:
return HttpResponseNotFound('Unknown event')
if (not self.event.settings.get('pretixdroid_key')
or self.event.settings.get('pretixdroid_key') != request.GET.get('key', '-unset-')):
try:
self.config = self.event.appconfiguration_set.get(key=request.GET.get("key", "-unset-"))
except AppConfiguration.DoesNotExist:
return HttpResponseForbidden('Invalid key')
self.subevent = None
if self.event.has_subevents:
if 'subevent' in kwargs:
if self.config.subevent:
self.subevent = self.config.subevent
elif 'subevent' in kwargs:
self.subevent = get_object_or_404(SubEvent, event=self.event, pk=kwargs['subevent'])
else:
return HttpResponseForbidden('No subevent selected.')
@@ -112,7 +166,10 @@ class ApiRedeemView(ApiView):
op = OrderPosition.objects.select_related('item', 'variation', 'order', 'addon_to').get(
order__event=self.event, secret=secret, subevent=self.subevent
)
if op.order.status == Order.STATUS_PAID or force:
if not self.config.all_items and op.item_id not in [i.pk for i in self.config.items.all()]:
response['status'] = 'error'
response['reason'] = 'product'
elif op.order.status == Order.STATUS_PAID or force:
ci, created = Checkin.objects.get_or_create(position=op, defaults={
'datetime': dt,
'nonce': nonce,
@@ -186,14 +243,20 @@ class ApiSearchView(ApiView):
}
if len(query) >= 4:
ops = OrderPosition.objects.select_related('item', 'variation', 'order', 'addon_to', 'order__invoice_address').filter(
Q(order__event=self.event)
& Q(
Q(secret__istartswith=query) | Q(attendee_name__icontains=query) | Q(order__code__istartswith=query)
| Q(order__invoice_address__name__icontains=query)
)
& Q(subevent=self.subevent)
).annotate(checkin_cnt=Count('checkins'))[:25]
qs = OrderPosition.objects.select_related('item', 'variation', 'order', 'addon_to', 'order__invoice_address')
if not self.config.allow_search:
ops = qs.filter(
Q(order__event=self.event) & Q(secret__istartswith=query) & Q(subevent=self.subevent)
).annotate(checkin_cnt=Count('checkins'))[:25]
else:
ops = qs.filter(
Q(order__event=self.event)
& Q(
Q(secret__istartswith=query) | Q(attendee_name__icontains=query) | Q(order__code__istartswith=query)
| Q(order__invoice_address__name__icontains=query)
)
& Q(subevent=self.subevent)
).annotate(checkin_cnt=Count('checkins'))[:25]
response['results'] = [serialize_op(op, bool(op.checkin_cnt)) for op in ops]
else:
@@ -210,7 +273,11 @@ class ApiDownloadView(ApiView):
ops = OrderPosition.objects.select_related('item', 'variation', 'order', 'addon_to').filter(
Q(order__event=self.event) & Q(subevent=self.subevent)
).annotate(checkin_cnt=Count('checkins'))
)
if not self.config.all_items:
ops = ops.filter(item__in=self.config.items.all())
ops = ops.annotate(checkin_cnt=Count('checkins'))
response['results'] = [serialize_op(op, bool(op.checkin_cnt)) for op in ops]
return JsonResponse(response)

View File

@@ -8,6 +8,7 @@ from pretix.base.models import (
Checkin, Event, InvoiceAddress, Item, ItemVariation, Order, OrderPosition,
Organizer, Team, User,
)
from pretix.plugins.pretixdroid.models import AppConfiguration
from pretix.plugins.pretixdroid.views import API_VERSION
@@ -44,23 +45,9 @@ def env():
return event, user, o1, op1, op2
@pytest.mark.django_db
def test_flush_key(client, env):
env[0].settings.set('pretixdroid_key', 'abcdefg')
client.login(email='dummy@dummy.dummy', password='dummy')
client.get('/control/event/%s/%s/pretixdroid/' % (env[0].organizer.slug, env[0].slug))
env[0].settings.flush()
assert env[0].settings.get('pretixdroid_key') == 'abcdefg'
client.get('/control/event/%s/%s/pretixdroid/?flush_key=1' % (env[0].organizer.slug, env[0].slug))
env[0].settings.flush()
assert env[0].settings.get('pretixdroid_key') != 'abcdefg'
@pytest.mark.django_db
def test_custom_datetime(client, env):
env[0].settings.set('pretixdroid_key', 'abcdefg')
AppConfiguration.objects.create(event=env[0], key='abcdefg')
dt = now() - timedelta(days=1)
dt = dt.replace(microsecond=0)
resp = client.post('/pretixdroid/api/%s/%s/redeem/?key=%s' % (env[0].organizer.slug, env[0].slug, 'abcdefg'),
@@ -73,7 +60,7 @@ def test_custom_datetime(client, env):
@pytest.mark.django_db
def test_only_once(client, env):
env[0].settings.set('pretixdroid_key', 'abcdefg')
AppConfiguration.objects.create(event=env[0], key='abcdefg')
resp = client.post('/pretixdroid/api/%s/%s/redeem/?key=%s' % (env[0].organizer.slug, env[0].slug, 'abcdefg'),
data={'secret': '1234'})
@@ -87,9 +74,26 @@ def test_only_once(client, env):
assert jdata['reason'] == 'already_redeemed'
@pytest.mark.django_db
def test_item_scope(client, env):
ac = AppConfiguration.objects.create(event=env[0], key='abcdefg', all_items=False)
ac.items.add(env[4].item)
resp = client.post('/pretixdroid/api/%s/%s/redeem/?key=%s' % (env[0].organizer.slug, env[0].slug, 'abcdefg'),
data={'secret': env[4].secret})
jdata = json.loads(resp.content.decode("utf-8"))
assert jdata['version'] == API_VERSION
assert jdata['status'] == 'ok'
resp = client.post('/pretixdroid/api/%s/%s/redeem/?key=%s' % (env[0].organizer.slug, env[0].slug, 'abcdefg'),
data={'secret': env[3].secret})
jdata = json.loads(resp.content.decode("utf-8"))
assert jdata['status'] == 'error'
assert jdata['reason'] == 'product'
@pytest.mark.django_db
def test_reupload_same_nonce(client, env):
env[0].settings.set('pretixdroid_key', 'abcdefg')
AppConfiguration.objects.create(event=env[0], key='abcdefg')
resp = client.post('/pretixdroid/api/%s/%s/redeem/?key=%s' % (env[0].organizer.slug, env[0].slug, 'abcdefg'),
data={'secret': '1234', 'nonce': 'fooobar'})
@@ -105,7 +109,7 @@ def test_reupload_same_nonce(client, env):
@pytest.mark.django_db
def test_forced_multiple(client, env):
env[0].settings.set('pretixdroid_key', 'abcdefg')
AppConfiguration.objects.create(event=env[0], key='abcdefg')
resp = client.post('/pretixdroid/api/%s/%s/redeem/?key=%s' % (env[0].organizer.slug, env[0].slug, 'abcdefg'),
data={'secret': '1234'})
@@ -120,7 +124,7 @@ def test_forced_multiple(client, env):
@pytest.mark.django_db
def test_require_paid(client, env):
env[0].settings.set('pretixdroid_key', 'abcdefg')
AppConfiguration.objects.create(event=env[0], key='abcdefg')
env[2].status = Order.STATUS_PENDING
env[2].save()
@@ -133,7 +137,7 @@ def test_require_paid(client, env):
@pytest.mark.django_db
def test_unknown(client, env):
env[0].settings.set('pretixdroid_key', 'abcdefg')
AppConfiguration.objects.create(event=env[0], key='abcdefg')
resp = client.post('/pretixdroid/api/%s/%s/redeem/?key=%s' % (env[0].organizer.slug, env[0].slug, 'abcdefg'),
data={'secret': '4321'})
@@ -158,17 +162,36 @@ def test_unknown_event(client, env):
@pytest.mark.django_db
def test_search(client, env):
env[0].settings.set('pretixdroid_key', 'abcdefg')
AppConfiguration.objects.create(event=env[0], key='abcdefg')
resp = client.get('/pretixdroid/api/%s/%s/search/?key=%s&query=%s' % (
env[0].organizer.slug, env[0].slug, 'abcdefg', '567891'))
jdata = json.loads(resp.content.decode("utf-8"))
assert len(jdata['results']) == 1
assert jdata['results'][0]['secret'] == '5678910'
resp = client.get('/pretixdroid/api/%s/%s/search/?key=%s&query=%s' % (
env[0].organizer.slug, env[0].slug, 'abcdefg', 'Peter'))
jdata = json.loads(resp.content.decode("utf-8"))
assert len(jdata['results']) == 1
assert jdata['results'][0]['secret'] == '5678910'
@pytest.mark.django_db
def test_search_restricted(client, env):
AppConfiguration.objects.create(event=env[0], key='abcdefg', allow_search=False)
resp = client.get('/pretixdroid/api/%s/%s/search/?key=%s&query=%s' % (
env[0].organizer.slug, env[0].slug, 'abcdefg', '567891'))
jdata = json.loads(resp.content.decode("utf-8"))
assert len(jdata['results']) == 1
assert jdata['results'][0]['secret'] == '5678910'
resp = client.get('/pretixdroid/api/%s/%s/search/?key=%s&query=%s' % (
env[0].organizer.slug, env[0].slug, 'abcdefg', 'Peter'))
jdata = json.loads(resp.content.decode("utf-8"))
assert len(jdata['results']) == 0
@pytest.mark.django_db
def test_search_invoice_name(client, env):
env[0].settings.set('pretixdroid_key', 'abcdefg')
AppConfiguration.objects.create(event=env[0], key='abcdefg')
InvoiceAddress.objects.create(order=env[2], name="John")
resp = client.get('/pretixdroid/api/%s/%s/search/?key=%s&query=%s' % (
env[0].organizer.slug, env[0].slug, 'abcdefg', 'John'))
@@ -179,7 +202,7 @@ def test_search_invoice_name(client, env):
@pytest.mark.django_db
def test_download_all_data(client, env):
env[0].settings.set('pretixdroid_key', 'abcdefg')
AppConfiguration.objects.create(event=env[0], key='abcdefg')
resp = client.get('/pretixdroid/api/%s/%s/download/?key=%s' % (env[0].organizer.slug, env[0].slug, 'abcdefg'))
jdata = json.loads(resp.content.decode("utf-8"))
assert len(jdata['results']) == 2
@@ -187,9 +210,19 @@ def test_download_all_data(client, env):
assert jdata['results'][1]['secret'] == '5678910'
@pytest.mark.django_db
def test_download_item_restriction(client, env):
ac = AppConfiguration.objects.create(event=env[0], key='abcdefg', all_items=False)
ac.items.add(env[4].item)
resp = client.get('/pretixdroid/api/%s/%s/download/?key=%s' % (env[0].organizer.slug, env[0].slug, 'abcdefg'))
jdata = json.loads(resp.content.decode("utf-8"))
assert len(jdata['results']) == 1
assert jdata['results'][0]['secret'] == env[4].secret
@pytest.mark.django_db
def test_status(client, env):
env[0].settings.set('pretixdroid_key', 'abcdefg')
AppConfiguration.objects.create(event=env[0], key='abcdefg')
Checkin.objects.create(position=env[3])
resp = client.get('/pretixdroid/api/%s/%s/status/?key=%s' % (
env[0].organizer.slug, env[0].slug, 'abcdefg'))

View File

@@ -8,6 +8,7 @@ from pretix.base.models import (
Checkin, Event, Item, ItemVariation, Order, OrderPosition, Organizer, Team,
User,
)
from pretix.plugins.pretixdroid.models import AppConfiguration
from pretix.plugins.pretixdroid.views import API_VERSION
@@ -47,23 +48,9 @@ def env():
return event, user, o1, op1, op2, se1, se2
@pytest.mark.django_db
def test_config(client, env):
env[0].settings.set('pretixdroid_key', 'abcdefg')
client.login(email='dummy@dummy.dummy', password='dummy')
r = client.get('/control/event/%s/%s/pretixdroid/' % (env[0].organizer.slug, env[0].slug))
print(r.content)
assert 'qrcodeCanvas' not in r.rendered_content
r = client.get('/control/event/%s/%s/pretixdroid/?subevent=%d' % (env[0].organizer.slug, env[0].slug, env[5].pk))
assert 'qrcodeCanvas' in r.rendered_content
assert '/%d/' % env[5].pk in r.rendered_content
@pytest.mark.django_db
def test_custom_datetime(client, env):
env[0].settings.set('pretixdroid_key', 'abcdefg')
AppConfiguration.objects.create(event=env[0], key='abcdefg', subevent=env[5])
dt = now() - timedelta(days=1)
dt = dt.replace(microsecond=0)
resp = client.post('/pretixdroid/api/%s/%s/%d/redeem/?key=%s' % (
@@ -77,7 +64,7 @@ def test_custom_datetime(client, env):
@pytest.mark.django_db
def test_wrong_subevent(client, env):
env[0].settings.set('pretixdroid_key', 'abcdefg')
AppConfiguration.objects.create(event=env[0], key='abcdefg')
resp = client.post('/pretixdroid/api/%s/%s/%d/redeem/?key=%s' % (
env[0].organizer.slug, env[0].slug, env[5].pk, 'abcdefg'
@@ -93,9 +80,30 @@ def test_wrong_subevent(client, env):
assert jdata['status'] == 'ok'
@pytest.mark.django_db
def test_other_subevent_not_allowed(client, env):
ac = AppConfiguration.objects.create(event=env[0], key='abcdefg', subevent=env[5])
resp = client.post('/pretixdroid/api/%s/%s/%d/redeem/?key=%s' % (
env[0].organizer.slug, env[0].slug, env[6].pk, 'abcdefg'
), data={'secret': '5678910'})
jdata = json.loads(resp.content.decode("utf-8"))
assert jdata['status'] == 'error'
assert jdata['reason'] == 'unknown_ticket'
ac.subevent = env[6]
ac.save()
resp = client.post('/pretixdroid/api/%s/%s/%d/redeem/?key=%s' % (
env[0].organizer.slug, env[0].slug, env[6].pk, 'abcdefg'
), data={'secret': '5678910'})
jdata = json.loads(resp.content.decode("utf-8"))
assert jdata['status'] == 'ok'
@pytest.mark.django_db
def test_unknown_subevent(client, env):
env[0].settings.set('pretixdroid_key', 'abcdefg')
AppConfiguration.objects.create(event=env[0], key='abcdefg')
resp = client.post('/pretixdroid/api/%s/%s/%d/redeem/?key=%s' % (
env[0].organizer.slug, env[0].slug, env[6].pk + 1000, 'abcdefg'
), data={'secret': '5678910'})
@@ -112,7 +120,7 @@ def test_no_subevent(client, env):
@pytest.mark.django_db
def test_search(client, env):
env[0].settings.set('pretixdroid_key', 'abcdefg')
AppConfiguration.objects.create(event=env[0], key='abcdefg')
resp = client.get('/pretixdroid/api/%s/%s/%d/search/?key=%s&query=%s' % (
env[0].organizer.slug, env[0].slug, env[5].pk, 'abcdefg', '567891'))
jdata = json.loads(resp.content.decode("utf-8"))
@@ -126,7 +134,7 @@ def test_search(client, env):
@pytest.mark.django_db
def test_download_all_data(client, env):
env[0].settings.set('pretixdroid_key', 'abcdefg')
AppConfiguration.objects.create(event=env[0], key='abcdefg', subevent=env[5])
resp = client.get('/pretixdroid/api/%s/%s/%d/download/?key=%s' % (
env[0].organizer.slug, env[0].slug, env[5].pk, 'abcdefg'))
jdata = json.loads(resp.content.decode("utf-8"))
@@ -136,7 +144,7 @@ def test_download_all_data(client, env):
@pytest.mark.django_db
def test_status(client, env):
env[0].settings.set('pretixdroid_key', 'abcdefg')
AppConfiguration.objects.create(event=env[0], key='abcdefg', subevent=env[5])
Checkin.objects.create(position=env[3])
resp = client.get('/pretixdroid/api/%s/%s/%d/status/?key=%s' % (
env[0].organizer.slug, env[0].slug, env[5].pk, 'abcdefg'))