From 58aa79cad35226293cc067a1a3f6715a461dcbd9 Mon Sep 17 00:00:00 2001 From: Jelle Besseling Date: Sun, 17 Nov 2024 19:08:27 +0100 Subject: [PATCH] Big refactor --- .github/workflows/build-deploy.yml | 98 ---- .github/workflows/relock-dependencies.yml | 34 -- lock.x86_64-linux.json | 221 -------- src/manage.py => manage.py | 3 +- manifests/deployment.yaml | 384 -------------- manifests/ns.yaml | 6 - manifests/percona-db.yaml | 479 ------------------ pip-snapshot-date.txt | 1 - pyproject.toml | 36 +- src/adminsite/models.py | 3 - src/adminsite/tests.py | 3 - src/adminsite/views.py | 3 - ...ory_options_alter_file_options_and_more.py | 64 --- src/documents/tests.py | 3 - ...options_alter_homepage_content_and_more.py | 28 - src/home/tests.py | 3 - ...oup_contact_people_delete_contactperson.py | 24 - ...oup_options_alter_user_options_and_more.py | 74 --- src/members/tests.py | 3 - .../0002_alter_membership_options.py | 20 - src/membership/tests.py | 3 - src/membership/views.py | 3 - src/menu/admin.py | 3 - src/menu/tests.py | 3 - src/payments/admin.py | 33 -- ...ons_alter_subscription_options_and_more.py | 120 ----- src/payments/tests.py | 3 - src/payments/views.py | 3 - src/payments_dummy/admin.py | 3 - src/payments_dummy/forms.py | 7 - src/payments_dummy/models.py | 3 - src/payments_dummy/tests.py | 3 - src/payments_mollie/admin.py | 3 - src/payments_mollie/tests.py | 3 - ...ter_applicationpayment_options_and_more.py | 114 ----- src/signup/tests.py | 3 - src/theme/migrations/0001_initial.py | 31 -- .../migrations/0002_alter_tailwindkey_id.py | 18 - .../migrations/0003_currentthemeversion.py | 23 - .../0004_alter_currentthemeversion_version.py | 18 - ...ailwindkey_name_alter_tailwindkey_value.py | 31 -- ...0006_remove_currentthemeversion_version.py | 17 - .../0007_currentthemeversion_version.py | 22 - src/worker/migrations/0001_initial.py | 39 -- ...r_task_options_alter_task_args_and_more.py | 84 --- src/worker/tests.py | 3 - src/worker/views.py | 3 - {src/adminsite => symfexit}/__init__.py | 0 .../adminsite}/__init__.py | 0 {src => symfexit}/adminsite/admin.py | 4 +- {src => symfexit}/adminsite/apps.py | 5 +- .../adminsite/django_overrides.py | 1 - .../adminsite/locale/nl/LC_MESSAGES/django.mo | Bin .../adminsite/locale/nl/LC_MESSAGES/django.po | 0 .../adminsite/migrations}/__init__.py | 0 symfexit/adminsite/models.py | 1 + symfexit/adminsite/tests.py | 1 + symfexit/adminsite/views.py | 1 + .../documents}/__init__.py | 0 {src => symfexit}/documents/admin.py | 2 +- {src => symfexit}/documents/apps.py | 4 +- .../documents/locale/nl/LC_MESSAGES/django.mo | Bin .../documents/locale/nl/LC_MESSAGES/django.po | 0 .../documents/migrations/0001_initial.py | 36 +- .../documents/migrations}/__init__.py | 0 {src => symfexit}/documents/models.py | 5 +- .../templates/documents/breadcrumbs.html | 0 .../templates/documents/documents.html | 0 .../templates/documents/download_button.html | 0 .../templates/documents/image_file.html | 0 .../templates/documents/pdf_file.html | 0 symfexit/documents/tests.py | 1 + {src => symfexit}/documents/urls.py | 2 +- {src => symfexit}/documents/views.py | 2 +- .../migrations => symfexit/home}/__init__.py | 0 {src => symfexit}/home/admin.py | 5 +- {src => symfexit}/home/apps.py | 4 +- .../home/locale/nl/LC_MESSAGES/django.mo | Bin .../home/locale/nl/LC_MESSAGES/django.po | 0 .../home/migrations/0001_initial.py | 13 +- .../home/migrations}/__init__.py | 0 {src => symfexit}/home/models.py | 2 +- .../templates/admin/home/submit_line.html | 0 .../home/templates/home/home.html | 0 symfexit/home/tests.py | 1 + {src => symfexit}/home/urls.py | 2 +- {src => symfexit}/home/views.py | 5 +- .../members}/__init__.py | 0 {src => symfexit}/members/admin.py | 25 +- {src => symfexit}/members/apps.py | 4 +- {src => symfexit}/members/backends.py | 0 {src => symfexit}/members/forms.py | 5 +- .../members/locale/nl/LC_MESSAGES/django.mo | Bin .../members/locale/nl/LC_MESSAGES/django.po | 0 .../members/migrations/0001_initial.py | 77 ++- .../members/migrations}/__init__.py | 0 {src => symfexit}/members/models.py | 23 +- .../members/templates/members/logout.html | 0 .../members/templates/members/user_form.html | 0 .../members/templates/registration/login.html | 0 symfexit/members/tests.py | 1 + {src => symfexit}/members/urls.py | 2 +- {src => symfexit}/members/views.py | 15 +- .../membership}/__init__.py | 0 {src => symfexit}/membership/admin.py | 16 +- {src => symfexit}/membership/apps.py | 3 +- {src => symfexit}/membership/forms.py | 11 +- .../locale/nl/LC_MESSAGES/django.mo | Bin .../locale/nl/LC_MESSAGES/django.po | 0 .../membership/migrations/0001_initial.py | 3 +- .../membership/migrations}/__init__.py | 0 {src => symfexit}/membership/models.py | 23 +- .../admin/membership/payment_tiers.html | 0 symfexit/membership/tests.py | 1 + symfexit/membership/views.py | 1 + .../migrations => symfexit/menu}/__init__.py | 0 symfexit/menu/admin.py | 1 + {src => symfexit}/menu/apps.py | 2 +- .../menu/migrations}/__init__.py | 0 {src => symfexit}/menu/templates/menu.html | 0 {src => symfexit}/menu/templates/menu_lg.html | 0 .../menu/templates/menupage.html | 0 .../menu/templatetags}/__init__.py | 0 {src => symfexit}/menu/templatetags/menu.py | 0 symfexit/menu/tests.py | 1 + {src => symfexit}/payments/__init__.py | 2 +- symfexit/payments/admin.py | 46 ++ {src => symfexit}/payments/apps.py | 6 +- .../payments/dummy}/LC_MESSAGES/django.mo | Bin .../payments/dummy}/LC_MESSAGES/django.po | 0 .../payments/dummy}/__init__.py | 0 symfexit/payments/dummy/admin.py | 1 + .../payments/dummy}/apps.py | 2 +- symfexit/payments/dummy/forms.py | 7 + .../payments/dummy}/migrations/__init__.py | 0 symfexit/payments/dummy/models.py | 1 + .../payments/dummy}/payments.py | 12 +- .../templates/payments_dummy/dummy_pay.html | 0 symfexit/payments/dummy/tests.py | 1 + .../payments/dummy}/urls.py | 2 +- .../payments/dummy}/views.py | 5 +- .../payments/locale/nl/LC_MESSAGES/django.mo | Bin .../payments/locale/nl/LC_MESSAGES/django.po | 0 .../payments/migrations/0001_initial.py | 91 ++-- .../payments/migrations}/__init__.py | 0 {src => symfexit}/payments/models.py | 158 +++--- .../payments/mollie}/__init__.py | 0 symfexit/payments/mollie/admin.py | 1 + .../payments/mollie}/apps.py | 2 +- .../mollie}/migrations/0001_initial.py | 6 +- .../payments/mollie/migrations}/__init__.py | 0 .../payments/mollie}/models.py | 2 +- .../payments/mollie}/payments.py | 11 +- .../payments_mollie/select_method.html | 0 symfexit/payments/mollie/tests.py | 1 + .../payments/mollie}/urls.py | 2 +- .../payments/mollie}/views.py | 14 +- {src => symfexit}/payments/registry.py | 19 +- symfexit/payments/tests.py | 1 + symfexit/payments/views.py | 1 + .../migrations => symfexit/root}/__init__.py | 0 {src/symfexit => symfexit/root}/apps.py | 2 +- {src/symfexit => symfexit/root}/asgi.py | 2 +- symfexit/root/config.py | 7 + .../root}/context_processors.py | 0 {src/symfexit => symfexit/root}/helpers.py | 0 .../root}/locale/nl/LC_MESSAGES/django.mo | Bin .../root}/locale/nl/LC_MESSAGES/django.po | 0 {src/symfexit => symfexit/root}/settings.py | 90 ++-- {src/symfexit => symfexit/root}/urls.py | 42 +- {src/symfexit => symfexit/root}/utils.py | 4 +- {src/symfexit => symfexit/root}/wsgi.py | 2 +- {src/symfexit => symfexit/signup}/__init__.py | 0 {src => symfexit}/signup/admin.py | 73 ++- {src => symfexit}/signup/apps.py | 3 +- {src => symfexit}/signup/forms.py | 8 +- .../signup/locale/nl/LC_MESSAGES/django.mo | Bin .../signup/locale/nl/LC_MESSAGES/django.po | 0 .../signup/migrations/0001_initial.py | 83 ++- .../signup/migrations}/__init__.py | 0 {src => symfexit}/signup/models.py | 72 +-- .../signup/templates/signup/cancelled.html | 0 .../signup/templates/signup/forms/div.html | 0 .../signup/templates/signup/payment.html | 0 .../signup/templates/signup/return.html | 0 .../signup/templates/signup/signup.html | 0 symfexit/signup/tests.py | 1 + {src => symfexit}/signup/urls.py | 8 +- {src => symfexit}/signup/views.py | 19 +- {src => symfexit}/theme/.gitignore | 0 .../management => symfexit/theme}/__init__.py | 0 {src => symfexit}/theme/admin.py | 10 +- {src => symfexit}/theme/apps.py | 9 +- {src => symfexit}/theme/context.py | 10 +- .../theme/locale/nl/LC_MESSAGES/django.mo | Bin .../theme/locale/nl/LC_MESSAGES/django.po | 0 .../theme/management}/__init__.py | 0 .../theme/management/commands}/__init__.py | 0 .../theme/management/commands/exporttheme.py | 2 +- symfexit/theme/migrations/0001_initial.py | 54 ++ .../theme/migrations}/__init__.py | 0 {src => symfexit}/theme/models.py | 6 +- .../theme/static/img/header-logo.svg | 0 {src => symfexit}/theme/static_src/.gitignore | 0 .../theme/static_src/package-lock.json | 0 .../theme/static_src/package.json | 0 .../theme/static_src/postcss.config.js | 0 .../theme/static_src/src/styles.css | 0 .../theme/static_src/tailwind.config.js | 0 {src => symfexit}/theme/tasks.py | 11 +- .../admin/constance_theme/change_list.html | 0 .../includes/results_list.html | 0 .../templates/admin/rebuild_theme/index.html | 0 .../admin/tailwind_keys/change_list.html | 0 {src => symfexit}/theme/templates/base.html | 0 {src => symfexit}/theme/templates/page.html | 0 .../theme/templates/registration/login.html | 0 .../theme/tags/current_theme_css.html | 0 .../theme/tags/preload_current_theme_css.html | 0 .../theme/templatetags}/__init__.py | 0 .../theme/templatetags/current_theme.py | 3 + {src => symfexit}/theme/urls.py | 2 +- {src => symfexit}/theme/utils.py | 4 +- {src => symfexit}/theme/views.py | 0 {src => symfexit}/worker/__init__.py | 4 +- {src => symfexit}/worker/admin.py | 2 +- {src => symfexit}/worker/apps.py | 4 +- .../worker/locale/nl/LC_MESSAGES/django.mo | Bin .../worker/locale/nl/LC_MESSAGES/django.po | 0 {src => symfexit}/worker/logger.py | 0 .../worker/management}/__init__.py | 0 .../worker/management/commands}/__init__.py | 0 .../worker/management/commands/startworker.py | 7 +- symfexit/worker/migrations/0001_initial.py | 66 +++ symfexit/worker/migrations/__init__.py | 0 {src => symfexit}/worker/models.py | 4 +- {src => symfexit}/worker/registry.py | 4 +- symfexit/worker/tests.py | 1 + symfexit/worker/views.py | 1 + 239 files changed, 765 insertions(+), 2649 deletions(-) delete mode 100644 .github/workflows/build-deploy.yml delete mode 100644 .github/workflows/relock-dependencies.yml delete mode 100644 lock.x86_64-linux.json rename src/manage.py => manage.py (88%) delete mode 100644 manifests/deployment.yaml delete mode 100644 manifests/ns.yaml delete mode 100644 manifests/percona-db.yaml delete mode 100644 pip-snapshot-date.txt delete mode 100644 src/adminsite/models.py delete mode 100644 src/adminsite/tests.py delete mode 100644 src/adminsite/views.py delete mode 100644 src/documents/migrations/0002_alter_directory_options_alter_file_options_and_more.py delete mode 100644 src/documents/tests.py delete mode 100644 src/home/migrations/0002_alter_homepage_options_alter_homepage_content_and_more.py delete mode 100644 src/home/tests.py delete mode 100644 src/members/migrations/0002_localgroup_contact_people_delete_contactperson.py delete mode 100644 src/members/migrations/0003_alter_localgroup_options_alter_user_options_and_more.py delete mode 100644 src/members/tests.py delete mode 100644 src/membership/migrations/0002_alter_membership_options.py delete mode 100644 src/membership/tests.py delete mode 100644 src/membership/views.py delete mode 100644 src/menu/admin.py delete mode 100644 src/menu/tests.py delete mode 100644 src/payments/admin.py delete mode 100644 src/payments/migrations/0002_alter_order_options_alter_subscription_options_and_more.py delete mode 100644 src/payments/tests.py delete mode 100644 src/payments/views.py delete mode 100644 src/payments_dummy/admin.py delete mode 100644 src/payments_dummy/forms.py delete mode 100644 src/payments_dummy/models.py delete mode 100644 src/payments_dummy/tests.py delete mode 100644 src/payments_mollie/admin.py delete mode 100644 src/payments_mollie/tests.py delete mode 100644 src/signup/migrations/0002_alter_applicationpayment_options_and_more.py delete mode 100644 src/signup/tests.py delete mode 100644 src/theme/migrations/0001_initial.py delete mode 100644 src/theme/migrations/0002_alter_tailwindkey_id.py delete mode 100644 src/theme/migrations/0003_currentthemeversion.py delete mode 100644 src/theme/migrations/0004_alter_currentthemeversion_version.py delete mode 100644 src/theme/migrations/0005_alter_tailwindkey_name_alter_tailwindkey_value.py delete mode 100644 src/theme/migrations/0006_remove_currentthemeversion_version.py delete mode 100644 src/theme/migrations/0007_currentthemeversion_version.py delete mode 100644 src/worker/migrations/0001_initial.py delete mode 100644 src/worker/migrations/0002_alter_task_options_alter_task_args_and_more.py delete mode 100644 src/worker/tests.py delete mode 100644 src/worker/views.py rename {src/adminsite => symfexit}/__init__.py (100%) rename {src/adminsite/migrations => symfexit/adminsite}/__init__.py (100%) rename {src => symfexit}/adminsite/admin.py (96%) rename {src => symfexit}/adminsite/apps.py (78%) rename {src => symfexit}/adminsite/django_overrides.py (99%) rename {src => symfexit}/adminsite/locale/nl/LC_MESSAGES/django.mo (100%) rename {src => symfexit}/adminsite/locale/nl/LC_MESSAGES/django.po (100%) rename {src/documents => symfexit/adminsite/migrations}/__init__.py (100%) create mode 100644 symfexit/adminsite/models.py create mode 100644 symfexit/adminsite/tests.py create mode 100644 symfexit/adminsite/views.py rename {src/documents/migrations => symfexit/documents}/__init__.py (100%) rename {src => symfexit}/documents/admin.py (79%) rename {src => symfexit}/documents/apps.py (91%) rename {src => symfexit}/documents/locale/nl/LC_MESSAGES/django.mo (100%) rename {src => symfexit}/documents/locale/nl/LC_MESSAGES/django.po (100%) rename {src => symfexit}/documents/migrations/0001_initial.py (68%) rename {src/home => symfexit/documents/migrations}/__init__.py (100%) rename {src => symfexit}/documents/models.py (96%) rename {src => symfexit}/documents/templates/documents/breadcrumbs.html (100%) rename {src => symfexit}/documents/templates/documents/documents.html (100%) rename {src => symfexit}/documents/templates/documents/download_button.html (100%) rename {src => symfexit}/documents/templates/documents/image_file.html (100%) rename {src => symfexit}/documents/templates/documents/pdf_file.html (100%) create mode 100644 symfexit/documents/tests.py rename {src => symfexit}/documents/urls.py (84%) rename {src => symfexit}/documents/views.py (97%) rename {src/home/migrations => symfexit/home}/__init__.py (100%) rename {src => symfexit}/home/admin.py (97%) rename {src => symfexit}/home/apps.py (91%) rename {src => symfexit}/home/locale/nl/LC_MESSAGES/django.mo (100%) rename {src => symfexit}/home/locale/nl/LC_MESSAGES/django.po (100%) rename {src => symfexit}/home/migrations/0001_initial.py (63%) rename {src/members => symfexit/home/migrations}/__init__.py (100%) rename {src => symfexit}/home/models.py (100%) rename {src => symfexit}/home/templates/admin/home/submit_line.html (100%) rename {src => symfexit}/home/templates/home/home.html (100%) create mode 100644 symfexit/home/tests.py rename {src => symfexit}/home/urls.py (82%) rename {src => symfexit}/home/views.py (70%) rename {src/members/migrations => symfexit/members}/__init__.py (100%) rename {src => symfexit}/members/admin.py (95%) rename {src => symfexit}/members/apps.py (93%) rename {src => symfexit}/members/backends.py (100%) rename {src => symfexit}/members/forms.py (98%) rename {src => symfexit}/members/locale/nl/LC_MESSAGES/django.mo (100%) rename {src => symfexit}/members/locale/nl/LC_MESSAGES/django.po (100%) rename {src => symfexit}/members/migrations/0001_initial.py (74%) rename {src/membership => symfexit/members/migrations}/__init__.py (100%) rename {src => symfexit}/members/models.py (90%) rename {src => symfexit}/members/templates/members/logout.html (100%) rename {src => symfexit}/members/templates/members/user_form.html (100%) rename {src => symfexit}/members/templates/registration/login.html (100%) create mode 100644 symfexit/members/tests.py rename {src => symfexit}/members/urls.py (78%) rename {src => symfexit}/members/views.py (87%) rename {src/membership/migrations => symfexit/membership}/__init__.py (100%) rename {src => symfexit}/membership/admin.py (92%) rename {src => symfexit}/membership/apps.py (86%) rename {src => symfexit}/membership/forms.py (83%) rename {src => symfexit}/membership/locale/nl/LC_MESSAGES/django.mo (100%) rename {src => symfexit}/membership/locale/nl/LC_MESSAGES/django.po (100%) rename {src => symfexit}/membership/migrations/0001_initial.py (89%) rename {src/menu => symfexit/membership/migrations}/__init__.py (100%) rename {src => symfexit}/membership/models.py (68%) rename {src => symfexit}/membership/templates/admin/membership/payment_tiers.html (100%) create mode 100644 symfexit/membership/tests.py create mode 100644 symfexit/membership/views.py rename {src/menu/migrations => symfexit/menu}/__init__.py (100%) create mode 100644 symfexit/menu/admin.py rename {src => symfexit}/menu/apps.py (81%) rename {src/menu/templatetags => symfexit/menu/migrations}/__init__.py (100%) rename {src => symfexit}/menu/templates/menu.html (100%) rename {src => symfexit}/menu/templates/menu_lg.html (100%) rename {src => symfexit}/menu/templates/menupage.html (100%) rename {src/payments/migrations => symfexit/menu/templatetags}/__init__.py (100%) rename {src => symfexit}/menu/templatetags/menu.py (100%) create mode 100644 symfexit/menu/tests.py rename {src => symfexit}/payments/__init__.py (71%) create mode 100644 symfexit/payments/admin.py rename {src => symfexit}/payments/apps.py (76%) rename {src/payments_dummy/locale/nl => symfexit/payments/dummy}/LC_MESSAGES/django.mo (100%) rename {src/payments_dummy/locale/nl => symfexit/payments/dummy}/LC_MESSAGES/django.po (100%) rename {src/payments_dummy => symfexit/payments/dummy}/__init__.py (100%) create mode 100644 symfexit/payments/dummy/admin.py rename {src/payments_dummy => symfexit/payments/dummy}/apps.py (77%) create mode 100644 symfexit/payments/dummy/forms.py rename {src/payments_dummy => symfexit/payments/dummy}/migrations/__init__.py (100%) create mode 100644 symfexit/payments/dummy/models.py rename {src/payments_dummy => symfexit/payments/dummy}/payments.py (69%) rename {src/payments_dummy => symfexit/payments/dummy}/templates/payments_dummy/dummy_pay.html (100%) create mode 100644 symfexit/payments/dummy/tests.py rename {src/payments_dummy => symfexit/payments/dummy}/urls.py (72%) rename {src/payments_dummy => symfexit/payments/dummy}/views.py (83%) rename {src => symfexit}/payments/locale/nl/LC_MESSAGES/django.mo (100%) rename {src => symfexit}/payments/locale/nl/LC_MESSAGES/django.po (100%) rename {src => symfexit}/payments/migrations/0001_initial.py (60%) rename {src/payments_mollie => symfexit/payments/migrations}/__init__.py (100%) rename {src => symfexit}/payments/models.py (55%) rename {src/payments_mollie/migrations => symfexit/payments/mollie}/__init__.py (100%) create mode 100644 symfexit/payments/mollie/admin.py rename {src/payments_mollie => symfexit/payments/mollie}/apps.py (77%) rename {src/payments_mollie => symfexit/payments/mollie}/migrations/0001_initial.py (81%) rename {src/signup => symfexit/payments/mollie/migrations}/__init__.py (100%) rename {src/payments_mollie => symfexit/payments/mollie}/models.py (89%) rename {src/payments_mollie => symfexit/payments/mollie}/payments.py (84%) rename {src/payments_mollie => symfexit/payments/mollie}/templates/payments_mollie/select_method.html (100%) create mode 100644 symfexit/payments/mollie/tests.py rename {src/payments_mollie => symfexit/payments/mollie}/urls.py (90%) rename {src/payments_mollie => symfexit/payments/mollie}/views.py (88%) rename {src => symfexit}/payments/registry.py (72%) create mode 100644 symfexit/payments/tests.py create mode 100644 symfexit/payments/views.py rename {src/signup/migrations => symfexit/root}/__init__.py (100%) rename {src/symfexit => symfexit/root}/apps.py (85%) rename {src/symfexit => symfexit/root}/asgi.py (81%) create mode 100644 symfexit/root/config.py rename {src/symfexit => symfexit/root}/context_processors.py (100%) rename {src/symfexit => symfexit/root}/helpers.py (100%) rename {src/symfexit => symfexit/root}/locale/nl/LC_MESSAGES/django.mo (100%) rename {src/symfexit => symfexit/root}/locale/nl/LC_MESSAGES/django.po (100%) rename {src/symfexit => symfexit/root}/settings.py (80%) rename {src/symfexit => symfexit/root}/urls.py (57%) rename {src/symfexit => symfexit/root}/utils.py (76%) rename {src/symfexit => symfexit/root}/wsgi.py (81%) rename {src/symfexit => symfexit/signup}/__init__.py (100%) rename {src => symfexit}/signup/admin.py (50%) rename {src => symfexit}/signup/apps.py (87%) rename {src => symfexit}/signup/forms.py (95%) rename {src => symfexit}/signup/locale/nl/LC_MESSAGES/django.mo (100%) rename {src => symfexit}/signup/locale/nl/LC_MESSAGES/django.po (100%) rename {src => symfexit}/signup/migrations/0001_initial.py (53%) rename {src/theme => symfexit/signup/migrations}/__init__.py (100%) rename {src => symfexit}/signup/models.py (69%) rename {src => symfexit}/signup/templates/signup/cancelled.html (100%) rename {src => symfexit}/signup/templates/signup/forms/div.html (100%) rename {src => symfexit}/signup/templates/signup/payment.html (100%) rename {src => symfexit}/signup/templates/signup/return.html (100%) rename {src => symfexit}/signup/templates/signup/signup.html (100%) create mode 100644 symfexit/signup/tests.py rename {src => symfexit}/signup/urls.py (70%) rename {src => symfexit}/signup/views.py (80%) rename {src => symfexit}/theme/.gitignore (100%) rename {src/theme/management => symfexit/theme}/__init__.py (100%) rename {src => symfexit}/theme/admin.py (90%) rename {src => symfexit}/theme/apps.py (68%) rename {src => symfexit}/theme/context.py (75%) rename {src => symfexit}/theme/locale/nl/LC_MESSAGES/django.mo (100%) rename {src => symfexit}/theme/locale/nl/LC_MESSAGES/django.po (100%) rename {src/theme/management/commands => symfexit/theme/management}/__init__.py (100%) rename {src/theme/migrations => symfexit/theme/management/commands}/__init__.py (100%) rename {src => symfexit}/theme/management/commands/exporttheme.py (91%) create mode 100644 symfexit/theme/migrations/0001_initial.py rename {src/theme/templatetags => symfexit/theme/migrations}/__init__.py (100%) rename {src => symfexit}/theme/models.py (91%) rename {src => symfexit}/theme/static/img/header-logo.svg (100%) rename {src => symfexit}/theme/static_src/.gitignore (100%) rename {src => symfexit}/theme/static_src/package-lock.json (100%) rename {src => symfexit}/theme/static_src/package.json (100%) rename {src => symfexit}/theme/static_src/postcss.config.js (100%) rename {src => symfexit}/theme/static_src/src/styles.css (100%) rename {src => symfexit}/theme/static_src/tailwind.config.js (100%) rename {src => symfexit}/theme/tasks.py (86%) rename {src => symfexit}/theme/templates/admin/constance_theme/change_list.html (100%) rename {src => symfexit}/theme/templates/admin/constance_theme/includes/results_list.html (100%) rename {src => symfexit}/theme/templates/admin/rebuild_theme/index.html (100%) rename {src => symfexit}/theme/templates/admin/tailwind_keys/change_list.html (100%) rename {src => symfexit}/theme/templates/base.html (100%) rename {src => symfexit}/theme/templates/page.html (100%) rename {src => symfexit}/theme/templates/registration/login.html (100%) rename {src => symfexit}/theme/templates/theme/tags/current_theme_css.html (100%) rename {src => symfexit}/theme/templates/theme/tags/preload_current_theme_css.html (100%) rename {src/worker/management => symfexit/theme/templatetags}/__init__.py (100%) rename {src => symfexit}/theme/templatetags/current_theme.py (99%) rename {src => symfexit}/theme/urls.py (72%) rename {src => symfexit}/theme/utils.py (79%) rename {src => symfexit}/theme/views.py (100%) rename {src => symfexit}/worker/__init__.py (63%) rename {src => symfexit}/worker/admin.py (76%) rename {src => symfexit}/worker/apps.py (90%) rename {src => symfexit}/worker/locale/nl/LC_MESSAGES/django.mo (100%) rename {src => symfexit}/worker/locale/nl/LC_MESSAGES/django.po (100%) rename {src => symfexit}/worker/logger.py (100%) rename {src/worker/management/commands => symfexit/worker/management}/__init__.py (100%) rename {src/worker/migrations => symfexit/worker/management/commands}/__init__.py (100%) rename {src => symfexit}/worker/management/commands/startworker.py (94%) create mode 100644 symfexit/worker/migrations/0001_initial.py create mode 100644 symfexit/worker/migrations/__init__.py rename {src => symfexit}/worker/models.py (90%) rename {src => symfexit}/worker/registry.py (85%) create mode 100644 symfexit/worker/tests.py create mode 100644 symfexit/worker/views.py diff --git a/.github/workflows/build-deploy.yml b/.github/workflows/build-deploy.yml deleted file mode 100644 index 1533e00..0000000 --- a/.github/workflows/build-deploy.yml +++ /dev/null @@ -1,98 +0,0 @@ -name: Build Docker Image and Deploy to Kubernetes - -on: - push: - branches: - - main - -permissions: - contents: read - packages: write - id-token: write # This is required for requesting the JWT - -jobs: - build: - runs-on: ubuntu-latest - outputs: - imageTags: ${{ steps.meta.outputs.json }} - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Install Nix - uses: DeterminateSystems/nix-installer-action@main - - uses: DeterminateSystems/magic-nix-cache-action@main - - - name: Docker meta - id: meta - uses: docker/metadata-action@v5 - with: - # list of Docker images to use as base name for tags - images: | - ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }} - # generate Docker tags based on the following events/attributes - tags: | - type=schedule - type=ref,event=branch - type=ref,event=pr - type=semver,pattern={{version}} - type=semver,pattern={{major}}.{{minor}} - type=semver,pattern={{major}} - type=sha - - - name: Log in to the GitHub Container Registry - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Build Docker image - run: | - nix run '.#symfexit-docker' | docker load - echo "FROM symfexit:$(nix run '.#symfexit-docker-tag')" > Dockerfile - - - name: Build Docker image - uses: docker/build-push-action@v6 - with: - context: . - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - - deploy-staging: - name: Deploy to staging - if: github.ref == 'refs/heads/main' - environment: - name: staging - url: https://symfexit-staging.yele.dev/ - runs-on: ubuntu-latest - needs: [build] - steps: - - name: Prepare kubeconfig - uses: actions/github-script@v7 - id: idtoken - with: - script: | - let id_token = await core.getIDToken(process.env.K8S_AUDIENCE) - let kubeConfig = JSON.parse(process.env.KUBECONFIG) - kubeConfig.users[0].user.token = id_token - const output = JSON.stringify(kubeConfig) - core.setOutput('kubeconfig', output) - core.setSecret(output) - env: - KUBECONFIG: ${{ secrets.K8S_KUBECONFIG }} - K8S_AUDIENCE: ${{ secrets.K8S_AUDIENCE }} - - name: Setup Kube Context - uses: azure/k8s-set-context@v4 - with: - kubeconfig: ${{ steps.idtoken.outputs.kubeconfig }} - - name: Extract the image tag - id: image - run: | - echo '${{ needs.build.outputs.imageTags }}' | jq -r '.tags[] | select(test("ghcr.io/[a-z]+/[a-z]+:sha")) | "imageTag=\(.)"' >> "$GITHUB_OUTPUT" - - name: Set the image for the deployments - run: | - kubectl set image deployment/symfexit symfexit=${{ steps.image.outputs.imageTag }} symfexit-migrations=${{ steps.image.outputs.imageTag }} - kubectl set image deployment/symfexit-worker symfexit-worker=${{ steps.image.outputs.imageTag }} - kubectl set image deployment/symfexit-nginx nginx=${{ steps.image.outputs.imageTag }} diff --git a/.github/workflows/relock-dependencies.yml b/.github/workflows/relock-dependencies.yml deleted file mode 100644 index cdaaccd..0000000 --- a/.github/workflows/relock-dependencies.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: Update lock.json -on: - push: - branches: - - dependabot/pip/** - - update_flake_lock_action - pull_request: - branches: - - dependabot/pip/** - - update_flake_lock_action - workflow_dispatch: # allows manual triggering - -permissions: - # Give the default GITHUB_TOKEN write permission to commit and push the - # added or changed files to the repository. - contents: write - -jobs: - lockfile: - name: Commit new lock.json - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - name: Install Nix - uses: DeterminateSystems/nix-installer-action@main - - uses: DeterminateSystems/magic-nix-cache-action@main - - name: Relock dependencies after requirements.txt change - run: | - nix run '.#relock-dependencies' - - uses: stefanzweifel/git-auto-commit-action@v5.0.1 - with: - commit_message: "[dependabot skip] Relock dependencies" - branch: ${{ github.head_ref }} diff --git a/lock.x86_64-linux.json b/lock.x86_64-linux.json deleted file mode 100644 index 9cfe226..0000000 --- a/lock.x86_64-linux.json +++ /dev/null @@ -1,221 +0,0 @@ -{ - "fetchPipMetadata": { - "sources": { - "asgiref": { - "is_direct": false, - "sha256": "3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47", - "type": "url", - "url": "https://files.pythonhosted.org/packages/39/e3/893e8757be2612e6c266d9bb58ad2e3651524b5b40cf56761e985a28b13e/asgiref-3.8.1-py3-none-any.whl", - "version": "3.8.1" - }, - "certifi": { - "is_direct": false, - "sha256": "c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90", - "type": "url", - "url": "https://files.pythonhosted.org/packages/1c/d5/c84e1a17bf61d4df64ca866a1c9a913874b4e9bdc131ec689a0ad013fb36/certifi-2024.7.4-py3-none-any.whl", - "version": "2024.7.4" - }, - "charset-normalizer": { - "is_direct": false, - "sha256": "90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b", - "type": "url", - "url": "https://files.pythonhosted.org/packages/ee/fb/14d30eb4956408ee3ae09ad34299131fb383c47df355ddb428a7331cfa1e/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", - "version": "3.3.2" - }, - "dj-database-url": { - "is_direct": false, - "sha256": "3e792567b0aa9a4884860af05fe2aa4968071ad351e033b6db632f97ac6db9de", - "type": "url", - "url": "https://files.pythonhosted.org/packages/6f/9a/13f173c716d07283661e821f7e1624d0904835151b4f099687455dbef81e/dj_database_url-2.2.0-py3-none-any.whl", - "version": "2.2.0" - }, - "django": { - "is_direct": false, - "sha256": "71603f27dac22a6533fb38d83072eea9ddb4017fead6f67f2562a40402d61c3f", - "type": "url", - "url": "https://files.pythonhosted.org/packages/ba/aa/b423e37e9ba5480d3fd1d187e3fdbd09f9f71b991468881a45413522ccd3/Django-5.1.1-py3-none-any.whl", - "version": "5.1.1" - }, - "django-constance": { - "is_direct": false, - "sha256": "e5e05acbf329c3addec141f3911989d58c423ebc3bc92e1359f9c1dd77e08e95", - "type": "url", - "url": "https://files.pythonhosted.org/packages/1c/1a/530a132d6b02f00324518833a6c7ca41c46d50932aae30fd854d93ee37dd/django_constance-4.1.3-py3-none-any.whl", - "version": "4.1.3" - }, - "django-picklefield": { - "is_direct": false, - "sha256": "e9a73539d110f69825d9320db18bcb82e5189ff48dbed41821c026a20497764c", - "type": "url", - "url": "https://files.pythonhosted.org/packages/52/f9/1502538efa2d4cd3a88ff806cdbd08b1c681dd828d05b6dbc8bcb50a8586/django_picklefield-3.2-py3-none-any.whl", - "version": "3.2" - }, - "django-tailwind": { - "is_direct": false, - "sha256": "fa969c5b95d314b173fe2b2ed2cb2c03f2e2c94fdc2c01ff73a993fa159085da", - "type": "url", - "url": "https://files.pythonhosted.org/packages/cf/14/20c40882d9ee91f7a2a20d3c0175cf813340c02ae31c975ce567de2c7c67/django_tailwind-3.8.0-py3-none-any.whl", - "version": "3.8.0" - }, - "django-tinymce": { - "is_direct": false, - "sha256": "9804836e6d2b08de3b03a27c100f8c2e9633549913eff8b323678a10cd48b94e", - "type": "url", - "url": "https://files.pythonhosted.org/packages/91/a6/467464d08495360689380906db8e67427c381545ce8af9ce633e0128b004/django_tinymce-4.1.0-py3-none-any.whl", - "version": "4.1.0" - }, - "fontawesomefree": { - "is_direct": false, - "sha256": "599b574431c9bd92ed5fc054d1045a07c42335da36c17884f2b934755eef9089", - "type": "url", - "url": "https://files.pythonhosted.org/packages/bb/e9/d43f5133b73e7ef9047bda28daaa6905e00b7d39f093b547f7e78ee2fc40/fontawesomefree-6.6.0-py3-none-any.whl", - "version": "6.6.0" - }, - "hashids": { - "is_direct": false, - "sha256": "8bddd1acba501bfc9306e7e5a99a1667f4f2cacdc20cbd70bcc5ddfa5147c94c", - "type": "url", - "url": "https://files.pythonhosted.org/packages/6e/46/ffdf25b1f6dbb1ce588ccb818e983df9e3d30594679f5a08c865a59cead7/hashids-1.3.1-py2.py3-none-any.whl", - "version": "1.3.1" - }, - "idna": { - "is_direct": false, - "sha256": "946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", - "type": "url", - "url": "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", - "version": "3.10" - }, - "mollie-api-python": { - "is_direct": false, - "sha256": "d5d448194a0cf2e70fc7515c619d2a44eab3499e0d9482d838f79a4955e294fb", - "type": "url", - "url": "https://files.pythonhosted.org/packages/3f/a1/847db69cb37ed0e50f8b952d99bb103ebe88061e1b4f7f5e7cf450646b14/mollie_api_python-3.7.2-py3-none-any.whl", - "version": "3.7.2" - }, - "oauthlib": { - "is_direct": false, - "sha256": "8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca", - "type": "url", - "url": "https://files.pythonhosted.org/packages/7e/80/cab10959dc1faead58dc8384a781dfbf93cb4d33d50988f7a69f1b7c9bbe/oauthlib-3.2.2-py3-none-any.whl", - "version": "3.2.2" - }, - "pillow": { - "is_direct": false, - "sha256": "86dcb5a1eb778d8b25659d5e4341269e8590ad6b4e8b44d9f4b07f8d136c414a", - "type": "url", - "url": "https://files.pythonhosted.org/packages/55/77/40daddf677897a923d5d33329acd52a2144d54a9644f2a5422c028c6bf2d/pillow-10.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", - "version": "10.4.0" - }, - "psycopg": { - "is_direct": false, - "sha256": "644d3973fe26908c73d4be746074f6e5224b03c1101d302d9a53bf565ad64907", - "type": "url", - "url": "https://files.pythonhosted.org/packages/ce/21/534b8f5bd9734b7a2fcd3a16b1ee82ef6cad81a4796e95ebf4e0c6a24119/psycopg-3.2.3-py3-none-any.whl", - "version": "3.2.3" - }, - "psycopg-c": { - "is_direct": false, - "sha256": "06ae7db8eaec1a3845960fa7f997f4ccdb1a7a7ab8dc593a680bcc74e1359671", - "type": "url", - "url": "https://files.pythonhosted.org/packages/53/ba/74caf4eab78d95a173e65cb81507a589365aeafb1d9c84f374002b51dc53/psycopg_c-3.2.3.tar.gz", - "version": "3.2.3" - }, - "requests": { - "is_direct": false, - "sha256": "70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", - "type": "url", - "url": "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", - "version": "2.32.3" - }, - "requests-oauthlib": { - "is_direct": false, - "sha256": "7dd8a5c40426b779b0868c404bdef9768deccf22749cde15852df527e6269b36", - "type": "url", - "url": "https://files.pythonhosted.org/packages/3b/5d/63d4ae3b9daea098d5d6f5da83984853c1bbacd5dc826764b249fe119d24/requests_oauthlib-2.0.0-py2.py3-none-any.whl", - "version": "2.0.0" - }, - "setuptools": { - "is_direct": false, - "sha256": "35ab7fd3bcd95e6b7fd704e4a1539513edad446c097797f2985e0e4b960772f2", - "type": "url", - "url": "https://files.pythonhosted.org/packages/ff/ae/f19306b5a221f6a436d8f2238d5b80925004093fa3edea59835b514d9057/setuptools-75.1.0-py3-none-any.whl", - "version": "75.1.0" - }, - "sqlparse": { - "is_direct": false, - "sha256": "773dcbf9a5ab44a090f3441e2180efe2560220203dc2f8c0b0fa141e18b505e4", - "type": "url", - "url": "https://files.pythonhosted.org/packages/5d/a5/b2860373aa8de1e626b2bdfdd6df4355f0565b47e51f7d0c54fe70faf8fe/sqlparse-0.5.1-py3-none-any.whl", - "version": "0.5.1" - }, - "typing-extensions": { - "is_direct": false, - "sha256": "04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", - "type": "url", - "url": "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", - "version": "4.12.2" - }, - "urllib3": { - "is_direct": false, - "sha256": "ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", - "type": "url", - "url": "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl", - "version": "2.2.3" - } - }, - "targets": { - "default": { - "asgiref": [], - "certifi": [], - "charset-normalizer": [], - "dj-database-url": [ - "django", - "typing-extensions" - ], - "django": [ - "asgiref", - "sqlparse" - ], - "django-constance": [], - "django-picklefield": [ - "django" - ], - "django-tailwind": [ - "django" - ], - "django-tinymce": [ - "django" - ], - "fontawesomefree": [], - "hashids": [], - "idna": [], - "mollie-api-python": [ - "requests", - "requests-oauthlib", - "urllib3" - ], - "oauthlib": [], - "pillow": [], - "psycopg": [ - "typing-extensions" - ], - "psycopg-c": [], - "requests": [ - "certifi", - "charset-normalizer", - "idna", - "urllib3" - ], - "requests-oauthlib": [ - "oauthlib", - "requests" - ], - "setuptools": [], - "sqlparse": [], - "typing-extensions": [], - "urllib3": [] - } - } - }, - "invalidationHash": "d7bc81fd9dbcf78f2698bb29faf9abb258f2eb127bff73b1c3994fa5b0098d97" -} \ No newline at end of file diff --git a/src/manage.py b/manage.py similarity index 88% rename from src/manage.py rename to manage.py index 86beac5..b2c368d 100755 --- a/src/manage.py +++ b/manage.py @@ -1,12 +1,13 @@ #!/usr/bin/env python """Django's command-line utility for administrative tasks.""" + import os import sys def main(): """Run administrative tasks.""" - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "symfexit.settings") + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "symfexit.root.settings") try: from django.core.management import execute_from_command_line except ImportError as exc: diff --git a/manifests/deployment.yaml b/manifests/deployment.yaml deleted file mode 100644 index 50dc4f2..0000000 --- a/manifests/deployment.yaml +++ /dev/null @@ -1,384 +0,0 @@ -# PVC for the app data, should allow multiple writers -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: symfexit-data - namespace: symfexit-staging -spec: - accessModes: - - ReadWriteMany - resources: - requests: - storage: 20Gi - storageClassName: ceph-filesystem ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: symfexit - namespace: symfexit-staging - labels: - app: symfexit -spec: - replicas: 3 - selector: - matchLabels: - app: symfexit - template: - metadata: - labels: - app: symfexit - spec: - initContainers: - - name: symfexit-migrations - image: ghcr.io/roodjong/symfexit:main - imagePullPolicy: Always - args: - - django-admin - - migrate - env: - - name: DJANGO_ENV - value: production - - name: CONTENT_DIR - value: /data - - name: SYMFEXIT_SECRET_KEY - valueFrom: - secretKeyRef: - name: symfexit-secret - key: secret_key - - name: STATIC_ROOT - value: /staticfiles - - name: ALLOWED_HOSTS - value: "*" - - name: DATABASE_URL - valueFrom: - secretKeyRef: - name: symfexit-pguser-symfexit - key: pgbouncer-uri - containers: - - name: symfexit - image: ghcr.io/roodjong/symfexit:main - imagePullPolicy: Always - ports: - - containerPort: 8000 - args: - - uvicorn - - symfexit.asgi:application - - --host - - 0.0.0.0 - env: - - name: DJANGO_ENV - value: production - - name: CONTENT_DIR - value: /data - - name: SYMFEXIT_SECRET_KEY - valueFrom: - secretKeyRef: - name: symfexit-secret - key: secret_key - - name: STATIC_ROOT - value: /staticfiles - - name: ALLOWED_HOSTS - value: "*" - - name: DATABASE_URL - valueFrom: - secretKeyRef: - name: symfexit-pguser-symfexit - key: pgbouncer-uri - livenessProbe: - httpGet: - path: /healthz - port: 8000 - initialDelaySeconds: 2 - periodSeconds: 5 - volumeMounts: - - name: symfexit-data - mountPath: /data - volumes: - - name: symfexit-data - persistentVolumeClaim: - claimName: symfexit-data ---- -apiVersion: v1 -kind: Service -metadata: - name: symfexit - namespace: symfexit-staging -spec: - selector: - app: symfexit - ports: - - protocol: TCP - port: 8000 - targetPort: 8000 ---- -# Symfexit worker -apiVersion: apps/v1 -kind: Deployment -metadata: - name: symfexit-worker - namespace: symfexit-staging - labels: - app: symfexit-worker -spec: - replicas: 1 - selector: - matchLabels: - app: symfexit-worker - template: - metadata: - labels: - app: symfexit-worker - spec: - containers: - - name: symfexit-worker - image: ghcr.io/roodjong/symfexit:main - imagePullPolicy: Always - args: - - django-admin - - startworker - env: - - name: DJANGO_ENV - value: production - - name: CONTENT_DIR - value: /data - - name: SYMFEXIT_SECRET_KEY - valueFrom: - secretKeyRef: - name: symfexit-secret - key: secret_key - - name: STATIC_ROOT - value: /staticfiles - - name: ALLOWED_HOSTS - value: "*" - - name: DATABASE_URL - valueFrom: - secretKeyRef: - name: symfexit-pguser-symfexit - key: pgbouncer-uri - volumeMounts: - - name: symfexit-data - mountPath: /data - volumes: - - name: symfexit-data - persistentVolumeClaim: - claimName: symfexit-data ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: symfexit-nginx-config - namespace: symfexit-staging -data: - nginx.conf: | - worker_processes 1; - events { worker_connections 1024; } - http { - sendfile on; - upstream symfexit { - server symfexit:8000; - } - server { - listen 80; - location / { - proxy_pass http://symfexit; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $http_x_real_ip; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto; - proxy_set_header X-Request-ID $http_x_request_id; - } - location /static/ { - alias /staticfiles/; - } - location /media/ { - alias /data/media/; - } - location /theme/ { - alias /data/theme/; - } - location /.proxy-bin/healthz { - return 200; - } - } - types { - text/html html htm shtml; - text/css css; - text/xml xml; - image/gif gif; - image/jpeg jpeg jpg; - application/javascript js; - application/atom+xml atom; - application/rss+xml rss; - - text/mathml mml; - text/plain txt; - text/vnd.sun.j2me.app-descriptor jad; - text/vnd.wap.wml wml; - text/x-component htc; - - image/avif avif; - image/png png; - image/svg+xml svg svgz; - image/tiff tif tiff; - image/vnd.wap.wbmp wbmp; - image/webp webp; - image/x-icon ico; - image/x-jng jng; - image/x-ms-bmp bmp; - - font/woff woff; - font/woff2 woff2; - - application/java-archive jar war ear; - application/json json; - application/mac-binhex40 hqx; - application/msword doc; - application/pdf pdf; - application/postscript ps eps ai; - application/rtf rtf; - application/vnd.apple.mpegurl m3u8; - application/vnd.google-earth.kml+xml kml; - application/vnd.google-earth.kmz kmz; - application/vnd.ms-excel xls; - application/vnd.ms-fontobject eot; - application/vnd.ms-powerpoint ppt; - application/vnd.oasis.opendocument.graphics odg; - application/vnd.oasis.opendocument.presentation odp; - application/vnd.oasis.opendocument.spreadsheet ods; - application/vnd.oasis.opendocument.text odt; - application/vnd.openxmlformats-officedocument.presentationml.presentation - pptx; - application/vnd.openxmlformats-officedocument.spreadsheetml.sheet - xlsx; - application/vnd.openxmlformats-officedocument.wordprocessingml.document - docx; - application/vnd.wap.wmlc wmlc; - application/wasm wasm; - application/x-7z-compressed 7z; - application/x-cocoa cco; - application/x-java-archive-diff jardiff; - application/x-java-jnlp-file jnlp; - application/x-makeself run; - application/x-perl pl pm; - application/x-pilot prc pdb; - application/x-rar-compressed rar; - application/x-redhat-package-manager rpm; - application/x-sea sea; - application/x-shockwave-flash swf; - application/x-stuffit sit; - application/x-tcl tcl tk; - application/x-x509-ca-cert der pem crt; - application/x-xpinstall xpi; - application/xhtml+xml xhtml; - application/xspf+xml xspf; - application/zip zip; - - application/octet-stream bin exe dll; - application/octet-stream deb; - application/octet-stream dmg; - application/octet-stream iso img; - application/octet-stream msi msp msm; - - audio/midi mid midi kar; - audio/mpeg mp3; - audio/ogg ogg; - audio/x-m4a m4a; - audio/x-realaudio ra; - - video/3gpp 3gpp 3gp; - video/mp2t ts; - video/mp4 mp4; - video/mpeg mpeg mpg; - video/quicktime mov; - video/webm webm; - video/x-flv flv; - video/x-m4v m4v; - video/x-mng mng; - video/x-ms-asf asx asf; - video/x-ms-wmv wmv; - video/x-msvideo avi; - } - } ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: symfexit-nginx - namespace: symfexit-staging - labels: - app: symfexit-nginx -spec: - replicas: 3 - selector: - matchLabels: - app: symfexit-nginx - template: - metadata: - labels: - app: symfexit-nginx - spec: - containers: - - name: nginx - image: ghcr.io/roodjong/symfexit:main - imagePullPolicy: Always - args: - - nginx - - -c - - /etc/nginx/nginx.conf - volumeMounts: - - name: symfexit-nginx-config - mountPath: /etc/nginx/nginx.conf - subPath: nginx.conf - - name: symfexit-data - mountPath: /data - livenessProbe: - httpGet: - path: /.proxy-bin/healthz - port: 80 - initialDelaySeconds: 2 - periodSeconds: 5 - volumes: - - name: symfexit-nginx-config - configMap: - name: symfexit-nginx-config - - name: symfexit-data - persistentVolumeClaim: - claimName: symfexit-data ---- -# Service for symfexit-nginx -apiVersion: v1 -kind: Service -metadata: - name: symfexit-nginx - namespace: symfexit-staging -spec: - selector: - app: symfexit-nginx - ports: - - protocol: TCP - port: 80 - targetPort: 80 ---- -apiVersion: gateway.networking.k8s.io/v1beta1 -kind: HTTPRoute -metadata: - name: symfexit-nginx - namespace: symfexit-staging -spec: - parentRefs: - - name: eg - namespace: default - hostnames: - - "symfexit-staging.yele.dev" - rules: - - backendRefs: - - group: "" - kind: Service - name: symfexit-nginx - port: 80 - weight: 1 - matches: - - path: - type: PathPrefix - value: / diff --git a/manifests/ns.yaml b/manifests/ns.yaml deleted file mode 100644 index a5242e7..0000000 --- a/manifests/ns.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: symfexit-staging - labels: - shared-gateway-access: "true" diff --git a/manifests/percona-db.yaml b/manifests/percona-db.yaml deleted file mode 100644 index e569989..0000000 --- a/manifests/percona-db.yaml +++ /dev/null @@ -1,479 +0,0 @@ -# ConfigMap for databaseInitSQL -apiVersion: v1 -kind: ConfigMap -metadata: - name: symfexit-staging-init-sql -data: - init.sql: | - ALTER DATABASE symfexit OWNER TO symfexit; ---- -apiVersion: pgv2.percona.com/v2 -kind: PerconaPGCluster -metadata: - name: symfexit -# finalizers: -# - percona.com/delete-pvc -# - percona.com/delete-ssl -spec: - crVersion: 2.4.0 -# secrets: -# customTLSSecret: -# name: cluster1-cert -# customReplicationTLSSecret: -# name: replication1-cert - -# standby: -# enabled: true -# host: "" -# port: "" -# repoName: repo1 - -# openshift: true - - databaseInitSQL: - key: init.sql - name: symfexit-staging-init-sql - -# pause: true -# unmanaged: true -# dataSource: -# postgresCluster: -# clusterName: cluster1 -# repoName: repo1 -# options: -# - --type=time -# - --target="2021-06-09 14:15:11-04" -# tolerations: -# - effect: NoSchedule -# key: role -# operator: Equal -# value: connection-poolers -# pgbackrest: -# stanza: db -# configuration: -# - secret: -# name: pgo-s3-creds -# global: -# repo1-path: /pgbackrest/postgres-operator/hippo/repo1 -# repo: -# name: repo1 -# s3: -# bucket: "my-bucket" -# endpoint: "s3.ca-central-1.amazonaws.com" -# region: "ca-central-1" -# tolerations: -# - effect: NoSchedule -# key: role -# operator: Equal -# value: connection-poolers -# volumes: -# pgDataVolume: -# pvcName: cluster1 -# directory: cluster1 -# tolerations: -# - effect: NoSchedule -# key: role -# operator: Equal -# value: connection-poolers -# annotations: -# test-annotation: value -# labels: -# test-label: value -# pgWALVolume: -# pvcName: cluster1-pvc-name -# directory: some-dir -# tolerations: -# - effect: NoSchedule -# key: role -# operator: Equal -# value: connection-poolers -# annotations: -# test-annotation: value -# labels: -# test-label: value -# pgBackRestVolume: -# pvcName: cluster1-pgbr-repo -# directory: cluster1-backrest-shared-repo -# tolerations: -# - effect: NoSchedule -# key: role -# operator: Equal -# value: connection-poolers -# annotations: -# test-annotation: value -# labels: -# test-label: value - - - image: percona/percona-postgresql-operator:2.4.0-ppg16.3-postgres - imagePullPolicy: Always - postgresVersion: 16 -# port: 5432 - -# expose: -# annotations: -# my-annotation: value1 -# labels: -# my-label: value2 -# type: LoadBalancer -# loadBalancerSourceRanges: -# - 10.0.0.0/8 -# exposeReplicas: -# annotations: -# my-annotation: value1 -# labels: -# my-label: value2 -# type: LoadBalancer -# loadBalancerSourceRanges: -# - 10.0.0.0/8 - - instances: - - name: instance1 - replicas: 3 - - affinity: - podAntiAffinity: - preferredDuringSchedulingIgnoredDuringExecution: - - weight: 1 - podAffinityTerm: - labelSelector: - matchLabels: - postgres-operator.crunchydata.com/data: postgres - topologyKey: kubernetes.io/hostname -# resources: -# limits: -# cpu: 2.0 -# memory: 4Gi -# containers: -# replicaCertCopy: -# resources: -# limits: -# cpu: 200m -# memory: 128Mi -# sidecars: -# - name: testcontainer -# image: mycontainer1:latest -# - name: testcontainer2 -# image: mycontainer1:latest -# -# topologySpreadConstraints: -# - maxSkew: 1 -# topologyKey: my-node-label -# whenUnsatisfiable: DoNotSchedule -# labelSelector: -# matchLabels: -# postgres-operator.crunchydata.com/instance-set: instance1 -# -# tolerations: -# - effect: NoSchedule -# key: role -# operator: Equal -# value: connection-poolers -# -# priorityClassName: high-priority -# -# securityContext: -# fsGroup: 1001 -# runAsUser: 1001 -# runAsNonRoot: true -# fsGroupChangePolicy: "OnRootMismatch" -# runAsGroup: 1001 -# seLinuxOptions: -# type: spc_t -# level: s0:c123,c456 -# seccompProfile: -# type: Localhost -# localhostProfile: localhost/profile.json -# supplementalGroups: -# - 1001 -# sysctls: -# - name: net.ipv4.tcp_keepalive_time -# value: "600" -# - name: net.ipv4.tcp_keepalive_intvl -# value: "60" -# -# walVolumeClaimSpec: -# storageClassName: standard -# accessModes: -# - ReadWriteOnce -# resources: -# requests: -# storage: 1Gi -# - dataVolumeClaimSpec: -# storageClassName: standard - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 1Gi -# tablespaceVolumes: -# - name: user -# dataVolumeClaimSpec: -# accessModes: -# - 'ReadWriteOnce' -# resources: -# requests: -# storage: 1Gi - - proxy: - pgBouncer: - replicas: 3 - image: percona/percona-postgresql-operator:2.4.0-ppg16.3-pgbouncer1.22.1 -# resources: -# limits: -# cpu: 200m -# memory: 128Mi -# containers: -# pgbouncerConfig: -# resources: -# limits: -# cpu: 200m -# memory: 128Mi -# -# expose: -# annotations: -# my-annotation: value1 -# labels: -# my-label: value2 -# type: LoadBalancer -# loadBalancerSourceRanges: -# - 10.0.0.0/8 -# - affinity: - podAntiAffinity: - preferredDuringSchedulingIgnoredDuringExecution: - - weight: 1 - podAffinityTerm: - labelSelector: - matchLabels: - postgres-operator.crunchydata.com/role: pgbouncer - topologyKey: kubernetes.io/hostname -# -# tolerations: -# - effect: NoSchedule -# key: role -# operator: Equal -# value: connection-poolers -# -# securityContext: -# fsGroup: 1001 -# runAsUser: 1001 -# runAsNonRoot: true -# fsGroupChangePolicy: "OnRootMismatch" -# runAsGroup: 1001 -# seLinuxOptions: -# type: spc_t -# level: s0:c123,c456 -# seccompProfile: -# type: Localhost -# localhostProfile: localhost/profile.json -# supplementalGroups: -# - 1001 -# sysctls: -# - name: net.ipv4.tcp_keepalive_time -# value: "600" -# - name: net.ipv4.tcp_keepalive_intvl -# value: "60" -# -# topologySpreadConstraints: -# - maxSkew: 1 -# topologyKey: my-node-label -# whenUnsatisfiable: ScheduleAnyway -# labelSelector: -# matchLabels: -# postgres-operator.crunchydata.com/role: pgbouncer -# -# sidecars: -# - name: bouncertestcontainer1 -# image: mycontainer1:latest -# -# customTLSSecret: -# name: keycloakdb-pgbouncer.tls -# -# config: -# global: -# pool_mode: transaction - - backups: - pgbackrest: -# metadata: -# labels: - image: percona/percona-postgresql-operator:2.4.0-ppg16.3-pgbackrest2.51-1 -# -# containers: -# pgbackrest: -# resources: -# limits: -# cpu: 200m -# memory: 128Mi -# pgbackrestConfig: -# resources: -# limits: -# cpu: 200m -# memory: 128Mi -# -# configuration: -# - secret: -# name: cluster1-pgbackrest-secrets -# jobs: -# priorityClassName: high-priority -# resources: -# limits: -# cpu: 200m -# memory: 128Mi -# tolerations: -# - effect: NoSchedule -# key: role -# operator: Equal -# value: connection-poolers -# -# securityContext: -# fsGroup: 1001 -# runAsUser: 1001 -# runAsNonRoot: true -# fsGroupChangePolicy: "OnRootMismatch" -# runAsGroup: 1001 -# seLinuxOptions: -# type: spc_t -# level: s0:c123,c456 -# seccompProfile: -# type: Localhost -# localhostProfile: localhost/profile.json -# supplementalGroups: -# - 1001 -# sysctls: -# - name: net.ipv4.tcp_keepalive_time -# value: "600" -# - name: net.ipv4.tcp_keepalive_intvl -# value: "60" -# -# global: -# repo1-retention-full: "14" -# repo1-retention-full-type: time -# repo1-path: /pgbackrest/postgres-operator/cluster1/repo1 -# repo1-cipher-type: aes-256-cbc -# repo1-s3-uri-style: path -# repo2-path: /pgbackrest/postgres-operator/cluster1-multi-repo/repo2 -# repo3-path: /pgbackrest/postgres-operator/cluster1-multi-repo/repo3 -# repo4-path: /pgbackrest/postgres-operator/cluster1-multi-repo/repo4 - repoHost: - affinity: - podAntiAffinity: - preferredDuringSchedulingIgnoredDuringExecution: - - weight: 1 - podAffinityTerm: - labelSelector: - matchLabels: - postgres-operator.crunchydata.com/data: pgbackrest - topologyKey: kubernetes.io/hostname -# tolerations: -# - effect: NoSchedule -# key: role -# operator: Equal -# value: connection-poolers -# priorityClassName: high-priority -# -# topologySpreadConstraints: -# - maxSkew: 1 -# topologyKey: my-node-label -# whenUnsatisfiable: ScheduleAnyway -# labelSelector: -# matchLabels: -# postgres-operator.crunchydata.com/pgbackrest: "" -# -# securityContext: -# fsGroup: 1001 -# runAsUser: 1001 -# runAsNonRoot: true -# fsGroupChangePolicy: "OnRootMismatch" -# runAsGroup: 1001 -# seLinuxOptions: -# type: spc_t -# level: s0:c123,c456 -# seccompProfile: -# type: Localhost -# localhostProfile: localhost/profile.json -# supplementalGroups: -# - 1001 -# sysctls: -# - name: net.ipv4.tcp_keepalive_time -# value: "600" -# - name: net.ipv4.tcp_keepalive_intvl -# value: "60" -# - manual: - repoName: repo1 - options: - - --type=full - repos: - - name: repo1 - schedules: - full: "0 0 * * 6" -# differential: "0 1 * * 1-6" -# incremental: "0 1 * * 1-6" - volume: - volumeClaimSpec: -# storageClassName: standard - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 1Gi -# - name: repo2 -# s3: -# bucket: "" -# endpoint: "" -# region: "" -# - name: repo3 -# gcs: -# bucket: "" -# - name: repo4 -# azure: -# container: "" -# -# restore: -# repoName: repo1 -# tolerations: -# - effect: NoSchedule -# key: role -# operator: Equal -# value: connection-poolers - - pmm: - enabled: false - image: percona/pmm-client:2.42.0 -# imagePullPolicy: IfNotPresent - secret: cluster1-pmm-secret - serverHost: monitoring-service -# patroni: -# # Some values of the Liveness/Readiness probes of the patroni container are calulated using syncPeriodSeconds by the following formulas: -# # - timeoutSeconds: syncPeriodSeconds / 2; -# # - periodSeconds: syncPeriodSeconds; -# # - failureThreshold: leaderLeaseDurationSeconds / syncPeriodSeconds. -# syncPeriodSeconds: 10 # default: 10 -# leaderLeaseDurationSeconds: 30 # default: 30 -# dynamicConfiguration: -# postgresql: -# parameters: -# max_parallel_workers: 2 -# max_worker_processes: 2 -# shared_buffers: 1GB -# work_mem: 2MB - -# extensions: -# image: percona/percona-postgresql-operator:2.4.0 -# imagePullPolicy: Always -# storage: -# type: s3 -# bucket: pg-extensions -# region: eu-central-1 -# endpoint: s3.eu-central-1.amazonaws.com -# secret: -# name: cluster1-extensions-secret -# builtin: -# pg_stat_monitor: true -# pg_audit: true -# custom: -# - name: pg_cron -# version: 1.6.1 diff --git a/pip-snapshot-date.txt b/pip-snapshot-date.txt deleted file mode 100644 index 03784f8..0000000 --- a/pip-snapshot-date.txt +++ /dev/null @@ -1 +0,0 @@ -2024-11-16 diff --git a/pyproject.toml b/pyproject.toml index ea912cb..a671be8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,13 +21,14 @@ dependencies = [ "pillow ~= 10.0", "psycopg[c] ~= 3.2.1", ] -requires-python = ">= 3.10" +requires-python = ">= 3.12" optional-dependencies.dev = [ "black", "django-browser-reload ~= 1.6", "isort", "pip-tools", + "ruff>=0.6.8", ] [tool.setuptools] @@ -43,3 +44,36 @@ where = ["src"] [build-system] requires = ["setuptools>=61.0"] build-backend = "setuptools.build_meta" + +[tool.black] +line-length = 100 +target-version = ['py312'] +exclude = 'node_modules' + +[tool.ruff] +line-length = 100 +target-version = "py312" +exclude = ["**/migrations/**", "**/node_modules/**"] + +[tool.ruff.lint] +select = [ + # pycodestyle + "E", + # Pyflakes + "F", + # isort + "I", + # pyupgrade + "UP", + # flake8-bugbear + "B", + # django + "DJ", + # pylint + "PL", +] + +[tool.ruff.lint.pylint] +max-args = 7 +max-branches = 18 +max-returns = 10 diff --git a/src/adminsite/models.py b/src/adminsite/models.py deleted file mode 100644 index 71a8362..0000000 --- a/src/adminsite/models.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.db import models - -# Create your models here. diff --git a/src/adminsite/tests.py b/src/adminsite/tests.py deleted file mode 100644 index 7ce503c..0000000 --- a/src/adminsite/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/src/adminsite/views.py b/src/adminsite/views.py deleted file mode 100644 index 91ea44a..0000000 --- a/src/adminsite/views.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.shortcuts import render - -# Create your views here. diff --git a/src/documents/migrations/0002_alter_directory_options_alter_file_options_and_more.py b/src/documents/migrations/0002_alter_directory_options_alter_file_options_and_more.py deleted file mode 100644 index 458f2c3..0000000 --- a/src/documents/migrations/0002_alter_directory_options_alter_file_options_and_more.py +++ /dev/null @@ -1,64 +0,0 @@ -# Generated by Django 5.0.6 on 2024-07-10 12:49 - -import django.db.models.deletion -import documents.models -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("documents", "0001_initial"), - ] - - operations = [ - migrations.AlterModelOptions( - name="directory", - options={"verbose_name": "directory", "verbose_name_plural": "directories"}, - ), - migrations.AlterModelOptions( - name="file", - options={"verbose_name": "file", "verbose_name_plural": "files"}, - ), - migrations.AlterField( - model_name="file", - name="content", - field=models.FileField( - upload_to=documents.models.file_location, verbose_name="content" - ), - ), - migrations.AlterField( - model_name="file", - name="content_type", - field=models.TextField( - default="application/octet-stream", verbose_name="content type" - ), - ), - migrations.AlterField( - model_name="file", - name="size", - field=models.IntegerField(default=0, verbose_name="size"), - ), - migrations.AlterField( - model_name="filenode", - name="created_at", - field=models.DateTimeField(auto_now_add=True, verbose_name="created at"), - ), - migrations.AlterField( - model_name="filenode", - name="name", - field=models.TextField(verbose_name="name"), - ), - migrations.AlterField( - model_name="filenode", - name="parent", - field=models.ForeignKey( - blank=True, - null=True, - on_delete=django.db.models.deletion.CASCADE, - related_name="children", - to="documents.directory", - verbose_name="parent directory", - ), - ), - ] diff --git a/src/documents/tests.py b/src/documents/tests.py deleted file mode 100644 index 7ce503c..0000000 --- a/src/documents/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/src/home/migrations/0002_alter_homepage_options_alter_homepage_content_and_more.py b/src/home/migrations/0002_alter_homepage_options_alter_homepage_content_and_more.py deleted file mode 100644 index 4d74b4f..0000000 --- a/src/home/migrations/0002_alter_homepage_options_alter_homepage_content_and_more.py +++ /dev/null @@ -1,28 +0,0 @@ -# Generated by Django 5.0.6 on 2024-07-10 12:49 - -import tinymce.models -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("home", "0001_initial"), - ] - - operations = [ - migrations.AlterModelOptions( - name="homepage", - options={"verbose_name": "home page", "verbose_name_plural": "home pages"}, - ), - migrations.AlterField( - model_name="homepage", - name="content", - field=tinymce.models.HTMLField(verbose_name="Content"), - ), - migrations.AlterField( - model_name="homepage", - name="title", - field=models.CharField(blank=True, max_length=50, verbose_name="Title"), - ), - ] diff --git a/src/home/tests.py b/src/home/tests.py deleted file mode 100644 index 7ce503c..0000000 --- a/src/home/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/src/members/migrations/0002_localgroup_contact_people_delete_contactperson.py b/src/members/migrations/0002_localgroup_contact_people_delete_contactperson.py deleted file mode 100644 index 1df4cd3..0000000 --- a/src/members/migrations/0002_localgroup_contact_people_delete_contactperson.py +++ /dev/null @@ -1,24 +0,0 @@ -# Generated by Django 5.0.6 on 2024-07-09 18:31 - -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("members", "0001_initial"), - ] - - operations = [ - migrations.AddField( - model_name="localgroup", - name="contact_people", - field=models.ManyToManyField( - related_name="contact_person_for_groups", to=settings.AUTH_USER_MODEL - ), - ), - migrations.DeleteModel( - name="ContactPerson", - ), - ] diff --git a/src/members/migrations/0003_alter_localgroup_options_alter_user_options_and_more.py b/src/members/migrations/0003_alter_localgroup_options_alter_user_options_and_more.py deleted file mode 100644 index be79b8e..0000000 --- a/src/members/migrations/0003_alter_localgroup_options_alter_user_options_and_more.py +++ /dev/null @@ -1,74 +0,0 @@ -# Generated by Django 5.0.6 on 2024-07-10 12:49 - -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("members", "0002_localgroup_contact_people_delete_contactperson"), - ] - - operations = [ - migrations.AlterModelOptions( - name="localgroup", - options={ - "verbose_name": "local group", - "verbose_name_plural": "local groups", - }, - ), - migrations.AlterModelOptions( - name="user", - options={"verbose_name": "member", "verbose_name_plural": "members"}, - ), - migrations.AlterField( - model_name="localgroup", - name="contact_people", - field=models.ManyToManyField( - related_name="contact_person_for_groups", - to=settings.AUTH_USER_MODEL, - verbose_name="contact people", - ), - ), - migrations.AlterField( - model_name="user", - name="address", - field=models.TextField(verbose_name="address"), - ), - migrations.AlterField( - model_name="user", - name="city", - field=models.TextField(verbose_name="cith"), - ), - migrations.AlterField( - model_name="user", - name="email", - field=models.EmailField(max_length=254, verbose_name="email"), - ), - migrations.AlterField( - model_name="user", - name="first_name", - field=models.TextField(verbose_name="first name"), - ), - migrations.AlterField( - model_name="user", - name="last_name", - field=models.TextField(verbose_name="last name"), - ), - migrations.AlterField( - model_name="user", - name="member_identifier", - field=models.TextField(unique=True, verbose_name="member number"), - ), - migrations.AlterField( - model_name="user", - name="phone_number", - field=models.TextField(verbose_name="phone number"), - ), - migrations.AlterField( - model_name="user", - name="postal_code", - field=models.TextField(verbose_name="postal code"), - ), - ] diff --git a/src/members/tests.py b/src/members/tests.py deleted file mode 100644 index 7ce503c..0000000 --- a/src/members/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/src/membership/migrations/0002_alter_membership_options.py b/src/membership/migrations/0002_alter_membership_options.py deleted file mode 100644 index 23a86a8..0000000 --- a/src/membership/migrations/0002_alter_membership_options.py +++ /dev/null @@ -1,20 +0,0 @@ -# Generated by Django 5.0.6 on 2024-07-10 12:49 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ("membership", "0001_initial"), - ] - - operations = [ - migrations.AlterModelOptions( - name="membership", - options={ - "verbose_name": "membership", - "verbose_name_plural": "memberships", - }, - ), - ] diff --git a/src/membership/tests.py b/src/membership/tests.py deleted file mode 100644 index 7ce503c..0000000 --- a/src/membership/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/src/membership/views.py b/src/membership/views.py deleted file mode 100644 index 91ea44a..0000000 --- a/src/membership/views.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.shortcuts import render - -# Create your views here. diff --git a/src/menu/admin.py b/src/menu/admin.py deleted file mode 100644 index 8c38f3f..0000000 --- a/src/menu/admin.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.contrib import admin - -# Register your models here. diff --git a/src/menu/tests.py b/src/menu/tests.py deleted file mode 100644 index 7ce503c..0000000 --- a/src/menu/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/src/payments/admin.py b/src/payments/admin.py deleted file mode 100644 index 4909628..0000000 --- a/src/payments/admin.py +++ /dev/null @@ -1,33 +0,0 @@ -from django.contrib import admin - -from payments.models import BillingAddress, Order - - -# Register your models here. -@admin.register(Order) -class PayableAdmin(admin.ModelAdmin): - # show the eid - list_display = ("eid", "price", "description", "payment_status") - # show the eid in the detail display as a readonly field - readonly_fields = ("eid", "price", "description", "payment_status") - - # don't show the add button - def has_add_permission(self, request): - return False - - # don't show the delete button - def has_delete_permission(self, request, obj: Order = None): - if obj is None: - return False - return obj.payment_status == Order.Status.EXPIRED - - # don't show the change button - def has_change_permission(self, request, obj=None): - return False - - -@admin.register(BillingAddress) -class BillingAddressAdmin(admin.ModelAdmin): - search_fields = ("id", "name") - list_display = ("id", "name", "address", "city") - fields = ("name", "address", "city", "postal_code", "user") diff --git a/src/payments/migrations/0002_alter_order_options_alter_subscription_options_and_more.py b/src/payments/migrations/0002_alter_order_options_alter_subscription_options_and_more.py deleted file mode 100644 index 2d21b13..0000000 --- a/src/payments/migrations/0002_alter_order_options_alter_subscription_options_and_more.py +++ /dev/null @@ -1,120 +0,0 @@ -# Generated by Django 5.0.6 on 2024-07-10 12:49 - -import django.db.models.deletion -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("payments", "0001_initial"), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.AlterModelOptions( - name="order", - options={"verbose_name": "order", "verbose_name_plural": "orders"}, - ), - migrations.AlterModelOptions( - name="subscription", - options={ - "verbose_name": "subscription", - "verbose_name_plural": "subscriptions", - }, - ), - migrations.AlterField( - model_name="billingaddress", - name="address", - field=models.CharField(max_length=100, verbose_name="address"), - ), - migrations.AlterField( - model_name="billingaddress", - name="city", - field=models.CharField(max_length=100, verbose_name="city"), - ), - migrations.AlterField( - model_name="billingaddress", - name="name", - field=models.CharField(max_length=100, verbose_name="name"), - ), - migrations.AlterField( - model_name="billingaddress", - name="postal_code", - field=models.CharField(max_length=100, verbose_name="postal code"), - ), - migrations.AlterField( - model_name="billingaddress", - name="user", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - to=settings.AUTH_USER_MODEL, - verbose_name="user", - ), - ), - migrations.AlterField( - model_name="order", - name="address", - field=models.ForeignKey( - on_delete=django.db.models.deletion.PROTECT, - to="payments.billingaddress", - verbose_name="billing address", - ), - ), - migrations.AlterField( - model_name="order", - name="description", - field=models.TextField(verbose_name="description"), - ), - migrations.AlterField( - model_name="order", - name="done_at", - field=models.DateTimeField(null=True, verbose_name="done at"), - ), - migrations.AlterField( - model_name="order", - name="payment_method", - field=models.CharField( - max_length=100, null=True, verbose_name="payment method" - ), - ), - migrations.AlterField( - model_name="order", - name="payment_status", - field=models.CharField( - choices=[ - ("created", "Created"), - ("pending", "Pending"), - ("paid", "Paid"), - ("failed", "Failed"), - ("cancelled", "Cancelled"), - ("expired", "Expired"), - ], - default="created", - max_length=10, - verbose_name="payment status", - ), - ), - migrations.AlterField( - model_name="order", - name="price", - field=models.IntegerField(verbose_name="price"), - ), - migrations.AlterField( - model_name="order", - name="return_url", - field=models.URLField(null=True, verbose_name="return URL"), - ), - migrations.AlterField( - model_name="order", - name="subscription", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.RESTRICT, - to="payments.subscription", - verbose_name="subscription", - ), - ), - ] diff --git a/src/payments/tests.py b/src/payments/tests.py deleted file mode 100644 index 7ce503c..0000000 --- a/src/payments/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/src/payments/views.py b/src/payments/views.py deleted file mode 100644 index 91ea44a..0000000 --- a/src/payments/views.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.shortcuts import render - -# Create your views here. diff --git a/src/payments_dummy/admin.py b/src/payments_dummy/admin.py deleted file mode 100644 index 8c38f3f..0000000 --- a/src/payments_dummy/admin.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.contrib import admin - -# Register your models here. diff --git a/src/payments_dummy/forms.py b/src/payments_dummy/forms.py deleted file mode 100644 index 284214f..0000000 --- a/src/payments_dummy/forms.py +++ /dev/null @@ -1,7 +0,0 @@ -from django import forms - -from payments.models import Order - - -class FakePayForm(forms.Form): - payment_status = forms.ChoiceField(choices=Order.Status.choices) diff --git a/src/payments_dummy/models.py b/src/payments_dummy/models.py deleted file mode 100644 index 71a8362..0000000 --- a/src/payments_dummy/models.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.db import models - -# Create your models here. diff --git a/src/payments_dummy/tests.py b/src/payments_dummy/tests.py deleted file mode 100644 index 7ce503c..0000000 --- a/src/payments_dummy/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/src/payments_mollie/admin.py b/src/payments_mollie/admin.py deleted file mode 100644 index 8c38f3f..0000000 --- a/src/payments_mollie/admin.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.contrib import admin - -# Register your models here. diff --git a/src/payments_mollie/tests.py b/src/payments_mollie/tests.py deleted file mode 100644 index 7ce503c..0000000 --- a/src/payments_mollie/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/src/signup/migrations/0002_alter_applicationpayment_options_and_more.py b/src/signup/migrations/0002_alter_applicationpayment_options_and_more.py deleted file mode 100644 index ddd9cf4..0000000 --- a/src/signup/migrations/0002_alter_applicationpayment_options_and_more.py +++ /dev/null @@ -1,114 +0,0 @@ -# Generated by Django 5.0.6 on 2024-07-10 12:49 - -import django.db.models.deletion -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("members", "0003_alter_localgroup_options_alter_user_options_and_more"), - ("signup", "0001_initial"), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.AlterModelOptions( - name="applicationpayment", - options={ - "verbose_name": "application payment", - "verbose_name_plural": "application payments", - }, - ), - migrations.AlterModelOptions( - name="membershipapplication", - options={ - "verbose_name": "membership application", - "verbose_name_plural": "membership applications", - }, - ), - migrations.AlterField( - model_name="membershipapplication", - name="address", - field=models.CharField(max_length=100, verbose_name="address"), - ), - migrations.AlterField( - model_name="membershipapplication", - name="birth_date", - field=models.DateField(verbose_name="date of birth"), - ), - migrations.AlterField( - model_name="membershipapplication", - name="city", - field=models.CharField(max_length=100, verbose_name="city"), - ), - migrations.AlterField( - model_name="membershipapplication", - name="created_at", - field=models.DateTimeField(auto_now_add=True, verbose_name="created at"), - ), - migrations.AlterField( - model_name="membershipapplication", - name="email", - field=models.EmailField(max_length=254, verbose_name="email address"), - ), - migrations.AlterField( - model_name="membershipapplication", - name="first_name", - field=models.CharField(max_length=100, verbose_name="first name"), - ), - migrations.AlterField( - model_name="membershipapplication", - name="last_name", - field=models.CharField(max_length=100, verbose_name="last name"), - ), - migrations.AlterField( - model_name="membershipapplication", - name="payment_amount", - field=models.IntegerField(verbose_name="payment amount in cents"), - ), - migrations.AlterField( - model_name="membershipapplication", - name="phone_number", - field=models.CharField(max_length=100, verbose_name="phone number"), - ), - migrations.AlterField( - model_name="membershipapplication", - name="postal_code", - field=models.CharField(max_length=100, verbose_name="postal code"), - ), - migrations.AlterField( - model_name="membershipapplication", - name="preferred_group", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="members.localgroup", - verbose_name="preferred group", - ), - ), - migrations.AlterField( - model_name="membershipapplication", - name="status", - field=models.CharField( - choices=[ - ("created", "Created"), - ("accepted", "Accepted"), - ("rejected", "Rejected"), - ], - default="created", - max_length=10, - verbose_name="status", - ), - ), - migrations.AlterField( - model_name="membershipapplication", - name="user", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - to=settings.AUTH_USER_MODEL, - verbose_name="user", - ), - ), - ] diff --git a/src/signup/tests.py b/src/signup/tests.py deleted file mode 100644 index 7ce503c..0000000 --- a/src/signup/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/src/theme/migrations/0001_initial.py b/src/theme/migrations/0001_initial.py deleted file mode 100644 index 468930a..0000000 --- a/src/theme/migrations/0001_initial.py +++ /dev/null @@ -1,31 +0,0 @@ -# Generated by Django 5.0 on 2024-05-11 15:41 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [] - - operations = [ - migrations.CreateModel( - name="TailwindKey", - fields=[ - ("id", models.IntegerField(primary_key=True, serialize=False)), - ( - "name", - models.CharField( - choices=[ - ("primary", "Primary Color"), - ("secondary", "Secondary Color"), - ], - max_length=20, - unique=True, - ), - ), - ("value", models.TextField()), - ], - ), - ] diff --git a/src/theme/migrations/0002_alter_tailwindkey_id.py b/src/theme/migrations/0002_alter_tailwindkey_id.py deleted file mode 100644 index b452c54..0000000 --- a/src/theme/migrations/0002_alter_tailwindkey_id.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 5.0 on 2024-05-18 12:11 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("theme", "0001_initial"), - ] - - operations = [ - migrations.AlterField( - model_name="tailwindkey", - name="id", - field=models.AutoField(primary_key=True, serialize=False), - ), - ] diff --git a/src/theme/migrations/0003_currentthemeversion.py b/src/theme/migrations/0003_currentthemeversion.py deleted file mode 100644 index 58ecade..0000000 --- a/src/theme/migrations/0003_currentthemeversion.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.0.6 on 2024-06-22 11:26 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("theme", "0002_alter_tailwindkey_id"), - ] - - operations = [ - migrations.CreateModel( - name="CurrentThemeVersion", - fields=[ - ("id", models.AutoField(primary_key=True, serialize=False)), - ("version", models.DateField(auto_now=True)), - ], - options={ - "get_latest_by": "version", - }, - ), - ] diff --git a/src/theme/migrations/0004_alter_currentthemeversion_version.py b/src/theme/migrations/0004_alter_currentthemeversion_version.py deleted file mode 100644 index 0c6724f..0000000 --- a/src/theme/migrations/0004_alter_currentthemeversion_version.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 5.0.6 on 2024-06-22 11:29 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("theme", "0003_currentthemeversion"), - ] - - operations = [ - migrations.AlterField( - model_name="currentthemeversion", - name="version", - field=models.DateTimeField(auto_now=True), - ), - ] diff --git a/src/theme/migrations/0005_alter_tailwindkey_name_alter_tailwindkey_value.py b/src/theme/migrations/0005_alter_tailwindkey_name_alter_tailwindkey_value.py deleted file mode 100644 index 3ee9cae..0000000 --- a/src/theme/migrations/0005_alter_tailwindkey_name_alter_tailwindkey_value.py +++ /dev/null @@ -1,31 +0,0 @@ -# Generated by Django 5.0.6 on 2024-07-10 12:49 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("theme", "0004_alter_currentthemeversion_version"), - ] - - operations = [ - migrations.AlterField( - model_name="tailwindkey", - name="name", - field=models.CharField( - choices=[ - ("primary", "Primary Color"), - ("secondary", "Secondary Color"), - ], - max_length=20, - unique=True, - verbose_name="name", - ), - ), - migrations.AlterField( - model_name="tailwindkey", - name="value", - field=models.TextField(verbose_name="value"), - ), - ] diff --git a/src/theme/migrations/0006_remove_currentthemeversion_version.py b/src/theme/migrations/0006_remove_currentthemeversion_version.py deleted file mode 100644 index 895fd6f..0000000 --- a/src/theme/migrations/0006_remove_currentthemeversion_version.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 5.0.6 on 2024-07-10 15:04 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ("theme", "0005_alter_tailwindkey_name_alter_tailwindkey_value"), - ] - - operations = [ - migrations.RemoveField( - model_name="currentthemeversion", - name="version", - ), - ] diff --git a/src/theme/migrations/0007_currentthemeversion_version.py b/src/theme/migrations/0007_currentthemeversion_version.py deleted file mode 100644 index b83961e..0000000 --- a/src/theme/migrations/0007_currentthemeversion_version.py +++ /dev/null @@ -1,22 +0,0 @@ -# Generated by Django 5.0.6 on 2024-07-10 15:04 - -import theme.utils -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("theme", "0006_remove_currentthemeversion_version"), - ] - - operations = [ - migrations.RunSQL('DELETE FROM theme_currentthemeversion'), - migrations.AddField( - model_name="currentthemeversion", - name="version", - field=models.BigIntegerField( - default=theme.utils.get_time_millis, unique=True, verbose_name="version" - ), - ), - ] diff --git a/src/worker/migrations/0001_initial.py b/src/worker/migrations/0001_initial.py deleted file mode 100644 index 38c9c90..0000000 --- a/src/worker/migrations/0001_initial.py +++ /dev/null @@ -1,39 +0,0 @@ -# Generated by Django 5.0 on 2024-05-18 12:24 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [] - - operations = [ - migrations.CreateModel( - name="Task", - fields=[ - ("id", models.AutoField(primary_key=True, serialize=False)), - ("name", models.CharField(max_length=20)), - ("args", models.BinaryField(blank=True, null=True)), - ("kwargs", models.BinaryField(blank=True, null=True)), - ("output", models.TextField(blank=True, null=True)), - ( - "status", - models.CharField( - choices=[ - ("queued", "Queued"), - ("completed", "Completed"), - ("not_registered", "Unknown task (not registered)"), - ("exception", "Exception"), - ], - default="queued", - max_length=20, - ), - ), - ("created_at", models.DateTimeField(auto_now_add=True)), - ("picked_up_at", models.DateTimeField(blank=True, null=True)), - ("completed_at", models.DateTimeField(blank=True, null=True)), - ], - ), - ] diff --git a/src/worker/migrations/0002_alter_task_options_alter_task_args_and_more.py b/src/worker/migrations/0002_alter_task_options_alter_task_args_and_more.py deleted file mode 100644 index 57b49e8..0000000 --- a/src/worker/migrations/0002_alter_task_options_alter_task_args_and_more.py +++ /dev/null @@ -1,84 +0,0 @@ -# Generated by Django 5.0.6 on 2024-07-10 12:49 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("worker", "0001_initial"), - ] - - operations = [ - migrations.AlterModelOptions( - name="task", - options={ - "ordering": ["-created_at"], - "verbose_name": "task", - "verbose_name_plural": "tasks", - }, - ), - migrations.AlterField( - model_name="task", - name="args", - field=models.BinaryField(blank=True, null=True, verbose_name="arguments"), - ), - migrations.AlterField( - model_name="task", - name="completed_at", - field=models.DateTimeField( - blank=True, null=True, verbose_name="completed at" - ), - ), - migrations.AlterField( - model_name="task", - name="created_at", - field=models.DateTimeField(auto_now_add=True, verbose_name="created at"), - ), - migrations.AlterField( - model_name="task", - name="id", - field=models.AutoField( - primary_key=True, serialize=False, verbose_name="identifier" - ), - ), - migrations.AlterField( - model_name="task", - name="kwargs", - field=models.BinaryField( - blank=True, null=True, verbose_name="keyword arguments" - ), - ), - migrations.AlterField( - model_name="task", - name="name", - field=models.CharField(max_length=20, verbose_name="name"), - ), - migrations.AlterField( - model_name="task", - name="output", - field=models.TextField(blank=True, null=True, verbose_name="output"), - ), - migrations.AlterField( - model_name="task", - name="picked_up_at", - field=models.DateTimeField( - blank=True, null=True, verbose_name="picked up at" - ), - ), - migrations.AlterField( - model_name="task", - name="status", - field=models.CharField( - choices=[ - ("queued", "Queued"), - ("completed", "Completed"), - ("not_registered", "Unknown task (not registered)"), - ("exception", "Exception"), - ], - default="queued", - max_length=20, - verbose_name="status", - ), - ), - ] diff --git a/src/worker/tests.py b/src/worker/tests.py deleted file mode 100644 index 7ce503c..0000000 --- a/src/worker/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/src/worker/views.py b/src/worker/views.py deleted file mode 100644 index 91ea44a..0000000 --- a/src/worker/views.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.shortcuts import render - -# Create your views here. diff --git a/src/adminsite/__init__.py b/symfexit/__init__.py similarity index 100% rename from src/adminsite/__init__.py rename to symfexit/__init__.py diff --git a/src/adminsite/migrations/__init__.py b/symfexit/adminsite/__init__.py similarity index 100% rename from src/adminsite/migrations/__init__.py rename to symfexit/adminsite/__init__.py diff --git a/src/adminsite/admin.py b/symfexit/adminsite/admin.py similarity index 96% rename from src/adminsite/admin.py rename to symfexit/adminsite/admin.py index 5ff70e4..3dd3ad9 100644 --- a/src/adminsite/admin.py +++ b/symfexit/adminsite/admin.py @@ -1,10 +1,8 @@ from functools import update_wrapper -from typing import List from constance import config from django.contrib import admin from django.urls.resolvers import URLResolver - from django.utils.text import format_lazy from django.utils.translation import gettext_lazy as _ @@ -29,7 +27,7 @@ def index_title(self): # Text to put at the top of the admin index page. return format_lazy(_("{site_title} administration"), site_title=config.SITE_TITLE) - def get_urls(self) -> List[URLResolver]: + def get_urls(self) -> list[URLResolver]: from django.apps import apps from django.urls import include, path, re_path diff --git a/src/adminsite/apps.py b/symfexit/adminsite/apps.py similarity index 78% rename from src/adminsite/apps.py rename to symfexit/adminsite/apps.py index 439d5c7..2d0869c 100644 --- a/src/adminsite/apps.py +++ b/symfexit/adminsite/apps.py @@ -1,15 +1,14 @@ from django.apps import AppConfig from django.contrib.admin.apps import AdminConfig - from django.utils.translation import gettext_lazy as _ class MyAdminConfig(AdminConfig): - default_site = "adminsite.admin.get_admin_site" + default_site = "symfexit.adminsite.admin.get_admin_site" # Required for the translations to be loaded class AdminSiteConfig(AppConfig): default_auto_field = "django.db.models.BigAutoField" - name = "adminsite" + name = "symfexit.adminsite" verbose_name = _("Adminsite") diff --git a/src/adminsite/django_overrides.py b/symfexit/adminsite/django_overrides.py similarity index 99% rename from src/adminsite/django_overrides.py rename to symfexit/adminsite/django_overrides.py index 3659b5a..797d9fa 100644 --- a/src/adminsite/django_overrides.py +++ b/symfexit/adminsite/django_overrides.py @@ -1,6 +1,5 @@ from django.utils.translation import gettext - gettext("Add %s") gettext("Change %s") gettext("View %s") diff --git a/src/adminsite/locale/nl/LC_MESSAGES/django.mo b/symfexit/adminsite/locale/nl/LC_MESSAGES/django.mo similarity index 100% rename from src/adminsite/locale/nl/LC_MESSAGES/django.mo rename to symfexit/adminsite/locale/nl/LC_MESSAGES/django.mo diff --git a/src/adminsite/locale/nl/LC_MESSAGES/django.po b/symfexit/adminsite/locale/nl/LC_MESSAGES/django.po similarity index 100% rename from src/adminsite/locale/nl/LC_MESSAGES/django.po rename to symfexit/adminsite/locale/nl/LC_MESSAGES/django.po diff --git a/src/documents/__init__.py b/symfexit/adminsite/migrations/__init__.py similarity index 100% rename from src/documents/__init__.py rename to symfexit/adminsite/migrations/__init__.py diff --git a/symfexit/adminsite/models.py b/symfexit/adminsite/models.py new file mode 100644 index 0000000..6b20219 --- /dev/null +++ b/symfexit/adminsite/models.py @@ -0,0 +1 @@ +# Create your models here. diff --git a/symfexit/adminsite/tests.py b/symfexit/adminsite/tests.py new file mode 100644 index 0000000..a39b155 --- /dev/null +++ b/symfexit/adminsite/tests.py @@ -0,0 +1 @@ +# Create your tests here. diff --git a/symfexit/adminsite/views.py b/symfexit/adminsite/views.py new file mode 100644 index 0000000..60f00ef --- /dev/null +++ b/symfexit/adminsite/views.py @@ -0,0 +1 @@ +# Create your views here. diff --git a/src/documents/migrations/__init__.py b/symfexit/documents/__init__.py similarity index 100% rename from src/documents/migrations/__init__.py rename to symfexit/documents/__init__.py diff --git a/src/documents/admin.py b/symfexit/documents/admin.py similarity index 79% rename from src/documents/admin.py rename to symfexit/documents/admin.py index 126ce80..b39dd76 100644 --- a/src/documents/admin.py +++ b/symfexit/documents/admin.py @@ -1,6 +1,6 @@ from django.contrib import admin -from documents.models import Directory, File +from symfexit.documents.models import Directory, File # Register your models here. diff --git a/src/documents/apps.py b/symfexit/documents/apps.py similarity index 91% rename from src/documents/apps.py rename to symfexit/documents/apps.py index 95db019..e3e4894 100644 --- a/src/documents/apps.py +++ b/symfexit/documents/apps.py @@ -1,10 +1,10 @@ from django.apps import AppConfig - from django.utils.translation import gettext_lazy as _ + class DocumentsConfig(AppConfig): default_auto_field = "django.db.models.BigAutoField" - name = "documents" + name = "symfexit.documents" verbose_name = _("Documents") def menu_items(self): diff --git a/src/documents/locale/nl/LC_MESSAGES/django.mo b/symfexit/documents/locale/nl/LC_MESSAGES/django.mo similarity index 100% rename from src/documents/locale/nl/LC_MESSAGES/django.mo rename to symfexit/documents/locale/nl/LC_MESSAGES/django.mo diff --git a/src/documents/locale/nl/LC_MESSAGES/django.po b/symfexit/documents/locale/nl/LC_MESSAGES/django.po similarity index 100% rename from src/documents/locale/nl/LC_MESSAGES/django.po rename to symfexit/documents/locale/nl/LC_MESSAGES/django.po diff --git a/src/documents/migrations/0001_initial.py b/symfexit/documents/migrations/0001_initial.py similarity index 68% rename from src/documents/migrations/0001_initial.py rename to symfexit/documents/migrations/0001_initial.py index 42829fb..ea4d955 100644 --- a/src/documents/migrations/0001_initial.py +++ b/symfexit/documents/migrations/0001_initial.py @@ -1,11 +1,12 @@ -# Generated by Django 5.0 on 2024-05-11 15:41 - -import uuid +# Generated by Django 5.1.1 on 2024-09-28 15:41 import django.db.models.deletion +import uuid from django.db import migrations, models -import documents.models + +def file_location(instance, filename): + return f"{instance.id}" class Migration(migrations.Migration): @@ -27,8 +28,11 @@ class Migration(migrations.Migration): serialize=False, ), ), - ("name", models.TextField()), - ("created_at", models.DateTimeField(auto_now_add=True)), + ("name", models.TextField(verbose_name="name")), + ( + "created_at", + models.DateTimeField(auto_now_add=True, verbose_name="created at"), + ), ], ), migrations.CreateModel( @@ -47,6 +51,7 @@ class Migration(migrations.Migration): ), ], options={ + "verbose_name": "directory", "verbose_name_plural": "directories", }, bases=("documents.filenode",), @@ -65,10 +70,22 @@ class Migration(migrations.Migration): to="documents.filenode", ), ), - ("content", models.FileField(upload_to=documents.models.file_location)), - ("size", models.IntegerField(default=0)), - ("content_type", models.TextField(default="application/octet-stream")), + ( + "content", + models.FileField(upload_to=file_location, verbose_name="content"), + ), + ("size", models.IntegerField(default=0, verbose_name="size")), + ( + "content_type", + models.TextField( + default="application/octet-stream", verbose_name="content type" + ), + ), ], + options={ + "verbose_name": "file", + "verbose_name_plural": "files", + }, bases=("documents.filenode",), ), migrations.AddField( @@ -80,6 +97,7 @@ class Migration(migrations.Migration): on_delete=django.db.models.deletion.CASCADE, related_name="children", to="documents.directory", + verbose_name="parent directory", ), ), ] diff --git a/src/home/__init__.py b/symfexit/documents/migrations/__init__.py similarity index 100% rename from src/home/__init__.py rename to symfexit/documents/migrations/__init__.py diff --git a/src/documents/models.py b/symfexit/documents/models.py similarity index 96% rename from src/documents/models.py rename to symfexit/documents/models.py index b5852e7..02bcc6d 100644 --- a/src/documents/models.py +++ b/symfexit/documents/models.py @@ -1,7 +1,6 @@ import uuid from django.db import models - from django.utils.translation import gettext_lazy as _ @@ -59,10 +58,8 @@ class Meta: verbose_name = _("file") verbose_name_plural = _("files") -class Directory(FileNode): - class Meta: - verbose_name_plural = "directories" +class Directory(FileNode): def __str__(self) -> str: return "Directory: " + self.name diff --git a/src/documents/templates/documents/breadcrumbs.html b/symfexit/documents/templates/documents/breadcrumbs.html similarity index 100% rename from src/documents/templates/documents/breadcrumbs.html rename to symfexit/documents/templates/documents/breadcrumbs.html diff --git a/src/documents/templates/documents/documents.html b/symfexit/documents/templates/documents/documents.html similarity index 100% rename from src/documents/templates/documents/documents.html rename to symfexit/documents/templates/documents/documents.html diff --git a/src/documents/templates/documents/download_button.html b/symfexit/documents/templates/documents/download_button.html similarity index 100% rename from src/documents/templates/documents/download_button.html rename to symfexit/documents/templates/documents/download_button.html diff --git a/src/documents/templates/documents/image_file.html b/symfexit/documents/templates/documents/image_file.html similarity index 100% rename from src/documents/templates/documents/image_file.html rename to symfexit/documents/templates/documents/image_file.html diff --git a/src/documents/templates/documents/pdf_file.html b/symfexit/documents/templates/documents/pdf_file.html similarity index 100% rename from src/documents/templates/documents/pdf_file.html rename to symfexit/documents/templates/documents/pdf_file.html diff --git a/symfexit/documents/tests.py b/symfexit/documents/tests.py new file mode 100644 index 0000000..a39b155 --- /dev/null +++ b/symfexit/documents/tests.py @@ -0,0 +1 @@ +# Create your tests here. diff --git a/src/documents/urls.py b/symfexit/documents/urls.py similarity index 84% rename from src/documents/urls.py rename to symfexit/documents/urls.py index 1fa5dc6..9572314 100644 --- a/src/documents/urls.py +++ b/symfexit/documents/urls.py @@ -1,6 +1,6 @@ from django.urls import path -from documents.views import Documents, file, file_download, file_pdf +from symfexit.documents.views import Documents, file, file_download, file_pdf app_name = "documents" diff --git a/src/documents/views.py b/symfexit/documents/views.py similarity index 97% rename from src/documents/views.py rename to symfexit/documents/views.py index c8c7b2c..1f06fb7 100644 --- a/src/documents/views.py +++ b/symfexit/documents/views.py @@ -4,7 +4,7 @@ from django.views.decorators.clickjacking import xframe_options_exempt from django.views.generic import TemplateView -from documents.models import Directory, File +from symfexit.documents.models import Directory, File # Create your views here. diff --git a/src/home/migrations/__init__.py b/symfexit/home/__init__.py similarity index 100% rename from src/home/migrations/__init__.py rename to symfexit/home/__init__.py diff --git a/src/home/admin.py b/symfexit/home/admin.py similarity index 97% rename from src/home/admin.py rename to symfexit/home/admin.py index 90ef5f2..e3877e7 100644 --- a/src/home/admin.py +++ b/symfexit/home/admin.py @@ -1,10 +1,9 @@ from constance import config from django.contrib import admin - -from home.models import HomePage - from django.utils.translation import gettext_lazy as _ +from symfexit.home.models import HomePage + @admin.register(HomePage) class HomePageAdmin(admin.ModelAdmin): diff --git a/src/home/apps.py b/symfexit/home/apps.py similarity index 91% rename from src/home/apps.py rename to symfexit/home/apps.py index 0e26594..ff0f0a2 100644 --- a/src/home/apps.py +++ b/symfexit/home/apps.py @@ -1,10 +1,10 @@ from django.apps import AppConfig - from django.utils.translation import gettext_lazy as _ + class HomeConfig(AppConfig): default_auto_field = "django.db.models.BigAutoField" - name = "home" + name = "symfexit.home" verbose_name = _("Home") def menu_items(self): diff --git a/src/home/locale/nl/LC_MESSAGES/django.mo b/symfexit/home/locale/nl/LC_MESSAGES/django.mo similarity index 100% rename from src/home/locale/nl/LC_MESSAGES/django.mo rename to symfexit/home/locale/nl/LC_MESSAGES/django.mo diff --git a/src/home/locale/nl/LC_MESSAGES/django.po b/symfexit/home/locale/nl/LC_MESSAGES/django.po similarity index 100% rename from src/home/locale/nl/LC_MESSAGES/django.po rename to symfexit/home/locale/nl/LC_MESSAGES/django.po diff --git a/src/home/migrations/0001_initial.py b/symfexit/home/migrations/0001_initial.py similarity index 63% rename from src/home/migrations/0001_initial.py rename to symfexit/home/migrations/0001_initial.py index 72a7dee..0e5fb0e 100644 --- a/src/home/migrations/0001_initial.py +++ b/symfexit/home/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.0 on 2024-05-11 15:41 +# Generated by Django 5.1.1 on 2024-09-28 15:41 import tinymce.models from django.db import migrations, models @@ -23,10 +23,17 @@ class Migration(migrations.Migration): verbose_name="ID", ), ), - ("title", models.CharField(blank=True, max_length=50)), - ("content", tinymce.models.HTMLField()), + ( + "title", + models.CharField(blank=True, max_length=50, verbose_name="Title"), + ), + ("content", tinymce.models.HTMLField(verbose_name="Content")), ("created", models.DateTimeField(auto_now_add=True)), ("modified", models.DateTimeField(auto_now=True)), ], + options={ + "verbose_name": "home page", + "verbose_name_plural": "home pages", + }, ), ] diff --git a/src/members/__init__.py b/symfexit/home/migrations/__init__.py similarity index 100% rename from src/members/__init__.py rename to symfexit/home/migrations/__init__.py diff --git a/src/home/models.py b/symfexit/home/models.py similarity index 100% rename from src/home/models.py rename to symfexit/home/models.py index 3e4cb5f..33f7c8a 100644 --- a/src/home/models.py +++ b/symfexit/home/models.py @@ -1,7 +1,7 @@ from django.db import models +from django.utils.translation import gettext_lazy as _ from tinymce.models import HTMLField -from django.utils.translation import gettext_lazy as _ class HomePage(models.Model): title = models.CharField(_("Title"), max_length=50, blank=True) diff --git a/src/home/templates/admin/home/submit_line.html b/symfexit/home/templates/admin/home/submit_line.html similarity index 100% rename from src/home/templates/admin/home/submit_line.html rename to symfexit/home/templates/admin/home/submit_line.html diff --git a/src/home/templates/home/home.html b/symfexit/home/templates/home/home.html similarity index 100% rename from src/home/templates/home/home.html rename to symfexit/home/templates/home/home.html diff --git a/symfexit/home/tests.py b/symfexit/home/tests.py new file mode 100644 index 0000000..a39b155 --- /dev/null +++ b/symfexit/home/tests.py @@ -0,0 +1 @@ +# Create your tests here. diff --git a/src/home/urls.py b/symfexit/home/urls.py similarity index 82% rename from src/home/urls.py rename to symfexit/home/urls.py index 2bd3646..0837981 100644 --- a/src/home/urls.py +++ b/symfexit/home/urls.py @@ -1,6 +1,6 @@ from django.urls import path -from home.views import Home +from symfexit.home.views import Home app_name = "home" diff --git a/src/home/views.py b/symfexit/home/views.py similarity index 70% rename from src/home/views.py rename to symfexit/home/views.py index 018104b..184f177 100644 --- a/src/home/views.py +++ b/symfexit/home/views.py @@ -1,11 +1,8 @@ from constance import config -from django.contrib.admin.views.decorators import staff_member_required -from django.contrib.auth.decorators import permission_required from django.contrib.auth.mixins import LoginRequiredMixin -from django.shortcuts import render from django.views.generic import TemplateView -from home.models import HomePage +from symfexit.home.models import HomePage # Create your views here. diff --git a/src/members/migrations/__init__.py b/symfexit/members/__init__.py similarity index 100% rename from src/members/migrations/__init__.py rename to symfexit/members/__init__.py diff --git a/src/members/admin.py b/symfexit/members/admin.py similarity index 95% rename from src/members/admin.py rename to symfexit/members/admin.py index d50779e..dc73f75 100644 --- a/src/members/admin.py +++ b/symfexit/members/admin.py @@ -1,3 +1,4 @@ +from django.conf import settings from django.contrib import admin, messages from django.contrib.admin.options import IS_POPUP_VAR, csrf_protect_m from django.contrib.admin.utils import unquote @@ -15,19 +16,16 @@ from django.template.response import TemplateResponse from django.urls import path, reverse from django.utils.html import escape - -from members.models import LocalGroup, User -from membership.models import Membership - from django.utils.translation import gettext_lazy as _ +from symfexit.members.models import LocalGroup, User -class MembershipInline(admin.StackedInline): - model = Membership - extra = 0 +# class MembershipInline(admin.StackedInline): +# model = Membership +# extra = 0 - autocomplete_fields = ("address",) - exclude = () +# # autocomplete_fields = ("address",) +# exclude = () # Modified from django.contrib.auth.admin.UserAdmin to remove username field @@ -88,7 +86,7 @@ class UserAdmin(admin.ModelAdmin): "user_permissions", ) - inlines = (MembershipInline,) + # inlines = (MembershipInline,) def get_fieldsets(self, request, obj=None): if not obj: @@ -116,9 +114,7 @@ def get_urls(self): def lookup_allowed(self, lookup, value): # Don't allow lookups involving passwords. - return not lookup.startswith("password") and super().lookup_allowed( - lookup, value - ) + return not lookup.startswith("password") and super().lookup_allowed(lookup, value) @sensitive_post_parameters_m @csrf_protect_m @@ -216,8 +212,7 @@ def user_change_password(self, request, id, form_url=""): return TemplateResponse( request, - self.change_user_password_template - or "admin/auth/user/change_password.html", + self.change_user_password_template or "admin/auth/user/change_password.html", context, ) diff --git a/src/members/apps.py b/symfexit/members/apps.py similarity index 93% rename from src/members/apps.py rename to symfexit/members/apps.py index 6b4d9c5..dae29f4 100644 --- a/src/members/apps.py +++ b/symfexit/members/apps.py @@ -1,10 +1,10 @@ from django.apps import AppConfig - from django.utils.translation import gettext_lazy as _ + class MembersConfig(AppConfig): default_auto_field = "django.db.models.BigAutoField" - name = "members" + name = "symfexit.members" verbose_name = _("Members") def menu_items(self): diff --git a/src/members/backends.py b/symfexit/members/backends.py similarity index 100% rename from src/members/backends.py rename to symfexit/members/backends.py diff --git a/src/members/forms.py b/symfexit/members/forms.py similarity index 98% rename from src/members/forms.py rename to symfexit/members/forms.py index 93ba1ee..6f056b9 100644 --- a/src/members/forms.py +++ b/symfexit/members/forms.py @@ -1,9 +1,8 @@ from django import forms - -from members.models import User - from django.utils.translation import gettext_lazy as _ +from symfexit.members.models import User + class NameWidget(forms.MultiWidget): def __init__(self, attrs=None): diff --git a/src/members/locale/nl/LC_MESSAGES/django.mo b/symfexit/members/locale/nl/LC_MESSAGES/django.mo similarity index 100% rename from src/members/locale/nl/LC_MESSAGES/django.mo rename to symfexit/members/locale/nl/LC_MESSAGES/django.mo diff --git a/src/members/locale/nl/LC_MESSAGES/django.po b/symfexit/members/locale/nl/LC_MESSAGES/django.po similarity index 100% rename from src/members/locale/nl/LC_MESSAGES/django.po rename to symfexit/members/locale/nl/LC_MESSAGES/django.po diff --git a/src/members/migrations/0001_initial.py b/symfexit/members/migrations/0001_initial.py similarity index 74% rename from src/members/migrations/0001_initial.py rename to symfexit/members/migrations/0001_initial.py index fcfac6d..3630abb 100644 --- a/src/members/migrations/0001_initial.py +++ b/symfexit/members/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.0 on 2024-05-11 15:41 +# Generated by Django 5.1.1 on 2024-09-28 15:41 import django.contrib.auth.models import django.db.models.deletion @@ -12,30 +12,10 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ("auth", "0012_alter_user_first_name_max_length"), + ("auth", "0001_initial"), ] operations = [ - migrations.CreateModel( - name="LocalGroup", - fields=[ - ( - "group_ptr", - models.OneToOneField( - auto_created=True, - on_delete=django.db.models.deletion.CASCADE, - parent_link=True, - primary_key=True, - serialize=False, - to="auth.group", - ), - ), - ], - bases=("auth.group",), - managers=[ - ("objects", django.contrib.auth.models.GroupManager()), - ], - ), migrations.CreateModel( name="User", fields=[ @@ -51,9 +31,7 @@ class Migration(migrations.Migration): ("password", models.CharField(max_length=128, verbose_name="password")), ( "last_login", - models.DateTimeField( - blank=True, null=True, verbose_name="last login" - ), + models.DateTimeField(blank=True, null=True, verbose_name="last login"), ), ( "is_superuser", @@ -65,15 +43,15 @@ class Migration(migrations.Migration): ), ( "member_identifier", - models.TextField(unique=True, verbose_name="Lidnummer"), + models.TextField(unique=True, verbose_name="member number"), ), - ("first_name", models.TextField(verbose_name="Voornaam")), - ("last_name", models.TextField(verbose_name="Achternaam")), - ("email", models.EmailField(max_length=254)), - ("phone_number", models.TextField(verbose_name="Telefoonnummer")), - ("address", models.TextField(verbose_name="Adres")), - ("city", models.TextField(verbose_name="Plaats")), - ("postal_code", models.TextField(verbose_name="Postcode")), + ("first_name", models.TextField(verbose_name="first name")), + ("last_name", models.TextField(verbose_name="last name")), + ("email", models.EmailField(max_length=254, verbose_name="email")), + ("phone_number", models.TextField(verbose_name="phone number")), + ("address", models.TextField(verbose_name="address")), + ("city", models.TextField(verbose_name="cith")), + ("postal_code", models.TextField(verbose_name="postal code")), ( "is_staff", models.BooleanField( @@ -121,34 +99,39 @@ class Migration(migrations.Migration): ], options={ "verbose_name": "member", + "verbose_name_plural": "members", }, ), migrations.CreateModel( - name="ContactPerson", + name="LocalGroup", fields=[ ( - "id", - models.BigAutoField( + "group_ptr", + models.OneToOneField( auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, primary_key=True, serialize=False, - verbose_name="ID", + to="auth.group", ), ), ( - "user", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, + "contact_people", + models.ManyToManyField( + related_name="contact_person_for_groups", to=settings.AUTH_USER_MODEL, + verbose_name="contact people", ), ), - ( - "for_group", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="members.localgroup", - ), - ), + ], + options={ + "verbose_name": "local group", + "verbose_name_plural": "local groups", + }, + bases=("auth.group",), + managers=[ + ("objects", django.contrib.auth.models.GroupManager()), ], ), migrations.AddConstraint( diff --git a/src/membership/__init__.py b/symfexit/members/migrations/__init__.py similarity index 100% rename from src/membership/__init__.py rename to symfexit/members/migrations/__init__.py diff --git a/src/members/models.py b/symfexit/members/models.py similarity index 90% rename from src/members/models.py rename to symfexit/members/models.py index a2066e3..d387fab 100644 --- a/src/members/models.py +++ b/symfexit/members/models.py @@ -15,9 +15,7 @@ def generate_member_number(): try: return str(int(largest_member_number.member_identifier) + 1) except ValueError as e: - raise ValueError( - "Did not expect non-integers in the member_identifier field" - ) from e + raise ValueError("Did not expect non-integers in the member_identifier field") from e class UserManager(BaseUserManager): @@ -71,7 +69,9 @@ class User(AbstractBaseUser, PermissionsMixin): is_active = models.BooleanField( _("active"), default=True, - help_text=_("Designates whether this user should be treated as active. Unselect this instead of deleting accounts."), + help_text=_( + "Designates whether this user should be treated as active. Unselect this instead of deleting accounts." + ), ) date_joined = models.DateTimeField(_("date joined"), default=timezone.now) @@ -85,11 +85,12 @@ class Meta: verbose_name = _("member") verbose_name_plural = _("members") constraints = [ - models.UniqueConstraint( - fields=["email"], name="members_user_unique_email_key" - ), + models.UniqueConstraint(fields=["email"], name="members_user_unique_email_key"), ] + def __str__(self): + return f"{self.first_name} {self.last_name} ({self.email})" + def clean(self): super().clean() self.email = self.__class__.objects.normalize_email(self.email) @@ -98,7 +99,7 @@ def get_full_name(self): """ Return the first_name plus the last_name, with a space in between. """ - full_name = "%s %s" % (self.first_name, self.last_name) + full_name = f"{self.first_name} {self.last_name}" return full_name.strip() def get_short_name(self): @@ -109,15 +110,15 @@ def email_user(self, subject, message, from_email=None, **kwargs): """Send an email to this user.""" send_mail(subject, message, from_email, [self.email], **kwargs) - def __str__(self): - return f"{self.first_name} {self.last_name} ({self.email})" - class LocalGroup(Group): class Meta: verbose_name = _("local group") verbose_name_plural = _("local groups") + def __str__(self): + return self.name + contact_people = models.ManyToManyField( User, related_name="contact_person_for_groups", verbose_name=_("contact people") ) diff --git a/src/members/templates/members/logout.html b/symfexit/members/templates/members/logout.html similarity index 100% rename from src/members/templates/members/logout.html rename to symfexit/members/templates/members/logout.html diff --git a/src/members/templates/members/user_form.html b/symfexit/members/templates/members/user_form.html similarity index 100% rename from src/members/templates/members/user_form.html rename to symfexit/members/templates/members/user_form.html diff --git a/src/members/templates/registration/login.html b/symfexit/members/templates/registration/login.html similarity index 100% rename from src/members/templates/registration/login.html rename to symfexit/members/templates/registration/login.html diff --git a/symfexit/members/tests.py b/symfexit/members/tests.py new file mode 100644 index 0000000..a39b155 --- /dev/null +++ b/symfexit/members/tests.py @@ -0,0 +1 @@ +# Create your tests here. diff --git a/src/members/urls.py b/symfexit/members/urls.py similarity index 78% rename from src/members/urls.py rename to symfexit/members/urls.py index cf2f074..ee5a27c 100644 --- a/src/members/urls.py +++ b/symfexit/members/urls.py @@ -1,6 +1,6 @@ from django.urls import path -from members.views import Logout, MemberData, payment_start +from symfexit.members.views import Logout, MemberData, payment_start app_name = "members" diff --git a/src/members/views.py b/symfexit/members/views.py similarity index 87% rename from src/members/views.py rename to symfexit/members/views.py index f2e58ae..ec70734 100644 --- a/src/members/views.py +++ b/symfexit/members/views.py @@ -6,10 +6,9 @@ from django.utils import timezone from django.views.generic import TemplateView -from members.forms import PasswordChangeForm, UserForm -from members.models import User -from membership.models import Membership -from payments.models import BillingAddress +from symfexit.members.forms import PasswordChangeForm, UserForm +from symfexit.membership.models import Membership +from symfexit.payments.models import BillingAddress class MemberData(LoginRequiredMixin, TemplateView): @@ -33,16 +32,12 @@ def get(self, request, *args, **kwargs): def post(self, request, *args, **kwargs): if "user_form" in request.POST: - user_form = UserForm( - request.POST, instance=request.user, prefix="user_form" - ) + user_form = UserForm(request.POST, instance=request.user, prefix="user_form") if user_form.is_valid(): user_form.save() return redirect("members:memberdata") else: - password_form = PasswordChangeForm( - user=request.user, prefix="password_form" - ) + password_form = PasswordChangeForm(user=request.user, prefix="password_form") return render( request, self.template_name, diff --git a/src/membership/migrations/__init__.py b/symfexit/membership/__init__.py similarity index 100% rename from src/membership/migrations/__init__.py rename to symfexit/membership/__init__.py diff --git a/src/membership/admin.py b/symfexit/membership/admin.py similarity index 92% rename from src/membership/admin.py rename to symfexit/membership/admin.py index 52615d5..6d246a1 100644 --- a/src/membership/admin.py +++ b/symfexit/membership/admin.py @@ -11,9 +11,9 @@ from django.utils import timezone from django.utils.translation import gettext_lazy as _ -from membership.forms import PaymentTier, PaymentTierInfo -from membership.models import Membership -from payments.models import Order +from symfexit.membership.forms import PaymentTier, PaymentTierInfo +from symfexit.membership.models import Membership +from symfexit.payments.models import Order def save_new_tiers(tiers): @@ -56,13 +56,9 @@ def changelist_view(self, request, extra_context=None): raise PermissionDenied initial = json.loads(config.PAYMENT_TIERS_JSON) - PaymentTierFormSet = forms.formset_factory( - PaymentTier, extra=1, can_delete=True - ) + PaymentTierFormSet = forms.formset_factory(PaymentTier, extra=1, can_delete=True) - if request.method == "POST" and request.user.has_perm( - "membership.change_config" - ): + if request.method == "POST" and request.user.has_perm("membership.change_config"): payment_tier_info = PaymentTierInfo(request.POST, prefix="info") form = PaymentTierFormSet(request.POST, initial=initial, prefix="tiers") if form.is_valid(): @@ -153,7 +149,7 @@ def __init__(self, *args, **kwargs): class OrderInline(admin.StackedInline): model = Order extra = 0 - readonly_fields = ("created_at", "done_at", "return_url") + readonly_fields = ("created_at", "updated_at") autocomplete_fields = ("address",) form = OrderInlineForm diff --git a/src/membership/apps.py b/symfexit/membership/apps.py similarity index 86% rename from src/membership/apps.py rename to symfexit/membership/apps.py index 23af390..c8de40a 100644 --- a/src/membership/apps.py +++ b/symfexit/membership/apps.py @@ -1,9 +1,8 @@ from django.apps import AppConfig - from django.utils.translation import gettext_lazy as _ class MembershipConfig(AppConfig): default_auto_field = "django.db.models.BigAutoField" - name = "membership" + name = "symfexit.membership" verbose_name = _("Membership") diff --git a/src/membership/forms.py b/symfexit/membership/forms.py similarity index 83% rename from src/membership/forms.py rename to symfexit/membership/forms.py index 5a0692e..8eec4d7 100644 --- a/src/membership/forms.py +++ b/symfexit/membership/forms.py @@ -1,7 +1,6 @@ from decimal import Decimal from django import forms - from django.utils.translation import gettext_lazy as _ @@ -19,9 +18,7 @@ class PaymentTierInfo(forms.Form): class PaymentTier(forms.Form): - help_text = forms.CharField( - widget=forms.TextInput, required=True, label=_("Help text") - ) + help_text = forms.CharField(widget=forms.TextInput, required=True, label=_("Help text")) cents_per_period = forms.DecimalField( max_digits=6, decimal_places=2, @@ -35,8 +32,8 @@ def __init__(self, *args, **kwargs): if "cents_per_period" not in initial: initial["cents_per_period"] = 0 else: - initial["cents_per_period"] = ( - Decimal(initial["cents_per_period"]) / 100 - ).quantize(Decimal(10) ** -2) + initial["cents_per_period"] = (Decimal(initial["cents_per_period"]) / 100).quantize( + Decimal(10) ** -2 + ) super().__init__(*args, **kwargs) self.fields["cents_per_period"].widget.attrs.update({"step": "0.01"}) diff --git a/src/membership/locale/nl/LC_MESSAGES/django.mo b/symfexit/membership/locale/nl/LC_MESSAGES/django.mo similarity index 100% rename from src/membership/locale/nl/LC_MESSAGES/django.mo rename to symfexit/membership/locale/nl/LC_MESSAGES/django.mo diff --git a/src/membership/locale/nl/LC_MESSAGES/django.po b/symfexit/membership/locale/nl/LC_MESSAGES/django.po similarity index 100% rename from src/membership/locale/nl/LC_MESSAGES/django.po rename to symfexit/membership/locale/nl/LC_MESSAGES/django.po diff --git a/src/membership/migrations/0001_initial.py b/symfexit/membership/migrations/0001_initial.py similarity index 89% rename from src/membership/migrations/0001_initial.py rename to symfexit/membership/migrations/0001_initial.py index fb52139..edba496 100644 --- a/src/membership/migrations/0001_initial.py +++ b/symfexit/membership/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.0 on 2024-05-11 15:41 +# Generated by Django 5.1.1 on 2024-09-28 15:41 import django.db.models.deletion from django.db import migrations, models @@ -30,6 +30,7 @@ class Migration(migrations.Migration): ], options={ "verbose_name": "membership", + "verbose_name_plural": "memberships", }, bases=("payments.subscription",), ), diff --git a/src/menu/__init__.py b/symfexit/membership/migrations/__init__.py similarity index 100% rename from src/menu/__init__.py rename to symfexit/membership/migrations/__init__.py diff --git a/src/membership/models.py b/symfexit/membership/models.py similarity index 68% rename from src/membership/models.py rename to symfexit/membership/models.py index 3aabb89..a200422 100644 --- a/src/membership/models.py +++ b/symfexit/membership/models.py @@ -1,9 +1,8 @@ from django.utils import formats, timezone - -from payments.models import Subscription - from django.utils.translation import gettext_lazy as _ +from symfexit.payments.models import Subscription + class Membership(Subscription): class Meta: @@ -12,24 +11,20 @@ class Meta: @classmethod def current_for_user(cls, user): - return cls.objects.filter( - user=user, active_from_to__contains=timezone.now() - ).first() + return cls.objects.filter(user=user, active_from_to__contains=timezone.now()).first() def new_order(self, *, initial, return_url, description=None): from signup.models import ApplicationPayment if description is None: - description = "Membership fee for {}".format(self.address.name) - if initial == False: + description = f"Membership fee for {self.address.name}" + if not initial: description += " (initial payment)" - order = super().new_order( - initial=initial, return_url=return_url, description=description - ) + order = super().new_order(initial=initial, return_url=return_url, description=description) appl_pay = ApplicationPayment(order_ptr=order) appl_pay.save_base(raw=True) - if initial == True: + if initial: from signup.models import MembershipApplication appl = MembershipApplication.objects.filter(_subscription=self).first() @@ -44,9 +39,7 @@ def __str__(self): formats.date_format(self.active_from_to.lower), ) if self.active_from_to.upper is not None: - text += " stopped at {}".format( - formats.date_format(self.active_from_to.upper) - ) + text += f" stopped at {formats.date_format(self.active_from_to.upper)}" else: text += " (active)" return text diff --git a/src/membership/templates/admin/membership/payment_tiers.html b/symfexit/membership/templates/admin/membership/payment_tiers.html similarity index 100% rename from src/membership/templates/admin/membership/payment_tiers.html rename to symfexit/membership/templates/admin/membership/payment_tiers.html diff --git a/symfexit/membership/tests.py b/symfexit/membership/tests.py new file mode 100644 index 0000000..a39b155 --- /dev/null +++ b/symfexit/membership/tests.py @@ -0,0 +1 @@ +# Create your tests here. diff --git a/symfexit/membership/views.py b/symfexit/membership/views.py new file mode 100644 index 0000000..60f00ef --- /dev/null +++ b/symfexit/membership/views.py @@ -0,0 +1 @@ +# Create your views here. diff --git a/src/menu/migrations/__init__.py b/symfexit/menu/__init__.py similarity index 100% rename from src/menu/migrations/__init__.py rename to symfexit/menu/__init__.py diff --git a/symfexit/menu/admin.py b/symfexit/menu/admin.py new file mode 100644 index 0000000..846f6b4 --- /dev/null +++ b/symfexit/menu/admin.py @@ -0,0 +1 @@ +# Register your models here. diff --git a/src/menu/apps.py b/symfexit/menu/apps.py similarity index 81% rename from src/menu/apps.py rename to symfexit/menu/apps.py index 7aa7ab3..1cca6ba 100644 --- a/src/menu/apps.py +++ b/symfexit/menu/apps.py @@ -3,4 +3,4 @@ class MenuConfig(AppConfig): default_auto_field = "django.db.models.BigAutoField" - name = "menu" + name = "symfexit.menu" diff --git a/src/menu/templatetags/__init__.py b/symfexit/menu/migrations/__init__.py similarity index 100% rename from src/menu/templatetags/__init__.py rename to symfexit/menu/migrations/__init__.py diff --git a/src/menu/templates/menu.html b/symfexit/menu/templates/menu.html similarity index 100% rename from src/menu/templates/menu.html rename to symfexit/menu/templates/menu.html diff --git a/src/menu/templates/menu_lg.html b/symfexit/menu/templates/menu_lg.html similarity index 100% rename from src/menu/templates/menu_lg.html rename to symfexit/menu/templates/menu_lg.html diff --git a/src/menu/templates/menupage.html b/symfexit/menu/templates/menupage.html similarity index 100% rename from src/menu/templates/menupage.html rename to symfexit/menu/templates/menupage.html diff --git a/src/payments/migrations/__init__.py b/symfexit/menu/templatetags/__init__.py similarity index 100% rename from src/payments/migrations/__init__.py rename to symfexit/menu/templatetags/__init__.py diff --git a/src/menu/templatetags/menu.py b/symfexit/menu/templatetags/menu.py similarity index 100% rename from src/menu/templatetags/menu.py rename to symfexit/menu/templatetags/menu.py diff --git a/symfexit/menu/tests.py b/symfexit/menu/tests.py new file mode 100644 index 0000000..a39b155 --- /dev/null +++ b/symfexit/menu/tests.py @@ -0,0 +1 @@ +# Create your tests here. diff --git a/src/payments/__init__.py b/symfexit/payments/__init__.py similarity index 71% rename from src/payments/__init__.py rename to symfexit/payments/__init__.py index 312e799..cf55145 100644 --- a/src/payments/__init__.py +++ b/symfexit/payments/__init__.py @@ -1,6 +1,6 @@ from django.utils.module_loading import autodiscover_modules -from payments.registry import PaymentProcessor, payments_registry +from symfexit.payments.registry import PaymentProcessor, payments_registry __all__ = ["PaymentProcessor"] diff --git a/symfexit/payments/admin.py b/symfexit/payments/admin.py new file mode 100644 index 0000000..942f2e8 --- /dev/null +++ b/symfexit/payments/admin.py @@ -0,0 +1,46 @@ +from django.contrib import admin + +from symfexit.payments.models import BillingAddress, Subscription + +# Register your models here. +# @admin.register(Order) +# class OrderAdmin(admin.ModelAdmin): +# # show the eid +# list_display = ("eid", "price", "description", "payment_status") +# # show the eid in the detail display as a readonly field +# readonly_fields = ("eid", "price", "description", "payment_status") + +# # don't show the add button +# def has_add_permission(self, request): +# return False + +# # don't show the delete button +# def has_delete_permission(self, request, obj: Order = None): +# if obj is None: +# return False +# return obj.payment_status == Order.Status.EXPIRED + +# # don't show the change button +# def has_change_permission(self, request, obj=None): +# return False + + +@admin.register(BillingAddress) +class BillingAddressAdmin(admin.ModelAdmin): + search_fields = ("id", "name") + list_display = ("id", "name", "address", "city") + fields = ("name", "address", "city", "postal_code", "user") + + +@admin.register(Subscription) +class SubscriptionAdmin(admin.ModelAdmin): + list_display = ( + "eid", + "name", + "description", + "price_per_period", + "period_quantity", + "period_unit", + "created_at", + "updated_at", + ) diff --git a/src/payments/apps.py b/symfexit/payments/apps.py similarity index 76% rename from src/payments/apps.py rename to symfexit/payments/apps.py index f2bf32a..3aca342 100644 --- a/src/payments/apps.py +++ b/symfexit/payments/apps.py @@ -1,14 +1,14 @@ from django.apps import AppConfig - from django.utils.translation import gettext_lazy as _ + class PaymentsConfig(AppConfig): default_auto_field = "django.db.models.BigAutoField" - name = "payments" + name = "symfexit.payments" verbose_name = _("Payments") def ready(self): - from payments.registry import payments_registry + from symfexit.payments.registry import payments_registry self.module.autodiscover() payments_registry.initialize() diff --git a/src/payments_dummy/locale/nl/LC_MESSAGES/django.mo b/symfexit/payments/dummy/LC_MESSAGES/django.mo similarity index 100% rename from src/payments_dummy/locale/nl/LC_MESSAGES/django.mo rename to symfexit/payments/dummy/LC_MESSAGES/django.mo diff --git a/src/payments_dummy/locale/nl/LC_MESSAGES/django.po b/symfexit/payments/dummy/LC_MESSAGES/django.po similarity index 100% rename from src/payments_dummy/locale/nl/LC_MESSAGES/django.po rename to symfexit/payments/dummy/LC_MESSAGES/django.po diff --git a/src/payments_dummy/__init__.py b/symfexit/payments/dummy/__init__.py similarity index 100% rename from src/payments_dummy/__init__.py rename to symfexit/payments/dummy/__init__.py diff --git a/symfexit/payments/dummy/admin.py b/symfexit/payments/dummy/admin.py new file mode 100644 index 0000000..846f6b4 --- /dev/null +++ b/symfexit/payments/dummy/admin.py @@ -0,0 +1 @@ +# Register your models here. diff --git a/src/payments_dummy/apps.py b/symfexit/payments/dummy/apps.py similarity index 77% rename from src/payments_dummy/apps.py rename to symfexit/payments/dummy/apps.py index 4571627..4e13764 100644 --- a/src/payments_dummy/apps.py +++ b/symfexit/payments/dummy/apps.py @@ -3,4 +3,4 @@ class PaymentsDummyConfig(AppConfig): default_auto_field = "django.db.models.BigAutoField" - name = "payments_dummy" + name = "symfexit.payments.dummy" diff --git a/symfexit/payments/dummy/forms.py b/symfexit/payments/dummy/forms.py new file mode 100644 index 0000000..ddd49c4 --- /dev/null +++ b/symfexit/payments/dummy/forms.py @@ -0,0 +1,7 @@ +from django import forms + +from symfexit.payments.models import Payment + + +class FakePayForm(forms.Form): + payment_status = forms.ChoiceField(choices=Payment.Status.choices) diff --git a/src/payments_dummy/migrations/__init__.py b/symfexit/payments/dummy/migrations/__init__.py similarity index 100% rename from src/payments_dummy/migrations/__init__.py rename to symfexit/payments/dummy/migrations/__init__.py diff --git a/symfexit/payments/dummy/models.py b/symfexit/payments/dummy/models.py new file mode 100644 index 0000000..6b20219 --- /dev/null +++ b/symfexit/payments/dummy/models.py @@ -0,0 +1 @@ +# Create your models here. diff --git a/src/payments_dummy/payments.py b/symfexit/payments/dummy/payments.py similarity index 69% rename from src/payments_dummy/payments.py rename to symfexit/payments/dummy/payments.py index 46e420c..6c863b4 100644 --- a/src/payments_dummy/payments.py +++ b/symfexit/payments/dummy/payments.py @@ -1,10 +1,10 @@ +from django.conf import settings from django.shortcuts import render -from payments import PaymentProcessor -from payments.models import Subscription -from payments.registry import payments_registry -from payments_dummy.forms import FakePayForm -from symfexit import settings +from symfexit.payments import PaymentProcessor +from symfexit.payments.dummy.forms import FakePayForm +from symfexit.payments.models import Subscription +from symfexit.payments.registry import payments_registry DUMMY_NAME = "dummy" @@ -15,7 +15,7 @@ def initialize(self): pass def is_available(self): - return settings.DEBUG == True + return bool(settings.DEBUG) def start_subscription_flow(self, request, subscription: Subscription, return_url): order = subscription.new_order(initial=True, return_url=return_url) diff --git a/src/payments_dummy/templates/payments_dummy/dummy_pay.html b/symfexit/payments/dummy/templates/payments_dummy/dummy_pay.html similarity index 100% rename from src/payments_dummy/templates/payments_dummy/dummy_pay.html rename to symfexit/payments/dummy/templates/payments_dummy/dummy_pay.html diff --git a/symfexit/payments/dummy/tests.py b/symfexit/payments/dummy/tests.py new file mode 100644 index 0000000..a39b155 --- /dev/null +++ b/symfexit/payments/dummy/tests.py @@ -0,0 +1 @@ +# Create your tests here. diff --git a/src/payments_dummy/urls.py b/symfexit/payments/dummy/urls.py similarity index 72% rename from src/payments_dummy/urls.py rename to symfexit/payments/dummy/urls.py index e2ff41a..3fdc717 100644 --- a/src/payments_dummy/urls.py +++ b/symfexit/payments/dummy/urls.py @@ -1,6 +1,6 @@ from django.urls import path -from payments_dummy.views import initiate_dummy +from symfexit.payments.dummy.views import initiate_dummy app_name = "payments_dummy" diff --git a/src/payments_dummy/views.py b/symfexit/payments/dummy/views.py similarity index 83% rename from src/payments_dummy/views.py rename to symfexit/payments/dummy/views.py index 0852647..461af9b 100644 --- a/src/payments_dummy/views.py +++ b/symfexit/payments/dummy/views.py @@ -1,9 +1,8 @@ from django.http import HttpResponseNotAllowed, HttpResponseRedirect -from django.shortcuts import render from django.utils import timezone -from payments.models import Order -from payments_dummy.forms import FakePayForm +from symfexit.payments.dummy.forms import FakePayForm +from symfexit.payments.models import Order def initiate_dummy(request, order_id): diff --git a/src/payments/locale/nl/LC_MESSAGES/django.mo b/symfexit/payments/locale/nl/LC_MESSAGES/django.mo similarity index 100% rename from src/payments/locale/nl/LC_MESSAGES/django.mo rename to symfexit/payments/locale/nl/LC_MESSAGES/django.mo diff --git a/src/payments/locale/nl/LC_MESSAGES/django.po b/symfexit/payments/locale/nl/LC_MESSAGES/django.po similarity index 100% rename from src/payments/locale/nl/LC_MESSAGES/django.po rename to symfexit/payments/locale/nl/LC_MESSAGES/django.po diff --git a/src/payments/migrations/0001_initial.py b/symfexit/payments/migrations/0001_initial.py similarity index 60% rename from src/payments/migrations/0001_initial.py rename to symfexit/payments/migrations/0001_initial.py index 5e3143d..97dc902 100644 --- a/src/payments/migrations/0001_initial.py +++ b/symfexit/payments/migrations/0001_initial.py @@ -1,6 +1,5 @@ -# Generated by Django 5.0 on 2024-05-11 15:41 +# Generated by Django 5.1.1 on 2024-09-28 15:41 -import django.contrib.postgres.fields.ranges import django.db.models.deletion from django.conf import settings from django.db import migrations, models @@ -15,14 +14,45 @@ class Migration(migrations.Migration): ] operations = [ + migrations.CreateModel( + name="Subscription", + fields=[ + ("id", models.AutoField(primary_key=True, serialize=False)), + ("name", models.TextField()), + ("description", models.TextField(blank=True)), + ("price_per_period", models.IntegerField(null=True)), + ("period_quantity", models.IntegerField()), + ( + "period_unit", + models.CharField( + choices=[ + ("day", "Day"), + ("week", "Week"), + ("month", "Month"), + ("year", "Year"), + ], + max_length=5, + ), + ), + ("created_at", models.DateTimeField(auto_now_add=True)), + ("updated_at", models.DateTimeField(auto_now=True)), + ], + options={ + "verbose_name": "subscription", + "verbose_name_plural": "subscriptions", + }, + ), migrations.CreateModel( name="BillingAddress", fields=[ ("id", models.AutoField(primary_key=True, serialize=False)), - ("name", models.CharField(max_length=100)), - ("address", models.CharField(max_length=100)), - ("city", models.CharField(max_length=100)), - ("postal_code", models.CharField(max_length=100)), + ("name", models.CharField(max_length=100, verbose_name="name")), + ("address", models.CharField(max_length=100, verbose_name="address")), + ("city", models.CharField(max_length=100, verbose_name="city")), + ( + "postal_code", + models.CharField(max_length=100, verbose_name="postal code"), + ), ("created_at", models.DateTimeField(auto_now_add=True)), ( "user", @@ -30,6 +60,7 @@ class Migration(migrations.Migration): null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, + verbose_name="user", ), ), ], @@ -39,14 +70,10 @@ class Migration(migrations.Migration): }, ), migrations.CreateModel( - name="Subscription", + name="Order", fields=[ ("id", models.AutoField(primary_key=True, serialize=False)), - ("created_at", models.DateTimeField(auto_now_add=True)), - ( - "active_from_to", - django.contrib.postgres.fields.ranges.DateTimeRangeField(), - ), + ("description", models.TextField(verbose_name="description")), ("price_per_period", models.IntegerField()), ("period_quantity", models.IntegerField()), ( @@ -61,32 +88,38 @@ class Migration(migrations.Migration): max_length=5, ), ), + ("created_at", models.DateTimeField(auto_now_add=True)), + ("updated_at", models.DateTimeField(auto_now=True)), ( "address", models.ForeignKey( on_delete=django.db.models.deletion.PROTECT, to="payments.billingaddress", + verbose_name="billing address", ), ), ( - "user", + "subscription", models.ForeignKey( - blank=True, null=True, - on_delete=django.db.models.deletion.CASCADE, - to=settings.AUTH_USER_MODEL, + on_delete=django.db.models.deletion.SET_NULL, + to="payments.subscription", + verbose_name="subscription", ), ), ], + options={ + "verbose_name": "order", + "verbose_name_plural": "orders", + }, ), migrations.CreateModel( - name="Order", + name="Payment", fields=[ ("id", models.AutoField(primary_key=True, serialize=False)), - ("price", models.IntegerField()), - ("description", models.TextField()), + ("created_at", models.DateTimeField(auto_now_add=True)), ( - "payment_status", + "status", models.CharField( choices=[ ("created", "Created"), @@ -98,25 +131,15 @@ class Migration(migrations.Migration): ], default="created", max_length=10, - ), - ), - ("created_at", models.DateTimeField(auto_now_add=True)), - ("done_at", models.DateTimeField(null=True)), - ("payment_method", models.CharField(max_length=100, null=True)), - ("return_url", models.URLField(null=True)), - ( - "address", - models.ForeignKey( - on_delete=django.db.models.deletion.PROTECT, - to="payments.billingaddress", + verbose_name="payment status", ), ), ( - "subscription", + "order", models.ForeignKey( - null=True, on_delete=django.db.models.deletion.RESTRICT, - to="payments.subscription", + to="payments.order", + verbose_name="order", ), ), ], diff --git a/src/payments_mollie/__init__.py b/symfexit/payments/migrations/__init__.py similarity index 100% rename from src/payments_mollie/__init__.py rename to symfexit/payments/migrations/__init__.py diff --git a/src/payments/models.py b/symfexit/payments/models.py similarity index 55% rename from src/payments/models.py rename to symfexit/payments/models.py index 06b44c7..53a74a9 100644 --- a/src/payments/models.py +++ b/symfexit/payments/models.py @@ -1,9 +1,7 @@ from django.conf import settings from django.contrib.auth import get_user_model -from django.contrib.postgres.fields import DateTimeRangeField from django.db import models from django.shortcuts import get_object_or_404 -from django.utils import timezone from django.utils.translation import gettext_lazy as _ from hashids import Hashids @@ -12,11 +10,14 @@ User = get_user_model() -class BillingAddress(models.Model): - class Meta: - verbose_name = _("billing address") - verbose_name_plural = _("billing addresses") +class PeriodUnit(models.TextChoices): + DAY = "day", _("Day") + WEEK = "week", _("Week") + MONTH = "month", _("Month") + YEAR = "year", _("Year") + +class BillingAddress(models.Model): id = models.AutoField(primary_key=True) user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, verbose_name=_("user")) name = models.CharField(_("name"), max_length=100) @@ -25,16 +26,15 @@ class Meta: postal_code = models.CharField(_("postal code"), max_length=100) created_at = models.DateTimeField(auto_now_add=True) - def __str__(self): - return "[{}] {}: {}\n{}\n{}".format( - self.id, self.name, self.address, self.postal_code, self.city - ) - class Meta: verbose_name = _("billing address") verbose_name_plural = _("billing addresses") -class Order(models.Model): + def __str__(self): + return f"[{self.id}] {self.name}: {self.address}\n{self.postal_code}\n{self.city}" + + +class Payment(models.Model): class Status(models.TextChoices): INITIAL = "created", _("Created") PENDING = "pending", _("Pending") @@ -44,82 +44,116 @@ class Status(models.TextChoices): EXPIRED = "expired", _("Expired") id = models.AutoField(primary_key=True) - price = models.IntegerField(_("price")) # in cents - description = models.TextField(_("description")) - address = models.ForeignKey("BillingAddress", on_delete=models.PROTECT, verbose_name=_("billing address")) - payment_status = models.CharField( - max_length=10, choices=Status.choices, default=Status.INITIAL, verbose_name=_("payment status") - ) created_at = models.DateTimeField(auto_now_add=True) - done_at = models.DateTimeField(null=True, verbose_name=_("done at")) - payment_method = models.CharField(max_length=100, null=True, verbose_name=_("payment method")) + status = models.CharField( + max_length=10, + choices=Status.choices, + default=Status.INITIAL, + verbose_name=_("payment status"), + ) + + order = models.ForeignKey( + "Order", + on_delete=models.RESTRICT, + null=False, + verbose_name=_("order"), + ) - return_url = models.URLField(null=True, verbose_name=_("return URL")) + +class Order(models.Model): + """An order is a subscription instance. + + When a subscription is started, we say the user "ordered" the subscription product. + + The order will receive multiple payments, which fulfill the subscription payment structure. + """ + + id = models.AutoField(primary_key=True) + + description = models.TextField(_("description")) + address = models.ForeignKey( + "BillingAddress", on_delete=models.PROTECT, verbose_name=_("billing address") + ) subscription = models.ForeignKey( - "Subscription", on_delete=models.RESTRICT, null=True, verbose_name=_("subscription") + "Subscription", + on_delete=models.SET_NULL, + null=True, + verbose_name=_("subscription"), ) + price_per_period = models.IntegerField() # in cents + period_quantity = models.IntegerField() + period_unit = models.CharField(max_length=5, choices=PeriodUnit.choices) + + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + class Meta: + verbose_name = _("order") + verbose_name_plural = _("orders") + + def __str__(self): + return ( + f"{self.description} voor {self.price / 100:.02f}" + f" ({Order.Status(self.payment_status).label})" + ) @property def eid(self): return hashids.encode(self.id) - eid.fget.short_description = _("EID") + eid.fget.short_description = _("external identifier") @classmethod def get_or_404(cls, eid) -> "Order": id = hashids.decode(eid)[0] return get_object_or_404(cls, id=id) - def save(self, *args, **kwargs): - if self.payment_status == Order.Status.PAID and self.done_at is None: - self.done_at = timezone.now() - return super().save(*args, **kwargs) - - def __str__(self): - return "{} voor {:.02f} ({})".format( - self.description, self.price / 100, Order.Status(self.payment_status).label - ) - class Meta: - verbose_name = _("order") - verbose_name_plural = _("orders") -class SubscriptionManager(models.Manager): - def current(self): - return self.get_queryset().filter(active_from_to__contains=timezone.now()) +class Subscription(models.Model): + """A subscription is a type of product that requires multiple payments. + The payment structure of a subscription is given by the price_per_period, + the period_quantity and the period_unit. -class Subscription(models.Model): - class PeriodUnit(models.TextChoices): - DAY = "day", _("Day") - WEEK = "week", _("Week") - MONTH = "month", _("Month") - YEAR = "year", _("Year") + Subscriptions have an indefinite duration by default. + """ id = models.AutoField(primary_key=True) - user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True) - address = models.ForeignKey("BillingAddress", on_delete=models.PROTECT) - created_at = models.DateTimeField(auto_now_add=True) - active_from_to = DateTimeRangeField(null=False) - price_per_period = models.IntegerField() # in cents + name = models.TextField(null=False, blank=False) + description = models.TextField(null=False, blank=True) + + price_per_period = models.IntegerField( + null=True, blank=True + ) # in cents, if null then it must be set in the order period_quantity = models.IntegerField() period_unit = models.CharField(max_length=5, choices=PeriodUnit.choices) - objects = SubscriptionManager() + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + class Meta: + verbose_name = _("subscription") + verbose_name_plural = _("subscriptions") + + def __str__(self): + return self.description @property def eid(self): return hashids.encode(self.id) - @property - def is_current(self): - return self.active_from_to.lower <= timezone.now() < self.active_from_to.upper + eid.fget.short_description = _("external identifier") + + @classmethod + def get_or_404(cls, eid) -> "Subscription": + id = hashids.decode(eid)[0] + return get_object_or_404(cls, id=id) def new_order(self, *, initial, return_url, description=None): + """Create a subscription "instance" of this subscription type.""" if description is None: - description = "Subscription for {}".format(self.address.name) - if initial == False: - description += " (initial payment)" + description = f"Subscription for {self.address.name}" return Order.objects.create( price=self.price_per_period, description=description, @@ -127,15 +161,3 @@ def new_order(self, *, initial, return_url, description=None): subscription=self, return_url=return_url, ) - - @classmethod - def get_or_404(cls, eid) -> "Subscription": - id = hashids.decode(eid)[0] - return get_object_or_404(cls, id=id) - - def __str__(self): - return "Subscription for {}".format(self.address.name) - - class Meta: - verbose_name = _("subscription") - verbose_name_plural = _("subscriptions") diff --git a/src/payments_mollie/migrations/__init__.py b/symfexit/payments/mollie/__init__.py similarity index 100% rename from src/payments_mollie/migrations/__init__.py rename to symfexit/payments/mollie/__init__.py diff --git a/symfexit/payments/mollie/admin.py b/symfexit/payments/mollie/admin.py new file mode 100644 index 0000000..846f6b4 --- /dev/null +++ b/symfexit/payments/mollie/admin.py @@ -0,0 +1 @@ +# Register your models here. diff --git a/src/payments_mollie/apps.py b/symfexit/payments/mollie/apps.py similarity index 77% rename from src/payments_mollie/apps.py rename to symfexit/payments/mollie/apps.py index 1323fd7..a9ebc44 100644 --- a/src/payments_mollie/apps.py +++ b/symfexit/payments/mollie/apps.py @@ -3,4 +3,4 @@ class PaymentsMollieConfig(AppConfig): default_auto_field = "django.db.models.BigAutoField" - name = "payments_mollie" + name = "symfexit.payments.mollie" diff --git a/src/payments_mollie/migrations/0001_initial.py b/symfexit/payments/mollie/migrations/0001_initial.py similarity index 81% rename from src/payments_mollie/migrations/0001_initial.py rename to symfexit/payments/mollie/migrations/0001_initial.py index b5cbb9c..7029b4f 100644 --- a/src/payments_mollie/migrations/0001_initial.py +++ b/symfexit/payments/mollie/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.0 on 2024-05-11 15:41 +# Generated by Django 5.1.1 on 2024-09-28 15:41 import django.db.models.deletion from django.db import migrations, models @@ -28,9 +28,7 @@ class Migration(migrations.Migration): ], options={ "indexes": [ - models.Index( - fields=["payment_id"], name="payments_mo_payment_1abcfa_idx" - ) + models.Index(fields=["payment_id"], name="payments_mo_payment_1abcfa_idx") ], }, ), diff --git a/src/signup/__init__.py b/symfexit/payments/mollie/migrations/__init__.py similarity index 100% rename from src/signup/__init__.py rename to symfexit/payments/mollie/migrations/__init__.py diff --git a/src/payments_mollie/models.py b/symfexit/payments/mollie/models.py similarity index 89% rename from src/payments_mollie/models.py rename to symfexit/payments/mollie/models.py index 4918b43..c71b3dd 100644 --- a/src/payments_mollie/models.py +++ b/symfexit/payments/mollie/models.py @@ -1,6 +1,6 @@ from django.db import models -from payments.models import Order +from symfexit.payments.models import Order # Create your models here. diff --git a/src/payments_mollie/payments.py b/symfexit/payments/mollie/payments.py similarity index 84% rename from src/payments_mollie/payments.py rename to symfexit/payments/mollie/payments.py index 7a17b0a..2b1bd3a 100644 --- a/src/payments_mollie/payments.py +++ b/symfexit/payments/mollie/payments.py @@ -1,12 +1,11 @@ import logging +from django.conf import settings from django.shortcuts import render -from django.template.loader import get_template -from payments import PaymentProcessor -from payments.models import Order, Subscription -from payments.registry import payments_registry -from symfexit import settings +from symfexit.payments import PaymentProcessor +from symfexit.payments.models import Subscription +from symfexit.payments.registry import payments_registry try: from mollie.api.client import Client @@ -48,7 +47,7 @@ def start_subscription_flow(self, request, subscription: Subscription, return_ur payment_methods = self.client.methods.list( sequenceType="first", locale="nl_NL", - amount={"value": "{:.02f}".format(order.price / 100), "currency": "EUR"}, + amount={"value": f"{order.price / 100:.02f}", "currency": "EUR"}, billingCountry="NL", include="issuers", ) diff --git a/src/payments_mollie/templates/payments_mollie/select_method.html b/symfexit/payments/mollie/templates/payments_mollie/select_method.html similarity index 100% rename from src/payments_mollie/templates/payments_mollie/select_method.html rename to symfexit/payments/mollie/templates/payments_mollie/select_method.html diff --git a/symfexit/payments/mollie/tests.py b/symfexit/payments/mollie/tests.py new file mode 100644 index 0000000..a39b155 --- /dev/null +++ b/symfexit/payments/mollie/tests.py @@ -0,0 +1 @@ +# Create your tests here. diff --git a/src/payments_mollie/urls.py b/symfexit/payments/mollie/urls.py similarity index 90% rename from src/payments_mollie/urls.py rename to symfexit/payments/mollie/urls.py index e558e93..3bd67a5 100644 --- a/src/payments_mollie/urls.py +++ b/symfexit/payments/mollie/urls.py @@ -1,6 +1,6 @@ from django.urls import path -from payments_mollie.views import ( +from symfexit.payments.mollie.views import ( initiate_ideal, mollie_cancel, mollie_return, diff --git a/src/payments_mollie/views.py b/symfexit/payments/mollie/views.py similarity index 88% rename from src/payments_mollie/views.py rename to symfexit/payments/mollie/views.py index 3be6066..8ffeef8 100644 --- a/src/payments_mollie/views.py +++ b/symfexit/payments/mollie/views.py @@ -1,5 +1,3 @@ -import json - from django.db import transaction from django.http import ( Http404, @@ -10,9 +8,9 @@ from django.urls import reverse from django.views.decorators.csrf import csrf_exempt -from payments.models import Order -from payments_mollie.models import MolliePayment -from payments_mollie.payments import MollieProcessor +from symfexit.payments.models import Order +from symfexit.payments.mollie.models import MolliePayment +from symfexit.payments.mollie.payments import MollieProcessor def initiate_ideal(request, issuer_id, order_id): @@ -30,7 +28,7 @@ def initiate_ideal(request, issuer_id, order_id): "method": "ideal", "issuer": issuer_id, "amount": { - "value": "{:.02f}".format(order.price / 100), + "value": f"{order.price / 100:.02f}", "currency": "EUR", }, "description": order.description, @@ -40,9 +38,7 @@ def initiate_ideal(request, issuer_id, order_id): "cancelUrl": request.build_absolute_uri( reverse("payments_mollie:cancel", args=[order_id]) ), - "webhookUrl": request.build_absolute_uri( - reverse("payments_mollie:webhook") - ), + "webhookUrl": request.build_absolute_uri(reverse("payments_mollie:webhook")), } ) MolliePayment.objects.create(order=order, payment_id=payment["id"], body=payment) diff --git a/src/payments/registry.py b/symfexit/payments/registry.py similarity index 72% rename from src/payments/registry.py rename to symfexit/payments/registry.py index ca729c0..e2ed01f 100644 --- a/src/payments/registry.py +++ b/symfexit/payments/registry.py @@ -1,7 +1,6 @@ import abc import bisect import logging -from typing import List, Tuple logger = logging.getLogger(__name__) @@ -10,23 +9,17 @@ class PaymentsRegistry: def __init__(self): - self._registry: List[Tuple[int, PaymentProcessor]] = [] + self._registry: list[tuple[int, PaymentProcessor]] = [] self._names = {} def register(self, *, name, priority=0): def _register(cls): if not issubclass(cls, PaymentProcessor): - raise ValueError( - "Registered class must be a subclass of PaymentProcessor" - ) + raise ValueError("Registered class must be a subclass of PaymentProcessor") instance = cls() - bisect.insort_right( - self._registry, (priority, instance), key=lambda x: x[0] - ) + bisect.insort_right(self._registry, (priority, instance), key=lambda x: x[0]) self._names[name] = instance - logging.info( - f"Registered payment processor {name} with priority {priority}" - ) + logging.info(f"Registered payment processor {name} with priority {priority}") return cls return _register @@ -41,9 +34,7 @@ def get_main(self): logging.info(f"Using payment processor {processor}") return processor except Exception as e: - logging.error( - f"Error checking availability of processor {processor}: {e}" - ) + logging.error(f"Error checking availability of processor {processor}: {e}") pass raise RuntimeError("No available payment processor found") diff --git a/symfexit/payments/tests.py b/symfexit/payments/tests.py new file mode 100644 index 0000000..a39b155 --- /dev/null +++ b/symfexit/payments/tests.py @@ -0,0 +1 @@ +# Create your tests here. diff --git a/symfexit/payments/views.py b/symfexit/payments/views.py new file mode 100644 index 0000000..60f00ef --- /dev/null +++ b/symfexit/payments/views.py @@ -0,0 +1 @@ +# Create your views here. diff --git a/src/signup/migrations/__init__.py b/symfexit/root/__init__.py similarity index 100% rename from src/signup/migrations/__init__.py rename to symfexit/root/__init__.py diff --git a/src/symfexit/apps.py b/symfexit/root/apps.py similarity index 85% rename from src/symfexit/apps.py rename to symfexit/root/apps.py index 13353ec..ceb28ff 100644 --- a/src/symfexit/apps.py +++ b/symfexit/root/apps.py @@ -3,5 +3,5 @@ class SymfexitConfig(AppConfig): default_auto_field = "django.db.models.BigAutoField" - name = "symfexit" + name = "symfexit.root" verbose_name = "Symfexit" diff --git a/src/symfexit/asgi.py b/symfexit/root/asgi.py similarity index 81% rename from src/symfexit/asgi.py rename to symfexit/root/asgi.py index 51d6cb0..d95e269 100644 --- a/src/symfexit/asgi.py +++ b/symfexit/root/asgi.py @@ -11,6 +11,6 @@ from django.core.asgi import get_asgi_application -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "symfexit.settings") +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "symfexit.root.settings") application = get_asgi_application() diff --git a/symfexit/root/config.py b/symfexit/root/config.py new file mode 100644 index 0000000..9f9febc --- /dev/null +++ b/symfexit/root/config.py @@ -0,0 +1,7 @@ +from django.apps import AppConfig + + +class SymfexitConfig(AppConfig): + """Configuration class for the symfexit app.""" + + title: str = "Symfexit" diff --git a/src/symfexit/context_processors.py b/symfexit/root/context_processors.py similarity index 100% rename from src/symfexit/context_processors.py rename to symfexit/root/context_processors.py diff --git a/src/symfexit/helpers.py b/symfexit/root/helpers.py similarity index 100% rename from src/symfexit/helpers.py rename to symfexit/root/helpers.py diff --git a/src/symfexit/locale/nl/LC_MESSAGES/django.mo b/symfexit/root/locale/nl/LC_MESSAGES/django.mo similarity index 100% rename from src/symfexit/locale/nl/LC_MESSAGES/django.mo rename to symfexit/root/locale/nl/LC_MESSAGES/django.mo diff --git a/src/symfexit/locale/nl/LC_MESSAGES/django.po b/symfexit/root/locale/nl/LC_MESSAGES/django.po similarity index 100% rename from src/symfexit/locale/nl/LC_MESSAGES/django.po rename to symfexit/root/locale/nl/LC_MESSAGES/django.po diff --git a/src/symfexit/settings.py b/symfexit/root/settings.py similarity index 80% rename from src/symfexit/settings.py rename to symfexit/root/settings.py index 805e0c0..3c034de 100644 --- a/src/symfexit/settings.py +++ b/symfexit/root/settings.py @@ -15,13 +15,12 @@ from pathlib import Path import dj_database_url - -from symfexit.utils import enable_if - from django.utils.translation import gettext_lazy as _ +from symfexit.root.utils import enable_if + try: - import django_browser_reload + import django_browser_reload # noqa django_browser_reload_enabled = True except ImportError: @@ -77,36 +76,30 @@ def setting_from_env( try: return os.environ[name] except KeyError: - if DJANGO_ENV == "production" or ( - DJANGO_ENV == "staging" and staging is _NOT_SET - ): + if DJANGO_ENV == "production" or (DJANGO_ENV == "staging" and staging is _NOT_SET): if production is _NOT_SET and os.environ.get("MANAGE_PY", "0") == "0": # pylint: disable=raise-missing-from raise Misconfiguration( f"Environment variable `{name}` must be supplied in production" - ) + ) from None if production is _NOT_SET and os.environ.get("MANAGE_PY", "0") == "1": - logger.warning( - "Ignoring unset %s because we're running a management command", name - ) + logger.warning("Ignoring unset %s because we're running a management command", name) return development return production if DJANGO_ENV == "staging": return staging - if DJANGO_ENV == "development" or ( - DJANGO_ENV == "testing" and testing is _NOT_SET - ): + if DJANGO_ENV == "development" or (DJANGO_ENV == "testing" and testing is _NOT_SET): return development if DJANGO_ENV == "testing": return testing # pylint: disable=raise-missing-from - raise Misconfiguration(f"DJANGO_ENV set to unsupported value: {DJANGO_ENV}") + raise Misconfiguration(f"DJANGO_ENV set to unsupported value: {DJANGO_ENV}") from None # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent -CONTENT_DIR = Path(setting_from_env("CONTENT_DIR", development=BASE_DIR)) +CONTENT_DIR = Path(setting_from_env("CONTENT_DIR", development=BASE_DIR.parent / "content")) DJANGO_ENV = os.getenv("DJANGO_ENV", "development") @@ -117,18 +110,14 @@ def setting_from_env( ) # https://docs.djangoproject.com/en/5.0/ref/settings/#secure-proxy-ssl-header -SECURE_PROXY_SSL_HEADER = setting( - development=None, production=("HTTP_X_FORWARDED_PROTO", "https") -) +SECURE_PROXY_SSL_HEADER = setting(development=None, production=("HTTP_X_FORWARDED_PROTO", "https")) MOLLIE_API_KEY = setting_from_env("MOLLIE_API_KEY", production=None) # SECURITY WARNING: don't run with debug turned on in production! DEBUG = setting(development=True, production=False, testing=False) -ALLOWED_HOSTS = setting( - development=["*"], production=os.getenv("ALLOWED_HOSTS", "").split(",") -) +ALLOWED_HOSTS = setting(development=["*"], production=os.getenv("ALLOWED_HOSTS", "").split(",")) if DEBUG: CSRF_TRUSTED_ORIGINS = ["https://*.ngrok-free.app"] @@ -139,15 +128,6 @@ def setting_from_env( # Application definition -DOCS_ENABLED = os.getenv("ENABLE_DOCS", True) -HOME_ENABLED = os.getenv("ENABLE_HOME", True) -SIGNUP_ENABLED = os.getenv("ENABLE_SIGNUP", True) -MEMBERSHIP_ENABLED = os.getenv("ENABLE_MEMBERSHIP", True) -THEMING_ENABLED = os.getenv("ENABLE_THEMING", True) - -if DJANGO_ENV == "development": - SITE_ID = 1 - INSTALLED_APPS = ( [ "django.contrib.auth", @@ -155,7 +135,6 @@ def setting_from_env( "django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles", - "django.contrib.sites", "tailwind", "fontawesomefree", ] @@ -165,24 +144,24 @@ def setting_from_env( "constance.backends.database", "tinymce", # our own apps - "theme", + "symfexit.theme", # Order of the adminsite apps is important as MyAdminConfig points to the # django.contrib.admin, which contains translations which should be # overwritten by our own translations in AdminSiteConfig - "adminsite.apps.AdminSiteConfig", - "menu.apps.MenuConfig", - "members.apps.MembersConfig", - "worker.apps.WorkerConfig", - "payments.apps.PaymentsConfig", - "payments_dummy.apps.PaymentsDummyConfig", - "payments_mollie.apps.PaymentsMollieConfig", - "symfexit.apps.SymfexitConfig", + "symfexit.adminsite.apps.AdminSiteConfig", + "symfexit.menu.apps.MenuConfig", + "symfexit.members.apps.MembersConfig", + "symfexit.worker.apps.WorkerConfig", + "symfexit.payments.apps.PaymentsConfig", + "symfexit.payments.dummy.apps.PaymentsDummyConfig", + "symfexit.payments.mollie.apps.PaymentsMollieConfig", + "symfexit.root.apps.SymfexitConfig", + "symfexit.documents.apps.DocumentsConfig", + "symfexit.home.apps.HomeConfig", + "symfexit.signup.apps.SignupConfig", + "symfexit.membership.apps.MembershipConfig", + "symfexit.adminsite.apps.MyAdminConfig", ] - + enable_if(DOCS_ENABLED, ["documents.apps.DocumentsConfig"]) - + enable_if(HOME_ENABLED, ["home.apps.HomeConfig"]) - + enable_if(SIGNUP_ENABLED, ["signup.apps.SignupConfig"]) - + enable_if(MEMBERSHIP_ENABLED, ["membership.apps.MembershipConfig"]) - + ["adminsite.apps.MyAdminConfig"] ) MIDDLEWARE = [ @@ -199,7 +178,7 @@ def setting_from_env( ["django_browser_reload.middleware.BrowserReloadMiddleware"], ) -ROOT_URLCONF = "symfexit.urls" +ROOT_URLCONF = "symfexit.root.urls" TEMPLATES = [ { @@ -212,8 +191,8 @@ def setting_from_env( "django.template.context_processors.request", "django.contrib.auth.context_processors.auth", "django.contrib.messages.context_processors.messages", - "symfexit.context_processors.constance_vars", - "theme.context.current_theme", + "symfexit.root.context_processors.constance_vars", + "symfexit.theme.context.current_theme", ], "string_if_invalid": ("😱 MISSING VARIABLE %s 😱" if DEBUG else ""), }, @@ -222,7 +201,7 @@ def setting_from_env( FORM_RENDERER = "django.forms.renderers.DjangoDivFormRenderer" -WSGI_APPLICATION = "symfexit.wsgi.application" +WSGI_APPLICATION = "symfexit.root.wsgi.application" # Database @@ -270,9 +249,7 @@ def setting_from_env( USE_L10N = True -LANGUAGE_CODE = setting_from_env( - "DEFAULT_LANGUAGE_CODE", production="nl-NL", development="nl-NL" -) +LANGUAGE_CODE = setting_from_env("DEFAULT_LANGUAGE_CODE", production="nl-NL", development="nl-NL") # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/5.0/howto/static-files/ @@ -331,7 +308,7 @@ def setting_from_env( CONSTANCE_ADDITIONAL_FIELDS = { "image_field": [ "django.forms.FileField", - {"required": False, "widget": "symfexit.helpers.ClearableFileInputFromStr"}, + {"required": False, "widget": "symfexit.root.helpers.ClearableFileInputFromStr"}, ] } @@ -340,7 +317,10 @@ def setting_from_env( "SITE_TITLE": ("Membersite", _("Main title of this site")), "LOGO_IMAGE": ("", _("Organisation logo"), "image_field"), "MAIN_SITE": ("https://roodjongeren.nl/", _("Main site of the organisation")), - "HOMEPAGE_CURRENT": (0, _("Current home page (configure this on the home pages admin)")), + "HOMEPAGE_CURRENT": ( + 0, + _("Current home page (configure this on the home pages admin)"), + ), "PAYMENT_TIERS_JSON": ( "{}", _("JSON with payment tiers (configure this on the membership admin)"), diff --git a/src/symfexit/urls.py b/symfexit/root/urls.py similarity index 57% rename from src/symfexit/urls.py rename to symfexit/root/urls.py index 30c0e62..b00734c 100644 --- a/src/symfexit/urls.py +++ b/symfexit/root/urls.py @@ -13,52 +13,40 @@ 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ + from django.conf import settings from django.conf.urls.static import static from django.http import HttpResponse from django.urls import include, path -from django.views.generic import RedirectView -from adminsite.admin import admin_site -from symfexit.settings import DOCS_ENABLED, HOME_ENABLED, SIGNUP_ENABLED -from symfexit.utils import enable_if +from symfexit.adminsite.admin import admin_site +from symfexit.root.utils import enable_if try: - import django_browser_reload + import django_browser_reload # noqa django_browser_reload_enabled = True except ImportError: django_browser_reload_enabled = False + def health_check(request): return HttpResponse("OK") + urlpatterns = ( - [path("tinymce/", include("tinymce.urls"))] - + enable_if( - HOME_ENABLED, - lambda: [path("", include("home.urls"))], - otherwise=lambda: [ - path( - "", - RedirectView.as_view(pattern_name="members:memberdata"), - name="index", - ) - ], - ) - + [ - path("", include("members.urls")), - path("healthz", health_check, name="healthz") + [ + path("healthz", health_check, name="healthz"), + path("tinymce/", include("tinymce.urls")), + path("", include("symfexit.home.urls")), + path("", include("symfexit.members.urls")), + path("", include("symfexit.documents.urls")), + path("", include("symfexit.signup.urls")), + path("mollie/", include("symfexit.payments.mollie.urls")), ] - + enable_if(DOCS_ENABLED, lambda: [path("", include("documents.urls"))]) - + enable_if(SIGNUP_ENABLED, lambda: [path("", include("signup.urls"))]) - + enable_if( - settings.MOLLIE_API_KEY, - lambda: [path("mollie/", include("payments_mollie.urls"))], - ) + enable_if( settings.DEBUG, - lambda: [path("dummy/", include("payments_dummy.urls"))], + lambda: [path("dummy/", include("symfexit.payments.dummy.urls"))], ) + [ path("admin/", admin_site.urls), diff --git a/src/symfexit/utils.py b/symfexit/root/utils.py similarity index 76% rename from src/symfexit/utils.py rename to symfexit/root/utils.py index 8a32135..281b20a 100644 --- a/src/symfexit/utils.py +++ b/symfexit/root/utils.py @@ -1,9 +1,7 @@ def enable_if(condition, value, otherwise=None): if otherwise is None: otherwise = [] - if isinstance(condition, str) and ( - condition.lower() == "false" or condition == "0" - ): + if isinstance(condition, str) and (condition.lower() == "false" or condition == "0"): condition = False if condition and callable(value): value = value() diff --git a/src/symfexit/wsgi.py b/symfexit/root/wsgi.py similarity index 81% rename from src/symfexit/wsgi.py rename to symfexit/root/wsgi.py index 684e33b..69327d0 100644 --- a/src/symfexit/wsgi.py +++ b/symfexit/root/wsgi.py @@ -11,6 +11,6 @@ from django.core.wsgi import get_wsgi_application -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "symfexit.settings") +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "symfexit.root.settings") application = get_wsgi_application() diff --git a/src/symfexit/__init__.py b/symfexit/signup/__init__.py similarity index 100% rename from src/symfexit/__init__.py rename to symfexit/signup/__init__.py diff --git a/src/signup/admin.py b/symfexit/signup/admin.py similarity index 50% rename from src/signup/admin.py rename to symfexit/signup/admin.py index f4defe7..58bd51f 100644 --- a/src/signup/admin.py +++ b/symfexit/signup/admin.py @@ -1,54 +1,47 @@ -from typing import Any - -from django import forms from django.contrib import admin, messages -from django.http.request import HttpRequest -from django.utils.html import format_html -from django.utils.safestring import mark_safe - -from signup.models import ApplicationPayment, DuplicateEmailError, MembershipApplication +from symfexit.signup.models import DuplicateEmailError, MembershipApplication -class ApplicationPaymentForm(forms.ModelForm): - class Meta: - help_texts = { - "payment_url": "Auto-generated payment URL. You can send this to the user so they can complete their payment.", - } +# class ApplicationPaymentForm(forms.ModelForm): +# class Meta: +# help_texts = { +# "payment_url": "Auto-generated payment URL. You can send this to the user so they can complete their payment.", +# } - model = ApplicationPayment - exclude = () +# model = ApplicationPayment +# exclude = () -@admin.register(ApplicationPayment) -class ApplicationPaymentAdmin(admin.ModelAdmin): - form = ApplicationPaymentForm +# @admin.register(ApplicationPayment) +# class ApplicationPaymentAdmin(admin.ModelAdmin): +# form = ApplicationPaymentForm - list_display = ("created_at", "price", "description", "payment_status") - readonly_fields = ("created_at", "done_at", "payment_url") +# list_display = ("created_at", "price", "description", "payment_status") +# readonly_fields = ("created_at", "done_at", "payment_url") - def get_form(self, request, *args, **kwargs): - self.request = request - return super().get_form(request, *args, **kwargs) +# def get_form(self, request, *args, **kwargs): +# self.request = request +# return super().get_form(request, *args, **kwargs) - def payment_url(self, obj: ApplicationPayment): - url = obj.payment_url - if url is None: - raise ValueError("Payment URL is not set") - absolute_url = self.request.build_absolute_uri(url) - html = format_html('{}', absolute_url, url) - return mark_safe(html) +# def payment_url(self, obj: ApplicationPayment): +# url = obj.payment_url +# if url is None: +# raise ValueError("Payment URL is not set") +# absolute_url = self.request.build_absolute_uri(url) +# html = format_html('{}', absolute_url, url) +# return mark_safe(html) - # don't show the add button - def has_add_permission(self, request): - return False +# # don't show the add button +# def has_add_permission(self, request): +# return False - # don't show the delete button - def has_delete_permission(self, request, obj=None): - return False +# # don't show the delete button +# def has_delete_permission(self, request, obj=None): +# return False - # don't show the change button - def has_change_permission(self, request, obj=None): - return False +# # don't show the change button +# def has_change_permission(self, request, obj=None): +# return False @admin.register(MembershipApplication) @@ -75,7 +68,7 @@ class MembershipApplicationAdmin(admin.ModelAdmin): "created_at", "payment_amount", "_order", - "_subscription", + # "_subscription", "user", ) diff --git a/src/signup/apps.py b/symfexit/signup/apps.py similarity index 87% rename from src/signup/apps.py rename to symfexit/signup/apps.py index e924b89..c63473a 100644 --- a/src/signup/apps.py +++ b/symfexit/signup/apps.py @@ -1,9 +1,8 @@ from django.apps import AppConfig - from django.utils.translation import gettext_lazy as _ class SignupConfig(AppConfig): default_auto_field = "django.db.models.BigAutoField" - name = "signup" + name = "symfexit.signup" verbose_name = _("Signup") diff --git a/src/signup/forms.py b/symfexit/signup/forms.py similarity index 95% rename from src/signup/forms.py rename to symfexit/signup/forms.py index 2664b35..9e31372 100644 --- a/src/signup/forms.py +++ b/symfexit/signup/forms.py @@ -3,8 +3,8 @@ from django import forms from django.utils import timezone -from members.models import LocalGroup -from signup.models import MembershipApplication +from symfexit.members.models import LocalGroup +from symfexit.signup.models import MembershipApplication def with_classes(field, classes): @@ -96,9 +96,7 @@ def __init__(self, *args, **kwargs): for name, field in self.fields.items(): if hasattr(field, "extra_css_classes"): boundfield = self[name] - boundfield.css_classes = wrap_css_classes( - boundfield, field.extra_css_classes - ) + boundfield.css_classes = wrap_css_classes(boundfield, field.extra_css_classes) initial_birth_date = timezone.now() initial_birth_date = initial_birth_date.replace( day=1, month=1, year=initial_birth_date.year - 18 diff --git a/src/signup/locale/nl/LC_MESSAGES/django.mo b/symfexit/signup/locale/nl/LC_MESSAGES/django.mo similarity index 100% rename from src/signup/locale/nl/LC_MESSAGES/django.mo rename to symfexit/signup/locale/nl/LC_MESSAGES/django.mo diff --git a/src/signup/locale/nl/LC_MESSAGES/django.po b/symfexit/signup/locale/nl/LC_MESSAGES/django.po similarity index 100% rename from src/signup/locale/nl/LC_MESSAGES/django.po rename to symfexit/signup/locale/nl/LC_MESSAGES/django.po diff --git a/src/signup/migrations/0001_initial.py b/symfexit/signup/migrations/0001_initial.py similarity index 53% rename from src/signup/migrations/0001_initial.py rename to symfexit/signup/migrations/0001_initial.py index d63b43c..e1dc2ff 100644 --- a/src/signup/migrations/0001_initial.py +++ b/symfexit/signup/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.0 on 2024-05-11 15:41 +# Generated by Django 5.1.1 on 2024-09-28 15:41 import django.db.models.deletion from django.conf import settings @@ -11,45 +11,42 @@ class Migration(migrations.Migration): dependencies = [ ("members", "0001_initial"), - ("membership", "0001_initial"), ("payments", "0001_initial"), migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ - migrations.CreateModel( - name="ApplicationPayment", - fields=[ - ( - "order_ptr", - models.OneToOneField( - auto_created=True, - on_delete=django.db.models.deletion.CASCADE, - parent_link=True, - primary_key=True, - serialize=False, - to="payments.order", - ), - ), - ], - options={ - "verbose_name": "application payment", - }, - bases=("payments.order",), - ), migrations.CreateModel( name="MembershipApplication", fields=[ ("id", models.AutoField(primary_key=True, serialize=False)), - ("first_name", models.CharField(max_length=100)), - ("last_name", models.CharField(max_length=100)), - ("email", models.EmailField(max_length=254)), - ("phone_number", models.CharField(max_length=100)), - ("birth_date", models.DateField()), - ("address", models.CharField(max_length=100)), - ("city", models.CharField(max_length=100)), - ("postal_code", models.CharField(max_length=100)), - ("payment_amount", models.IntegerField()), + ( + "first_name", + models.CharField(max_length=100, verbose_name="first name"), + ), + ( + "last_name", + models.CharField(max_length=100, verbose_name="last name"), + ), + ( + "email", + models.EmailField(max_length=254, verbose_name="email address"), + ), + ( + "phone_number", + models.CharField(max_length=100, verbose_name="phone number"), + ), + ("birth_date", models.DateField(verbose_name="date of birth")), + ("address", models.CharField(max_length=100, verbose_name="address")), + ("city", models.CharField(max_length=100, verbose_name="city")), + ( + "postal_code", + models.CharField(max_length=100, verbose_name="postal code"), + ), + ( + "payment_amount", + models.IntegerField(verbose_name="payment amount in cents"), + ), ( "status", models.CharField( @@ -60,25 +57,24 @@ class Migration(migrations.Migration): ], default="created", max_length=10, + verbose_name="status", ), ), - ("created_at", models.DateTimeField(auto_now_add=True)), ( - "_order", - models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - to="signup.applicationpayment", - verbose_name="payment order", - ), + "created_at", + models.DateTimeField(auto_now_add=True, verbose_name="created at"), ), ( - "_subscription", + "updated_at", + models.DateTimeField(auto_now=True, verbose_name="updated at"), + ), + ( + "_order", models.ForeignKey( null=True, on_delete=django.db.models.deletion.SET_NULL, - to="membership.membership", - verbose_name="associated subscription", + to="payments.order", + verbose_name="subscription order", ), ), ( @@ -86,6 +82,7 @@ class Migration(migrations.Migration): models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, to="members.localgroup", + verbose_name="preferred group", ), ), ( @@ -94,11 +91,13 @@ class Migration(migrations.Migration): null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, + verbose_name="user", ), ), ], options={ "verbose_name": "membership application", + "verbose_name_plural": "membership applications", }, ), ] diff --git a/src/theme/__init__.py b/symfexit/signup/migrations/__init__.py similarity index 100% rename from src/theme/__init__.py rename to symfexit/signup/migrations/__init__.py diff --git a/src/signup/models.py b/symfexit/signup/models.py similarity index 69% rename from src/signup/models.py rename to symfexit/signup/models.py index 5377b88..27dd7c8 100644 --- a/src/signup/models.py +++ b/symfexit/signup/models.py @@ -1,6 +1,6 @@ from django.conf import settings from django.contrib.auth import get_user_model -from django.db import IntegrityError, models, transaction +from django.db import IntegrityError, models from django.db.backends.postgresql.psycopg_any import DateTimeTZRange from django.shortcuts import get_object_or_404 from django.urls import reverse @@ -8,33 +8,19 @@ from django.utils.translation import gettext_lazy as _ from hashids import Hashids -from membership.models import Membership -from payments.models import BillingAddress, Order +from symfexit.membership.models import Membership +from symfexit.payments.models import BillingAddress, Order hashids = Hashids(salt=settings.SECRET_KEY, min_length=8) User = get_user_model() -class ApplicationPayment(Order): - @property - def payment_url(self): - appl = MembershipApplication.objects.filter(_order=self).first() - if appl is None: - return None - return appl.get_absolute_url() - - class Meta: - verbose_name = _("application payment") - verbose_name_plural = _("application payments") - - class DuplicateEmailError(Exception): pass class MembershipApplication(models.Model): - class Status(models.TextChoices): CREATED = ("created", _("Created")) ACCEPTED = ("accepted", _("Accepted")) @@ -50,33 +36,27 @@ class Status(models.TextChoices): city = models.CharField(_("city"), max_length=100) postal_code = models.CharField(_("postal code"), max_length=100) - preferred_group = models.ForeignKey("members.LocalGroup", on_delete=models.CASCADE, verbose_name=_("preferred group")) + preferred_group = models.ForeignKey( + "members.LocalGroup", + on_delete=models.CASCADE, + verbose_name=_("preferred group"), + ) payment_amount = models.IntegerField(_("payment amount in cents")) # in cents - status = models.CharField(_("status"), - max_length=10, choices=Status.choices, default=Status.CREATED + status = models.CharField( + _("status"), max_length=10, choices=Status.choices, default=Status.CREATED ) user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, verbose_name=_("user")) _order = models.ForeignKey( - ApplicationPayment, - on_delete=models.SET_NULL, - null=True, - verbose_name=_("payment order"), - ) - _subscription = models.ForeignKey( - Membership, + Order, on_delete=models.SET_NULL, null=True, - verbose_name=_("associated subscription"), + verbose_name=_("subscription order"), ) created_at = models.DateTimeField(_("created at"), auto_now_add=True) - - @classmethod - def get_or_404(cls, eid): - id = hashids.decode(eid)[0] - return get_object_or_404(MembershipApplication, id=id) + updated_at = models.DateTimeField(_("updated at"), auto_now=True) @property def eid(self): @@ -84,6 +64,11 @@ def eid(self): eid.fget.short_description = _("external identifier") + @classmethod + def get_or_404(cls, eid): + id = hashids.decode(eid)[0] + return get_object_or_404(MembershipApplication, id=id) + def get_absolute_url(self): return reverse("signup:payment", kwargs={"application_id": self.eid}) @@ -109,16 +94,15 @@ def get_or_create_subscription(self): def create_user(self): try: - with transaction.atomic(): - user = User.objects.create_user( - email=self.email, - first_name=self.first_name, - last_name=self.last_name, - phone_number=self.phone_number, - address=self.address, - city=self.city, - postal_code=self.postal_code, - ) + user = User.objects.create_user( + email=self.email, + first_name=self.first_name, + last_name=self.last_name, + phone_number=self.phone_number, + address=self.address, + city=self.city, + postal_code=self.postal_code, + ) except IntegrityError as e: if "members_user_unique_email_key" in e.args[0]: raise DuplicateEmailError @@ -133,7 +117,7 @@ def create_user(self): return user def __str__(self): - return "{} {}".format(self.first_name, self.last_name) + return f"{self.first_name} {self.last_name}" class Meta: verbose_name = _("membership application") diff --git a/src/signup/templates/signup/cancelled.html b/symfexit/signup/templates/signup/cancelled.html similarity index 100% rename from src/signup/templates/signup/cancelled.html rename to symfexit/signup/templates/signup/cancelled.html diff --git a/src/signup/templates/signup/forms/div.html b/symfexit/signup/templates/signup/forms/div.html similarity index 100% rename from src/signup/templates/signup/forms/div.html rename to symfexit/signup/templates/signup/forms/div.html diff --git a/src/signup/templates/signup/payment.html b/symfexit/signup/templates/signup/payment.html similarity index 100% rename from src/signup/templates/signup/payment.html rename to symfexit/signup/templates/signup/payment.html diff --git a/src/signup/templates/signup/return.html b/symfexit/signup/templates/signup/return.html similarity index 100% rename from src/signup/templates/signup/return.html rename to symfexit/signup/templates/signup/return.html diff --git a/src/signup/templates/signup/signup.html b/symfexit/signup/templates/signup/signup.html similarity index 100% rename from src/signup/templates/signup/signup.html rename to symfexit/signup/templates/signup/signup.html diff --git a/symfexit/signup/tests.py b/symfexit/signup/tests.py new file mode 100644 index 0000000..a39b155 --- /dev/null +++ b/symfexit/signup/tests.py @@ -0,0 +1 @@ +# Create your tests here. diff --git a/src/signup/urls.py b/symfexit/signup/urls.py similarity index 70% rename from src/signup/urls.py rename to symfexit/signup/urls.py index 8037b9b..abd7673 100644 --- a/src/signup/urls.py +++ b/symfexit/signup/urls.py @@ -1,19 +1,17 @@ from django.urls import path -from signup.views import ( +from symfexit.signup.views import ( MemberSignup, member_signup_pay, member_signup_pay_retry, return_view, ) -app_name = "signup" +app_name = "symfexit.signup" urlpatterns = [ path("aanmelden/", MemberSignup.as_view(), name="signup"), path("aanmelden/betalen/", member_signup_pay, name="payment"), path("aanmelden/return/", return_view, name="return"), - path( - "aanmelden/retry/", member_signup_pay_retry, name="retry" - ), + path("aanmelden/retry/", member_signup_pay_retry, name="retry"), ] diff --git a/src/signup/views.py b/symfexit/signup/views.py similarity index 80% rename from src/signup/views.py rename to symfexit/signup/views.py index 70ea272..afbd0d2 100644 --- a/src/signup/views.py +++ b/symfexit/signup/views.py @@ -1,22 +1,15 @@ import logging -from base64 import urlsafe_b64decode, urlsafe_b64encode -from django.conf import settings from django.contrib.auth import logout -from django.http import ( - Http404, - HttpResponseNotAllowed, - HttpResponseNotFound, - HttpResponseRedirect, -) -from django.shortcuts import get_object_or_404, render +from django.http import Http404, HttpResponseNotAllowed, HttpResponseRedirect +from django.shortcuts import render from django.urls import reverse, reverse_lazy from django.views.generic import FormView -from payments.models import Order -from payments.registry import payments_registry -from signup.forms import SignupForm -from signup.models import MembershipApplication +from symfexit.payments.models import Order +from symfexit.payments.registry import payments_registry +from symfexit.signup.forms import SignupForm +from symfexit.signup.models import MembershipApplication logger = logging.getLogger(__name__) diff --git a/src/theme/.gitignore b/symfexit/theme/.gitignore similarity index 100% rename from src/theme/.gitignore rename to symfexit/theme/.gitignore diff --git a/src/theme/management/__init__.py b/symfexit/theme/__init__.py similarity index 100% rename from src/theme/management/__init__.py rename to symfexit/theme/__init__.py diff --git a/src/theme/admin.py b/symfexit/theme/admin.py similarity index 90% rename from src/theme/admin.py rename to symfexit/theme/admin.py index d24c60e..aacab2c 100644 --- a/src/theme/admin.py +++ b/symfexit/theme/admin.py @@ -1,13 +1,12 @@ from constance.admin import Config, ConstanceAdmin -from django.conf import settings from django.contrib import admin from django.template.response import TemplateResponse from django.urls import path from django.urls.resolvers import URLPattern from django.views.generic import TemplateView -from theme.models import TailwindKey -from worker.registry import add_task +from symfexit.theme.models import TailwindKey +from symfexit.worker.registry import add_task class ConfigAdmin(ConstanceAdmin): @@ -35,8 +34,9 @@ def get_urls(self) -> list[URLPattern]: def rebuild(self, request): return TemplateResponse(request, "admin/rebuild_theme.html", {}) -if settings.THEMING_ENABLED: - admin.site.register([TailwindKey], TailwindAdmin) + +admin.site.register([TailwindKey], TailwindAdmin) + class RebuildTheme(TemplateView): template_name = "admin/rebuild_theme/index.html" diff --git a/src/theme/apps.py b/symfexit/theme/apps.py similarity index 68% rename from src/theme/apps.py rename to symfexit/theme/apps.py index 42af17d..0fbc9e8 100644 --- a/src/theme/apps.py +++ b/symfexit/theme/apps.py @@ -1,22 +1,19 @@ from django.apps import AppConfig from django.conf import settings - from django.utils.translation import gettext_lazy as _ class ThemeConfig(AppConfig): - name = "theme" + name = "symfexit.theme" verbose_name = _("Theme") def get_app_admin_urls(self, admin_site): from django.urls import path - from theme.admin import RebuildTheme + from symfexit.theme.admin import RebuildTheme if not settings.THEMING_ENABLED: return [] rebuild_theme = RebuildTheme.as_view(admin_site=admin_site) - return [ - path("rebuild/", admin_site.admin_view(rebuild_theme), name="rebuild_theme") - ] + return [path("rebuild/", admin_site.admin_view(rebuild_theme), name="rebuild_theme")] diff --git a/src/theme/context.py b/symfexit/theme/context.py similarity index 75% rename from src/theme/context.py rename to symfexit/theme/context.py index 0ff0e5e..db9486e 100644 --- a/src/theme/context.py +++ b/symfexit/theme/context.py @@ -2,15 +2,16 @@ from django.conf import settings from django.templatetags.static import static -from theme.models import CurrentThemeVersion - from tailwind import get_config -from theme.utils import get_theme_filename +from symfexit.theme.models import CurrentThemeVersion +from symfexit.theme.utils import get_theme_filename + def is_path_absolute(path): return path.startswith("/") or path.startswith("http") + def current_theme(request): try: version = CurrentThemeVersion.objects.latest().version @@ -26,5 +27,6 @@ def current_theme(request): "current_theme_css_file": builtin_css, } return { - "current_theme_css_file": "/" + urllib.parse.urljoin(settings.DYNAMIC_THEME_URL, get_theme_filename(version)), + "current_theme_css_file": "/" + + urllib.parse.urljoin(settings.DYNAMIC_THEME_URL, get_theme_filename(version)), } diff --git a/src/theme/locale/nl/LC_MESSAGES/django.mo b/symfexit/theme/locale/nl/LC_MESSAGES/django.mo similarity index 100% rename from src/theme/locale/nl/LC_MESSAGES/django.mo rename to symfexit/theme/locale/nl/LC_MESSAGES/django.mo diff --git a/src/theme/locale/nl/LC_MESSAGES/django.po b/symfexit/theme/locale/nl/LC_MESSAGES/django.po similarity index 100% rename from src/theme/locale/nl/LC_MESSAGES/django.po rename to symfexit/theme/locale/nl/LC_MESSAGES/django.po diff --git a/src/theme/management/commands/__init__.py b/symfexit/theme/management/__init__.py similarity index 100% rename from src/theme/management/commands/__init__.py rename to symfexit/theme/management/__init__.py diff --git a/src/theme/migrations/__init__.py b/symfexit/theme/management/commands/__init__.py similarity index 100% rename from src/theme/migrations/__init__.py rename to symfexit/theme/management/commands/__init__.py diff --git a/src/theme/management/commands/exporttheme.py b/symfexit/theme/management/commands/exporttheme.py similarity index 91% rename from src/theme/management/commands/exporttheme.py rename to symfexit/theme/management/commands/exporttheme.py index 807fbdf..be0cec3 100644 --- a/src/theme/management/commands/exporttheme.py +++ b/symfexit/theme/management/commands/exporttheme.py @@ -2,7 +2,7 @@ from django.core.management import BaseCommand -from theme.models import TailwindKey +from symfexit.theme.models import TailwindKey class Command(BaseCommand): diff --git a/symfexit/theme/migrations/0001_initial.py b/symfexit/theme/migrations/0001_initial.py new file mode 100644 index 0000000..877c315 --- /dev/null +++ b/symfexit/theme/migrations/0001_initial.py @@ -0,0 +1,54 @@ +# Generated by Django 5.1.1 on 2024-09-28 15:41 + +from datetime import datetime +from django.db import migrations, models + + +def get_time_millis() -> int: + return int(datetime.now().timestamp() * 1000) + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [] + + operations = [ + migrations.CreateModel( + name="CurrentThemeVersion", + fields=[ + ("id", models.AutoField(primary_key=True, serialize=False)), + ( + "version", + models.BigIntegerField( + default=get_time_millis, + unique=True, + verbose_name="version", + ), + ), + ], + options={ + "get_latest_by": "version", + }, + ), + migrations.CreateModel( + name="TailwindKey", + fields=[ + ("id", models.AutoField(primary_key=True, serialize=False)), + ( + "name", + models.CharField( + choices=[ + ("primary", "Primary Color"), + ("secondary", "Secondary Color"), + ], + max_length=20, + unique=True, + verbose_name="name", + ), + ), + ("value", models.TextField(verbose_name="value")), + ], + ), + ] diff --git a/src/theme/templatetags/__init__.py b/symfexit/theme/migrations/__init__.py similarity index 100% rename from src/theme/templatetags/__init__.py rename to symfexit/theme/migrations/__init__.py diff --git a/src/theme/models.py b/symfexit/theme/models.py similarity index 91% rename from src/theme/models.py rename to symfexit/theme/models.py index 4b65171..f046780 100644 --- a/src/theme/models.py +++ b/symfexit/theme/models.py @@ -1,9 +1,8 @@ -from datetime import datetime from django.db import models - from django.utils.translation import gettext_lazy as _ -from theme.utils import get_time_millis +from symfexit.theme.utils import get_time_millis + class TailwindKey(models.Model): COLOR_KEY_CHOICES = [ @@ -17,6 +16,7 @@ class TailwindKey(models.Model): def __str__(self) -> str: return f"{self.name}: {self.value}" + class CurrentThemeVersion(models.Model): id = models.AutoField(primary_key=True) version = models.BigIntegerField(_("version"), unique=True, default=get_time_millis) diff --git a/src/theme/static/img/header-logo.svg b/symfexit/theme/static/img/header-logo.svg similarity index 100% rename from src/theme/static/img/header-logo.svg rename to symfexit/theme/static/img/header-logo.svg diff --git a/src/theme/static_src/.gitignore b/symfexit/theme/static_src/.gitignore similarity index 100% rename from src/theme/static_src/.gitignore rename to symfexit/theme/static_src/.gitignore diff --git a/src/theme/static_src/package-lock.json b/symfexit/theme/static_src/package-lock.json similarity index 100% rename from src/theme/static_src/package-lock.json rename to symfexit/theme/static_src/package-lock.json diff --git a/src/theme/static_src/package.json b/symfexit/theme/static_src/package.json similarity index 100% rename from src/theme/static_src/package.json rename to symfexit/theme/static_src/package.json diff --git a/src/theme/static_src/postcss.config.js b/symfexit/theme/static_src/postcss.config.js similarity index 100% rename from src/theme/static_src/postcss.config.js rename to symfexit/theme/static_src/postcss.config.js diff --git a/src/theme/static_src/src/styles.css b/symfexit/theme/static_src/src/styles.css similarity index 100% rename from src/theme/static_src/src/styles.css rename to symfexit/theme/static_src/src/styles.css diff --git a/src/theme/static_src/tailwind.config.js b/symfexit/theme/static_src/tailwind.config.js similarity index 100% rename from src/theme/static_src/tailwind.config.js rename to symfexit/theme/static_src/tailwind.config.js diff --git a/src/theme/tasks.py b/symfexit/theme/tasks.py similarity index 86% rename from src/theme/tasks.py rename to symfexit/theme/tasks.py index 0555c3f..edc715f 100644 --- a/src/theme/tasks.py +++ b/symfexit/theme/tasks.py @@ -3,16 +3,15 @@ from django.conf import settings -from django.utils import timezone - -from theme.models import CurrentThemeVersion -from theme.utils import get_theme_filename, get_time_millis -from worker import logger -from worker.registry import task_registry +from symfexit.theme.models import CurrentThemeVersion +from symfexit.theme.utils import get_theme_filename, get_time_millis +from symfexit.worker import logger +from symfexit.worker.registry import task_registry NPM_COMMAND = os.getenv("NPM_COMMAND", "npm") THEME_SRC_DIR = os.getenv("THEME_SRC_DIR", str(settings.BASE_DIR / "theme" / "static_src")) + @task_registry.register("rebuild_theme") def rebuild_theme(): logger.log("Rebuilding theme") diff --git a/src/theme/templates/admin/constance_theme/change_list.html b/symfexit/theme/templates/admin/constance_theme/change_list.html similarity index 100% rename from src/theme/templates/admin/constance_theme/change_list.html rename to symfexit/theme/templates/admin/constance_theme/change_list.html diff --git a/src/theme/templates/admin/constance_theme/includes/results_list.html b/symfexit/theme/templates/admin/constance_theme/includes/results_list.html similarity index 100% rename from src/theme/templates/admin/constance_theme/includes/results_list.html rename to symfexit/theme/templates/admin/constance_theme/includes/results_list.html diff --git a/src/theme/templates/admin/rebuild_theme/index.html b/symfexit/theme/templates/admin/rebuild_theme/index.html similarity index 100% rename from src/theme/templates/admin/rebuild_theme/index.html rename to symfexit/theme/templates/admin/rebuild_theme/index.html diff --git a/src/theme/templates/admin/tailwind_keys/change_list.html b/symfexit/theme/templates/admin/tailwind_keys/change_list.html similarity index 100% rename from src/theme/templates/admin/tailwind_keys/change_list.html rename to symfexit/theme/templates/admin/tailwind_keys/change_list.html diff --git a/src/theme/templates/base.html b/symfexit/theme/templates/base.html similarity index 100% rename from src/theme/templates/base.html rename to symfexit/theme/templates/base.html diff --git a/src/theme/templates/page.html b/symfexit/theme/templates/page.html similarity index 100% rename from src/theme/templates/page.html rename to symfexit/theme/templates/page.html diff --git a/src/theme/templates/registration/login.html b/symfexit/theme/templates/registration/login.html similarity index 100% rename from src/theme/templates/registration/login.html rename to symfexit/theme/templates/registration/login.html diff --git a/src/theme/templates/theme/tags/current_theme_css.html b/symfexit/theme/templates/theme/tags/current_theme_css.html similarity index 100% rename from src/theme/templates/theme/tags/current_theme_css.html rename to symfexit/theme/templates/theme/tags/current_theme_css.html diff --git a/src/theme/templates/theme/tags/preload_current_theme_css.html b/symfexit/theme/templates/theme/tags/preload_current_theme_css.html similarity index 100% rename from src/theme/templates/theme/tags/preload_current_theme_css.html rename to symfexit/theme/templates/theme/tags/preload_current_theme_css.html diff --git a/src/worker/management/__init__.py b/symfexit/theme/templatetags/__init__.py similarity index 100% rename from src/worker/management/__init__.py rename to symfexit/theme/templatetags/__init__.py diff --git a/src/theme/templatetags/current_theme.py b/symfexit/theme/templatetags/current_theme.py similarity index 99% rename from src/theme/templatetags/current_theme.py rename to symfexit/theme/templatetags/current_theme.py index d7e404a..efc521e 100644 --- a/src/theme/templatetags/current_theme.py +++ b/symfexit/theme/templatetags/current_theme.py @@ -1,9 +1,11 @@ import time + from django import template from django.conf import settings register = template.Library() + @register.inclusion_tag("theme/tags/current_theme_css.html", takes_context=True) def theme_css_file(context): v = None @@ -15,6 +17,7 @@ def theme_css_file(context): "css_file": context["current_theme_css_file"], } + @register.inclusion_tag("theme/tags/preload_current_theme_css.html", takes_context=True) def preload_css_file(context): return { diff --git a/src/theme/urls.py b/symfexit/theme/urls.py similarity index 72% rename from src/theme/urls.py rename to symfexit/theme/urls.py index a33916b..ab08af6 100644 --- a/src/theme/urls.py +++ b/symfexit/theme/urls.py @@ -1,6 +1,6 @@ from django.urls import path -from theme.views import current_style +from symfexit.theme.views import current_style app_name = "theme" diff --git a/src/theme/utils.py b/symfexit/theme/utils.py similarity index 79% rename from src/theme/utils.py rename to symfexit/theme/utils.py index e8739ca..0fcddeb 100644 --- a/src/theme/utils.py +++ b/symfexit/theme/utils.py @@ -1,13 +1,13 @@ from datetime import datetime -from typing import Optional from django.conf import settings + def get_time_millis() -> int: return int(datetime.now().timestamp() * 1000) -def get_theme_filename(version: Optional[int]): +def get_theme_filename(version: int | None): if not version: return "styles.css" if settings.DJANGO_ENV == "development": diff --git a/src/theme/views.py b/symfexit/theme/views.py similarity index 100% rename from src/theme/views.py rename to symfexit/theme/views.py diff --git a/src/worker/__init__.py b/symfexit/worker/__init__.py similarity index 63% rename from src/worker/__init__.py rename to symfexit/worker/__init__.py index 1135a2f..3436edc 100644 --- a/src/worker/__init__.py +++ b/symfexit/worker/__init__.py @@ -1,7 +1,7 @@ from django.utils.module_loading import autodiscover_modules -from worker.logger import Logger -from worker.registry import task_registry +from symfexit.worker.logger import Logger +from symfexit.worker.registry import task_registry def autodiscover(): diff --git a/src/worker/admin.py b/symfexit/worker/admin.py similarity index 76% rename from src/worker/admin.py rename to symfexit/worker/admin.py index ab22225..7d20af3 100644 --- a/src/worker/admin.py +++ b/symfexit/worker/admin.py @@ -1,6 +1,6 @@ from django.contrib import admin -from worker.models import Task +from symfexit.worker.models import Task # Register your models here. diff --git a/src/worker/apps.py b/symfexit/worker/apps.py similarity index 90% rename from src/worker/apps.py rename to symfexit/worker/apps.py index 603ad26..eeef66d 100644 --- a/src/worker/apps.py +++ b/symfexit/worker/apps.py @@ -1,10 +1,10 @@ from django.apps import AppConfig - from django.utils.translation import gettext_lazy as _ + class WorkerConfig(AppConfig): default_auto_field = "django.db.models.BigAutoField" - name = "worker" + name = "symfexit.worker" verbose_name = _("Worker") def ready(self): diff --git a/src/worker/locale/nl/LC_MESSAGES/django.mo b/symfexit/worker/locale/nl/LC_MESSAGES/django.mo similarity index 100% rename from src/worker/locale/nl/LC_MESSAGES/django.mo rename to symfexit/worker/locale/nl/LC_MESSAGES/django.mo diff --git a/src/worker/locale/nl/LC_MESSAGES/django.po b/symfexit/worker/locale/nl/LC_MESSAGES/django.po similarity index 100% rename from src/worker/locale/nl/LC_MESSAGES/django.po rename to symfexit/worker/locale/nl/LC_MESSAGES/django.po diff --git a/src/worker/logger.py b/symfexit/worker/logger.py similarity index 100% rename from src/worker/logger.py rename to symfexit/worker/logger.py diff --git a/src/worker/management/commands/__init__.py b/symfexit/worker/management/__init__.py similarity index 100% rename from src/worker/management/commands/__init__.py rename to symfexit/worker/management/__init__.py diff --git a/src/worker/migrations/__init__.py b/symfexit/worker/management/commands/__init__.py similarity index 100% rename from src/worker/migrations/__init__.py rename to symfexit/worker/management/commands/__init__.py diff --git a/src/worker/management/commands/startworker.py b/symfexit/worker/management/commands/startworker.py similarity index 94% rename from src/worker/management/commands/startworker.py rename to symfexit/worker/management/commands/startworker.py index f63e8f4..f716111 100644 --- a/src/worker/management/commands/startworker.py +++ b/symfexit/worker/management/commands/startworker.py @@ -6,9 +6,9 @@ from django.db import transaction from django.utils import timezone -from worker import logger -from worker.models import Task -from worker.registry import task_registry +from symfexit.worker import logger +from symfexit.worker.models import Task +from symfexit.worker.registry import task_registry class Command(BaseCommand): @@ -18,7 +18,6 @@ def add_arguments(self, parser: CommandParser) -> None: parser.add_argument("--batch_size", type=int, default=10) def handle(self, *args, **options): - self.stdout.write("Starting worker") last_sleep = 0 while True: diff --git a/symfexit/worker/migrations/0001_initial.py b/symfexit/worker/migrations/0001_initial.py new file mode 100644 index 0000000..6deb5d2 --- /dev/null +++ b/symfexit/worker/migrations/0001_initial.py @@ -0,0 +1,66 @@ +# Generated by Django 5.1.1 on 2024-09-28 15:41 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [] + + operations = [ + migrations.CreateModel( + name="Task", + fields=[ + ( + "id", + models.AutoField(primary_key=True, serialize=False, verbose_name="identifier"), + ), + ("name", models.CharField(max_length=20, verbose_name="name")), + ( + "args", + models.BinaryField(blank=True, null=True, verbose_name="arguments"), + ), + ( + "kwargs", + models.BinaryField(blank=True, null=True, verbose_name="keyword arguments"), + ), + ( + "output", + models.TextField(blank=True, null=True, verbose_name="output"), + ), + ( + "status", + models.CharField( + choices=[ + ("queued", "Queued"), + ("completed", "Completed"), + ("not_registered", "Unknown task (not registered)"), + ("exception", "Exception"), + ], + default="queued", + max_length=20, + verbose_name="status", + ), + ), + ( + "created_at", + models.DateTimeField(auto_now_add=True, verbose_name="created at"), + ), + ( + "picked_up_at", + models.DateTimeField(blank=True, null=True, verbose_name="picked up at"), + ), + ( + "completed_at", + models.DateTimeField(blank=True, null=True, verbose_name="completed at"), + ), + ], + options={ + "verbose_name": "task", + "verbose_name_plural": "tasks", + "ordering": ["-created_at"], + }, + ), + ] diff --git a/symfexit/worker/migrations/__init__.py b/symfexit/worker/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/worker/models.py b/symfexit/worker/models.py similarity index 90% rename from src/worker/models.py rename to symfexit/worker/models.py index 647621a..2e73bd3 100644 --- a/src/worker/models.py +++ b/symfexit/worker/models.py @@ -25,7 +25,9 @@ class Status(models.TextChoices): completed_at = models.DateTimeField(_("completed at"), null=True, blank=True) def __str__(self) -> str: - return f"{self.name}: {self.created_at} {_('(done)') if self.completed_at is not None else ''}" + return ( + f"{self.name}: {self.created_at} {_('(done)') if self.completed_at is not None else ''}" + ) class Meta: verbose_name = _("task") diff --git a/src/worker/registry.py b/symfexit/worker/registry.py similarity index 85% rename from src/worker/registry.py rename to symfexit/worker/registry.py index 499f016..669217b 100644 --- a/src/worker/registry.py +++ b/symfexit/worker/registry.py @@ -27,7 +27,5 @@ def __contains__(self, key): def add_task(name, *args, **kwargs): from worker.models import Task - task = Task.objects.create( - name=name, args=pickle.dumps(args), kwargs=pickle.dumps(kwargs) - ) + task = Task.objects.create(name=name, args=pickle.dumps(args), kwargs=pickle.dumps(kwargs)) return task diff --git a/symfexit/worker/tests.py b/symfexit/worker/tests.py new file mode 100644 index 0000000..a39b155 --- /dev/null +++ b/symfexit/worker/tests.py @@ -0,0 +1 @@ +# Create your tests here. diff --git a/symfexit/worker/views.py b/symfexit/worker/views.py new file mode 100644 index 0000000..60f00ef --- /dev/null +++ b/symfexit/worker/views.py @@ -0,0 +1 @@ +# Create your views here.