upgrade to new pretix, remove download, add page links

This commit is contained in:
_Bastler 2023-12-15 22:09:23 +01:00
parent f106e3ce4f
commit d1bd82080a
25 changed files with 528 additions and 137 deletions

108
.github/workflows/style.yml vendored Normal file
View File

@ -0,0 +1,108 @@
name: Code Style
on:
push:
branches: [ main, master ]
paths-ignore:
- 'pretix_digital_items/locale/**'
- 'pretix_digital_items/static/**'
pull_request:
branches: [ main, master ]
paths-ignore:
- 'pretix_digital_items/locale/**'
- 'pretix_digital_items/static/**'
jobs:
isort:
name: isort
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python 3.8
uses: actions/setup-python@v1
with:
python-version: 3.8
- uses: actions/cache@v1
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/setup.py') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Install pretix
run: pip3 install pretix
- name: Install Dependencies
run: pip3 install isort -Ue .
- name: Run isort
run: isort -c .
flake:
name: flake8
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python 3.8
uses: actions/setup-python@v1
with:
python-version: 3.8
- uses: actions/cache@v1
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/setup.py') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Install pretix
run: pip3 install pretix
- name: Install Dependencies
run: pip3 install flake8 -Ue .
- name: Run flake8
run: flake8 .
working-directory: .
black:
name: black
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python 3.8
uses: actions/setup-python@v1
with:
python-version: 3.8
- uses: actions/cache@v1
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/setup.py') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Install pretix
run: pip3 install pretix
- name: Install Dependencies
run: pip3 install black -Ue .
- name: Run black
run: black --check .
working-directory: .
packaging:
name: packaging
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python 3.8
uses: actions/setup-python@v1
with:
python-version: 3.8
- uses: actions/cache@v1
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/setup.py') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Install pretix
run: pip3 install pretix
- name: Install Dependencies
run: pip3 install twine check-manifest -Ue .
- name: Run check-manifest
run: check-manifest .
working-directory: .
- name: Build package
run: python setup.py sdist
working-directory: .
- name: Check package
run: twine check dist/*
working-directory: .

36
.github/workflows/tests.yml vendored Normal file
View File

@ -0,0 +1,36 @@
name: Tests
on:
push:
branches: [ main, master ]
paths-ignore:
- 'pretix_digital_items/locale/**'
pull_request:
branches: [ main, master ]
paths-ignore:
- 'pretix_digital_items/locale/**'
jobs:
test:
runs-on: ubuntu-latest
name: Tests
steps:
- uses: actions/checkout@v2
- name: Set up Python 3.8
uses: actions/setup-python@v1
with:
python-version: 3.8
- uses: actions/cache@v1
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/setup.py') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Install system dependencies
run: sudo apt update && sudo apt install gettext
- name: Install pretix
run: pip3 install pretix
- name: Install Dependencies
run: pip3 install pytest pytest-django -Ue .
- name: Run checks
run: py.test tests

1
.gitignore vendored
View File

@ -51,6 +51,7 @@ coverage.xml
# Django stuff:
*.log
data/
# Sphinx documentation
docs/_build/

16
.install-hooks.sh Executable file
View File

@ -0,0 +1,16 @@
#!/bin/sh
REPO_DIR=$(git rev-parse --show-toplevel)
GIT_DIR=$REPO_DIR/.git
VENV_ACTIVATE=$VIRTUAL_ENV/bin/activate
if [[ ! -f $VENV_ACTIVATE ]]
then
echo "Could not find your virtual environment"
fi
echo "#!/bin/sh" >> $GIT_DIR/hooks/pre-commit
echo "set -e" >> $GIT_DIR/hooks/pre-commit
echo "source $VENV_ACTIVATE" >> $GIT_DIR/hooks/pre-commit
echo "black --check ." >> $GIT_DIR/hooks/pre-commit
echo "isort -c ." >> $GIT_DIR/hooks/pre-commit
echo "flake8 ." >> $GIT_DIR/hooks/pre-commit
chmod +x $GIT_DIR/hooks/pre-commit

37
.update-locales.sh Executable file
View File

@ -0,0 +1,37 @@
#!/bin/sh
COMPONENTS=pretix/pretix-plugin-pretix-digital-items
DIR=pretix_digital_items/locale
# Renerates .po files used for translating the plugin
set -e
set -x
# Lock Weblate
for c in $COMPONENTS; do
wlc lock $c;
done
# Push changes from Weblate to GitHub
for c in $COMPONENTS; do
wlc commit $c;
done
# Pull changes from GitHub
git pull --rebase
# Update po files itself
make localegen
# Commit changes
git add $DIR/*/*/*.po
git add $DIR/*.pot
git commit -s -m "Update po files
[CI skip]"
# Push changes
git push
# Unlock Weblate
for c in $COMPONENTS; do
wlc unlock $c;
done

View File

@ -1,5 +1,5 @@
Copyright 2020 _Bastler
Copyright 2023 _Bastler
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@ -1,3 +1,5 @@
recursive-include pretix_digital_items/static *
recursive-include pretix_digital_items/templates *
recursive-include pretix_digital_items/locale *
include LICENSE
exclude .gitlab-ci.yml

View File

@ -10,7 +10,7 @@ Development setup
1. Make sure that you have a working `pretix development setup`_.
2. Clone this repository, eg to ``local/pretix-digital-items``.
2. Clone this repository.
3. Activate the virtual environment you use for pretix development.
@ -21,12 +21,29 @@ Development setup
6. Restart your local pretix server. You can now use the plugin from this repository for your events by enabling it in
the 'plugins' tab in the settings.
This plugin has CI set up to enforce a few code style rules. To check locally, you need these packages installed::
pip install flake8 isort black
To check your plugin for rule violations, run::
black --check .
isort -c .
flake8 .
You can auto-fix some of these issues by running::
isort .
black .
To automatically check for these issues before you commit, you can run ``.install-hooks``.
License
-------
Copyright 2020 _Bastler
Copyright 2023 _Bastler
Released under the terms of the Apache License 2.0

View File

@ -1,28 +1 @@
from django.utils.translation import gettext_lazy
try:
from pretix.base.plugins import PluginConfig
except ImportError:
raise RuntimeError("Please use pretix 2.7 or above to run this plugin!")
__version__ = '1.0.0'
class PluginApp(PluginConfig):
name = 'pretix_digital_items'
verbose_name = 'Digital Items'
class PretixPluginMeta:
name = gettext_lazy('Digital Items')
author = '_Bastler'
description = gettext_lazy('Sell digital Items by using secrets as tokens. Adds secrets to email placeholders, output secret as simple TXT file.')
visible = True
version = __version__
category = 'FEATURE'
compatibility = "pretix>=2.7.0"
def ready(self):
from . import signals # NOQA
default_app_config = 'pretix_digital_items.PluginApp'
__version__ = "2.0.0"

View File

@ -0,0 +1,27 @@
from django.utils.translation import gettext_lazy
from . import __version__
try:
from pretix.base.plugins import PluginConfig
except ImportError:
raise RuntimeError("Please use pretix 2.7 or above to run this plugin!")
class PluginApp(PluginConfig):
default = True
name = "pretix_digital_items"
verbose_name = "Digital Items"
class PretixPluginMeta:
name = gettext_lazy("Digital Items")
author = "_Bastler"
description = gettext_lazy("Sell digital Items by using secrets as tokens. Adds secrets to email placeholders, output secret as simple TXT file.")
visible = True
version = __version__
category = "FEATURE"
compatibility = "pretix>=2.7.0"
def ready(self):
from . import signals # NOQA

View File

@ -1,16 +1,30 @@
from django import forms
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from pretix.base.forms import SettingsForm
class PretixDigitalItemsSettingsForm(SettingsForm):
digitalitems_token_mail_format = forms.CharField(
label=_("Token mail format"),
help_text=_("This text will be included for every token in an email. Available placeholder are {name} for the item name and {secret} for the token code."),
widget=forms.TextInput(attrs={'placeholder': '{name}: {secret}'}),
required=False)
digitalitems_token_export_format = forms.CharField(
label=_("Token export format"),
help_text=_("This text will be included for every token in a TXT export. Available placeholder are {name} for the item name and {secret} for the token code."),
widget=forms.TextInput(attrs={'placeholder': '{name}: {secret}'}),
required=False)
class PretixDigitalItemsSettingsForm(SettingsForm):
digitalitems_token_url_format = forms.CharField(
label=_("Token url format"),
help_text=_(
"This should return an url to link to. Available placeholder are {name} for the item name and {secret} for the token code."
),
widget=forms.TextInput(attrs={"placeholder": "http://localhost?secret={secret}"}),
required=False,
)
digitalitems_token_mail_format = forms.CharField(
label=_("Token mail format"),
help_text=_(
"This text will be included for every token in an email. Available placeholder are {name} for the item name and {secret} for the token code."
),
widget=forms.TextInput(attrs={"placeholder": "{name}: {secret}"}),
required=False,
)
digitalitems_token_export_format = forms.CharField(
label=_("Token export format"),
help_text=_(
"This text will be included for every token in a TXT export. Available placeholder are {name} for the item name and {secret} for the token code."
),
widget=forms.TextInput(attrs={"placeholder": "{name}: {secret}"}),
required=False,
)

View File

@ -1,11 +0,0 @@
from django import forms
from django.utils.translation import ugettext_lazy as _
from pretix.base.forms import SettingsForm
class PretixDigitalItemsSettingsForm(SettingsForm):
digitalitems_token_mail_format = forms.CharField(lel=_("Token mail format"),
help_text=_("This text will be included for every token in an email. Available placeholder are {name} for the item name and {secret} for the token code.")
widget=forms.TextInput(attrs={'placeholder': '{name}: {secret}'}),
required=False)
digitalitems_token_export_format = forms.CharField(label=_("Token export format"), widget=forms.TextInput(attrs={'placeholder': '{name}: {secret}'}), required=False)

View File

@ -38,3 +38,14 @@ msgid ""
"This text will be included for every token in a TXT export. Available placeholder are {name} for the item name and {secret} for the token code."
msgstr "Dieser Text wird für jedes Token in einem TXT Export eingefügt. Verfügbare Platzhalter sind {name} für den Item-Namen und {secret} für den Token-Code."
#: pretix_digital_items/templates/tokens.html:1
msgid "Tokens"
msgstr "Tokens"
#: pretix_digital_items/templates/tokens.html:2
msgid "Token already redeemed"
msgstr "Token bereits eingelöst"
#: pretix_digital_items/templates/tokens.html:3
msgid "Redeem token"
msgstr "Token einlösen"

View File

@ -38,3 +38,14 @@ msgid ""
"This text will be included for every token in a TXT export. Available placeholder are {name} for the item name and {secret} for the token code."
msgstr "Dieser Text wird für jedes Token in einem TXT Export eingefügt. Verfügbare Platzhalter sind {name} für den Item-Namen und {secret} für den Token-Code."
#: pretix_digital_items/templates/tokens.html:1
msgid "Tokens"
msgstr "Tokens"
#: pretix_digital_items/templates/tokens.html:2
msgid "Token already redeemed"
msgstr "Token bereits eingelöst"
#: pretix_digital_items/templates/tokens.html:3
msgid "Redeem token"
msgstr "Token einlösen"

View File

@ -1,32 +1,105 @@
from django.dispatch import receiver
from django.urls import resolve, reverse
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from pretix.base.signals import (register_mail_placeholders, register_ticket_outputs)
from pretix.base.models import Order
from pretix.base.signals import register_mail_placeholders, register_ticket_outputs
from pretix.base.email import SimpleFunctionalMailTextPlaceholder
from pretix.control.signals import nav_event_settings
from pretix.presale.signals import order_info_top
from django.template.loader import get_template
from pretix.base.signals import register_mail_placeholders, register_ticket_outputs
from pretix.base.email import SimpleFunctionalMailTextPlaceholder
from pretix.control.signals import nav_event_settings
@receiver(register_mail_placeholders, dispatch_uid="pretix_digital_items_mail_placeholder")
@receiver(
register_mail_placeholders, dispatch_uid="pretix_digital_items_mail_placeholder"
)
def register_mail_secrets(sender, **kwargs):
token_mail_format = "{name}: {secret}"
if sender.settings.digitalitems_token_mail_format:
token_mail_format = sender.settings.digitalitems_token_mail_format
return SimpleFunctionalMailTextPlaceholder('secrets', ['order'], lambda order: '\n' + '\n\n'.join(token_mail_format.format(secret = position.secret, name = str(position.item.name)) for position in order.positions.all() if position.item.admission), '\nej7f73xs8vfmwvkk2p73yeve4fueq849\n\np8yct9752a897rpsmqzf7beby34a2w25\n\nwwqxtw6guy5s8c5tdarfhyez2ft2juap')
token_mail_format = "{name}: {secret}"
if sender.settings.digitalitems_token_mail_format:
token_mail_format = sender.settings.digitalitems_token_mail_format
return SimpleFunctionalMailTextPlaceholder(
"secrets",
["order"],
lambda order: "\n"
+ "\n\n".join(
token_mail_format.format(
secret=position.secret, name=str(position.item.name)
)
for position in order.positions.all()
if position.item.admission
),
"\nej7f73xs8vfmwvkk2p73yeve4fueq849\n\np8yct9752a897rpsmqzf7beby34a2w25\n\nwwqxtw6guy5s8c5tdarfhyez2ft2juap",
)
@receiver(register_ticket_outputs, dispatch_uid="pretix_digital_items_ticket_output")
def register_ticket_outputs(sender, **kwargs):
from .textticketoutput import TextTicketOutput
return TextTicketOutput
@receiver(nav_event_settings, dispatch_uid='pretix_digital_items_nav_settings')
# @receiver(register_ticket_outputs, dispatch_uid="pretix_digital_items_ticket_output")
# def register_ticket_outputs(sender, **kwargs):
# from .textticketoutput import TextTicketOutput
#
# return TextTicketOutput
@receiver(nav_event_settings, dispatch_uid="pretix_digital_items_nav_settings")
def navbar_settings(sender, request, **kwargs):
url = resolve(request.path_info)
return [{
'label': _('Digital Items'),
'url': reverse('plugins:pretix_digital_items:settings', kwargs={
'event': request.event.slug,
'organizer': request.organizer.slug,
}),
'active': url.namespace == 'plugins:pretix_digital_items' and url.url_name == 'settings',
}]
return [
{
"label": _("Digital Items"),
"url": reverse(
"plugins:pretix_digital_items:settings",
kwargs={
"event": request.event.slug,
"organizer": request.organizer.slug,
},
),
"active": url.namespace == "plugins:pretix_digital_items"
and url.url_name == "settings",
}
]
@receiver(order_info_top, dispatch_uid="pretix_digital_items_order_tokens")
def list_tokens(sender, request, order: Order, **kwargs):
if (order.status != Order.STATUS_PAID) or not order.positions.exists():
return
positions = [
p for p in order.positions.filter(item__admission=True, addon_to__isnull=True)
]
if not positions:
return
token_url_format = "http://localhost?token={secret}"
if sender.settings.digitalitems_token_url_format:
token_url_format = sender.settings.digitalitems_token_url_format
tokenUrls = list(
map(
lambda position: token_url_format.format(
secret=position.secret, name=str(position.item.name)
),
positions,
)
)
checkins = list(
map(
lambda position: position.checkins.count() != 0,
positions,
)
)
data = zip(positions, tokenUrls, checkins)
template = get_template("pretix_digital_items/tokens.html")
ctx = {
"data": data,
}
return template.render(ctx, request=request)

View File

@ -5,7 +5,7 @@
<h1>{% trans "Digital Items" %}</h1>
<form action="" method="post" class="form-horizontal">
{% csrf_token %}
{% bootstrap_form_errors form %}
{% bootstrap_form_errors form %}
{% bootstrap_form form layout="horizontal" %}
<div class="form-group submit-group">
<button type="submit" class="btn btn-primary btn-save">
@ -13,4 +13,4 @@
</button>
</div>
</form>
{% endblock %}
{% endblock %}

View File

@ -0,0 +1,19 @@
{% load i18n %}
{% load bootstrap3 %}
{% load rich_text %}
<h3>{% trans "Tokens" %}</h3>
<div class="list-group">
{% for p,url,checkin in data %}
{% if checkin %}
<p>
{{ p.item.name }}: <code><s>{{ p.secret }}</s></code><br>
({% trans "Token already redeemed" %})
</p>
{% else %}
<p>
{{ p.item.name }}: <code>{{ p.secret }}</code><br>
<a class="btn btn-lg btn-primary" href="{{url}}" target="_blank">{% trans "Redeem token" %}</a>
</p>
{% endif %}
{% endfor %}
</div>

View File

@ -1,18 +1,36 @@
from pretix.base.ticketoutput import BaseTicketOutput
class TextTicketOutput(BaseTicketOutput):
identifier = 'tokens'
verbose_name = 'Download token as in simple textfile'
download_button_text = 'Download Token'
identifier = "tokens"
verbose_name = "Download token as in simple textfile"
download_button_text = "Download Token"
def generate(self, position):
token_export_format = "{name}: {secret}"
if position.event.settings.digitalitems_token_export_format:
token_export_format = position.event.settings.digitalitems_token_export_format
return 'token.txt', 'text/plain', token_export_format.format(secret = position.secret, name = str(position.item.name))
def generate(self, position):
token_export_format = "{name}: {secret}"
if position.event.settings.digitalitems_token_export_format:
token_export_format = (
position.event.settings.digitalitems_token_export_format
)
return (
"token.txt",
"text/plain",
token_export_format.format(
secret=position.secret, name=str(position.item.name)
),
)
def generate_order(self, order):
token_export_format = "{name}: {secret}"
if order.event.settings.digitalitems_token_export_format:
token_export_format = order.event.settings.digitalitems_token_export_format
return 'tokens.txt', 'text/plain', '\n'.join(token_export_format.format(secret = position.secret, name = str(position.item.name)) for position in order.positions.all())
def generate_order(self, order):
token_export_format = "{name}: {secret}"
if order.event.settings.digitalitems_token_export_format:
token_export_format = order.event.settings.digitalitems_token_export_format
return (
"tokens.txt",
"text/plain",
"\n".join(
token_export_format.format(
secret=position.secret, name=str(position.item.name)
)
for position in order.positions.all()
),
)

View File

@ -1,9 +1,9 @@
from django.conf.urls import url
from django.urls import re_path
from .views import SettingsView
urlpatterns = [
url(
re_path(
r"^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/pretix_digital_items/settings",
SettingsView.as_view(),
name="settings",

5
pretixplugin.toml Normal file
View File

@ -0,0 +1,5 @@
[plugin]
package = "pretix-digital-items"
modules = [ "pretix_digital_items" ]
marketplace_name = "digital-items"

42
pyproject.toml Normal file
View File

@ -0,0 +1,42 @@
[project]
name = "pretix-digital-items"
dynamic = ["version"]
description = "Sell digital Items by using secrets as tokens. Adds secrets to email placeholders, output secret as simple TXT file."
readme = "README.rst"
license = {text = "Apache"}
keywords = ["pretix"]
authors = [
{name = "_Bastler", email = "pretix-digital-items@bstly.de"},
]
maintainers = [
{name = "_Bastler", email = "pretix-digital-items@bstly.de"},
]
dependencies = [
]
[project.entry-points."pretix.plugin"]
pretix_digital_items = "pretix_digital_items:PretixPluginMeta"
[project.entry-points."distutils.commands"]
build = "pretix_plugin_build.build:CustomBuild"
[build-system]
requires = [
"setuptools",
"pretix-plugin-build",
]
[project.urls]
homepage = "https://git.lh8.de/_Bastler/pretix-digital-items"
repository = "https://git.lh8.de/_Bastler/pretix-digital-items"
[tool.setuptools]
include-package-data = true
[tool.setuptools.dynamic]
version = {attr = "pretix_digital_items.__version__"}
[tool.setuptools.packages.find]
include = ["pretix*"]
namespaces = false

View File

@ -9,6 +9,36 @@ default_section = THIRDPARTY
include_trailing_comma = true
known_third_party = pretix
known_standard_library = typing
multi_line_output = 5
not_skip = __init__.py
multi_line_output = 3
skip = setup.py
use_parentheses = True
force_grid_wrap = 0
line_length = 88
known_first_party = pretix_digital_items
[tool:pytest]
DJANGO_SETTINGS_MODULE = pretix.testutils.settings
[coverage:run]
source = pretix_digital_items
omit = */migrations/*,*/urls.py,*/tests/*
[coverage:report]
exclude_lines =
pragma: no cover
def __str__
der __repr__
if settings.DEBUG
NOQA
NotImplementedError
[check-manifest]
ignore =
.update-locales.sh
.install-hooks.sh
pretixplugin.toml
Makefile
manage.py
tests/*
*.po
.gitkeep

View File

@ -1,46 +1,4 @@
import os
from distutils.command.build import build
from django.core import management
from setuptools import find_packages, setup
from pretix_digital_items import __version__
from setuptools import setup
try:
with open(os.path.join(os.path.dirname(__file__), 'README.rst'), encoding='utf-8') as f:
long_description = f.read()
except:
long_description = ''
class CustomBuild(build):
def run(self):
management.call_command('compilemessages', verbosity=1)
build.run(self)
cmdclass = {
'build': CustomBuild
}
setup(
name='pretix-digital-items',
version=__version__,
description='Sell digital Items by using secrets as tokens. Adds secrets to email placeholders, output secret as simple TXT file.',
long_description=long_description,
url='https://git.lh8.de/_Bastler/pretix-digital-items',
author='_Bastler',
author_email='pretix-digital-items@bstly.de',
license='Apache',
install_requires=[],
packages=find_packages(exclude=['tests', 'tests.*']),
include_package_data=True,
cmdclass=cmdclass,
entry_points="""
[pretix.plugin]
pretix_digital_items=pretix_digital_items:PretixPluginMeta
""",
)
setup()

1
tests/conftest.py Normal file
View File

@ -0,0 +1 @@
# put your pytest fixtures here

3
tests/test_main.py Normal file
View File

@ -0,0 +1,3 @@
def test_empty():
# put your first tests here
assert 1 + 1 == 2