django-program 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- django_program-0.1.0/PKG-INFO +56 -0
- django_program-0.1.0/README.md +23 -0
- django_program-0.1.0/pyproject.toml +344 -0
- django_program-0.1.0/src/django_program/__init__.py +5 -0
- django_program-0.1.0/src/django_program/__metadata__.py +3 -0
- django_program-0.1.0/src/django_program/conference/__init__.py +1 -0
- django_program-0.1.0/src/django_program/conference/admin.py +150 -0
- django_program-0.1.0/src/django_program/conference/apps.py +12 -0
- django_program-0.1.0/src/django_program/conference/management/__init__.py +1 -0
- django_program-0.1.0/src/django_program/conference/management/commands/__init__.py +1 -0
- django_program-0.1.0/src/django_program/conference/management/commands/bootstrap_conference.py +989 -0
- django_program-0.1.0/src/django_program/conference/management/commands/setup_groups.py +144 -0
- django_program-0.1.0/src/django_program/conference/migrations/0001_initial.py +59 -0
- django_program-0.1.0/src/django_program/conference/migrations/0002_encrypt_stripe_fields.py +28 -0
- django_program-0.1.0/src/django_program/conference/migrations/0003_conference_address.py +15 -0
- django_program-0.1.0/src/django_program/conference/migrations/__init__.py +0 -0
- django_program-0.1.0/src/django_program/conference/models.py +64 -0
- django_program-0.1.0/src/django_program/config_loader.py +168 -0
- django_program-0.1.0/src/django_program/manage/__init__.py +1 -0
- django_program-0.1.0/src/django_program/manage/apps.py +12 -0
- django_program-0.1.0/src/django_program/manage/forms.py +489 -0
- django_program-0.1.0/src/django_program/manage/templates/django_program/manage/_pagination.html +11 -0
- django_program-0.1.0/src/django_program/manage/templates/django_program/manage/activity_dashboard.html +118 -0
- django_program-0.1.0/src/django_program/manage/templates/django_program/manage/activity_edit.html +136 -0
- django_program-0.1.0/src/django_program/manage/templates/django_program/manage/activity_list.html +63 -0
- django_program-0.1.0/src/django_program/manage/templates/django_program/manage/addon_edit.html +45 -0
- django_program-0.1.0/src/django_program/manage/templates/django_program/manage/addon_list.html +54 -0
- django_program-0.1.0/src/django_program/manage/templates/django_program/manage/base.html +1134 -0
- django_program-0.1.0/src/django_program/manage/templates/django_program/manage/conference_edit.html +161 -0
- django_program-0.1.0/src/django_program/manage/templates/django_program/manage/conference_list.html +41 -0
- django_program-0.1.0/src/django_program/manage/templates/django_program/manage/dashboard.html +480 -0
- django_program-0.1.0/src/django_program/manage/templates/django_program/manage/import_pretalx.html +662 -0
- django_program-0.1.0/src/django_program/manage/templates/django_program/manage/order_detail.html +219 -0
- django_program-0.1.0/src/django_program/manage/templates/django_program/manage/order_list.html +79 -0
- django_program-0.1.0/src/django_program/manage/templates/django_program/manage/receipt_review.html +98 -0
- django_program-0.1.0/src/django_program/manage/templates/django_program/manage/room_edit.html +58 -0
- django_program-0.1.0/src/django_program/manage/templates/django_program/manage/room_list.html +51 -0
- django_program-0.1.0/src/django_program/manage/templates/django_program/manage/schedule_list.html +215 -0
- django_program-0.1.0/src/django_program/manage/templates/django_program/manage/section_edit.html +45 -0
- django_program-0.1.0/src/django_program/manage/templates/django_program/manage/section_list.html +47 -0
- django_program-0.1.0/src/django_program/manage/templates/django_program/manage/slot_edit.html +67 -0
- django_program-0.1.0/src/django_program/manage/templates/django_program/manage/speaker_detail.html +367 -0
- django_program-0.1.0/src/django_program/manage/templates/django_program/manage/speaker_list.html +58 -0
- django_program-0.1.0/src/django_program/manage/templates/django_program/manage/sponsor_edit.html +84 -0
- django_program-0.1.0/src/django_program/manage/templates/django_program/manage/sponsor_level_edit.html +45 -0
- django_program-0.1.0/src/django_program/manage/templates/django_program/manage/sponsor_level_list.html +50 -0
- django_program-0.1.0/src/django_program/manage/templates/django_program/manage/sponsor_list.html +52 -0
- django_program-0.1.0/src/django_program/manage/templates/django_program/manage/talk_detail.html +118 -0
- django_program-0.1.0/src/django_program/manage/templates/django_program/manage/talk_edit.html +71 -0
- django_program-0.1.0/src/django_program/manage/templates/django_program/manage/talk_list.html +93 -0
- django_program-0.1.0/src/django_program/manage/templates/django_program/manage/ticket_type_edit.html +45 -0
- django_program-0.1.0/src/django_program/manage/templates/django_program/manage/ticket_type_list.html +62 -0
- django_program-0.1.0/src/django_program/manage/templates/django_program/manage/travel_grant_edit.html +313 -0
- django_program-0.1.0/src/django_program/manage/templates/django_program/manage/travel_grant_list.html +152 -0
- django_program-0.1.0/src/django_program/manage/templates/django_program/manage/voucher_edit.html +45 -0
- django_program-0.1.0/src/django_program/manage/templates/django_program/manage/voucher_list.html +70 -0
- django_program-0.1.0/src/django_program/manage/urls.py +198 -0
- django_program-0.1.0/src/django_program/manage/views.py +2783 -0
- django_program-0.1.0/src/django_program/pretalx/__init__.py +1 -0
- django_program-0.1.0/src/django_program/pretalx/admin.py +68 -0
- django_program-0.1.0/src/django_program/pretalx/apps.py +12 -0
- django_program-0.1.0/src/django_program/pretalx/management/__init__.py +1 -0
- django_program-0.1.0/src/django_program/pretalx/management/commands/__init__.py +1 -0
- django_program-0.1.0/src/django_program/pretalx/management/commands/sync_pretalx.py +141 -0
- django_program-0.1.0/src/django_program/pretalx/migrations/0001_initial.py +127 -0
- django_program-0.1.0/src/django_program/pretalx/migrations/0002_room_alter_scheduleslot_room_alter_talk_room.py +62 -0
- django_program-0.1.0/src/django_program/pretalx/migrations/0003_add_scheduleslot_unique_constraint.py +20 -0
- django_program-0.1.0/src/django_program/pretalx/migrations/0004_talk_tags.py +15 -0
- django_program-0.1.0/src/django_program/pretalx/migrations/0005_alter_room_unique_together_alter_room_pretalx_id_and_more.py +30 -0
- django_program-0.1.0/src/django_program/pretalx/migrations/__init__.py +0 -0
- django_program-0.1.0/src/django_program/pretalx/models.py +190 -0
- django_program-0.1.0/src/django_program/pretalx/profiles/__init__.py +13 -0
- django_program-0.1.0/src/django_program/pretalx/profiles/base.py +20 -0
- django_program-0.1.0/src/django_program/pretalx/profiles/default.py +9 -0
- django_program-0.1.0/src/django_program/pretalx/profiles/pyconus.py +26 -0
- django_program-0.1.0/src/django_program/pretalx/profiles/resolver.py +20 -0
- django_program-0.1.0/src/django_program/pretalx/sync.py +752 -0
- django_program-0.1.0/src/django_program/pretalx/templates/django_program/pretalx/base.html +578 -0
- django_program-0.1.0/src/django_program/pretalx/templates/django_program/pretalx/schedule.html +70 -0
- django_program-0.1.0/src/django_program/pretalx/templates/django_program/pretalx/speaker_detail.html +39 -0
- django_program-0.1.0/src/django_program/pretalx/templates/django_program/pretalx/speaker_list.html +31 -0
- django_program-0.1.0/src/django_program/pretalx/templates/django_program/pretalx/talk_detail.html +76 -0
- django_program-0.1.0/src/django_program/pretalx/urls.py +29 -0
- django_program-0.1.0/src/django_program/pretalx/views.py +238 -0
- django_program-0.1.0/src/django_program/programs/__init__.py +1 -0
- django_program-0.1.0/src/django_program/programs/admin.py +111 -0
- django_program-0.1.0/src/django_program/programs/apps.py +12 -0
- django_program-0.1.0/src/django_program/programs/forms.py +288 -0
- django_program-0.1.0/src/django_program/programs/migrations/0001_initial.py +156 -0
- django_program-0.1.0/src/django_program/programs/migrations/0002_alter_activity_activity_type.py +29 -0
- django_program-0.1.0/src/django_program/programs/migrations/0003_activity_pretalx_submission_type_activity_room_and_more.py +83 -0
- django_program-0.1.0/src/django_program/programs/migrations/0004_travel_grant_pycon_model.py +299 -0
- django_program-0.1.0/src/django_program/programs/migrations/0005_alter_travelgrant_application_type_paymentinfo_and_more.py +206 -0
- django_program-0.1.0/src/django_program/programs/migrations/0006_travelgrant_disbursed_amount_and_more.py +64 -0
- django_program-0.1.0/src/django_program/programs/migrations/0007_alter_receipt_receipt_file.py +25 -0
- django_program-0.1.0/src/django_program/programs/migrations/0008_alter_activitysignup_unique_together_and_more.py +44 -0
- django_program-0.1.0/src/django_program/programs/migrations/0009_alter_activity_options_activity_organizers.py +31 -0
- django_program-0.1.0/src/django_program/programs/migrations/__init__.py +0 -0
- django_program-0.1.0/src/django_program/programs/models.py +644 -0
- django_program-0.1.0/src/django_program/programs/templates/django_program/programs/activity_detail.html +165 -0
- django_program-0.1.0/src/django_program/programs/templates/django_program/programs/activity_list.html +76 -0
- django_program-0.1.0/src/django_program/programs/templates/django_program/programs/travel_grant_form.html +1059 -0
- django_program-0.1.0/src/django_program/programs/templates/django_program/programs/travel_grant_payment_info.html +569 -0
- django_program-0.1.0/src/django_program/programs/templates/django_program/programs/travel_grant_provide_info.html +149 -0
- django_program-0.1.0/src/django_program/programs/templates/django_program/programs/travel_grant_receipts.html +809 -0
- django_program-0.1.0/src/django_program/programs/templates/django_program/programs/travel_grant_status.html +962 -0
- django_program-0.1.0/src/django_program/programs/urls.py +46 -0
- django_program-0.1.0/src/django_program/programs/views.py +606 -0
- django_program-0.1.0/src/django_program/py.typed +0 -0
- django_program-0.1.0/src/django_program/registration/__init__.py +1 -0
- django_program-0.1.0/src/django_program/registration/admin.py +215 -0
- django_program-0.1.0/src/django_program/registration/apps.py +12 -0
- django_program-0.1.0/src/django_program/registration/forms.py +56 -0
- django_program-0.1.0/src/django_program/registration/migrations/0001_initial.py +480 -0
- django_program-0.1.0/src/django_program/registration/migrations/0002_fix_cartitem_on_delete.py +35 -0
- django_program-0.1.0/src/django_program/registration/migrations/0003_stripeevent_payment_status_eventprocessingexception_and_more.py +99 -0
- django_program-0.1.0/src/django_program/registration/migrations/0004_cartitem_registration_cartitem_unique_ticket_per_cart_and_more.py +28 -0
- django_program-0.1.0/src/django_program/registration/migrations/0005_order_hold_expires_at_credit_remaining_amount.py +39 -0
- django_program-0.1.0/src/django_program/registration/migrations/__init__.py +0 -0
- django_program-0.1.0/src/django_program/registration/models.py +651 -0
- django_program-0.1.0/src/django_program/registration/services/__init__.py +1 -0
- django_program-0.1.0/src/django_program/registration/services/cart.py +730 -0
- django_program-0.1.0/src/django_program/registration/services/checkout.py +418 -0
- django_program-0.1.0/src/django_program/registration/services/payment.py +214 -0
- django_program-0.1.0/src/django_program/registration/services/refund.py +202 -0
- django_program-0.1.0/src/django_program/registration/signals.py +13 -0
- django_program-0.1.0/src/django_program/registration/stripe_client.py +200 -0
- django_program-0.1.0/src/django_program/registration/stripe_utils.py +101 -0
- django_program-0.1.0/src/django_program/registration/templates/django_program/emails/grant_decision.html +105 -0
- django_program-0.1.0/src/django_program/registration/templates/django_program/emails/order_confirmation.html +107 -0
- django_program-0.1.0/src/django_program/registration/templates/django_program/emails/order_refund.html +83 -0
- django_program-0.1.0/src/django_program/registration/templates/django_program/registration/cart.html +155 -0
- django_program-0.1.0/src/django_program/registration/templates/django_program/registration/checkout.html +92 -0
- django_program-0.1.0/src/django_program/registration/templates/django_program/registration/order_confirmation.html +68 -0
- django_program-0.1.0/src/django_program/registration/templates/django_program/registration/order_detail.html +122 -0
- django_program-0.1.0/src/django_program/registration/templates/django_program/registration/ticket_select.html +72 -0
- django_program-0.1.0/src/django_program/registration/templatetags/__init__.py +1 -0
- django_program-0.1.0/src/django_program/registration/templatetags/registration_tags.py +126 -0
- django_program-0.1.0/src/django_program/registration/templatetags/stripe_tags.py +29 -0
- django_program-0.1.0/src/django_program/registration/urls.py +35 -0
- django_program-0.1.0/src/django_program/registration/views.py +744 -0
- django_program-0.1.0/src/django_program/registration/webhooks.py +483 -0
- django_program-0.1.0/src/django_program/settings.py +145 -0
- django_program-0.1.0/src/django_program/sponsors/__init__.py +1 -0
- django_program-0.1.0/src/django_program/sponsors/admin.py +32 -0
- django_program-0.1.0/src/django_program/sponsors/apps.py +16 -0
- django_program-0.1.0/src/django_program/sponsors/management/__init__.py +1 -0
- django_program-0.1.0/src/django_program/sponsors/management/commands/__init__.py +1 -0
- django_program-0.1.0/src/django_program/sponsors/management/commands/sync_sponsors.py +57 -0
- django_program-0.1.0/src/django_program/sponsors/migrations/0001_initial.py +151 -0
- django_program-0.1.0/src/django_program/sponsors/migrations/0002_alter_sponsor_slug_alter_sponsorlevel_slug.py +22 -0
- django_program-0.1.0/src/django_program/sponsors/migrations/0003_add_external_id_and_logo_url.py +31 -0
- django_program-0.1.0/src/django_program/sponsors/migrations/__init__.py +0 -0
- django_program-0.1.0/src/django_program/sponsors/models.py +136 -0
- django_program-0.1.0/src/django_program/sponsors/profiles/__init__.py +13 -0
- django_program-0.1.0/src/django_program/sponsors/profiles/base.py +22 -0
- django_program-0.1.0/src/django_program/sponsors/profiles/default.py +10 -0
- django_program-0.1.0/src/django_program/sponsors/profiles/pyconus.py +15 -0
- django_program-0.1.0/src/django_program/sponsors/profiles/resolver.py +28 -0
- django_program-0.1.0/src/django_program/sponsors/signals.py +53 -0
- django_program-0.1.0/src/django_program/sponsors/sync.py +210 -0
- django_program-0.1.0/src/django_program/sponsors/templates/django_program/sponsors/sponsor_detail.html +33 -0
- django_program-0.1.0/src/django_program/sponsors/templates/django_program/sponsors/sponsor_list.html +30 -0
- django_program-0.1.0/src/django_program/sponsors/templatetags/__init__.py +1 -0
- django_program-0.1.0/src/django_program/sponsors/templatetags/sponsor_tags.py +89 -0
- django_program-0.1.0/src/django_program/sponsors/urls.py +20 -0
- django_program-0.1.0/src/django_program/sponsors/views.py +82 -0
- django_program-0.1.0/src/django_program/templates/django_program/base.html +585 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: django-program
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Modern conference management plugin for Django
|
|
5
|
+
Keywords: django,conference,registration,program,schedule,tickets
|
|
6
|
+
Author: Jacob Coffee
|
|
7
|
+
Author-email: Jacob Coffee <jacob@python.org>
|
|
8
|
+
License: MIT
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Environment :: Web Environment
|
|
11
|
+
Classifier: Framework :: Django
|
|
12
|
+
Classifier: Framework :: Django :: 5.2
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
18
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
19
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
20
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Requires-Dist: django>=5.2
|
|
23
|
+
Requires-Dist: django-fernet-encrypted-fields>=0.3.1
|
|
24
|
+
Requires-Dist: pillow>=12.1.1
|
|
25
|
+
Requires-Dist: pretalx-client>=0.1.0
|
|
26
|
+
Requires-Dist: stripe>=12.0.0
|
|
27
|
+
Requires-Python: >=3.14
|
|
28
|
+
Project-URL: Changelog, https://github.com/JacobCoffee/django-program/releases/
|
|
29
|
+
Project-URL: Documentation, https://jacobcoffee.github.io/django-program
|
|
30
|
+
Project-URL: Issue Tracker, https://github.com/JacobCoffee/django-program/issues
|
|
31
|
+
Project-URL: Repository, https://github.com/JacobCoffee/django-program
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
|
|
34
|
+
An attempt to modernize the conference workflow.
|
|
35
|
+
|
|
36
|
+
Inspirations
|
|
37
|
+
- [Symposion](https://github.com/pinax/symposion)
|
|
38
|
+
- [Registrasion](https://github.com/chrisjrn/registrasion)
|
|
39
|
+
|
|
40
|
+
## Example Dev Server
|
|
41
|
+
|
|
42
|
+
A runnable Django project lives in `examples/` for interacting with models via the admin, shell, and management commands.
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
make dev
|
|
46
|
+
# Visit http://localhost:8000/admin/ (login: admin/admin)
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Or step by step:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
uv run python examples/manage.py migrate
|
|
53
|
+
uv run python examples/manage.py bootstrap_conference --config conference.example.toml
|
|
54
|
+
uv run python examples/manage.py createsuperuser
|
|
55
|
+
uv run python examples/manage.py runserver
|
|
56
|
+
```
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
An attempt to modernize the conference workflow.
|
|
2
|
+
|
|
3
|
+
Inspirations
|
|
4
|
+
- [Symposion](https://github.com/pinax/symposion)
|
|
5
|
+
- [Registrasion](https://github.com/chrisjrn/registrasion)
|
|
6
|
+
|
|
7
|
+
## Example Dev Server
|
|
8
|
+
|
|
9
|
+
A runnable Django project lives in `examples/` for interacting with models via the admin, shell, and management commands.
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
make dev
|
|
13
|
+
# Visit http://localhost:8000/admin/ (login: admin/admin)
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Or step by step:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
uv run python examples/manage.py migrate
|
|
20
|
+
uv run python examples/manage.py bootstrap_conference --config conference.example.toml
|
|
21
|
+
uv run python examples/manage.py createsuperuser
|
|
22
|
+
uv run python examples/manage.py runserver
|
|
23
|
+
```
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
build-backend = "uv_build"
|
|
3
|
+
requires = ["uv_build>=0.9.11,<0.11.0"]
|
|
4
|
+
|
|
5
|
+
[dependency-groups]
|
|
6
|
+
docs = [
|
|
7
|
+
"linkify-it-py>=2.0.0",
|
|
8
|
+
"myst-parser>=2.0.0",
|
|
9
|
+
"shibuya>=2024.8.0",
|
|
10
|
+
"sphinx>=7.0.0",
|
|
11
|
+
"sphinx-autobuild>=2024.0.0",
|
|
12
|
+
"sphinx-autodoc-typehints>=2.0.0",
|
|
13
|
+
"sphinx-copybutton>=0.5.0",
|
|
14
|
+
"sphinx-design>=0.5.0",
|
|
15
|
+
]
|
|
16
|
+
lint = ["codespell>=2.2.6", "prek>=0.2.18", "ruff>=0.8.0", "ty>=0.0.1a27"]
|
|
17
|
+
test = [
|
|
18
|
+
"model-bakery>=1.20.0",
|
|
19
|
+
"pytest>=8.1.1",
|
|
20
|
+
"pytest-cov>=4.1.0",
|
|
21
|
+
"pytest-django>=4.9.0",
|
|
22
|
+
"pytest-sugar>=1.1.1",
|
|
23
|
+
"pytest-xdist>=3.8.0",
|
|
24
|
+
]
|
|
25
|
+
dev = [
|
|
26
|
+
{ include-group = "docs" },
|
|
27
|
+
{ include-group = "lint" },
|
|
28
|
+
{ include-group = "test" },
|
|
29
|
+
"python-dotenv>=1.2.1",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[project]
|
|
33
|
+
authors = [{ name = "Jacob Coffee", email = "jacob@python.org" }]
|
|
34
|
+
classifiers = [
|
|
35
|
+
"Development Status :: 3 - Alpha",
|
|
36
|
+
"Environment :: Web Environment",
|
|
37
|
+
"Framework :: Django",
|
|
38
|
+
"Framework :: Django :: 5.2",
|
|
39
|
+
"Intended Audience :: Developers",
|
|
40
|
+
"License :: OSI Approved :: MIT License",
|
|
41
|
+
"Operating System :: OS Independent",
|
|
42
|
+
"Programming Language :: Python",
|
|
43
|
+
"Programming Language :: Python :: 3.14",
|
|
44
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
45
|
+
"Topic :: Internet :: WWW/HTTP",
|
|
46
|
+
"Topic :: Internet :: WWW/HTTP :: Dynamic Content",
|
|
47
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
48
|
+
]
|
|
49
|
+
dependencies = [
|
|
50
|
+
"django>=5.2",
|
|
51
|
+
"django-fernet-encrypted-fields>=0.3.1",
|
|
52
|
+
"pillow>=12.1.1",
|
|
53
|
+
"pretalx-client>=0.1.0",
|
|
54
|
+
"stripe>=12.0.0",
|
|
55
|
+
]
|
|
56
|
+
description = "Modern conference management plugin for Django"
|
|
57
|
+
keywords = [
|
|
58
|
+
"django",
|
|
59
|
+
"conference",
|
|
60
|
+
"registration",
|
|
61
|
+
"program",
|
|
62
|
+
"schedule",
|
|
63
|
+
"tickets",
|
|
64
|
+
]
|
|
65
|
+
license = { text = "MIT" }
|
|
66
|
+
name = "django-program"
|
|
67
|
+
readme = "README.md"
|
|
68
|
+
requires-python = ">=3.14"
|
|
69
|
+
version = "0.1.0"
|
|
70
|
+
|
|
71
|
+
[project.urls]
|
|
72
|
+
Changelog = "https://github.com/JacobCoffee/django-program/releases/"
|
|
73
|
+
Documentation = "https://jacobcoffee.github.io/django-program"
|
|
74
|
+
"Issue Tracker" = "https://github.com/JacobCoffee/django-program/issues"
|
|
75
|
+
Repository = "https://github.com/JacobCoffee/django-program"
|
|
76
|
+
|
|
77
|
+
[tool.codespell]
|
|
78
|
+
skip = "uv.lock"
|
|
79
|
+
|
|
80
|
+
[tool.coverage.report]
|
|
81
|
+
exclude_lines = [
|
|
82
|
+
"pragma: no cover",
|
|
83
|
+
"if TYPE_CHECKING:",
|
|
84
|
+
"raise NotImplementedError",
|
|
85
|
+
"\\.\\.\\.",
|
|
86
|
+
"@abstractmethod",
|
|
87
|
+
"class .*(Protocol):",
|
|
88
|
+
]
|
|
89
|
+
fail_under = 100
|
|
90
|
+
|
|
91
|
+
[tool.coverage.run]
|
|
92
|
+
concurrency = ["multiprocessing", "thread"]
|
|
93
|
+
omit = ["*/tests/*"]
|
|
94
|
+
parallel = true
|
|
95
|
+
source = ["django_program"]
|
|
96
|
+
|
|
97
|
+
[tool.git-cliff.changelog]
|
|
98
|
+
header = """
|
|
99
|
+
# Changelog
|
|
100
|
+
|
|
101
|
+
All notable changes to this project will be documented in this file.
|
|
102
|
+
|
|
103
|
+
"""
|
|
104
|
+
body = """
|
|
105
|
+
{% if version %}\
|
|
106
|
+
{% if previous.version %}\
|
|
107
|
+
## [{{ version | trim_start_matches(pat="v") }}]($REPO/compare/{{ previous.version }}..{{ version }}) - {{ timestamp | date(format="%Y-%m-%d") }}
|
|
108
|
+
{% else %}\
|
|
109
|
+
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
|
|
110
|
+
{% endif %}\
|
|
111
|
+
{% else %}\
|
|
112
|
+
## [unreleased]
|
|
113
|
+
{% endif %}\
|
|
114
|
+
{% for group, commits in commits | group_by(attribute="group") %}
|
|
115
|
+
|
|
116
|
+
### {{ group | striptags | trim | upper_first }}
|
|
117
|
+
|
|
118
|
+
{% for commit in commits
|
|
119
|
+
| filter(attribute="scope")
|
|
120
|
+
| sort(attribute="scope") %}
|
|
121
|
+
- **({{commit.scope}})**{% if commit.breaking %} [**breaking**]{% endif %} {{ commit.message }} - ([{{ commit.id | truncate(length=7, end="") }}]($REPO/commit/{{ commit.id }})) - {{ commit.author.name }}
|
|
122
|
+
{%- endfor -%}
|
|
123
|
+
{%- for commit in commits %}
|
|
124
|
+
{%- if commit.scope -%}
|
|
125
|
+
{% else %}
|
|
126
|
+
- {% if commit.breaking %}[**breaking**] {% endif %}{{ commit.message }} - ([{{ commit.id | truncate(length=7, end="") }}]($REPO/commit/{{ commit.id }})) - {{ commit.author.name }}
|
|
127
|
+
{% endif -%}
|
|
128
|
+
{% endfor -%}
|
|
129
|
+
{% endfor %}
|
|
130
|
+
"""
|
|
131
|
+
footer = """
|
|
132
|
+
---
|
|
133
|
+
*django-program Changelog*
|
|
134
|
+
"""
|
|
135
|
+
output = "docs/changelog.md"
|
|
136
|
+
postprocessors = [
|
|
137
|
+
{ pattern = '\$REPO', replace = "https://github.com/JacobCoffee/django-program" },
|
|
138
|
+
]
|
|
139
|
+
trim = true
|
|
140
|
+
|
|
141
|
+
[tool.git-cliff.git]
|
|
142
|
+
commit_parsers = [
|
|
143
|
+
{ message = "^feat", group = "Features" },
|
|
144
|
+
{ message = "^fix", group = "Bug Fixes" },
|
|
145
|
+
{ message = "^doc", group = "Documentation" },
|
|
146
|
+
{ message = "^perf", group = "Performance" },
|
|
147
|
+
{ message = "^refactor", group = "Refactoring" },
|
|
148
|
+
{ message = "^style", group = "Style" },
|
|
149
|
+
{ message = "^revert", group = "Revert" },
|
|
150
|
+
{ message = "^test", group = "Tests" },
|
|
151
|
+
{ message = "^chore\\(version\\):", skip = true },
|
|
152
|
+
{ message = "^chore", group = "Miscellaneous Chores" },
|
|
153
|
+
{ body = ".*security", group = "Security" },
|
|
154
|
+
]
|
|
155
|
+
conventional_commits = true
|
|
156
|
+
filter_unconventional = true
|
|
157
|
+
sort_commits = "oldest"
|
|
158
|
+
tag_pattern = "v[0-9].*"
|
|
159
|
+
|
|
160
|
+
[tool.pytest.ini_options]
|
|
161
|
+
addopts = [
|
|
162
|
+
"--strict-markers",
|
|
163
|
+
"--tb=short",
|
|
164
|
+
"-n", "auto",
|
|
165
|
+
"-p", "no:pastebin",
|
|
166
|
+
"-p", "no:doctest",
|
|
167
|
+
"-p", "no:legacypath",
|
|
168
|
+
]
|
|
169
|
+
DJANGO_SETTINGS_MODULE = "tests.settings"
|
|
170
|
+
filterwarnings = [
|
|
171
|
+
"error",
|
|
172
|
+
"ignore:The default scheme will be changed:DeprecationWarning",
|
|
173
|
+
]
|
|
174
|
+
markers = [
|
|
175
|
+
"unit: mark test as unit test",
|
|
176
|
+
"integration: mark test as integration test",
|
|
177
|
+
"e2e: mark test as end-to-end test",
|
|
178
|
+
]
|
|
179
|
+
norecursedirs = ["docs", "*.egg-info", ".git", ".tox", "dist", "build", "refcode", "examples"]
|
|
180
|
+
python_classes = ["Test*"]
|
|
181
|
+
python_files = ["test_*.py"]
|
|
182
|
+
python_functions = ["test_*"]
|
|
183
|
+
pythonpath = ["."]
|
|
184
|
+
testpaths = ["tests"]
|
|
185
|
+
|
|
186
|
+
[tool.ruff]
|
|
187
|
+
exclude = ["refcode/"]
|
|
188
|
+
fix = true
|
|
189
|
+
line-length = 120
|
|
190
|
+
src = ["src/django_program", "tests", "packages/pretalx-client/src/pretalx_client"]
|
|
191
|
+
target-version = "py314"
|
|
192
|
+
|
|
193
|
+
[tool.ruff.format]
|
|
194
|
+
docstring-code-format = true
|
|
195
|
+
docstring-code-line-length = 88
|
|
196
|
+
indent-style = "space"
|
|
197
|
+
quote-style = "double"
|
|
198
|
+
|
|
199
|
+
[tool.ruff.lint]
|
|
200
|
+
fixable = ["ALL"]
|
|
201
|
+
ignore = [
|
|
202
|
+
"COM812", # Missing trailing comma (conflicts with formatter)
|
|
203
|
+
"ISC001", # Single-line string concatenation (conflicts with formatter)
|
|
204
|
+
"ERA001", # Commented-out code
|
|
205
|
+
"TD", # TODOs
|
|
206
|
+
"FIX002", # Line contains TODO
|
|
207
|
+
"EM101", # Exception string literal
|
|
208
|
+
"EM102", # Exception f-string literal
|
|
209
|
+
"TRY003", # Long exception message
|
|
210
|
+
"RUF012", # Mutable class attributes (Django uses these extensively)
|
|
211
|
+
"D105", # Missing docstring in magic method (__str__ etc.)
|
|
212
|
+
"D106", # Missing docstring in public nested class (Django Meta)
|
|
213
|
+
"DJ001", # Avoid using null=True on string fields (not always applicable)
|
|
214
|
+
]
|
|
215
|
+
select = ["ALL"]
|
|
216
|
+
|
|
217
|
+
[tool.ruff.lint.isort]
|
|
218
|
+
known-first-party = ["django_program", "pretalx_client", "tests"]
|
|
219
|
+
|
|
220
|
+
[tool.ruff.lint.per-file-ignores]
|
|
221
|
+
"**/migrations/**/*.*" = [
|
|
222
|
+
"ANN", # Type annotations
|
|
223
|
+
"D", # Docstrings
|
|
224
|
+
"E501", # Line too long (auto-generated)
|
|
225
|
+
"INP001", # Implicit namespace package
|
|
226
|
+
]
|
|
227
|
+
"**/management/**/*.*" = [
|
|
228
|
+
"ANN401", # Any in management command signatures (Django convention)
|
|
229
|
+
"ARG002", # Unused *args in handle() (Django convention)
|
|
230
|
+
"N806", # User = get_user_model() (Django convention)
|
|
231
|
+
"PLR2004", # Magic values in verbosity checks
|
|
232
|
+
]
|
|
233
|
+
"docs/conf.py" = [
|
|
234
|
+
"A001", # Variable shadowing builtin
|
|
235
|
+
"INP001", # Implicit namespace package
|
|
236
|
+
"PTH", # Use pathlib
|
|
237
|
+
"DTZ", # Datetime timezone
|
|
238
|
+
]
|
|
239
|
+
"examples/**/*.*" = [
|
|
240
|
+
"INP001", # Implicit namespace package (standalone Django project)
|
|
241
|
+
"PLC0415", # Import not at top level (Django manage.py pattern)
|
|
242
|
+
"S105", # Hardcoded secret key (dev-only)
|
|
243
|
+
]
|
|
244
|
+
"scripts/**/*.*" = [
|
|
245
|
+
"D", # Docstrings (utility scripts)
|
|
246
|
+
"INP001", # Implicit namespace package
|
|
247
|
+
"S", # Security (local dev scripts)
|
|
248
|
+
"T201", # Print statements (CLI scripts)
|
|
249
|
+
"ANN", # Type annotations (utility scripts)
|
|
250
|
+
"C901", # Complexity (codegen functions are inherently complex)
|
|
251
|
+
"PLR0912", # Too many branches (codegen)
|
|
252
|
+
"PLR0915", # Too many statements (codegen)
|
|
253
|
+
]
|
|
254
|
+
"packages/**/tests/**/*.*" = [
|
|
255
|
+
"A",
|
|
256
|
+
"ANN",
|
|
257
|
+
"ARG",
|
|
258
|
+
"B",
|
|
259
|
+
"BLE",
|
|
260
|
+
"C901",
|
|
261
|
+
"D",
|
|
262
|
+
"DTZ",
|
|
263
|
+
"EM",
|
|
264
|
+
"ERA001",
|
|
265
|
+
"F841",
|
|
266
|
+
"FBT",
|
|
267
|
+
"G",
|
|
268
|
+
"N",
|
|
269
|
+
"PGH",
|
|
270
|
+
"PIE",
|
|
271
|
+
"PLR",
|
|
272
|
+
"PLW",
|
|
273
|
+
"PTH",
|
|
274
|
+
"RET504",
|
|
275
|
+
"RSE",
|
|
276
|
+
"S",
|
|
277
|
+
"S101",
|
|
278
|
+
"SIM",
|
|
279
|
+
"SLF001",
|
|
280
|
+
"TCH",
|
|
281
|
+
"TRY",
|
|
282
|
+
"UP006",
|
|
283
|
+
]
|
|
284
|
+
"tests/**/*.*" = [
|
|
285
|
+
"A",
|
|
286
|
+
"ANN",
|
|
287
|
+
"ARG",
|
|
288
|
+
"B",
|
|
289
|
+
"BLE",
|
|
290
|
+
"C901",
|
|
291
|
+
"D",
|
|
292
|
+
"DTZ",
|
|
293
|
+
"EM",
|
|
294
|
+
"ERA001",
|
|
295
|
+
"F841",
|
|
296
|
+
"FBT",
|
|
297
|
+
"G",
|
|
298
|
+
"N",
|
|
299
|
+
"PGH",
|
|
300
|
+
"PIE",
|
|
301
|
+
"PLR",
|
|
302
|
+
"PLW",
|
|
303
|
+
"PTH",
|
|
304
|
+
"RET504",
|
|
305
|
+
"RSE",
|
|
306
|
+
"S",
|
|
307
|
+
"S101",
|
|
308
|
+
"SIM",
|
|
309
|
+
"SLF001",
|
|
310
|
+
"TCH",
|
|
311
|
+
"TRY",
|
|
312
|
+
"UP006",
|
|
313
|
+
]
|
|
314
|
+
|
|
315
|
+
[tool.ruff.lint.pydocstyle]
|
|
316
|
+
convention = "google"
|
|
317
|
+
|
|
318
|
+
[tool.ty]
|
|
319
|
+
|
|
320
|
+
[tool.ty.environment]
|
|
321
|
+
python = ".venv"
|
|
322
|
+
|
|
323
|
+
[tool.ty.rules]
|
|
324
|
+
deprecated = "warn"
|
|
325
|
+
# Django's ORM dynamically adds .objects, so ty can't resolve it
|
|
326
|
+
unresolved-attribute = "warn"
|
|
327
|
+
# Django field types (CharField etc.) don't resolve to Python builtins
|
|
328
|
+
invalid-return-type = "warn"
|
|
329
|
+
# Django field descriptors don't implement SupportsInt/SupportsIndex protocols
|
|
330
|
+
unsupported-operator = "warn"
|
|
331
|
+
invalid-argument-type = "warn"
|
|
332
|
+
|
|
333
|
+
[tool.ty.src]
|
|
334
|
+
exclude = ["docs/conf.py", "tests/", "refcode/", "packages/*/tests/", "scripts/"]
|
|
335
|
+
|
|
336
|
+
[tool.uv]
|
|
337
|
+
default-groups = ["dev"]
|
|
338
|
+
constraint-dependencies = ["django>=5.2,<5.3"]
|
|
339
|
+
|
|
340
|
+
[tool.uv.sources]
|
|
341
|
+
pretalx-client = { workspace = true }
|
|
342
|
+
|
|
343
|
+
[tool.uv.workspace]
|
|
344
|
+
members = ["packages/*"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Conference and section management for django-program."""
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"""Django admin configuration for the conference app."""
|
|
2
|
+
|
|
3
|
+
from django import forms
|
|
4
|
+
from django.contrib import admin
|
|
5
|
+
|
|
6
|
+
from django_program.conference.models import Conference, Section
|
|
7
|
+
|
|
8
|
+
SECRET_PLACEHOLDER = "\u2022" * 12
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class SecretInput(forms.PasswordInput):
|
|
12
|
+
"""Password widget that shows a placeholder instead of the real value.
|
|
13
|
+
|
|
14
|
+
When a value already exists in the database the widget renders
|
|
15
|
+
``SECRET_PLACEHOLDER`` as the visible value so admins know a key is
|
|
16
|
+
set, but the actual secret never appears in the HTML source. Submitting
|
|
17
|
+
the placeholder (or an empty string) signals "keep existing value".
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def format_value(self, value: str | None) -> str:
|
|
21
|
+
"""Return a dot placeholder when a value exists, empty string otherwise."""
|
|
22
|
+
if value:
|
|
23
|
+
return SECRET_PLACEHOLDER
|
|
24
|
+
return ""
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class SecretField(forms.CharField):
|
|
28
|
+
"""Char field that preserves the stored value when left unchanged.
|
|
29
|
+
|
|
30
|
+
Works with ``SecretInput``: if the submitted value is empty or equals
|
|
31
|
+
the placeholder, the field returns the original database value so
|
|
32
|
+
secrets are never accidentally blanked.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
widget = SecretInput
|
|
36
|
+
|
|
37
|
+
def __init__(self, **kwargs: object) -> None:
|
|
38
|
+
"""Set sensible defaults for secret fields."""
|
|
39
|
+
kwargs.setdefault("required", False)
|
|
40
|
+
super().__init__(**kwargs)
|
|
41
|
+
self.widget.attrs.setdefault("autocomplete", "off")
|
|
42
|
+
|
|
43
|
+
def has_changed(self, initial: str | None, data: str | None) -> bool:
|
|
44
|
+
"""Treat placeholder or blank submissions as unchanged."""
|
|
45
|
+
if not data or data == SECRET_PLACEHOLDER:
|
|
46
|
+
return False
|
|
47
|
+
return super().has_changed(initial, data)
|
|
48
|
+
|
|
49
|
+
def clean(self, value: str | None) -> str | None:
|
|
50
|
+
"""Return the stored value when the field is left blank or unchanged."""
|
|
51
|
+
if not value or value == SECRET_PLACEHOLDER:
|
|
52
|
+
return self.initial
|
|
53
|
+
return super().clean(value)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
_STRIPE_FIELDS = ("stripe_secret_key", "stripe_publishable_key", "stripe_webhook_secret")
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class ConferenceForm(forms.ModelForm):
|
|
60
|
+
"""Custom form that masks Stripe secret fields in the admin.
|
|
61
|
+
|
|
62
|
+
Uses ``SecretField`` / ``SecretInput`` so decrypted values are never
|
|
63
|
+
present in the rendered HTML. Admins see a dot placeholder when a
|
|
64
|
+
value is set; leaving the field unchanged preserves the stored secret.
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
stripe_secret_key = SecretField()
|
|
68
|
+
stripe_publishable_key = SecretField()
|
|
69
|
+
stripe_webhook_secret = SecretField()
|
|
70
|
+
|
|
71
|
+
class Meta:
|
|
72
|
+
model = Conference
|
|
73
|
+
exclude: list[str] = []
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class SectionInline(admin.TabularInline):
|
|
77
|
+
"""Inline editor for conference sections.
|
|
78
|
+
|
|
79
|
+
Allows adding and editing sections directly from the conference
|
|
80
|
+
admin change form.
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
model = Section
|
|
84
|
+
extra = 1
|
|
85
|
+
prepopulated_fields = {"slug": ("name",)}
|
|
86
|
+
fields = ("name", "slug", "start_date", "end_date", "order")
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@admin.register(Conference)
|
|
90
|
+
class ConferenceAdmin(admin.ModelAdmin):
|
|
91
|
+
"""Admin interface for managing conferences.
|
|
92
|
+
|
|
93
|
+
Groups fields into logical fieldsets: basic information, dates,
|
|
94
|
+
third-party integrations (Pretalx and Stripe), and status metadata.
|
|
95
|
+
Sections are editable inline via ``SectionInline``.
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
form = ConferenceForm
|
|
99
|
+
list_display = ("name", "slug", "start_date", "end_date", "is_active")
|
|
100
|
+
list_filter = ("is_active",)
|
|
101
|
+
search_fields = ("name", "slug")
|
|
102
|
+
prepopulated_fields = {"slug": ("name",)}
|
|
103
|
+
inlines = (SectionInline,)
|
|
104
|
+
|
|
105
|
+
fieldsets = (
|
|
106
|
+
(
|
|
107
|
+
None,
|
|
108
|
+
{
|
|
109
|
+
"fields": ("name", "slug", "venue", "address", "website_url"),
|
|
110
|
+
},
|
|
111
|
+
),
|
|
112
|
+
(
|
|
113
|
+
"Dates",
|
|
114
|
+
{
|
|
115
|
+
"fields": ("start_date", "end_date", "timezone"),
|
|
116
|
+
},
|
|
117
|
+
),
|
|
118
|
+
(
|
|
119
|
+
"Integrations",
|
|
120
|
+
{
|
|
121
|
+
"fields": (
|
|
122
|
+
"pretalx_event_slug",
|
|
123
|
+
"stripe_secret_key",
|
|
124
|
+
"stripe_publishable_key",
|
|
125
|
+
"stripe_webhook_secret",
|
|
126
|
+
),
|
|
127
|
+
"classes": ("collapse",),
|
|
128
|
+
},
|
|
129
|
+
),
|
|
130
|
+
(
|
|
131
|
+
"Status",
|
|
132
|
+
{
|
|
133
|
+
"fields": ("is_active",),
|
|
134
|
+
},
|
|
135
|
+
),
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
@admin.register(Section)
|
|
140
|
+
class SectionAdmin(admin.ModelAdmin):
|
|
141
|
+
"""Admin interface for managing conference sections.
|
|
142
|
+
|
|
143
|
+
Provides filtering by conference and search by name or slug.
|
|
144
|
+
The slug field is auto-populated from the section name.
|
|
145
|
+
"""
|
|
146
|
+
|
|
147
|
+
list_display = ("name", "conference", "start_date", "end_date", "order")
|
|
148
|
+
list_filter = ("conference",)
|
|
149
|
+
search_fields = ("name", "slug")
|
|
150
|
+
prepopulated_fields = {"slug": ("name",)}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""Django app configuration for the conference app."""
|
|
2
|
+
|
|
3
|
+
from django.apps import AppConfig
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class DjangoProgramConferenceConfig(AppConfig):
|
|
7
|
+
"""Configuration for the conference app."""
|
|
8
|
+
|
|
9
|
+
default_auto_field = "django.db.models.BigAutoField"
|
|
10
|
+
name = "django_program.conference"
|
|
11
|
+
label = "program_conference"
|
|
12
|
+
verbose_name = "Conference"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Management commands for the conference app."""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Conference management commands."""
|