Organizer-level plugins (#5305)

* Add version notes to the docs

* Adapt signal handling

* Add UI

* Add API

* API and tests

* Fix registry

* Update doc/development/api/plugins.rst

Co-authored-by: Felix Rindt <felix@rindt.me>

* Fix failing tests

* Apply suggestions from code review

Co-authored-by: Richard Schreiber <schreiber@rami.io>

* Update src/pretix/control/templates/pretixcontrol/organizers/plugin_events.html

Co-authored-by: luelista <weller@rami.io>

* Update src/pretix/control/templates/pretixcontrol/organizers/plugins.html

Co-authored-by: luelista <weller@rami.io>

* Update src/pretix/control/templates/pretixcontrol/organizers/plugins.html

Co-authored-by: luelista <weller@rami.io>

* Update src/pretix/control/navigation.py

Co-authored-by: luelista <weller@rami.io>

* Update src/pretix/control/urls.py

Co-authored-by: luelista <weller@rami.io>

* Apply suggestion from @wiffbi

* REbase migration

* Fix review note

* Fix test cases

* Remove plugin from all events if disabled on org level

* Update doc/development/api/plugins.rst

* Unify registries

* Rebase migration

---------

Co-authored-by: Felix Rindt <felix@rindt.me>
Co-authored-by: Richard Schreiber <schreiber@rami.io>
Co-authored-by: luelista <weller@rami.io>
This commit is contained in:
Raphael Michel
2025-08-19 11:33:34 +02:00
committed by GitHub
parent 56964b6764
commit a51a6123f5
50 changed files with 1623 additions and 192 deletions

View File

@@ -855,6 +855,39 @@ def test_event_update_plugins_validation(token_client, organizer, event, item, m
)
assert resp.status_code == 200
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
{
"plugins": ["tests.testdummyorga"]
},
format='json'
)
assert resp.status_code == 400
assert resp.data == {"plugins": ["Plugin cannot be enabled on this level: 'tests.testdummyorga'."]}
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
{
"plugins": ["tests.testdummyhybrid"]
},
format='json'
)
assert resp.status_code == 400
assert resp.data == {"plugins": ["Plugin should be enabled on organizer level first: 'tests.testdummyhybrid'."]}
with scopes_disabled():
organizer.enable_plugin("tests.testdummyhybrid")
organizer.save()
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
{
"plugins": ["tests.testdummyhybrid"]
},
format='json'
)
assert resp.status_code == 200
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
{

View File

@@ -423,7 +423,7 @@ def test_use_token_for_access_one_organizer(client, admin_user, organizer, appli
assert resp.status_code == 200
data = json.loads(resp.content.decode())
assert data == {'count': 1, 'next': None, 'previous': None, 'results': [
{'name': 'Dummy', 'slug': 'dummy', 'public_url': 'http://example.com/dummy/'}
{'name': 'Dummy', 'slug': 'dummy', 'public_url': 'http://example.com/dummy/', 'plugins': []}
]}
resp = client.get('/api/v1/organizers/dummy/events/', HTTP_AUTHORIZATION='Bearer %s' % access_token)
assert resp.status_code == 200
@@ -470,8 +470,8 @@ def test_use_token_for_access_two_organizers(client, admin_user, organizer, appl
assert resp.status_code == 200
data = json.loads(resp.content.decode())
assert data == {'count': 2, 'next': None, 'previous': None, 'results': [
{'name': 'A', 'slug': 'a', 'public_url': 'http://example.com/a/'},
{'name': 'Dummy', 'slug': 'dummy', 'public_url': 'http://example.com/dummy/'},
{'name': 'A', 'slug': 'a', 'public_url': 'http://example.com/a/', 'plugins': []},
{'name': 'Dummy', 'slug': 'dummy', 'public_url': 'http://example.com/dummy/', 'plugins': []},
]}
resp = client.get('/api/v1/organizers/dummy/events/', HTTP_AUTHORIZATION='Bearer %s' % access_token)
assert resp.status_code == 200

View File

@@ -19,14 +19,19 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
import zoneinfo
from datetime import datetime
import pytest
from django.core.files.base import ContentFile
from django_scopes import scopes_disabled
from tests.const import SAMPLE_PNG
TEST_ORGANIZER_RES = {
"name": "Dummy",
"slug": "dummy",
"public_url": "http://example.com/dummy/"
"public_url": "http://example.com/dummy/",
"plugins": [],
}
@@ -45,24 +50,57 @@ def test_organizer_detail(token_client, organizer):
@pytest.mark.django_db
def test_get_settings(token_client, organizer):
organizer.settings.event_list_type = "week"
resp = token_client.get(
'/api/v1/organizers/{}/settings/'.format(organizer.slug,),
def test_organizer_patch(token_client, organizer):
with scopes_disabled():
# An event needs to exist for the backwards-compatibility mechanism in get_all_plugins to trigger
event = organizer.events.create(
name="Event", slug="e2", live=True,
date_from=datetime(2020, 1, 10, 16, 0, tzinfo=zoneinfo.ZoneInfo("UTC")),
date_to=datetime(2020, 1, 10, 17, 0, tzinfo=zoneinfo.ZoneInfo("UTC")),
)
resp = token_client.patch(
'/api/v1/organizers/{}/'.format(organizer.slug),
{
'slug': 'willbeignored',
'name': 'Willbeignored',
'plugins': ['tests.testdummyorga', 'tests.testdummyhybrid']
},
format='json',
)
assert resp.status_code == 200
assert resp.data['event_list_type'] == "week"
assert resp.data['slug'] == 'dummy'
assert resp.data['name'] == 'Dummy'
assert set(resp.data['plugins']) == {'tests.testdummyorga', 'tests.testdummyhybrid'}
resp = token_client.get(
'/api/v1/organizers/{}/settings/?explain=true'.format(organizer.slug),
resp = token_client.patch(
'/api/v1/organizers/{}/'.format(organizer.slug),
{
'slug': 'willbeignored',
'name': 'Willbeignored',
'plugins': ['pretix.plugins.statistics']
},
format='json',
)
assert resp.status_code == 400
assert resp.data == {
"plugins": ["Plugin cannot be enabled on this level: 'pretix.plugins.statistics'."]
}
event.plugins = "tests.testdummyhybrid,tests.testdummy"
event.save()
resp = token_client.patch(
'/api/v1/organizers/{}/'.format(organizer.slug),
{
'slug': 'willbeignored',
'name': 'Willbeignored',
'plugins': ['tests.testdummyorga']
},
format='json',
)
assert resp.status_code == 200
assert resp.data['event_list_type'] == {
"value": "week",
"label": "Default overview style",
"help_text": "If your event series has more than 50 dates in the future, only the month or week calendar can be used.",
"readonly": False,
}
event.refresh_from_db()
assert event.plugins == "tests.testdummy"
@pytest.mark.django_db

View File

@@ -203,6 +203,7 @@ event_permission_sub_urls = [
]
org_permission_sub_urls = [
('patch', 'can_change_organizer_settings', '', 200),
('get', 'can_change_organizer_settings', 'settings/', 200),
('patch', 'can_change_organizer_settings', 'settings/', 200),
('get', 'can_change_organizer_settings', 'webhooks/', 200),

View File

@@ -182,6 +182,11 @@ def _register_with_fake_plugin_name(registry, obj, plugin_name):
class App:
name = plugin_name
class PretixPluginMeta:
pass
obj.__mocked_app = App
registry.register(obj)
registry.registered_entries[obj]['plugin'] = App

View File

@@ -22,10 +22,12 @@
from unittest import mock
import pytest
from django.apps import apps
from pretix.base.logentrytypes import (
ItemLogEntryType, LogEntryType, LogEntryTypeRegistry,
)
from pretix.base.models import Event
from pretix.base.signals import Registry
@@ -140,29 +142,38 @@ def test_logentrytype_registry():
reg = LogEntryTypeRegistry()
with mock.patch('pretix.base.signals.get_defining_app') as mock_get_defining_app:
mock_get_defining_app.return_value = 'my_plugin'
mock_get_defining_app.return_value = apps.get_app_config("testdummy")
@reg.new("foo.mytype")
class MyType(LogEntryType):
pass
@reg.new("foo.myothertype")
class MyOtherType(LogEntryType):
pass
with mock.patch('pretix.base.signals.get_defining_app') as mock_get_defining_app:
mock_get_defining_app.return_value = "CORE"
@reg.new("foo.myothertype")
class MyOtherType(LogEntryType):
pass
typ, meta = reg.get(action_type="foo.mytype")
assert isinstance(typ, MyType)
assert meta['action_type'] == "foo.mytype"
assert meta['plugin'] == 'my_plugin'
assert meta['plugin'] == apps.get_app_config("testdummy")
typ, meta = reg.get(action_type="foo.myothertype")
assert isinstance(typ, MyOtherType)
assert meta['action_type'] == "foo.myothertype"
assert meta['plugin'] is None
assert meta['plugin'] == "CORE"
by_my_plugin = reg.filter(plugin='my_plugin')
by_my_plugin = reg.filter(plugin=apps.get_app_config("testdummy"))
assert set(type(typ) for typ, meta in by_my_plugin) == {MyType}
by_active_plugin = reg.filter(active_in=Event(plugins=""))
assert set(type(typ) for typ, meta in by_active_plugin) == {MyOtherType}
by_active_plugin = reg.filter(active_in=Event(plugins="tests.testdummy"))
assert set(type(typ) for typ, meta in by_active_plugin) == {MyType, MyOtherType}
def test_logentrytype_registry_validation():
reg = LogEntryTypeRegistry()

View File

@@ -327,6 +327,28 @@ class EventsTest(SoupTest):
self.event1.refresh_from_db()
assert "testdummyrestricted" in self.event1.plugins
self.post_doc('/control/event/%s/%s/settings/plugins' % (self.orga1.slug, self.event1.slug),
{'plugin:tests.testdummyorga': 'enable'})
self.event1.refresh_from_db()
assert "testdummyorga" not in self.event1.plugins
self.post_doc('/control/event/%s/%s/settings/plugins' % (self.orga1.slug, self.event1.slug),
{'plugin:tests.testdummyhybrid': 'enable'})
self.event1.refresh_from_db()
assert "tests.testdummyhybrid" not in self.event1.plugins
self.orga1.refresh_from_db()
assert "tests.testdummyhybrid" not in self.orga1.plugins
t2 = Team.objects.create(organizer=self.orga1, can_change_organizer_settings=True)
t2.members.add(self.user)
self.post_doc('/control/event/%s/%s/settings/plugins' % (self.orga1.slug, self.event1.slug),
{'plugin:tests.testdummyhybrid': 'enable'})
self.event1.refresh_from_db()
assert "tests.testdummyhybrid" in self.event1.plugins
self.orga1.refresh_from_db()
assert "tests.testdummyhybrid" in self.orga1.plugins
def test_testmode_enable(self):
self.event1.testmode = False
self.event1.save()

View File

@@ -380,3 +380,76 @@ class OrganizerTest(SoupTest):
assert doc.select('.alert-danger')
with scopes_disabled():
assert self.orga1.sales_channels.filter(identifier="web").exists()
def test_plugins(self):
doc = self.get_doc('/control/organizer/%s/settings/plugins' % self.orga1.slug)
self.assertIn("Stripe", doc.select(".form-plugins")[0].text)
self.assertIn("Enable", doc.select("[name=\"plugin:tests.testdummyorga\"]")[0].text)
self.assertIn("Enable", doc.select("[name=\"plugin:tests.testdummyhybrid\"]")[0].text)
assert not doc.select("[name=\"plugin:pretix.plugins.stripe\"]")
assert not doc.select("[name=\"plugin:tests.testdummy\"]")
assert not doc.select("[name=\"plugin:tests.testdummyrestricted\"]")
assert not doc.select("[name=\"plugin:tests.testdummyorgarestricted\"]")
assert not doc.select("[name=\"plugin:tests.testdummyhidden\"]")
doc = self.post_doc('/control/organizer/%s/settings/plugins' % self.orga1.slug,
{'plugin:tests.testdummyorga': 'enable'})
self.assertIn("Disable", doc.select("[name=\"plugin:tests.testdummyorga\"]")[0].text)
doc = self.post_doc('/control/organizer/%s/settings/plugins' % self.orga1.slug,
{'plugin:tests.testdummyhybrid': 'enable'})
self.assertIn("Events with plugin testdummyhybrid", doc.select("h1")[0].text)
self.orga1.refresh_from_db()
assert "tests.testdummyhybrid" in self.orga1.get_plugins()
doc = self.post_doc('/control/organizer/%s/settings/plugins' % self.orga1.slug,
{'plugin:tests.testdummyhybrid': 'disable'})
self.assertIn("Enable", doc.select("[name=\"plugin:tests.testdummyhybrid\"]")[0].text)
self.post_doc('/control/organizer/%s/settings/plugins' % self.orga1.slug,
{'plugin:tests.testdummy': 'enable'})
self.orga1.refresh_from_db()
assert "tests.testdummy" not in self.orga1.get_plugins()
self.post_doc('/control/organizer/%s/settings/plugins' % self.orga1.slug,
{'plugin:tests.testdummyorgarestricted': 'enable'})
self.orga1.refresh_from_db()
assert "testdummyorgarestricted" not in self.orga1.get_plugins()
self.orga1.settings.allowed_restricted_plugins = ["tests.testdummyorgarestricted"]
self.post_doc('/control/organizer/%s/settings/plugins' % self.orga1.slug,
{'plugin:tests.testdummyorgarestricted': 'enable'})
self.orga1.refresh_from_db()
assert "tests.testdummyorgarestricted" in self.orga1.get_plugins()
def test_plugin_events(self):
resp = self.client.get('/control/organizer/%s/settings/plugins/tests.testdummyorga/events' % self.orga1.slug)
assert resp.status_code == 404
assert b"only be enabled for the entire organizer account" in resp.content
resp = self.client.get(
'/control/organizer/%s/settings/plugins/tests.testdummyrestricted/events' % self.orga1.slug)
assert resp.status_code == 404
assert b"currently not allowed" in resp.content
resp = self.client.get('/control/organizer/%s/settings/plugins/tests.testdummyhybrid/events' % self.orga1.slug)
assert resp.status_code == 404
assert b"currently not active on the organizer" in resp.content
resp = self.client.get('/control/organizer/%s/settings/plugins/pretix.plugins.stripe/events' % self.orga1.slug)
assert resp.status_code == 200
resp = self.client.post('/control/organizer/%s/settings/plugins/pretix.plugins.stripe/events' % self.orga1.slug,
{'events': self.event1.pk})
assert resp.status_code == 302
self.event1.refresh_from_db()
assert 'pretix.plugins.stripe' in self.event1.get_plugins()
assert 'pretix.plugins.banktransfer' in self.event1.get_plugins()
resp = self.client.post('/control/organizer/%s/settings/plugins/pretix.plugins.banktransfer/events' % self.orga1.slug,
{})
assert resp.status_code == 302
self.event1.refresh_from_db()
assert 'pretix.plugins.banktransfer' not in self.event1.get_plugins()
assert 'pretix.plugins.stripe' in self.event1.get_plugins()

View File

@@ -183,6 +183,8 @@ event_urls = [
organizer_urls = [
'organizer/abc/edit',
'organizer/abc/',
'organizer/abc/settings/plugins',
'organizer/abc/settings/plugins/pretix.plugins.sendmail/events',
'organizer/abc/settings/email',
'organizer/abc/settings/email/setup',
'organizer/abc/teams',
@@ -287,7 +289,7 @@ def test_wrong_event(perf_patch, client, env, url):
organizer=env[2], name='Dummy', slug='dummy2',
date_from=now(), plugins='pretix.plugins.banktransfer'
)
t = Team.objects.create(organizer=env[2], can_change_event_settings=True)
t = Team.objects.create(pk=2, organizer=env[2], can_change_event_settings=True)
t.members.add(env[1])
t.limit_events.add(event2)
@@ -418,7 +420,7 @@ event_permission_urls = [
@pytest.mark.parametrize("perm,url,code,http_method", event_permission_urls)
def test_wrong_event_permission(perf_patch, client, env, perm, url, code, http_method):
t = Team(
organizer=env[2], all_events=True
pk=2, organizer=env[2], all_events=True
)
setattr(t, perm, False)
t.save()
@@ -438,7 +440,7 @@ def test_limited_event_permission_for_other_event(perf_patch, client, env, perm,
organizer=env[2], name='Dummy', slug='dummy2',
date_from=now(), plugins='pretix.plugins.banktransfer'
)
t = Team.objects.create(organizer=env[2], can_change_event_settings=True)
t = Team.objects.create(pk=2, organizer=env[2], can_change_event_settings=True)
t.members.add(env[1])
t.limit_events.add(event2)
@@ -453,7 +455,7 @@ def test_limited_event_permission_for_other_event(perf_patch, client, env, perm,
@pytest.mark.django_db
def test_current_permission(client, env):
t = Team(
organizer=env[2], all_events=True
pk=2, organizer=env[2], all_events=True
)
setattr(t, 'can_change_event_settings', True)
t.save()
@@ -471,7 +473,7 @@ def test_current_permission(client, env):
@pytest.mark.django_db
@pytest.mark.parametrize("perm,url,code,http_method", event_permission_urls)
def test_correct_event_permission_all_events(perf_patch, client, env, perm, url, code, http_method):
t = Team(organizer=env[2], all_events=True)
t = Team(pk=2, organizer=env[2], all_events=True)
setattr(t, perm, True)
t.save()
t.members.add(env[1])
@@ -489,7 +491,7 @@ def test_correct_event_permission_all_events(perf_patch, client, env, perm, url,
@pytest.mark.django_db
@pytest.mark.parametrize("perm,url,code,http_method", event_permission_urls)
def test_correct_event_permission_limited(perf_patch, client, env, perm, url, code, http_method):
t = Team(organizer=env[2])
t = Team(pk=2, organizer=env[2])
setattr(t, perm, True)
t.save()
t.members.add(env[1])
@@ -522,6 +524,8 @@ organizer_permission_urls = [
("can_change_teams", "organizer/dummy/team/1/edit", 200),
("can_change_teams", "organizer/dummy/team/1/delete", 200),
("can_change_organizer_settings", "organizer/dummy/edit", 200),
("can_change_organizer_settings", "organizer/dummy/settings/plugins", 200),
("can_change_organizer_settings", "organizer/dummy/settings/plugins/pretix.plugins.sendmail/events", 200),
("can_change_organizer_settings", "organizer/dummy/settings/email", 200),
("can_change_organizer_settings", "organizer/dummy/settings/email/setup", 200),
("can_change_organizer_settings", "organizer/dummy/devices", 200),
@@ -580,7 +584,7 @@ organizer_permission_urls = [
@pytest.mark.django_db
@pytest.mark.parametrize("perm,url,code", organizer_permission_urls)
def test_wrong_organizer_permission(perf_patch, client, env, perm, url, code):
t = Team(organizer=env[2])
t = Team(pk=2, organizer=env[2])
setattr(t, perm, False)
t.save()
t.members.add(env[1])
@@ -592,7 +596,7 @@ def test_wrong_organizer_permission(perf_patch, client, env, perm, url, code):
@pytest.mark.django_db
@pytest.mark.parametrize("perm,url,code", organizer_permission_urls)
def test_correct_organizer_permission(perf_patch, client, env, perm, url, code):
t = Team(organizer=env[2])
t = Team(pk=2, organizer=env[2])
setattr(t, perm, True)
t.save()
t.members.add(env[1])

View File

@@ -30,6 +30,9 @@ TEMPLATES[0]['DIRS'].append(os.path.join(TEST_DIR, 'templates')) # NOQA
INSTALLED_APPS.append('tests.testdummy') # NOQA
INSTALLED_APPS.append('tests.testdummyrestricted') # NOQA
INSTALLED_APPS.append('tests.testdummyhidden') # NOQA
INSTALLED_APPS.append('tests.testdummyorga') # NOQA
INSTALLED_APPS.append('tests.testdummyhybrid') # NOQA
INSTALLED_APPS.append('tests.testdummyorgarestricted') # NOQA
PRETIX_AUTH_BACKENDS = [
'pretix.base.auth.NativeAuthBackend',

View File

@@ -19,10 +19,10 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from django.apps import AppConfig
from pretix.base.plugins import PluginConfig
class TestDummyApp(AppConfig):
class TestDummyApp(PluginConfig):
name = 'tests.testdummy'
verbose_name = '.testdummy'

View File

@@ -0,0 +1,21 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#

View File

@@ -0,0 +1,34 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from pretix.base.plugins import (
PLUGIN_LEVEL_EVENT_ORGANIZER_HYBRID, PluginConfig,
)
class TestDummyHybridApp(PluginConfig):
name = 'tests.testdummyhybrid'
verbose_name = 'testdummyhybrid'
class PretixPluginMeta:
name = 'testdummyhybrid'
version = '1.0.0'
level = PLUGIN_LEVEL_EVENT_ORGANIZER_HYBRID

View File

@@ -0,0 +1,21 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#

View File

@@ -0,0 +1,32 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from pretix.base.plugins import PLUGIN_LEVEL_ORGANIZER, PluginConfig
class TestDummyOrgaApp(PluginConfig):
name = 'tests.testdummyorga'
verbose_name = 'testdummyorga'
class PretixPluginMeta:
name = 'testdummyorga'
version = '1.0.0'
level = PLUGIN_LEVEL_ORGANIZER

View File

@@ -0,0 +1,21 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#

View File

@@ -0,0 +1,33 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from pretix.base.plugins import PLUGIN_LEVEL_ORGANIZER, PluginConfig
class TestDummyOrgaRestrictedApp(PluginConfig):
name = 'tests.testdummyorgarestricted'
verbose_name = 'testdummyorgarestricted'
class PretixPluginMeta:
name = 'testdummyorgarestricted'
version = '1.0.0'
level = PLUGIN_LEVEL_ORGANIZER
restricted = True