django-spire 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- django_spire-0.0.1/LICENSE.md +22 -0
- django_spire-0.0.1/PKG-INFO +39 -0
- django_spire-0.0.1/README.rst +62 -0
- django_spire-0.0.1/django_spire/__init__.py +0 -0
- django_spire-0.0.1/django_spire/ai/__init__.py +0 -0
- django_spire-0.0.1/django_spire/ai/apps.py +7 -0
- django_spire-0.0.1/django_spire/ai/migrations/__init__.py +0 -0
- django_spire-0.0.1/django_spire/ai/tests/__init__.py +0 -0
- django_spire-0.0.1/django_spire/ai/urls.py +14 -0
- django_spire-0.0.1/django_spire/ai/views.py +48 -0
- django_spire-0.0.1/django_spire/authentication/__init__.py +0 -0
- django_spire-0.0.1/django_spire/authentication/apps.py +7 -0
- django_spire-0.0.1/django_spire/authentication/mfa/__init__.py +0 -0
- django_spire-0.0.1/django_spire/authentication/mfa/admin.py +21 -0
- django_spire-0.0.1/django_spire/authentication/mfa/apps.py +7 -0
- django_spire-0.0.1/django_spire/authentication/mfa/forms.py +31 -0
- django_spire-0.0.1/django_spire/authentication/mfa/migrations/0001_initial.py +29 -0
- django_spire-0.0.1/django_spire/authentication/mfa/migrations/__init__.py +0 -0
- django_spire-0.0.1/django_spire/authentication/mfa/models.py +61 -0
- django_spire-0.0.1/django_spire/authentication/mfa/querysets.py +9 -0
- django_spire-0.0.1/django_spire/authentication/mfa/tests/__init__.py +0 -0
- django_spire-0.0.1/django_spire/authentication/mfa/urls/__init__.py +9 -0
- django_spire-0.0.1/django_spire/authentication/mfa/urls/page_urls.py +12 -0
- django_spire-0.0.1/django_spire/authentication/mfa/urls/redirect_urls.py +12 -0
- django_spire-0.0.1/django_spire/authentication/mfa/utils.py +17 -0
- django_spire-0.0.1/django_spire/authentication/mfa/views/__init__.py +0 -0
- django_spire-0.0.1/django_spire/authentication/mfa/views/page_views.py +36 -0
- django_spire-0.0.1/django_spire/authentication/mfa/views/redirect_views.py +20 -0
- django_spire-0.0.1/django_spire/authentication/migrations/__init__.py +0 -0
- django_spire-0.0.1/django_spire/authentication/templates/spire/authentication/mfa/mfa_form.html +25 -0
- django_spire-0.0.1/django_spire/authentication/templates/spire/authentication/page/authentication_page.html +26 -0
- django_spire-0.0.1/django_spire/authentication/templates/spire/authentication/page/login_page.html +23 -0
- django_spire-0.0.1/django_spire/authentication/templates/spire/authentication/page/logout_page.html +23 -0
- django_spire-0.0.1/django_spire/authentication/templates/spire/authentication/page/password_change_done_page.html +12 -0
- django_spire-0.0.1/django_spire/authentication/templates/spire/authentication/page/password_change_page.html +14 -0
- django_spire-0.0.1/django_spire/authentication/templates/spire/authentication/page/password_reset_complete_page.html +10 -0
- django_spire-0.0.1/django_spire/authentication/templates/spire/authentication/page/password_reset_confirmation_page.html +16 -0
- django_spire-0.0.1/django_spire/authentication/templates/spire/authentication/page/password_reset_done_page.html +10 -0
- django_spire-0.0.1/django_spire/authentication/templates/spire/authentication/page/password_reset_key_done_page.html +13 -0
- django_spire-0.0.1/django_spire/authentication/templates/spire/authentication/page/password_reset_key_form_page.html +24 -0
- django_spire-0.0.1/django_spire/authentication/templates/spire/authentication/page/password_reset_page.html +16 -0
- django_spire-0.0.1/django_spire/authentication/templates/spire/authentication/page/password_set_form_page.html +12 -0
- django_spire-0.0.1/django_spire/authentication/templates/spire/authentication/password_reset_email.html +14 -0
- django_spire-0.0.1/django_spire/authentication/tests/__init__.py +0 -0
- django_spire-0.0.1/django_spire/authentication/tests/test_url_endpoints.py +29 -0
- django_spire-0.0.1/django_spire/authentication/urls/__init__.py +10 -0
- django_spire-0.0.1/django_spire/authentication/urls/admin_urls.py +52 -0
- django_spire-0.0.1/django_spire/authentication/urls/redirect_urls.py +16 -0
- django_spire-0.0.1/django_spire/authentication/views/__init__.py +0 -0
- django_spire-0.0.1/django_spire/authentication/views/admin_views.py +48 -0
- django_spire-0.0.1/django_spire/authentication/views/redirect_views.py +26 -0
- django_spire-0.0.1/django_spire/breadcrumb/__init__.py +0 -0
- django_spire-0.0.1/django_spire/breadcrumb/apps.py +7 -0
- django_spire-0.0.1/django_spire/breadcrumb/models.py +76 -0
- django_spire-0.0.1/django_spire/breadcrumb/tests/__init__.py +0 -0
- django_spire-0.0.1/django_spire/comment/__init__.py +0 -0
- django_spire-0.0.1/django_spire/comment/admin.py +43 -0
- django_spire-0.0.1/django_spire/comment/apps.py +7 -0
- django_spire-0.0.1/django_spire/comment/factories.py +11 -0
- django_spire-0.0.1/django_spire/comment/forms.py +20 -0
- django_spire-0.0.1/django_spire/comment/migrations/0001_initial.py +40 -0
- django_spire-0.0.1/django_spire/comment/migrations/__init__.py +0 -0
- django_spire-0.0.1/django_spire/comment/mixins.py +37 -0
- django_spire-0.0.1/django_spire/comment/models.py +78 -0
- django_spire-0.0.1/django_spire/comment/querysets.py +20 -0
- django_spire-0.0.1/django_spire/comment/templates/spire/comment/card/comment_list_card.html +30 -0
- django_spire-0.0.1/django_spire/comment/templates/spire/comment/card/comment_textarea_card.html +7 -0
- django_spire-0.0.1/django_spire/comment/templates/spire/comment/container/comment_container.html +21 -0
- django_spire-0.0.1/django_spire/comment/templates/spire/comment/container/comment_reply_list_container.html +7 -0
- django_spire-0.0.1/django_spire/comment/templates/spire/comment/element/comment_button_element.html +165 -0
- django_spire-0.0.1/django_spire/comment/templates/spire/comment/element/comment_edit_link.html +5 -0
- django_spire-0.0.1/django_spire/comment/templates/spire/comment/element/comment_reply_element.html +8 -0
- django_spire-0.0.1/django_spire/comment/templates/spire/comment/element/comment_reply_link.html +5 -0
- django_spire-0.0.1/django_spire/comment/templates/spire/comment/element/comment_textarea_element.html +120 -0
- django_spire-0.0.1/django_spire/comment/templates/spire/comment/form/comment_form.html +18 -0
- django_spire-0.0.1/django_spire/comment/templates/spire/comment/form/content/comment_form_content.html +13 -0
- django_spire-0.0.1/django_spire/comment/templates/spire/comment/item/comment_item.html +42 -0
- django_spire-0.0.1/django_spire/comment/templates/spire/comment/item/comment_item_ellipsis.html +22 -0
- django_spire-0.0.1/django_spire/comment/templates/spire/comment/item/comment_reply_item.html +30 -0
- django_spire-0.0.1/django_spire/comment/templates/spire/comment/modal/comment_edit_modal.html +17 -0
- django_spire-0.0.1/django_spire/comment/templates/spire/comment/modal/comment_modal.html +17 -0
- django_spire-0.0.1/django_spire/comment/templates/spire/comment/modal/comment_reply_modal.html +23 -0
- django_spire-0.0.1/django_spire/comment/templates/spire/comment/widget/tagging_widget.html +130 -0
- django_spire-0.0.1/django_spire/comment/templatetags/__init__.py +0 -0
- django_spire-0.0.1/django_spire/comment/templatetags/comment_tags.py +29 -0
- django_spire-0.0.1/django_spire/comment/tests/__init__.py +0 -0
- django_spire-0.0.1/django_spire/comment/urls.py +20 -0
- django_spire-0.0.1/django_spire/comment/utils.py +45 -0
- django_spire-0.0.1/django_spire/comment/views.py +136 -0
- django_spire-0.0.1/django_spire/comment/widgets.py +28 -0
- django_spire-0.0.1/django_spire/consts.py +1 -0
- django_spire-0.0.1/django_spire/core/__init__.py +0 -0
- django_spire-0.0.1/django_spire/core/apps.py +7 -0
- django_spire-0.0.1/django_spire/core/context_processors.py +12 -0
- django_spire-0.0.1/django_spire/core/management/__init__.py +0 -0
- django_spire-0.0.1/django_spire/core/management/commands/__init__.py +0 -0
- django_spire-0.0.1/django_spire/core/management/commands/spire_bootstrap.py +93 -0
- django_spire-0.0.1/django_spire/core/management/commands/spire_remove_migration.py +62 -0
- django_spire-0.0.1/django_spire/core/redirect/__init__.py +1 -0
- django_spire-0.0.1/django_spire/core/redirect/generic_redirect.py +37 -0
- django_spire-0.0.1/django_spire/core/redirect/safe_redirect.py +70 -0
- django_spire-0.0.1/django_spire/core/shortcuts.py +47 -0
- django_spire-0.0.1/django_spire/core/static/spire/css/app-background.css +108 -0
- django_spire-0.0.1/django_spire/core/static/spire/css/app-border.css +105 -0
- django_spire-0.0.1/django_spire/core/static/spire/css/app-button.css +143 -0
- django_spire-0.0.1/django_spire/core/static/spire/css/app-text.css +101 -0
- django_spire-0.0.1/django_spire/core/static/spire/css/app.css +44 -0
- django_spire-0.0.1/django_spire/core/static/spire/css/base.css +53 -0
- django_spire-0.0.1/django_spire/core/static/spire/css/bootstrap-extension.css +640 -0
- django_spire-0.0.1/django_spire/core/static/spire/css/bootstrap-override.css +0 -0
- django_spire-0.0.1/django_spire/core/static/spire/css/bootstrap.css +7 -0
- django_spire-0.0.1/django_spire/core/static/spire/css/flatpickr.min.css +13 -0
- django_spire-0.0.1/django_spire/core/static/spire/favicons/android-chrome-192x192.png +0 -0
- django_spire-0.0.1/django_spire/core/static/spire/favicons/android-chrome-256x256.png +0 -0
- django_spire-0.0.1/django_spire/core/static/spire/favicons/apple-touch-icon.png +0 -0
- django_spire-0.0.1/django_spire/core/static/spire/favicons/favicon-16x16.png +0 -0
- django_spire-0.0.1/django_spire/core/static/spire/favicons/favicon-32x32.png +0 -0
- django_spire-0.0.1/django_spire/core/static/spire/favicons/mstile-150x150.png +0 -0
- django_spire-0.0.1/django_spire/core/static/spire/js/Chart.min.js +13 -0
- django_spire-0.0.1/django_spire/core/static/spire/js/ajax.js +25 -0
- django_spire-0.0.1/django_spire/core/static/spire/js/alpine-plugins.min.js +9 -0
- django_spire-0.0.1/django_spire/core/static/spire/js/alpine.min.js +5 -0
- django_spire-0.0.1/django_spire/core/static/spire/js/axios.min.js +3 -0
- django_spire-0.0.1/django_spire/core/static/spire/js/base.js +86 -0
- django_spire-0.0.1/django_spire/core/static/spire/js/bootstrap.bundle.min.js +7 -0
- django_spire-0.0.1/django_spire/core/static/spire/js/csrf.js +18 -0
- django_spire-0.0.1/django_spire/core/static/spire/js/dispatch_modal.js +5 -0
- django_spire-0.0.1/django_spire/core/static/spire/js/flatpickr.js +2 -0
- django_spire-0.0.1/django_spire/core/static/spire/js/spire_alpine.js +33 -0
- django_spire-0.0.1/django_spire/core/templates/spire/403.html +36 -0
- django_spire-0.0.1/django_spire/core/templates/spire/404.html +34 -0
- django_spire-0.0.1/django_spire/core/templates/spire/500.html +7 -0
- django_spire-0.0.1/django_spire/core/templates/spire/accordion/accordion.html +23 -0
- django_spire-0.0.1/django_spire/core/templates/spire/badge/accent_badge.html +3 -0
- django_spire-0.0.1/django_spire/core/templates/spire/badge/base_badge.html +8 -0
- django_spire-0.0.1/django_spire/core/templates/spire/badge/danger_badge.html +3 -0
- django_spire-0.0.1/django_spire/core/templates/spire/badge/primary_badge.html +3 -0
- django_spire-0.0.1/django_spire/core/templates/spire/badge/primary_outlined_badge.html +3 -0
- django_spire-0.0.1/django_spire/core/templates/spire/badge/secondary_badge.html +3 -0
- django_spire-0.0.1/django_spire/core/templates/spire/badge/secondary_outlined_badge.html +3 -0
- django_spire-0.0.1/django_spire/core/templates/spire/badge/success_badge.html +3 -0
- django_spire-0.0.1/django_spire/core/templates/spire/badge/warning_badge.html +3 -0
- django_spire-0.0.1/django_spire/core/templates/spire/base/base.html +91 -0
- django_spire-0.0.1/django_spire/core/templates/spire/button/accent_button.html +3 -0
- django_spire-0.0.1/django_spire/core/templates/spire/button/accent_dark_button.html +3 -0
- django_spire-0.0.1/django_spire/core/templates/spire/button/accent_outlined_button.html +3 -0
- django_spire-0.0.1/django_spire/core/templates/spire/button/base_button.html +16 -0
- django_spire-0.0.1/django_spire/core/templates/spire/button/danger_button.html +3 -0
- django_spire-0.0.1/django_spire/core/templates/spire/button/danger_dark_button.html +3 -0
- django_spire-0.0.1/django_spire/core/templates/spire/button/danger_outlined_button.html +3 -0
- django_spire-0.0.1/django_spire/core/templates/spire/button/primary_button.html +3 -0
- django_spire-0.0.1/django_spire/core/templates/spire/button/primary_dark_button.html +3 -0
- django_spire-0.0.1/django_spire/core/templates/spire/button/primary_outlined_button.html +3 -0
- django_spire-0.0.1/django_spire/core/templates/spire/button/secondary_button.html +3 -0
- django_spire-0.0.1/django_spire/core/templates/spire/button/secondary_dark_button.html +3 -0
- django_spire-0.0.1/django_spire/core/templates/spire/button/secondary_outlined_button.html +3 -0
- django_spire-0.0.1/django_spire/core/templates/spire/button/success_button.html +3 -0
- django_spire-0.0.1/django_spire/core/templates/spire/button/success_dark_button.html +3 -0
- django_spire-0.0.1/django_spire/core/templates/spire/button/success_outlined_button.html +3 -0
- django_spire-0.0.1/django_spire/core/templates/spire/button/warning_button.html +3 -0
- django_spire-0.0.1/django_spire/core/templates/spire/button/warning_dark_button.html +3 -0
- django_spire-0.0.1/django_spire/core/templates/spire/button/warning_outlined_button.html +3 -0
- django_spire-0.0.1/django_spire/core/templates/spire/card/card.html +7 -0
- django_spire-0.0.1/django_spire/core/templates/spire/card/form_card.html +21 -0
- django_spire-0.0.1/django_spire/core/templates/spire/card/title_card.html +31 -0
- django_spire-0.0.1/django_spire/core/templates/spire/container/container.html +27 -0
- django_spire-0.0.1/django_spire/core/templates/spire/container/form_container.html +15 -0
- django_spire-0.0.1/django_spire/core/templates/spire/dropdown/dropdown.html +14 -0
- django_spire-0.0.1/django_spire/core/templates/spire/dropdown/element/dropdown_link_element.html +15 -0
- django_spire-0.0.1/django_spire/core/templates/spire/dropdown/element/ellipsis_dropdown_modal_link_element.html +8 -0
- django_spire-0.0.1/django_spire/core/templates/spire/dropdown/ellipsis_dropdown.html +25 -0
- django_spire-0.0.1/django_spire/core/templates/spire/dropdown/ellipsis_modal_dropdown.html +25 -0
- django_spire-0.0.1/django_spire/core/templates/spire/element/attribute_element.html +34 -0
- django_spire-0.0.1/django_spire/core/templates/spire/element/breadcrumb_element.html +19 -0
- django_spire-0.0.1/django_spire/core/templates/spire/element/divider_element.html +11 -0
- django_spire-0.0.1/django_spire/core/templates/spire/element/no_data_element.html +3 -0
- django_spire-0.0.1/django_spire/core/templates/spire/element/page_loading_element.html +10 -0
- django_spire-0.0.1/django_spire/core/templates/spire/element/pagination_element.html +45 -0
- django_spire-0.0.1/django_spire/core/templates/spire/item/element/item_ellipsis_spacer_element.html +1 -0
- django_spire-0.0.1/django_spire/core/templates/spire/item/item.html +29 -0
- django_spire-0.0.1/django_spire/core/templates/spire/item/no_data_item.html +11 -0
- django_spire-0.0.1/django_spire/core/templates/spire/modal/center_modal.html +17 -0
- django_spire-0.0.1/django_spire/core/templates/spire/modal/content/modal_title_content.html +26 -0
- django_spire-0.0.1/django_spire/core/templates/spire/modal/dispatch_modal.html +8 -0
- django_spire-0.0.1/django_spire/core/templates/spire/modal/element/model_close_element.html +1 -0
- django_spire-0.0.1/django_spire/core/templates/spire/modal/modal.html +67 -0
- django_spire-0.0.1/django_spire/core/templates/spire/modal/title_modal.html +22 -0
- django_spire-0.0.1/django_spire/core/templates/spire/navigation/accordion/cookbook_accordion.html +20 -0
- django_spire-0.0.1/django_spire/core/templates/spire/navigation/accordion/dashboard_nav_accordion.html +12 -0
- django_spire-0.0.1/django_spire/core/templates/spire/navigation/accordion/nav_accordion.html +43 -0
- django_spire-0.0.1/django_spire/core/templates/spire/navigation/accordion/settings_nav_accordion.html +19 -0
- django_spire-0.0.1/django_spire/core/templates/spire/navigation/elements/nav_link.html +9 -0
- django_spire-0.0.1/django_spire/core/templates/spire/navigation/elements/nav_title_divider.html +3 -0
- django_spire-0.0.1/django_spire/core/templates/spire/navigation/elements/search_bar_element.html +15 -0
- django_spire-0.0.1/django_spire/core/templates/spire/navigation/mobile_navigation.html +34 -0
- django_spire-0.0.1/django_spire/core/templates/spire/navigation/navigation_links.html +19 -0
- django_spire-0.0.1/django_spire/core/templates/spire/navigation/side_navigation.html +21 -0
- django_spire-0.0.1/django_spire/core/templates/spire/navigation/top_navigation.html +73 -0
- django_spire-0.0.1/django_spire/core/templates/spire/note/info_note.html +3 -0
- django_spire-0.0.1/django_spire/core/templates/spire/note/note.html +14 -0
- django_spire-0.0.1/django_spire/core/templates/spire/page/center_card_page.html +19 -0
- django_spire-0.0.1/django_spire/core/templates/spire/page/form_full_page.html +15 -0
- django_spire-0.0.1/django_spire/core/templates/spire/page/full_page.html +38 -0
- django_spire-0.0.1/django_spire/core/templates/spire/page/page.html +18 -0
- django_spire-0.0.1/django_spire/core/templates/spire/tab/element/tab_section_element.html +8 -0
- django_spire-0.0.1/django_spire/core/templates/spire/tab/element/tab_trigger_element.html +12 -0
- django_spire-0.0.1/django_spire/core/templates/spire/tab/tab.html +67 -0
- django_spire-0.0.1/django_spire/core/templates/spire/wizard/wizard.html +66 -0
- django_spire-0.0.1/django_spire/core/templates/spire/wizard/wizard_page.html +3 -0
- django_spire-0.0.1/django_spire/core/templatetags/__init__.py +0 -0
- django_spire-0.0.1/django_spire/core/templatetags/core_tags.py +67 -0
- django_spire-0.0.1/django_spire/core/tests/__init__.py +0 -0
- django_spire-0.0.1/django_spire/core/tests/test_cases.py +16 -0
- django_spire-0.0.1/django_spire/file/__init__.py +0 -0
- django_spire-0.0.1/django_spire/file/admin.py +33 -0
- django_spire-0.0.1/django_spire/file/apps.py +7 -0
- django_spire-0.0.1/django_spire/file/fields.py +46 -0
- django_spire-0.0.1/django_spire/file/forms.py +25 -0
- django_spire-0.0.1/django_spire/file/interfaces.py +175 -0
- django_spire-0.0.1/django_spire/file/migrations/0001_initial.py +39 -0
- django_spire-0.0.1/django_spire/file/migrations/__init__.py +0 -0
- django_spire-0.0.1/django_spire/file/mixins.py +12 -0
- django_spire-0.0.1/django_spire/file/models.py +48 -0
- django_spire-0.0.1/django_spire/file/queryset.py +11 -0
- django_spire-0.0.1/django_spire/file/templates/spire/file/card/demo_detail_card.html +9 -0
- django_spire-0.0.1/django_spire/file/templates/spire/file/card/demo_file_list_card.html +20 -0
- django_spire-0.0.1/django_spire/file/templates/spire/file/card/demo_filler_card.html +9 -0
- django_spire-0.0.1/django_spire/file/templates/spire/file/card/demo_list_card.html +20 -0
- django_spire-0.0.1/django_spire/file/templates/spire/file/item/demo_item.html +16 -0
- django_spire-0.0.1/django_spire/file/templates/spire/file/item/file_item.html +22 -0
- django_spire-0.0.1/django_spire/file/templates/spire/file/navigation/file_navigation.html +2 -0
- django_spire-0.0.1/django_spire/file/templates/spire/file/page/demo_detail_page.html +19 -0
- django_spire-0.0.1/django_spire/file/templates/spire/file/page/demo_list_page.html +9 -0
- django_spire-0.0.1/django_spire/file/templates/spire/file/page/version_list_page.html +9 -0
- django_spire-0.0.1/django_spire/file/templates/spire/file/widget/multiple_file_widget.html +1 -0
- django_spire-0.0.1/django_spire/file/templates/spire/file/widget/single_file_widget.html +1 -0
- django_spire-0.0.1/django_spire/file/tests/__init__.py +0 -0
- django_spire-0.0.1/django_spire/file/urls.py +18 -0
- django_spire-0.0.1/django_spire/file/utils.py +8 -0
- django_spire-0.0.1/django_spire/file/views.py +33 -0
- django_spire-0.0.1/django_spire/file/widgets.py +39 -0
- django_spire-0.0.1/django_spire/form/__init__.py +0 -0
- django_spire-0.0.1/django_spire/form/confirmation_forms.py +62 -0
- django_spire-0.0.1/django_spire/form/templates/spire/form/button/form_submit_button.html +46 -0
- django_spire-0.0.1/django_spire/form/utils.py +16 -0
- django_spire-0.0.1/django_spire/gamification/__init__.py +0 -0
- django_spire-0.0.1/django_spire/gamification/static/spire/css/gamification.css +0 -0
- django_spire-0.0.1/django_spire/gamification/templates/spire/gamification/effect/kapow.html +0 -0
- django_spire-0.0.1/django_spire/help/__init__.py +0 -0
- django_spire-0.0.1/django_spire/help/apps.py +7 -0
- django_spire-0.0.1/django_spire/help/templates/spire/help/help_button.html +8 -0
- django_spire-0.0.1/django_spire/help/templates/spire/help/help_modal.html +41 -0
- django_spire-0.0.1/django_spire/help/templatetags/__init__.py +0 -0
- django_spire-0.0.1/django_spire/help/templatetags/help.py +32 -0
- django_spire-0.0.1/django_spire/history/__init__.py +0 -0
- django_spire-0.0.1/django_spire/history/admin.py +96 -0
- django_spire-0.0.1/django_spire/history/apps.py +9 -0
- django_spire-0.0.1/django_spire/history/migrations/0001_initial.py +74 -0
- django_spire-0.0.1/django_spire/history/migrations/__init__.py +0 -0
- django_spire-0.0.1/django_spire/history/mixins.py +121 -0
- django_spire-0.0.1/django_spire/history/models.py +129 -0
- django_spire-0.0.1/django_spire/history/querysets.py +16 -0
- django_spire-0.0.1/django_spire/history/static/spire/js/history.js +0 -0
- django_spire-0.0.1/django_spire/history/templates/spire/history/card/activity_list_card.html +17 -0
- django_spire-0.0.1/django_spire/history/templates/spire/history/item/activity_item.html +15 -0
- django_spire-0.0.1/django_spire/history/tests/__init__.py +0 -0
- django_spire-0.0.1/django_spire/history/utils.py +25 -0
- django_spire-0.0.1/django_spire/home/__init__.py +0 -0
- django_spire-0.0.1/django_spire/home/apps.py +9 -0
- django_spire-0.0.1/django_spire/home/migrations/__init__.py +0 -0
- django_spire-0.0.1/django_spire/home/templates/spire/home/card/home_detail_card.html +49 -0
- django_spire-0.0.1/django_spire/home/templates/spire/home/page/home_page.html +9 -0
- django_spire-0.0.1/django_spire/home/templates/spire/home/page/maintenance_mode_page.html +7 -0
- django_spire-0.0.1/django_spire/home/urls.py +16 -0
- django_spire-0.0.1/django_spire/home/views.py +42 -0
- django_spire-0.0.1/django_spire/maintenance/__init__.py +0 -0
- django_spire-0.0.1/django_spire/maintenance/middleware.py +22 -0
- django_spire-0.0.1/django_spire/modal/__init__.py +0 -0
- django_spire-0.0.1/django_spire/modal/static/spire/js/modal.js +0 -0
- django_spire-0.0.1/django_spire/modal/templates/spire/base/modal.html +43 -0
- django_spire-0.0.1/django_spire/notification/__init__.py +0 -0
- django_spire-0.0.1/django_spire/notification/admin.py +32 -0
- django_spire-0.0.1/django_spire/notification/apps.py +7 -0
- django_spire-0.0.1/django_spire/notification/automations.py +10 -0
- django_spire-0.0.1/django_spire/notification/email.py +50 -0
- django_spire-0.0.1/django_spire/notification/enums.py +24 -0
- django_spire-0.0.1/django_spire/notification/factories.py +19 -0
- django_spire-0.0.1/django_spire/notification/migrations/0001_initial.py +36 -0
- django_spire-0.0.1/django_spire/notification/migrations/__init__.py +0 -0
- django_spire-0.0.1/django_spire/notification/models.py +40 -0
- django_spire-0.0.1/django_spire/notification/sender.py +33 -0
- django_spire-0.0.1/django_spire/notification/templates/spire/notification/element/notification_element.html +48 -0
- django_spire-0.0.1/django_spire/notification/templates/spire/notification/notification.html +28 -0
- django_spire-0.0.1/django_spire/notification/templatetags/__init__.py +0 -0
- django_spire-0.0.1/django_spire/notification/templatetags/notification_tags.py +24 -0
- django_spire-0.0.1/django_spire/options/__init__.py +0 -0
- django_spire-0.0.1/django_spire/options/mixins.py +44 -0
- django_spire-0.0.1/django_spire/options/options.py +116 -0
- django_spire-0.0.1/django_spire/options/tests/__init__.py +0 -0
- django_spire-0.0.1/django_spire/options/tests/factories.py +60 -0
- django_spire-0.0.1/django_spire/options/tests/test_unit.py +152 -0
- django_spire-0.0.1/django_spire/pagination/__init__.py +0 -0
- django_spire-0.0.1/django_spire/pagination/pagination.py +12 -0
- django_spire-0.0.1/django_spire/pagination/templatetags/__init__.py +0 -0
- django_spire-0.0.1/django_spire/pagination/templatetags/pagination_tags.py +44 -0
- django_spire-0.0.1/django_spire/permission/__init__.py +0 -0
- django_spire-0.0.1/django_spire/permission/admin.py +44 -0
- django_spire-0.0.1/django_spire/permission/apps.py +7 -0
- django_spire-0.0.1/django_spire/permission/constants.py +30 -0
- django_spire-0.0.1/django_spire/permission/decorators.py +34 -0
- django_spire-0.0.1/django_spire/permission/factories.py +15 -0
- django_spire-0.0.1/django_spire/permission/forms.py +64 -0
- django_spire-0.0.1/django_spire/permission/migrations/0001_initial.py +48 -0
- django_spire-0.0.1/django_spire/permission/migrations/__init__.py +0 -0
- django_spire-0.0.1/django_spire/permission/models.py +60 -0
- django_spire-0.0.1/django_spire/permission/permissions.py +235 -0
- django_spire-0.0.1/django_spire/permission/querysets.py +8 -0
- django_spire-0.0.1/django_spire/permission/templates/spire/permission/card/group_detail_card.html +25 -0
- django_spire-0.0.1/django_spire/permission/templates/spire/permission/card/group_list_card.html +26 -0
- django_spire-0.0.1/django_spire/permission/templates/spire/permission/card/group_permission_list_card.html +13 -0
- django_spire-0.0.1/django_spire/permission/templates/spire/permission/card/group_user_list_card.html +24 -0
- django_spire-0.0.1/django_spire/permission/templates/spire/permission/card/permission_user_groups_form_card.html +77 -0
- django_spire-0.0.1/django_spire/permission/templates/spire/permission/container/user_detail_card.html +51 -0
- django_spire-0.0.1/django_spire/permission/templates/spire/permission/element/group_perm_element.html +45 -0
- django_spire-0.0.1/django_spire/permission/templates/spire/permission/element/group_perm_level_badge.html +11 -0
- django_spire-0.0.1/django_spire/permission/templates/spire/permission/element/group_special_role_element.html +48 -0
- django_spire-0.0.1/django_spire/permission/templates/spire/permission/element/is_active_badge.html +5 -0
- django_spire-0.0.1/django_spire/permission/templates/spire/permission/form/group_form.html +12 -0
- django_spire-0.0.1/django_spire/permission/templates/spire/permission/item/group_item.html +33 -0
- django_spire-0.0.1/django_spire/permission/templates/spire/permission/item/group_perm_item.html +28 -0
- django_spire-0.0.1/django_spire/permission/templates/spire/permission/item/group_user_item.html +24 -0
- django_spire-0.0.1/django_spire/permission/templates/spire/permission/item/permission_user_group_form_item.html +15 -0
- django_spire-0.0.1/django_spire/permission/templates/spire/permission/page/group_detail_page.html +21 -0
- django_spire-0.0.1/django_spire/permission/templates/spire/permission/page/group_list_page.html +9 -0
- django_spire-0.0.1/django_spire/permission/templatetags/__init__.py +0 -0
- django_spire-0.0.1/django_spire/permission/templatetags/permission_tags.py +11 -0
- django_spire-0.0.1/django_spire/permission/urls.py +44 -0
- django_spire-0.0.1/django_spire/permission/utils.py +83 -0
- django_spire-0.0.1/django_spire/permission/views.py +244 -0
- django_spire-0.0.1/django_spire/search/__init__.py +0 -0
- django_spire-0.0.1/django_spire/search/urls.py +12 -0
- django_spire-0.0.1/django_spire/search/views.py +45 -0
- django_spire-0.0.1/django_spire/template/__init__.py +0 -0
- django_spire-0.0.1/django_spire/template/app/__init__.py +0 -0
- django_spire-0.0.1/django_spire/template/app/apps.py +7 -0
- django_spire-0.0.1/django_spire/template/app/factories.py +1 -0
- django_spire-0.0.1/django_spire/template/app/forms.py +15 -0
- django_spire-0.0.1/django_spire/template/app/migrations/__init__.py +0 -0
- django_spire-0.0.1/django_spire/template/app/models.py +50 -0
- django_spire-0.0.1/django_spire/template/app/querysets.py +13 -0
- django_spire-0.0.1/django_spire/template/app/tests/__init__.py +0 -0
- django_spire-0.0.1/django_spire/template/app/urls.py +13 -0
- django_spire-0.0.1/django_spire/template/app/views.py +91 -0
- django_spire-0.0.1/django_spire/template/templates/card/placeholder_detail_card.html +24 -0
- django_spire-0.0.1/django_spire/template/templates/card/placeholder_form_card.html +9 -0
- django_spire-0.0.1/django_spire/template/templates/card/placeholder_list_card.html +18 -0
- django_spire-0.0.1/django_spire/template/templates/form/placeholder_form.html +21 -0
- django_spire-0.0.1/django_spire/template/templates/item/placeholder_item.html +22 -0
- django_spire-0.0.1/django_spire/template/templates/page/placeholder_detail_page.html +13 -0
- django_spire-0.0.1/django_spire/template/templates/page/placeholder_form_page.html +13 -0
- django_spire-0.0.1/django_spire/template/templates/page/placeholder_list_page.html +9 -0
- django_spire-0.0.1/django_spire/user_account/__init__.py +0 -0
- django_spire-0.0.1/django_spire/user_account/apps.py +7 -0
- django_spire-0.0.1/django_spire/user_account/factories.py +20 -0
- django_spire-0.0.1/django_spire/user_account/forms.py +108 -0
- django_spire-0.0.1/django_spire/user_account/migrations/__init__.py +0 -0
- django_spire-0.0.1/django_spire/user_account/seed.py +4 -0
- django_spire-0.0.1/django_spire/user_account/templates/spire/user_account/card/register_user_detail_form_card.html +55 -0
- django_spire-0.0.1/django_spire/user_account/templates/spire/user_account/card/user_detail_card.html +9 -0
- django_spire-0.0.1/django_spire/user_account/templates/spire/user_account/card/user_detail_title_card.html +38 -0
- django_spire-0.0.1/django_spire/user_account/templates/spire/user_account/card/user_form_card.html +47 -0
- django_spire-0.0.1/django_spire/user_account/templates/spire/user_account/card/user_group_list_card.html +25 -0
- django_spire-0.0.1/django_spire/user_account/templates/spire/user_account/card/user_list_card.html +28 -0
- django_spire-0.0.1/django_spire/user_account/templates/spire/user_account/card/user_profile_list_card.html +20 -0
- django_spire-0.0.1/django_spire/user_account/templates/spire/user_account/container/user_detail_container.html +16 -0
- django_spire-0.0.1/django_spire/user_account/templates/spire/user_account/container/user_list_container.html +12 -0
- django_spire-0.0.1/django_spire/user_account/templates/spire/user_account/element/is_active_badge.html +5 -0
- django_spire-0.0.1/django_spire/user_account/templates/spire/user_account/item/user_item.html +25 -0
- django_spire-0.0.1/django_spire/user_account/templates/spire/user_account/item/user_master_perm_item.html +18 -0
- django_spire-0.0.1/django_spire/user_account/templates/spire/user_account/item/user_profile_item.html +17 -0
- django_spire-0.0.1/django_spire/user_account/templates/spire/user_account/page/register_user_form_page.html +15 -0
- django_spire-0.0.1/django_spire/user_account/templates/spire/user_account/page/user_detail_page.html +17 -0
- django_spire-0.0.1/django_spire/user_account/templates/spire/user_account/page/user_form_page.html +9 -0
- django_spire-0.0.1/django_spire/user_account/templates/spire/user_account/page/user_list_page.html +9 -0
- django_spire-0.0.1/django_spire/user_account/tests/__init__.py +0 -0
- django_spire-0.0.1/django_spire/user_account/tests/factories.py +20 -0
- django_spire-0.0.1/django_spire/user_account/tests/test_factories.py +7 -0
- django_spire-0.0.1/django_spire/user_account/tests/test_unit.py +9 -0
- django_spire-0.0.1/django_spire/user_account/urls.py +27 -0
- django_spire-0.0.1/django_spire/user_account/views.py +174 -0
- django_spire-0.0.1/django_spire/views/__init__.py +0 -0
- django_spire-0.0.1/django_spire/views/modal_views.py +66 -0
- django_spire-0.0.1/django_spire/views/portal_views.py +246 -0
- django_spire-0.0.1/django_spire.egg-info/PKG-INFO +39 -0
- django_spire-0.0.1/django_spire.egg-info/SOURCES.txt +403 -0
- django_spire-0.0.1/django_spire.egg-info/dependency_links.txt +1 -0
- django_spire-0.0.1/django_spire.egg-info/not-zip-safe +1 -0
- django_spire-0.0.1/django_spire.egg-info/requires.txt +3 -0
- django_spire-0.0.1/django_spire.egg-info/top_level.txt +2 -0
- django_spire-0.0.1/pyproject.toml +55 -0
- django_spire-0.0.1/setup.cfg +4 -0
- django_spire-0.0.1/setup.py +75 -0
- django_spire-0.0.1/testing/__init__.py +0 -0
- django_spire-0.0.1/testing/manage.py +30 -0
- django_spire-0.0.1/testing/settings.py +81 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2024 Stratus Advanced Technologies and Contributors.
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person
|
|
4
|
+
obtaining a copy of this software and associated documentation
|
|
5
|
+
files (the "Software"), to deal in the Software without
|
|
6
|
+
restriction, including without limitation the rights to use,
|
|
7
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
copies of the Software, and to permit persons to whom the
|
|
9
|
+
Software is furnished to do so, subject to the following
|
|
10
|
+
conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be
|
|
13
|
+
included in all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
17
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
19
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
20
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
21
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: django-spire
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: A project for Django Spire
|
|
5
|
+
Home-page: https://github.com/stratusadv/django-spire
|
|
6
|
+
Author: Austin Sauer, Brayden Carlson, Nathan Johnson & Wesley Howery
|
|
7
|
+
Author-email: Brayden Carlson <braydenc@stratusadv.com>, Nathan Johnson <nathanj@stratusadv.com>
|
|
8
|
+
License: Copyright (c) 2024 Stratus Advanced Technologies and Contributors.
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person
|
|
11
|
+
obtaining a copy of this software and associated documentation
|
|
12
|
+
files (the "Software"), to deal in the Software without
|
|
13
|
+
restriction, including without limitation the rights to use,
|
|
14
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
15
|
+
copies of the Software, and to permit persons to whom the
|
|
16
|
+
Software is furnished to do so, subject to the following
|
|
17
|
+
conditions:
|
|
18
|
+
|
|
19
|
+
The above copyright notice and this permission notice shall be
|
|
20
|
+
included in all copies or substantial portions of the Software.
|
|
21
|
+
|
|
22
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
23
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
24
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
25
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
26
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
27
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
28
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
29
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
|
30
|
+
|
|
31
|
+
Keywords: portal,cmms
|
|
32
|
+
Classifier: Programming Language :: Python :: 3
|
|
33
|
+
Classifier: Operating System :: OS Independent
|
|
34
|
+
Requires-Python: >=3.10
|
|
35
|
+
Description-Content-Type: text/markdown
|
|
36
|
+
License-File: LICENSE.md
|
|
37
|
+
Requires-Dist: django>=5.1.4
|
|
38
|
+
Requires-Dist: django-glue>=0.7.8
|
|
39
|
+
Requires-Dist: dandy>=0.5.2
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
django-spire
|
|
2
|
+
============
|
|
3
|
+
|
|
4
|
+
.. image:: https://camo.githubusercontent.com/dbdd84d7f7838316851e62ce34b0066e7cc57abc8f348aaadedc3888819992a9/68747470733a2f2f692e696d6775722e636f6d2f4e736958794f582e706e67
|
|
5
|
+
:alt: Django Spire Logo
|
|
6
|
+
:align: center
|
|
7
|
+
|
|
8
|
+
``django_spire`` is a modular framework designed to enhance observability and improve the development of Django web applications.
|
|
9
|
+
|
|
10
|
+
Features
|
|
11
|
+
--------
|
|
12
|
+
|
|
13
|
+
- **Modular Architecture**: Select and install only the modules you need.
|
|
14
|
+
- **Seamless Integration**: Works alongside your existing Django application without intrusive changes.
|
|
15
|
+
- **Customizable & Extensible**: Configure and extend modules to suit specific project requirements.
|
|
16
|
+
|
|
17
|
+
Getting Started
|
|
18
|
+
---------------
|
|
19
|
+
|
|
20
|
+
To install ``django_spire``, run:
|
|
21
|
+
|
|
22
|
+
.. code-block:: bash
|
|
23
|
+
|
|
24
|
+
pip install django_spire
|
|
25
|
+
|
|
26
|
+
Add ``django_spire`` to your Django project’s ``INSTALLED_APPS``:
|
|
27
|
+
|
|
28
|
+
.. code-block:: python
|
|
29
|
+
|
|
30
|
+
INSTALLED_APPS = [
|
|
31
|
+
'django_spire.ai',
|
|
32
|
+
'django_spire.core',
|
|
33
|
+
'django_spire.authentication',
|
|
34
|
+
'django_spire.authentication.mfa',
|
|
35
|
+
'django_spire.breadcrumb',
|
|
36
|
+
'django_spire.comment',
|
|
37
|
+
'django_spire.core',
|
|
38
|
+
'django_spire.file',
|
|
39
|
+
'django_spire.form',
|
|
40
|
+
'django_spire.gamification',
|
|
41
|
+
'django_spire.help',
|
|
42
|
+
'django_spire.history',
|
|
43
|
+
'django_spire.maintenance',
|
|
44
|
+
'django_spire.modal',
|
|
45
|
+
'django_spire.notification',
|
|
46
|
+
'django_spire.options',
|
|
47
|
+
'django_spire.pagination',
|
|
48
|
+
'django_spire.permission',
|
|
49
|
+
'django_spire.search',
|
|
50
|
+
'django_spire.user_account',
|
|
51
|
+
'django_spire.user_account.profile'
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
Documentation
|
|
55
|
+
-------------
|
|
56
|
+
|
|
57
|
+
Please refer to our documentation for detailed setup, module configuration, and usage examples.
|
|
58
|
+
|
|
59
|
+
Contributing
|
|
60
|
+
------------
|
|
61
|
+
|
|
62
|
+
We welcome contributions! See our contributing guide for more details on how to get involved.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import whisper
|
|
4
|
+
|
|
5
|
+
from enum import Enum
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from django.core.files.storage import FileSystemStorage
|
|
9
|
+
from django.http import JsonResponse
|
|
10
|
+
from django.views.decorators.csrf import csrf_protect
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class WhisperModel(Enum):
|
|
14
|
+
TINY = 'tiny'
|
|
15
|
+
BASE = 'base'
|
|
16
|
+
SMALL = 'small'
|
|
17
|
+
MEDIUM = 'medium'
|
|
18
|
+
LARGE = 'large'
|
|
19
|
+
TURBO = 'turbo'
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
model = whisper.load_model(WhisperModel.TINY.value)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@csrf_protect
|
|
26
|
+
def transcribe_audio(request):
|
|
27
|
+
if request.method == 'POST':
|
|
28
|
+
file = request.FILES.get('audio')
|
|
29
|
+
|
|
30
|
+
if not file:
|
|
31
|
+
return JsonResponse({'error': 'No audio file provided'}, status=400)
|
|
32
|
+
|
|
33
|
+
storage = FileSystemStorage()
|
|
34
|
+
location = storage.save(file.name, file)
|
|
35
|
+
path = Path(storage.path(location))
|
|
36
|
+
|
|
37
|
+
try:
|
|
38
|
+
result = model.transcribe(str(path))
|
|
39
|
+
transcription = result['text']
|
|
40
|
+
except Exception as e:
|
|
41
|
+
return JsonResponse({'error': str(e)}, status=500)
|
|
42
|
+
finally:
|
|
43
|
+
if path.exists():
|
|
44
|
+
path.unlink()
|
|
45
|
+
|
|
46
|
+
return JsonResponse({'transcription': transcription}, status=200)
|
|
47
|
+
|
|
48
|
+
return JsonResponse({'error': 'Invalid request method'}, status=405)
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from django.contrib import admin
|
|
2
|
+
from django.urls import reverse
|
|
3
|
+
from django.utils.html import format_html
|
|
4
|
+
|
|
5
|
+
from django_spire.authentication.mfa import models
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@admin.register(models.MfaCode)
|
|
9
|
+
class MfaCodeAdmin(admin.ModelAdmin):
|
|
10
|
+
list_display = (
|
|
11
|
+
'id', 'user_link', 'code', 'expiration_datetime', 'is_valid'
|
|
12
|
+
)
|
|
13
|
+
list_filter = ('expiration_datetime',)
|
|
14
|
+
search_fields = ('id', 'user__username', 'code')
|
|
15
|
+
ordering = ('-expiration_datetime',)
|
|
16
|
+
|
|
17
|
+
def user_link(self, mfa_code: models.MfaCode) -> str:
|
|
18
|
+
url = reverse('admin:auth_user_change', args=[mfa_code.user.id])
|
|
19
|
+
return format_html(f'<a href="{url}">{mfa_code.user.username}</a>')
|
|
20
|
+
|
|
21
|
+
user_link.short_description = 'User'
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from django import forms
|
|
4
|
+
|
|
5
|
+
from crispy_forms.helper import FormHelper
|
|
6
|
+
from crispy_forms.layout import Layout, Row, Column, HTML
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class MFAForm(forms.Form):
|
|
10
|
+
def __init__(self, generated_mfa_code, *args, **kwargs):
|
|
11
|
+
super().__init__(*args, **kwargs)
|
|
12
|
+
|
|
13
|
+
self.helper = FormHelper(self)
|
|
14
|
+
self.helper.include_media = False
|
|
15
|
+
self.generated_mfa_code = generated_mfa_code
|
|
16
|
+
self.fields['mfa_code'] = forms.CharField(max_length=6, label='Authentication Code')
|
|
17
|
+
|
|
18
|
+
self.helper.layout = Layout(
|
|
19
|
+
Row(
|
|
20
|
+
Column('mfa_code', css_class='form-group col-12'),
|
|
21
|
+
),
|
|
22
|
+
HTML("{% include 'spire/form/form_submit_button.html' %}")
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
def clean(self) -> None:
|
|
26
|
+
cleaned_data = super().clean()
|
|
27
|
+
|
|
28
|
+
mfa_code = cleaned_data.get('mfa_code')
|
|
29
|
+
|
|
30
|
+
if mfa_code != self.generated_mfa_code.code:
|
|
31
|
+
self.add_error('mfa_code', 'Invalid MFA Code.')
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Generated by Django 5.1.3 on 2024-11-08 22:57
|
|
2
|
+
|
|
3
|
+
import django.db.models.deletion
|
|
4
|
+
from django.conf import settings
|
|
5
|
+
from django.db import migrations, models
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Migration(migrations.Migration):
|
|
9
|
+
|
|
10
|
+
initial = True
|
|
11
|
+
|
|
12
|
+
dependencies = [
|
|
13
|
+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
operations = [
|
|
17
|
+
migrations.CreateModel(
|
|
18
|
+
name='MfaCode',
|
|
19
|
+
fields=[
|
|
20
|
+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
21
|
+
('code', models.CharField(editable=False, max_length=6, unique=True)),
|
|
22
|
+
('expiration_datetime', models.DateTimeField(editable=False)),
|
|
23
|
+
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='mfa_codes', related_query_name='mfa_code', to=settings.AUTH_USER_MODEL)),
|
|
24
|
+
],
|
|
25
|
+
options={
|
|
26
|
+
'db_table': 'spire_authentication_mfa_code',
|
|
27
|
+
},
|
|
28
|
+
),
|
|
29
|
+
]
|
|
File without changes
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import random
|
|
4
|
+
|
|
5
|
+
from dateutil import relativedelta
|
|
6
|
+
|
|
7
|
+
from django.contrib.auth.models import User
|
|
8
|
+
from django.contrib.sites.models import Site
|
|
9
|
+
from django.db import models
|
|
10
|
+
from django.urls import reverse
|
|
11
|
+
from django.utils.timezone import localtime
|
|
12
|
+
|
|
13
|
+
from django_spire.notification.sender import SendGridEmailHelper
|
|
14
|
+
from django_spire.authentication.mfa.querysets import MfaCodeQuerySet
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class MfaCode(models.Model):
|
|
18
|
+
user = models.ForeignKey(User, on_delete=models.CASCADE, related_query_name='mfa_code', related_name='mfa_codes')
|
|
19
|
+
code = models.CharField(max_length=6, editable=False, unique=True)
|
|
20
|
+
expiration_datetime = models.DateTimeField(editable=False)
|
|
21
|
+
|
|
22
|
+
objects = MfaCodeQuerySet.as_manager()
|
|
23
|
+
|
|
24
|
+
def __str__(self):
|
|
25
|
+
return f'{self.expiration_datetime} - {self.code}'
|
|
26
|
+
|
|
27
|
+
def is_valid(self) -> bool:
|
|
28
|
+
return self.expiration_datetime > localtime()
|
|
29
|
+
|
|
30
|
+
def set_expired(self) -> None:
|
|
31
|
+
self.expiration_datetime = localtime()
|
|
32
|
+
self.save()
|
|
33
|
+
|
|
34
|
+
def send_notification(self):
|
|
35
|
+
user = self.user
|
|
36
|
+
|
|
37
|
+
context_data = {
|
|
38
|
+
'title': 'Authentication Code',
|
|
39
|
+
'body': f"Here is your multifactor authentication code: </br> <h3>{self.code}</h3>",
|
|
40
|
+
'name': user.first_name,
|
|
41
|
+
'button_url': f'{Site.objects.get_current()}/{reverse("authentication:redirect:login_redirect")[1:]}'
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
# Directly connecting to SendGrid to send MFA email faster
|
|
45
|
+
SendGridEmailHelper(
|
|
46
|
+
to=[user.email],
|
|
47
|
+
template_id='d-9ae6be6be95d4f79b0daad9055f03cc9',
|
|
48
|
+
template_data=context_data,
|
|
49
|
+
fail_silently=False
|
|
50
|
+
).send()
|
|
51
|
+
|
|
52
|
+
@classmethod
|
|
53
|
+
def generate_code(cls, user):
|
|
54
|
+
return MfaCode.objects.create(
|
|
55
|
+
user=user,
|
|
56
|
+
code=int(''.join([str(random.randint(0, 9)) for _ in range(6)])),
|
|
57
|
+
expiration_datetime=localtime() + relativedelta.relativedelta(minutes=5)
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
class Meta:
|
|
61
|
+
db_table = 'spire_authentication_mfa_code'
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from django.db.models import QuerySet
|
|
4
|
+
from django.utils.timezone import localtime
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class MfaCodeQuerySet(QuerySet):
|
|
8
|
+
def valid_code(self, user):
|
|
9
|
+
return self.filter(user=user, expiration_datetime__gte=localtime()).first()
|
|
File without changes
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
from django.urls import include, path
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
app_name = '__init__'
|
|
5
|
+
|
|
6
|
+
urlpatterns = [
|
|
7
|
+
path('', include('django_spire.authentication.mfa.urls.page_urls', namespace='page')),
|
|
8
|
+
path('', include('django_spire.authentication.mfa.urls.redirect_urls', namespace='redirect')),
|
|
9
|
+
]
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing_extensions import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from django_spire.authentication.mfa.models import MfaCode
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from django.contrib.auth.models import User
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def get_or_generate_user_mfa_code(user: User) -> MfaCode:
|
|
12
|
+
mfa_code = MfaCode.objects.valid_code(user)
|
|
13
|
+
|
|
14
|
+
if mfa_code:
|
|
15
|
+
return mfa_code
|
|
16
|
+
|
|
17
|
+
return MfaCode.generate_code(user)
|
|
File without changes
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from django.contrib import messages
|
|
4
|
+
from django.http import HttpResponseRedirect
|
|
5
|
+
from django.template.response import TemplateResponse
|
|
6
|
+
from django.urls import reverse
|
|
7
|
+
|
|
8
|
+
from django_spire.authentication.mfa.utils import get_or_generate_user_mfa_code
|
|
9
|
+
from django_spire.authentication.mfa import forms
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def mfa_form_view(request):
|
|
13
|
+
mfa_code = get_or_generate_user_mfa_code(request.user)
|
|
14
|
+
profile = request.user.profile
|
|
15
|
+
|
|
16
|
+
if request.method == 'POST':
|
|
17
|
+
form = forms.MFAForm(mfa_code, request.POST)
|
|
18
|
+
if form.is_valid():
|
|
19
|
+
mfa_code.set_expired()
|
|
20
|
+
profile.set_mfa_grace_period()
|
|
21
|
+
return HttpResponseRedirect(reverse('home:home'))
|
|
22
|
+
|
|
23
|
+
if 'mfa_code' in form.errors:
|
|
24
|
+
messages.error(request, form.errors['mfa_code'][0])
|
|
25
|
+
|
|
26
|
+
context_data = {
|
|
27
|
+
'form': forms.MFAForm(mfa_code, initial=request.POST),
|
|
28
|
+
'form_description': 'An authentication code has been sent to your email. Please enter it below to continue.',
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return TemplateResponse(
|
|
32
|
+
request,
|
|
33
|
+
context=context_data,
|
|
34
|
+
template='spire/authentication/mfa/mfa_form.html'
|
|
35
|
+
)
|
|
36
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from django.contrib import messages
|
|
4
|
+
from django.http import HttpResponseRedirect
|
|
5
|
+
from django.urls import reverse
|
|
6
|
+
|
|
7
|
+
from django_spire.authentication.mfa.utils import get_or_generate_user_mfa_code
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def mfa_notification_redirect_view(request):
|
|
11
|
+
mfa_code = get_or_generate_user_mfa_code(request.user)
|
|
12
|
+
|
|
13
|
+
if request.GET.get('resend', False):
|
|
14
|
+
mfa_code.set_expired()
|
|
15
|
+
mfa_code = get_or_generate_user_mfa_code(request.user)
|
|
16
|
+
|
|
17
|
+
mfa_code.send_notification()
|
|
18
|
+
messages.info(request, 'A authentication code has been sent to your email.')
|
|
19
|
+
|
|
20
|
+
return HttpResponseRedirect(reverse('authentication:mfa:page:form'))
|
|
File without changes
|
django_spire-0.0.1/django_spire/authentication/templates/spire/authentication/mfa/mfa_form.html
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{% extends "spire/page/center_card_page.html" %}
|
|
2
|
+
|
|
3
|
+
{% load crispy_forms_filters %}
|
|
4
|
+
|
|
5
|
+
{% load static %}
|
|
6
|
+
|
|
7
|
+
{% block base_title %}
|
|
8
|
+
Login
|
|
9
|
+
{% endblock %}
|
|
10
|
+
|
|
11
|
+
{% block page_center_card_content %}
|
|
12
|
+
{% include 'spire/notification/notification.html' %}
|
|
13
|
+
|
|
14
|
+
{% if form_description %}
|
|
15
|
+
{% include 'spire/note/info_note.html' with note_type='Note' note_text=form_description %}
|
|
16
|
+
{% endif %}
|
|
17
|
+
|
|
18
|
+
<form method="post">
|
|
19
|
+
{% csrf_token %}
|
|
20
|
+
{{ form|crispy }}
|
|
21
|
+
<button type="submit" class="w-100 btn btn-app-primary mt-2">Submit</button>
|
|
22
|
+
</form>
|
|
23
|
+
|
|
24
|
+
<a class="text-center text-decoration-none" href={% url 'user_account:authentication:mfa:redirect:notification' %}?resend=True>Resend Code?</a>
|
|
25
|
+
{% endblock %}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{% extends 'spire/page/page.html' %}
|
|
2
|
+
|
|
3
|
+
{% load static %}
|
|
4
|
+
|
|
5
|
+
{% block page_content %}
|
|
6
|
+
<div class="row justify-content-center ps-3 mt-5">
|
|
7
|
+
<div class="col-11 col-md-6 col-lg-4 bg-app-layer-one">
|
|
8
|
+
<div class="px-4 py-5">
|
|
9
|
+
{% block authentication_page_top_content %}
|
|
10
|
+
<div class="text-center pb-5">
|
|
11
|
+
<a href="/">
|
|
12
|
+
{% block authentication_page_img %}
|
|
13
|
+
<img class="ms-1 img-fluid" src="{% static 'spire/img/stratus_secondary_medium.png' %}"
|
|
14
|
+
alt="">
|
|
15
|
+
{% endblock %}
|
|
16
|
+
</a>
|
|
17
|
+
</div>
|
|
18
|
+
{% endblock %}
|
|
19
|
+
{% block authentication_page_content %}
|
|
20
|
+
|
|
21
|
+
{% endblock %}
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
{% endblock %}
|
|
26
|
+
|
django_spire-0.0.1/django_spire/authentication/templates/spire/authentication/page/login_page.html
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{% extends 'spire/authentication/page/authentication_page.html' %}
|
|
2
|
+
|
|
3
|
+
{% load crispy_forms_filters %}
|
|
4
|
+
|
|
5
|
+
{% block authentication_page_content %}
|
|
6
|
+
|
|
7
|
+
<form method="post" class="text-app-secondary">
|
|
8
|
+
{% csrf_token %}
|
|
9
|
+
{{ form|crispy }}
|
|
10
|
+
<button type="submit" class="d-block mx-auto btn btn-app-primary-outlined my-4 w-100">Login</button>
|
|
11
|
+
</form>
|
|
12
|
+
|
|
13
|
+
<div class="text-center">
|
|
14
|
+
<a href="{% url 'authentication:admin:password_reset' %}"
|
|
15
|
+
class="fs--1 text-app-secondary cursor-pointer">
|
|
16
|
+
Forgot my password
|
|
17
|
+
</a>
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
{% endblock %}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
django_spire-0.0.1/django_spire/authentication/templates/spire/authentication/page/logout_page.html
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{% extends 'spire/page/centered_card_page.html' %}
|
|
2
|
+
|
|
3
|
+
{% load crispy_forms_filters static %}
|
|
4
|
+
|
|
5
|
+
{% block page_card_content %}
|
|
6
|
+
<div class="row">
|
|
7
|
+
<div class="col-12">
|
|
8
|
+
<div class="d-flex justify-content-center align-items-end my-2">
|
|
9
|
+
<img height="70px" src="" alt="Logo Here">
|
|
10
|
+
<div class="h4">Application Logout</div>
|
|
11
|
+
|
|
12
|
+
</div>
|
|
13
|
+
<hr class="mt-0">
|
|
14
|
+
</div>
|
|
15
|
+
<div class="col px-4">
|
|
16
|
+
<form method="post" action="{% url 'authentication:redirect:logout' %}">
|
|
17
|
+
{% csrf_token %}
|
|
18
|
+
{{ form|crispy }}
|
|
19
|
+
<button type="submit" class="d-block mx-auto bg-light-primary shadow-sm text-white btn my-4 w-100">Logout</button>
|
|
20
|
+
</form>
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
{% endblock %}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{% extends 'spire/authentication/page/authentication_page.html' %}
|
|
2
|
+
|
|
3
|
+
{% load static %}
|
|
4
|
+
{% load crispy_forms_filters %}
|
|
5
|
+
|
|
6
|
+
{% block base_title %}Password Changed Successfully{% endblock %}
|
|
7
|
+
|
|
8
|
+
{% block authentication_page_content %}
|
|
9
|
+
<h3>Password Reset</h3>
|
|
10
|
+
<div class="py-2">You have successfully changed your password!</div>
|
|
11
|
+
<a class="w-100 btn btn-app-primary bg-app-primary mt-2" href="{% url 'home:home' %}">Home</a>
|
|
12
|
+
{% endblock %}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{% extends 'spire/authentication/page/authentication_page.html' %}
|
|
2
|
+
|
|
3
|
+
{% load crispy_forms_filters %}
|
|
4
|
+
|
|
5
|
+
{% block authentication_page_content %}
|
|
6
|
+
<h5 class="mb-2">Change Password</h5>
|
|
7
|
+
<div>
|
|
8
|
+
<form method="post">
|
|
9
|
+
{% csrf_token %}
|
|
10
|
+
{{ form|crispy }}
|
|
11
|
+
<button type="submit" class="w-100 btn btn-app-primary bg-app-primary mt-2">Submit</button>
|
|
12
|
+
</form>
|
|
13
|
+
</div>
|
|
14
|
+
{% endblock %}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{% extends 'spire/authentication/page/authentication_page.html' %}
|
|
2
|
+
|
|
3
|
+
{% load static %}
|
|
4
|
+
|
|
5
|
+
{% block base_title %}Password Reset Complete{% endblock %}
|
|
6
|
+
|
|
7
|
+
{% block authentication_page_content %}
|
|
8
|
+
<h3>Password Reset Complete</h3>
|
|
9
|
+
<div>Your new password has been set. You can log in now on the <a href="{% url 'user_account:authentication:admin:login' %}">log in page</a>.</div>
|
|
10
|
+
{% endblock %}
|