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.
Files changed (168) hide show
  1. django_program-0.1.0/PKG-INFO +56 -0
  2. django_program-0.1.0/README.md +23 -0
  3. django_program-0.1.0/pyproject.toml +344 -0
  4. django_program-0.1.0/src/django_program/__init__.py +5 -0
  5. django_program-0.1.0/src/django_program/__metadata__.py +3 -0
  6. django_program-0.1.0/src/django_program/conference/__init__.py +1 -0
  7. django_program-0.1.0/src/django_program/conference/admin.py +150 -0
  8. django_program-0.1.0/src/django_program/conference/apps.py +12 -0
  9. django_program-0.1.0/src/django_program/conference/management/__init__.py +1 -0
  10. django_program-0.1.0/src/django_program/conference/management/commands/__init__.py +1 -0
  11. django_program-0.1.0/src/django_program/conference/management/commands/bootstrap_conference.py +989 -0
  12. django_program-0.1.0/src/django_program/conference/management/commands/setup_groups.py +144 -0
  13. django_program-0.1.0/src/django_program/conference/migrations/0001_initial.py +59 -0
  14. django_program-0.1.0/src/django_program/conference/migrations/0002_encrypt_stripe_fields.py +28 -0
  15. django_program-0.1.0/src/django_program/conference/migrations/0003_conference_address.py +15 -0
  16. django_program-0.1.0/src/django_program/conference/migrations/__init__.py +0 -0
  17. django_program-0.1.0/src/django_program/conference/models.py +64 -0
  18. django_program-0.1.0/src/django_program/config_loader.py +168 -0
  19. django_program-0.1.0/src/django_program/manage/__init__.py +1 -0
  20. django_program-0.1.0/src/django_program/manage/apps.py +12 -0
  21. django_program-0.1.0/src/django_program/manage/forms.py +489 -0
  22. django_program-0.1.0/src/django_program/manage/templates/django_program/manage/_pagination.html +11 -0
  23. django_program-0.1.0/src/django_program/manage/templates/django_program/manage/activity_dashboard.html +118 -0
  24. django_program-0.1.0/src/django_program/manage/templates/django_program/manage/activity_edit.html +136 -0
  25. django_program-0.1.0/src/django_program/manage/templates/django_program/manage/activity_list.html +63 -0
  26. django_program-0.1.0/src/django_program/manage/templates/django_program/manage/addon_edit.html +45 -0
  27. django_program-0.1.0/src/django_program/manage/templates/django_program/manage/addon_list.html +54 -0
  28. django_program-0.1.0/src/django_program/manage/templates/django_program/manage/base.html +1134 -0
  29. django_program-0.1.0/src/django_program/manage/templates/django_program/manage/conference_edit.html +161 -0
  30. django_program-0.1.0/src/django_program/manage/templates/django_program/manage/conference_list.html +41 -0
  31. django_program-0.1.0/src/django_program/manage/templates/django_program/manage/dashboard.html +480 -0
  32. django_program-0.1.0/src/django_program/manage/templates/django_program/manage/import_pretalx.html +662 -0
  33. django_program-0.1.0/src/django_program/manage/templates/django_program/manage/order_detail.html +219 -0
  34. django_program-0.1.0/src/django_program/manage/templates/django_program/manage/order_list.html +79 -0
  35. django_program-0.1.0/src/django_program/manage/templates/django_program/manage/receipt_review.html +98 -0
  36. django_program-0.1.0/src/django_program/manage/templates/django_program/manage/room_edit.html +58 -0
  37. django_program-0.1.0/src/django_program/manage/templates/django_program/manage/room_list.html +51 -0
  38. django_program-0.1.0/src/django_program/manage/templates/django_program/manage/schedule_list.html +215 -0
  39. django_program-0.1.0/src/django_program/manage/templates/django_program/manage/section_edit.html +45 -0
  40. django_program-0.1.0/src/django_program/manage/templates/django_program/manage/section_list.html +47 -0
  41. django_program-0.1.0/src/django_program/manage/templates/django_program/manage/slot_edit.html +67 -0
  42. django_program-0.1.0/src/django_program/manage/templates/django_program/manage/speaker_detail.html +367 -0
  43. django_program-0.1.0/src/django_program/manage/templates/django_program/manage/speaker_list.html +58 -0
  44. django_program-0.1.0/src/django_program/manage/templates/django_program/manage/sponsor_edit.html +84 -0
  45. django_program-0.1.0/src/django_program/manage/templates/django_program/manage/sponsor_level_edit.html +45 -0
  46. django_program-0.1.0/src/django_program/manage/templates/django_program/manage/sponsor_level_list.html +50 -0
  47. django_program-0.1.0/src/django_program/manage/templates/django_program/manage/sponsor_list.html +52 -0
  48. django_program-0.1.0/src/django_program/manage/templates/django_program/manage/talk_detail.html +118 -0
  49. django_program-0.1.0/src/django_program/manage/templates/django_program/manage/talk_edit.html +71 -0
  50. django_program-0.1.0/src/django_program/manage/templates/django_program/manage/talk_list.html +93 -0
  51. django_program-0.1.0/src/django_program/manage/templates/django_program/manage/ticket_type_edit.html +45 -0
  52. django_program-0.1.0/src/django_program/manage/templates/django_program/manage/ticket_type_list.html +62 -0
  53. django_program-0.1.0/src/django_program/manage/templates/django_program/manage/travel_grant_edit.html +313 -0
  54. django_program-0.1.0/src/django_program/manage/templates/django_program/manage/travel_grant_list.html +152 -0
  55. django_program-0.1.0/src/django_program/manage/templates/django_program/manage/voucher_edit.html +45 -0
  56. django_program-0.1.0/src/django_program/manage/templates/django_program/manage/voucher_list.html +70 -0
  57. django_program-0.1.0/src/django_program/manage/urls.py +198 -0
  58. django_program-0.1.0/src/django_program/manage/views.py +2783 -0
  59. django_program-0.1.0/src/django_program/pretalx/__init__.py +1 -0
  60. django_program-0.1.0/src/django_program/pretalx/admin.py +68 -0
  61. django_program-0.1.0/src/django_program/pretalx/apps.py +12 -0
  62. django_program-0.1.0/src/django_program/pretalx/management/__init__.py +1 -0
  63. django_program-0.1.0/src/django_program/pretalx/management/commands/__init__.py +1 -0
  64. django_program-0.1.0/src/django_program/pretalx/management/commands/sync_pretalx.py +141 -0
  65. django_program-0.1.0/src/django_program/pretalx/migrations/0001_initial.py +127 -0
  66. django_program-0.1.0/src/django_program/pretalx/migrations/0002_room_alter_scheduleslot_room_alter_talk_room.py +62 -0
  67. django_program-0.1.0/src/django_program/pretalx/migrations/0003_add_scheduleslot_unique_constraint.py +20 -0
  68. django_program-0.1.0/src/django_program/pretalx/migrations/0004_talk_tags.py +15 -0
  69. django_program-0.1.0/src/django_program/pretalx/migrations/0005_alter_room_unique_together_alter_room_pretalx_id_and_more.py +30 -0
  70. django_program-0.1.0/src/django_program/pretalx/migrations/__init__.py +0 -0
  71. django_program-0.1.0/src/django_program/pretalx/models.py +190 -0
  72. django_program-0.1.0/src/django_program/pretalx/profiles/__init__.py +13 -0
  73. django_program-0.1.0/src/django_program/pretalx/profiles/base.py +20 -0
  74. django_program-0.1.0/src/django_program/pretalx/profiles/default.py +9 -0
  75. django_program-0.1.0/src/django_program/pretalx/profiles/pyconus.py +26 -0
  76. django_program-0.1.0/src/django_program/pretalx/profiles/resolver.py +20 -0
  77. django_program-0.1.0/src/django_program/pretalx/sync.py +752 -0
  78. django_program-0.1.0/src/django_program/pretalx/templates/django_program/pretalx/base.html +578 -0
  79. django_program-0.1.0/src/django_program/pretalx/templates/django_program/pretalx/schedule.html +70 -0
  80. django_program-0.1.0/src/django_program/pretalx/templates/django_program/pretalx/speaker_detail.html +39 -0
  81. django_program-0.1.0/src/django_program/pretalx/templates/django_program/pretalx/speaker_list.html +31 -0
  82. django_program-0.1.0/src/django_program/pretalx/templates/django_program/pretalx/talk_detail.html +76 -0
  83. django_program-0.1.0/src/django_program/pretalx/urls.py +29 -0
  84. django_program-0.1.0/src/django_program/pretalx/views.py +238 -0
  85. django_program-0.1.0/src/django_program/programs/__init__.py +1 -0
  86. django_program-0.1.0/src/django_program/programs/admin.py +111 -0
  87. django_program-0.1.0/src/django_program/programs/apps.py +12 -0
  88. django_program-0.1.0/src/django_program/programs/forms.py +288 -0
  89. django_program-0.1.0/src/django_program/programs/migrations/0001_initial.py +156 -0
  90. django_program-0.1.0/src/django_program/programs/migrations/0002_alter_activity_activity_type.py +29 -0
  91. django_program-0.1.0/src/django_program/programs/migrations/0003_activity_pretalx_submission_type_activity_room_and_more.py +83 -0
  92. django_program-0.1.0/src/django_program/programs/migrations/0004_travel_grant_pycon_model.py +299 -0
  93. django_program-0.1.0/src/django_program/programs/migrations/0005_alter_travelgrant_application_type_paymentinfo_and_more.py +206 -0
  94. django_program-0.1.0/src/django_program/programs/migrations/0006_travelgrant_disbursed_amount_and_more.py +64 -0
  95. django_program-0.1.0/src/django_program/programs/migrations/0007_alter_receipt_receipt_file.py +25 -0
  96. django_program-0.1.0/src/django_program/programs/migrations/0008_alter_activitysignup_unique_together_and_more.py +44 -0
  97. django_program-0.1.0/src/django_program/programs/migrations/0009_alter_activity_options_activity_organizers.py +31 -0
  98. django_program-0.1.0/src/django_program/programs/migrations/__init__.py +0 -0
  99. django_program-0.1.0/src/django_program/programs/models.py +644 -0
  100. django_program-0.1.0/src/django_program/programs/templates/django_program/programs/activity_detail.html +165 -0
  101. django_program-0.1.0/src/django_program/programs/templates/django_program/programs/activity_list.html +76 -0
  102. django_program-0.1.0/src/django_program/programs/templates/django_program/programs/travel_grant_form.html +1059 -0
  103. django_program-0.1.0/src/django_program/programs/templates/django_program/programs/travel_grant_payment_info.html +569 -0
  104. django_program-0.1.0/src/django_program/programs/templates/django_program/programs/travel_grant_provide_info.html +149 -0
  105. django_program-0.1.0/src/django_program/programs/templates/django_program/programs/travel_grant_receipts.html +809 -0
  106. django_program-0.1.0/src/django_program/programs/templates/django_program/programs/travel_grant_status.html +962 -0
  107. django_program-0.1.0/src/django_program/programs/urls.py +46 -0
  108. django_program-0.1.0/src/django_program/programs/views.py +606 -0
  109. django_program-0.1.0/src/django_program/py.typed +0 -0
  110. django_program-0.1.0/src/django_program/registration/__init__.py +1 -0
  111. django_program-0.1.0/src/django_program/registration/admin.py +215 -0
  112. django_program-0.1.0/src/django_program/registration/apps.py +12 -0
  113. django_program-0.1.0/src/django_program/registration/forms.py +56 -0
  114. django_program-0.1.0/src/django_program/registration/migrations/0001_initial.py +480 -0
  115. django_program-0.1.0/src/django_program/registration/migrations/0002_fix_cartitem_on_delete.py +35 -0
  116. django_program-0.1.0/src/django_program/registration/migrations/0003_stripeevent_payment_status_eventprocessingexception_and_more.py +99 -0
  117. django_program-0.1.0/src/django_program/registration/migrations/0004_cartitem_registration_cartitem_unique_ticket_per_cart_and_more.py +28 -0
  118. django_program-0.1.0/src/django_program/registration/migrations/0005_order_hold_expires_at_credit_remaining_amount.py +39 -0
  119. django_program-0.1.0/src/django_program/registration/migrations/__init__.py +0 -0
  120. django_program-0.1.0/src/django_program/registration/models.py +651 -0
  121. django_program-0.1.0/src/django_program/registration/services/__init__.py +1 -0
  122. django_program-0.1.0/src/django_program/registration/services/cart.py +730 -0
  123. django_program-0.1.0/src/django_program/registration/services/checkout.py +418 -0
  124. django_program-0.1.0/src/django_program/registration/services/payment.py +214 -0
  125. django_program-0.1.0/src/django_program/registration/services/refund.py +202 -0
  126. django_program-0.1.0/src/django_program/registration/signals.py +13 -0
  127. django_program-0.1.0/src/django_program/registration/stripe_client.py +200 -0
  128. django_program-0.1.0/src/django_program/registration/stripe_utils.py +101 -0
  129. django_program-0.1.0/src/django_program/registration/templates/django_program/emails/grant_decision.html +105 -0
  130. django_program-0.1.0/src/django_program/registration/templates/django_program/emails/order_confirmation.html +107 -0
  131. django_program-0.1.0/src/django_program/registration/templates/django_program/emails/order_refund.html +83 -0
  132. django_program-0.1.0/src/django_program/registration/templates/django_program/registration/cart.html +155 -0
  133. django_program-0.1.0/src/django_program/registration/templates/django_program/registration/checkout.html +92 -0
  134. django_program-0.1.0/src/django_program/registration/templates/django_program/registration/order_confirmation.html +68 -0
  135. django_program-0.1.0/src/django_program/registration/templates/django_program/registration/order_detail.html +122 -0
  136. django_program-0.1.0/src/django_program/registration/templates/django_program/registration/ticket_select.html +72 -0
  137. django_program-0.1.0/src/django_program/registration/templatetags/__init__.py +1 -0
  138. django_program-0.1.0/src/django_program/registration/templatetags/registration_tags.py +126 -0
  139. django_program-0.1.0/src/django_program/registration/templatetags/stripe_tags.py +29 -0
  140. django_program-0.1.0/src/django_program/registration/urls.py +35 -0
  141. django_program-0.1.0/src/django_program/registration/views.py +744 -0
  142. django_program-0.1.0/src/django_program/registration/webhooks.py +483 -0
  143. django_program-0.1.0/src/django_program/settings.py +145 -0
  144. django_program-0.1.0/src/django_program/sponsors/__init__.py +1 -0
  145. django_program-0.1.0/src/django_program/sponsors/admin.py +32 -0
  146. django_program-0.1.0/src/django_program/sponsors/apps.py +16 -0
  147. django_program-0.1.0/src/django_program/sponsors/management/__init__.py +1 -0
  148. django_program-0.1.0/src/django_program/sponsors/management/commands/__init__.py +1 -0
  149. django_program-0.1.0/src/django_program/sponsors/management/commands/sync_sponsors.py +57 -0
  150. django_program-0.1.0/src/django_program/sponsors/migrations/0001_initial.py +151 -0
  151. django_program-0.1.0/src/django_program/sponsors/migrations/0002_alter_sponsor_slug_alter_sponsorlevel_slug.py +22 -0
  152. django_program-0.1.0/src/django_program/sponsors/migrations/0003_add_external_id_and_logo_url.py +31 -0
  153. django_program-0.1.0/src/django_program/sponsors/migrations/__init__.py +0 -0
  154. django_program-0.1.0/src/django_program/sponsors/models.py +136 -0
  155. django_program-0.1.0/src/django_program/sponsors/profiles/__init__.py +13 -0
  156. django_program-0.1.0/src/django_program/sponsors/profiles/base.py +22 -0
  157. django_program-0.1.0/src/django_program/sponsors/profiles/default.py +10 -0
  158. django_program-0.1.0/src/django_program/sponsors/profiles/pyconus.py +15 -0
  159. django_program-0.1.0/src/django_program/sponsors/profiles/resolver.py +28 -0
  160. django_program-0.1.0/src/django_program/sponsors/signals.py +53 -0
  161. django_program-0.1.0/src/django_program/sponsors/sync.py +210 -0
  162. django_program-0.1.0/src/django_program/sponsors/templates/django_program/sponsors/sponsor_detail.html +33 -0
  163. django_program-0.1.0/src/django_program/sponsors/templates/django_program/sponsors/sponsor_list.html +30 -0
  164. django_program-0.1.0/src/django_program/sponsors/templatetags/__init__.py +1 -0
  165. django_program-0.1.0/src/django_program/sponsors/templatetags/sponsor_tags.py +89 -0
  166. django_program-0.1.0/src/django_program/sponsors/urls.py +20 -0
  167. django_program-0.1.0/src/django_program/sponsors/views.py +82 -0
  168. 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,5 @@
1
+ """Modern conference management for Django."""
2
+
3
+ from django_program.__metadata__ import __version__
4
+
5
+ __all__ = ["__version__"]
@@ -0,0 +1,3 @@
1
+ """django-program metadata."""
2
+
3
+ __version__ = "0.1.0"
@@ -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."""