django-chassis 1.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_chassis-1.0.1/LICENSE +21 -0
- django_chassis-1.0.1/MANIFEST.in +3 -0
- django_chassis-1.0.1/PKG-INFO +175 -0
- django_chassis-1.0.1/README.md +134 -0
- django_chassis-1.0.1/django_chassis/__init__.py +1 -0
- django_chassis-1.0.1/django_chassis/admins/__init__.py +15 -0
- django_chassis-1.0.1/django_chassis/admins/admin_audit_log.py +107 -0
- django_chassis-1.0.1/django_chassis/admins/group.py +56 -0
- django_chassis-1.0.1/django_chassis/admins/login_attempt.py +69 -0
- django_chassis-1.0.1/django_chassis/admins/login_attempt_schedule.py +44 -0
- django_chassis-1.0.1/django_chassis/admins/user.py +52 -0
- django_chassis-1.0.1/django_chassis/admins/user_session.py +100 -0
- django_chassis-1.0.1/django_chassis/apps.py +18 -0
- django_chassis-1.0.1/django_chassis/components/__init__.py +22 -0
- django_chassis-1.0.1/django_chassis/components/actions.py +145 -0
- django_chassis-1.0.1/django_chassis/components/alerts.py +80 -0
- django_chassis-1.0.1/django_chassis/components/base.py +69 -0
- django_chassis-1.0.1/django_chassis/components/charts.py +82 -0
- django_chassis-1.0.1/django_chassis/components/geo_ip_database_alert.py +46 -0
- django_chassis-1.0.1/django_chassis/components/metrics.py +97 -0
- django_chassis-1.0.1/django_chassis/components/navbar.py +101 -0
- django_chassis-1.0.1/django_chassis/components/toggle_actions.py +122 -0
- django_chassis-1.0.1/django_chassis/conf.py +32 -0
- django_chassis-1.0.1/django_chassis/decorators/__init__.py +25 -0
- django_chassis-1.0.1/django_chassis/decorators/object_action.py +99 -0
- django_chassis-1.0.1/django_chassis/decorators/related_items.py +25 -0
- django_chassis-1.0.1/django_chassis/dto/__init__.py +71 -0
- django_chassis-1.0.1/django_chassis/dto/admin_information_badge.py +14 -0
- django_chassis-1.0.1/django_chassis/dto/admin_information_row.py +21 -0
- django_chassis-1.0.1/django_chassis/dto/admin_information_section.py +21 -0
- django_chassis-1.0.1/django_chassis/dto/admin_navbar_child_item.py +16 -0
- django_chassis-1.0.1/django_chassis/dto/admin_navbar_item.py +21 -0
- django_chassis-1.0.1/django_chassis/dto/admin_page_action.py +17 -0
- django_chassis-1.0.1/django_chassis/dto/admin_page_alert.py +15 -0
- django_chassis-1.0.1/django_chassis/dto/admin_profile.py +22 -0
- django_chassis-1.0.1/django_chassis/dto/admin_sidebar_child_item.py +16 -0
- django_chassis-1.0.1/django_chassis/dto/admin_sidebar_item.py +28 -0
- django_chassis-1.0.1/django_chassis/dto/admin_timeline.py +14 -0
- django_chassis-1.0.1/django_chassis/dto/admin_timeline_group.py +14 -0
- django_chassis-1.0.1/django_chassis/dto/admin_timeline_item.py +17 -0
- django_chassis-1.0.1/django_chassis/dto/brand.py +13 -0
- django_chassis-1.0.1/django_chassis/dto/brand_badge.py +14 -0
- django_chassis-1.0.1/django_chassis/dto/client_device.py +13 -0
- django_chassis-1.0.1/django_chassis/dto/dashboard_action.py +23 -0
- django_chassis-1.0.1/django_chassis/dto/dashboard_action_variant.py +18 -0
- django_chassis-1.0.1/django_chassis/dto/dashboard_alert.py +20 -0
- django_chassis-1.0.1/django_chassis/dto/dashboard_block.py +21 -0
- django_chassis-1.0.1/django_chassis/dto/dashboard_chart.py +29 -0
- django_chassis-1.0.1/django_chassis/dto/dashboard_chart_data.py +15 -0
- django_chassis-1.0.1/django_chassis/dto/dashboard_chart_point.py +12 -0
- django_chassis-1.0.1/django_chassis/dto/dashboard_chart_series.py +15 -0
- django_chassis-1.0.1/django_chassis/dto/dashboard_metric.py +23 -0
- django_chassis-1.0.1/django_chassis/dto/dashboard_stacked_item.py +16 -0
- django_chassis-1.0.1/django_chassis/dto/export_field.py +16 -0
- django_chassis-1.0.1/django_chassis/dto/export_filter.py +17 -0
- django_chassis-1.0.1/django_chassis/dto/import_field.py +16 -0
- django_chassis-1.0.1/django_chassis/dto/import_preview.py +34 -0
- django_chassis-1.0.1/django_chassis/dto/login_attempt_availability.py +14 -0
- django_chassis-1.0.1/django_chassis/dto/request_client_metadata.py +17 -0
- django_chassis-1.0.1/django_chassis/dto/user_profile_activity.py +14 -0
- django_chassis-1.0.1/django_chassis/enums/__init__.py +57 -0
- django_chassis-1.0.1/django_chassis/enums/admin_audit_action.py +40 -0
- django_chassis-1.0.1/django_chassis/enums/admin_audit_result.py +30 -0
- django_chassis-1.0.1/django_chassis/enums/admin_error_status.py +73 -0
- django_chassis-1.0.1/django_chassis/enums/admin_navbar_item_type.py +11 -0
- django_chassis-1.0.1/django_chassis/enums/button_color.py +14 -0
- django_chassis-1.0.1/django_chassis/enums/choices_enum.py +36 -0
- django_chassis-1.0.1/django_chassis/enums/dashboard_alert_style.py +22 -0
- django_chassis-1.0.1/django_chassis/enums/dashboard_block_type.py +13 -0
- django_chassis-1.0.1/django_chassis/enums/dashboard_chart_color.py +11 -0
- django_chassis-1.0.1/django_chassis/enums/dashboard_chart_type.py +11 -0
- django_chassis-1.0.1/django_chassis/enums/dashboard_component_status.py +12 -0
- django_chassis-1.0.1/django_chassis/enums/dashboard_live_widget_type.py +12 -0
- django_chassis-1.0.1/django_chassis/enums/dashboard_metric_result_type.py +11 -0
- django_chassis-1.0.1/django_chassis/enums/dashboard_stacked_item_tone.py +12 -0
- django_chassis-1.0.1/django_chassis/enums/export_backend.py +22 -0
- django_chassis-1.0.1/django_chassis/enums/export_format.py +42 -0
- django_chassis-1.0.1/django_chassis/enums/export_status.py +28 -0
- django_chassis-1.0.1/django_chassis/enums/import_backend.py +22 -0
- django_chassis-1.0.1/django_chassis/enums/import_format.py +35 -0
- django_chassis-1.0.1/django_chassis/enums/import_status.py +30 -0
- django_chassis-1.0.1/django_chassis/enums/permission_check.py +10 -0
- django_chassis-1.0.1/django_chassis/enums/permission_name_language.py +9 -0
- django_chassis-1.0.1/django_chassis/enums/row_action_display.py +10 -0
- django_chassis-1.0.1/django_chassis/enums/row_action_type.py +12 -0
- django_chassis-1.0.1/django_chassis/enums/sidebar_icon_color.py +33 -0
- django_chassis-1.0.1/django_chassis/enums/tab_display.py +10 -0
- django_chassis-1.0.1/django_chassis/enums/user_session_end_reason.py +28 -0
- django_chassis-1.0.1/django_chassis/exceptions.py +33 -0
- django_chassis-1.0.1/django_chassis/filters/__init__.py +0 -0
- django_chassis-1.0.1/django_chassis/filters/user_session_state.py +42 -0
- django_chassis-1.0.1/django_chassis/forms/__init__.py +13 -0
- django_chassis-1.0.1/django_chassis/forms/admin_authentication.py +87 -0
- django_chassis-1.0.1/django_chassis/forms/confirmed_action.py +11 -0
- django_chassis-1.0.1/django_chassis/forms/export_form.py +103 -0
- django_chassis-1.0.1/django_chassis/forms/import_export_base.py +92 -0
- django_chassis-1.0.1/django_chassis/forms/import_form.py +65 -0
- django_chassis-1.0.1/django_chassis/forms/self_password_change.py +19 -0
- django_chassis-1.0.1/django_chassis/management/__init__.py +0 -0
- django_chassis-1.0.1/django_chassis/management/commands/__init__.py +0 -0
- django_chassis-1.0.1/django_chassis/management/commands/run_gunicorn.py +91 -0
- django_chassis-1.0.1/django_chassis/middlewares/__init__.py +5 -0
- django_chassis-1.0.1/django_chassis/middlewares/admin_audit.py +43 -0
- django_chassis-1.0.1/django_chassis/middlewares/admin_error_page.py +66 -0
- django_chassis-1.0.1/django_chassis/middlewares/user_session.py +46 -0
- django_chassis-1.0.1/django_chassis/migrations/0001_initial.py +217 -0
- django_chassis-1.0.1/django_chassis/migrations/__init__.py +0 -0
- django_chassis-1.0.1/django_chassis/mixins/__init__.py +6 -0
- django_chassis-1.0.1/django_chassis/mixins/admin.py +300 -0
- django_chassis-1.0.1/django_chassis/mixins/admin_site.py +355 -0
- django_chassis-1.0.1/django_chassis/mixins/core/__init__.py +3 -0
- django_chassis-1.0.1/django_chassis/mixins/core/actions.py +164 -0
- django_chassis-1.0.1/django_chassis/mixins/core/audit.py +68 -0
- django_chassis-1.0.1/django_chassis/mixins/core/base.py +73 -0
- django_chassis-1.0.1/django_chassis/mixins/core/changelist.py +207 -0
- django_chassis-1.0.1/django_chassis/mixins/core/import_export.py +193 -0
- django_chassis-1.0.1/django_chassis/mixins/core/object_page.py +306 -0
- django_chassis-1.0.1/django_chassis/mixins/core/permissions.py +75 -0
- django_chassis-1.0.1/django_chassis/mixins/core/presentation.py +395 -0
- django_chassis-1.0.1/django_chassis/mixins/no_delete_admin.py +14 -0
- django_chassis-1.0.1/django_chassis/mixins/read_only_admin.py +29 -0
- django_chassis-1.0.1/django_chassis/models/__init__.py +17 -0
- django_chassis-1.0.1/django_chassis/models/admin_audit_log.py +105 -0
- django_chassis-1.0.1/django_chassis/models/export_history.py +93 -0
- django_chassis-1.0.1/django_chassis/models/history_storage.py +32 -0
- django_chassis-1.0.1/django_chassis/models/import_history.py +93 -0
- django_chassis-1.0.1/django_chassis/models/login_attempt.py +52 -0
- django_chassis-1.0.1/django_chassis/models/login_attempt_schedule.py +39 -0
- django_chassis-1.0.1/django_chassis/models/managers.py +43 -0
- django_chassis-1.0.1/django_chassis/models/user_profile.py +58 -0
- django_chassis-1.0.1/django_chassis/models/user_session.py +99 -0
- django_chassis-1.0.1/django_chassis/navbar/__init__.py +3 -0
- django_chassis-1.0.1/django_chassis/navbar/admin_profile.py +40 -0
- django_chassis-1.0.1/django_chassis/navbar/password_change.py +40 -0
- django_chassis-1.0.1/django_chassis/navbar/theme.py +24 -0
- django_chassis-1.0.1/django_chassis/options/__init__.py +82 -0
- django_chassis-1.0.1/django_chassis/options/admin_page_group.py +15 -0
- django_chassis-1.0.1/django_chassis/options/badge_fields.py +14 -0
- django_chassis-1.0.1/django_chassis/options/date_hierarchy.py +15 -0
- django_chassis-1.0.1/django_chassis/options/decimal_amount.py +17 -0
- django_chassis-1.0.1/django_chassis/options/export.py +39 -0
- django_chassis-1.0.1/django_chassis/options/field_tabs.py +21 -0
- django_chassis-1.0.1/django_chassis/options/filters.py +16 -0
- django_chassis-1.0.1/django_chassis/options/foreign_key_tab_group.py +18 -0
- django_chassis-1.0.1/django_chassis/options/foreign_key_tabs.py +23 -0
- django_chassis-1.0.1/django_chassis/options/import_option.py +35 -0
- django_chassis-1.0.1/django_chassis/options/list_action.py +19 -0
- django_chassis-1.0.1/django_chassis/options/list_actions.py +12 -0
- django_chassis-1.0.1/django_chassis/options/object_actions.py +17 -0
- django_chassis-1.0.1/django_chassis/options/permission.py +35 -0
- django_chassis-1.0.1/django_chassis/options/pretty_json.py +10 -0
- django_chassis-1.0.1/django_chassis/options/related_entities.py +21 -0
- django_chassis-1.0.1/django_chassis/options/related_entity.py +23 -0
- django_chassis-1.0.1/django_chassis/options/row_action.py +19 -0
- django_chassis-1.0.1/django_chassis/options/row_actions.py +30 -0
- django_chassis-1.0.1/django_chassis/options/search.py +16 -0
- django_chassis-1.0.1/django_chassis/options/settings.py +13 -0
- django_chassis-1.0.1/django_chassis/options/sidebar_link.py +15 -0
- django_chassis-1.0.1/django_chassis/options/sidebar_model_item.py +14 -0
- django_chassis-1.0.1/django_chassis/options/sidebar_page_item.py +14 -0
- django_chassis-1.0.1/django_chassis/options/sidebar_section.py +22 -0
- django_chassis-1.0.1/django_chassis/options/table.py +21 -0
- django_chassis-1.0.1/django_chassis/options/table_action.py +24 -0
- django_chassis-1.0.1/django_chassis/options/table_action_url_kwarg.py +11 -0
- django_chassis-1.0.1/django_chassis/options/table_column.py +13 -0
- django_chassis-1.0.1/django_chassis/permissions.py +53 -0
- django_chassis-1.0.1/django_chassis/protocols.py +40 -0
- django_chassis-1.0.1/django_chassis/py.typed +0 -0
- django_chassis-1.0.1/django_chassis/registries/__init__.py +3 -0
- django_chassis-1.0.1/django_chassis/registries/permission_registry.py +33 -0
- django_chassis-1.0.1/django_chassis/renderers/__init__.py +3 -0
- django_chassis-1.0.1/django_chassis/renderers/admin_error_page_renderer.py +167 -0
- django_chassis-1.0.1/django_chassis/services/__init__.py +65 -0
- django_chassis-1.0.1/django_chassis/services/action_permission_validation_service.py +50 -0
- django_chassis-1.0.1/django_chassis/services/admin_audit_log_service.py +155 -0
- django_chassis-1.0.1/django_chassis/services/admin_navbar_service.py +118 -0
- django_chassis-1.0.1/django_chassis/services/admin_page_service.py +108 -0
- django_chassis-1.0.1/django_chassis/services/admin_permission_service.py +24 -0
- django_chassis-1.0.1/django_chassis/services/admin_profile_service.py +54 -0
- django_chassis-1.0.1/django_chassis/services/admin_sidebar_service.py +304 -0
- django_chassis-1.0.1/django_chassis/services/celery_availability_service.py +25 -0
- django_chassis-1.0.1/django_chassis/services/client_device_service.py +193 -0
- django_chassis-1.0.1/django_chassis/services/client_geo_ip_service.py +158 -0
- django_chassis-1.0.1/django_chassis/services/client_ip_service.py +56 -0
- django_chassis-1.0.1/django_chassis/services/confirmed_action_service.py +46 -0
- django_chassis-1.0.1/django_chassis/services/dashboard_analytics_cache_service.py +28 -0
- django_chassis-1.0.1/django_chassis/services/dashboard_live_serialization_service.py +68 -0
- django_chassis-1.0.1/django_chassis/services/dashboard_service.py +379 -0
- django_chassis-1.0.1/django_chassis/services/deleted_objects_service.py +164 -0
- django_chassis-1.0.1/django_chassis/services/import_apply_service.py +262 -0
- django_chassis-1.0.1/django_chassis/services/import_export_dispatch_service.py +146 -0
- django_chassis-1.0.1/django_chassis/services/import_export_field_service.py +157 -0
- django_chassis-1.0.1/django_chassis/services/import_export_filter_service.py +183 -0
- django_chassis-1.0.1/django_chassis/services/import_export_process_service.py +226 -0
- django_chassis-1.0.1/django_chassis/services/import_export_python_queue_service.py +91 -0
- django_chassis-1.0.1/django_chassis/services/import_export_serialization_service.py +493 -0
- django_chassis-1.0.1/django_chassis/services/login_attempt_limit_service.py +341 -0
- django_chassis-1.0.1/django_chassis/services/pagination_service.py +61 -0
- django_chassis-1.0.1/django_chassis/services/permission_initialization_service.py +35 -0
- django_chassis-1.0.1/django_chassis/services/permission_name_normalization_service.py +125 -0
- django_chassis-1.0.1/django_chassis/services/session_key_crypto_service.py +26 -0
- django_chassis-1.0.1/django_chassis/services/table_service.py +135 -0
- django_chassis-1.0.1/django_chassis/services/user_profile_service.py +117 -0
- django_chassis-1.0.1/django_chassis/services/user_session_service.py +266 -0
- django_chassis-1.0.1/django_chassis/signals/__init__.py +10 -0
- django_chassis-1.0.1/django_chassis/signals/initialize_permissions.py +15 -0
- django_chassis-1.0.1/django_chassis/signals/normalize_default_permission_names.py +13 -0
- django_chassis-1.0.1/django_chassis/signals/user_profile.py +42 -0
- django_chassis-1.0.1/django_chassis/singleton.py +17 -0
- django_chassis-1.0.1/django_chassis/static/admin/chassis/admin.css +1815 -0
- django_chassis-1.0.1/django_chassis/static/admin/chassis/alerts.css +264 -0
- django_chassis-1.0.1/django_chassis/static/admin/chassis/alerts.js +46 -0
- django_chassis-1.0.1/django_chassis/static/admin/chassis/apexcharts/apexcharts.css +1203 -0
- django_chassis-1.0.1/django_chassis/static/admin/chassis/apexcharts/apexcharts.min.js +5 -0
- django_chassis-1.0.1/django_chassis/static/admin/chassis/auth.css +311 -0
- django_chassis-1.0.1/django_chassis/static/admin/chassis/collapsibles.js +46 -0
- django_chassis-1.0.1/django_chassis/static/admin/chassis/dashboard.css +854 -0
- django_chassis-1.0.1/django_chassis/static/admin/chassis/dashboard_charts.js +234 -0
- django_chassis-1.0.1/django_chassis/static/admin/chassis/dashboard_live.js +332 -0
- django_chassis-1.0.1/django_chassis/static/admin/chassis/date_input_mask.js +237 -0
- django_chassis-1.0.1/django_chassis/static/admin/chassis/error_page.css +116 -0
- django_chassis-1.0.1/django_chassis/static/admin/chassis/filters.js +19 -0
- django_chassis-1.0.1/django_chassis/static/admin/chassis/fontawesome/css/all.min.css +9 -0
- django_chassis-1.0.1/django_chassis/static/admin/chassis/fontawesome/webfonts/fa-brands-400.woff2 +0 -0
- django_chassis-1.0.1/django_chassis/static/admin/chassis/fontawesome/webfonts/fa-regular-400.woff2 +0 -0
- django_chassis-1.0.1/django_chassis/static/admin/chassis/fontawesome/webfonts/fa-solid-900.woff2 +0 -0
- django_chassis-1.0.1/django_chassis/static/admin/chassis/fontawesome/webfonts/fa-v4compatibility.woff2 +0 -0
- django_chassis-1.0.1/django_chassis/static/admin/chassis/icon.svg +7 -0
- django_chassis-1.0.1/django_chassis/static/admin/chassis/navbar.css +374 -0
- django_chassis-1.0.1/django_chassis/static/admin/chassis/navbar_dropdown.js +29 -0
- django_chassis-1.0.1/django_chassis/static/admin/chassis/related_pagination.js +176 -0
- django_chassis-1.0.1/django_chassis/static/admin/chassis/secret_field.js +105 -0
- django_chassis-1.0.1/django_chassis/static/admin/chassis/sidebar.css +765 -0
- django_chassis-1.0.1/django_chassis/static/admin/chassis/sidebar.js +63 -0
- django_chassis-1.0.1/django_chassis/static/admin/chassis/table_selection.js +22 -0
- django_chassis-1.0.1/django_chassis/tasks/__init__.py +3 -0
- django_chassis-1.0.1/django_chassis/tasks/process_import_export.py +26 -0
- django_chassis-1.0.1/django_chassis/templates/admin/base.html +328 -0
- django_chassis-1.0.1/django_chassis/templates/admin/change_form.html +35 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/auth_alert.html +9 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/auth_alerts.html +40 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/blocked_profiles.html +80 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/brand.html +16 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/change_form.html +63 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/change_list.html +141 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/confirmed_action.html +29 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/dashboard/actions/base.html +21 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/dashboard/actions/toggle.html +45 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/dashboard/index.html +113 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/dashboard/sections/actions.html +14 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/dashboard/sections/alerts.html +27 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/dashboard/sections/chart.html +40 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/dashboard/sections/items/action.html +29 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/dashboard/sections/items/metric.html +75 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/dashboard/sections/metrics.html +14 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/dashboard/sections/metrics_and_actions.html +18 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/dashboard/sections/panel_heading.html +12 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/date_hierarchy.html +23 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/filters.html +49 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/form_rows.html +44 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/import_export_form.html +128 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/import_export_landing.html +42 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/import_export_preview.html +113 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/information_alert.html +7 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/information_page.html +24 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/information_sections.html +108 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/object_page.html +26 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/page.html +21 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/pagination.html +18 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/related_entities.html +41 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/row_actions.html +19 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/search.html +29 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/self_password_change.html +34 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/sidebar.html +74 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/table.html +54 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/timeline.html +37 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/widgets/date.html +1 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/widgets/split_datetime.html +16 -0
- django_chassis-1.0.1/django_chassis/templates/admin/chassis/widgets/time.html +1 -0
- django_chassis-1.0.1/django_chassis/templates/admin/error.html +37 -0
- django_chassis-1.0.1/django_chassis/templates/admin/footer.html +15 -0
- django_chassis-1.0.1/django_chassis/templates/admin/login.html +86 -0
- django_chassis-1.0.1/django_chassis/templates/admin/object_actions/base_action_view.html +18 -0
- django_chassis-1.0.1/django_chassis/templatetags/__init__.py +1 -0
- django_chassis-1.0.1/django_chassis/templatetags/admin_footer.py +15 -0
- django_chassis-1.0.1/django_chassis/templatetags/chassis_admin.py +95 -0
- django_chassis-1.0.1/django_chassis/type_aliases.py +5 -0
- django_chassis-1.0.1/django_chassis/utils/__init__.py +8 -0
- django_chassis-1.0.1/django_chassis/utils/fixed_point_decimal.py +39 -0
- django_chassis-1.0.1/django_chassis/utils/table_exists.py +8 -0
- django_chassis-1.0.1/django_chassis/validators/__init__.py +0 -0
- django_chassis-1.0.1/django_chassis/validators/login_attempt_unlock.py +16 -0
- django_chassis-1.0.1/django_chassis/validators/object_action_condition.py +23 -0
- django_chassis-1.0.1/django_chassis/validators/translation_management.py +15 -0
- django_chassis-1.0.1/django_chassis/validators/user_session_termination.py +20 -0
- django_chassis-1.0.1/django_chassis/views/__init__.py +19 -0
- django_chassis-1.0.1/django_chassis/views/admin_information_page.py +44 -0
- django_chassis-1.0.1/django_chassis/views/admin_object_page.py +214 -0
- django_chassis-1.0.1/django_chassis/views/admin_page.py +113 -0
- django_chassis-1.0.1/django_chassis/views/admin_profile.py +232 -0
- django_chassis-1.0.1/django_chassis/views/import_export.py +575 -0
- django_chassis-1.0.1/django_chassis/views/permission_admin_page.py +29 -0
- django_chassis-1.0.1/django_chassis/views/personal_admin_page.py +22 -0
- django_chassis-1.0.1/django_chassis/views/self_password_change.py +54 -0
- django_chassis-1.0.1/django_chassis/views/superuser_admin_page.py +24 -0
- django_chassis-1.0.1/django_chassis/widgets/__init__.py +33 -0
- django_chassis-1.0.1/django_chassis/widgets/date_input.py +33 -0
- django_chassis-1.0.1/django_chassis/widgets/date_time_input.py +27 -0
- django_chassis-1.0.1/django_chassis/widgets/execution_backend_select.py +35 -0
- django_chassis-1.0.1/django_chassis/widgets/input_mask.py +35 -0
- django_chassis-1.0.1/django_chassis/widgets/split_date_time.py +19 -0
- django_chassis-1.0.1/django_chassis/widgets/time_input.py +33 -0
- django_chassis-1.0.1/django_chassis.egg-info/PKG-INFO +175 -0
- django_chassis-1.0.1/django_chassis.egg-info/SOURCES.txt +349 -0
- django_chassis-1.0.1/django_chassis.egg-info/dependency_links.txt +1 -0
- django_chassis-1.0.1/django_chassis.egg-info/requires.txt +10 -0
- django_chassis-1.0.1/django_chassis.egg-info/top_level.txt +1 -0
- django_chassis-1.0.1/pyproject.toml +109 -0
- django_chassis-1.0.1/setup.cfg +4 -0
- django_chassis-1.0.1/tests/test_admin_mro.py +57 -0
- django_chassis-1.0.1/tests/test_admin_object_page.py +100 -0
- django_chassis-1.0.1/tests/test_admin_permissions.py +139 -0
- django_chassis-1.0.1/tests/test_admin_site.py +272 -0
- django_chassis-1.0.1/tests/test_badge_fields.py +75 -0
- django_chassis-1.0.1/tests/test_client_metadata.py +103 -0
- django_chassis-1.0.1/tests/test_collapsible_state.py +173 -0
- django_chassis-1.0.1/tests/test_custom_permissions.py +86 -0
- django_chassis-1.0.1/tests/test_dashboard_analytics_cache_service.py +58 -0
- django_chassis-1.0.1/tests/test_dashboard_live.py +356 -0
- django_chassis-1.0.1/tests/test_date_hierarchy.py +46 -0
- django_chassis-1.0.1/tests/test_date_input_mask.py +188 -0
- django_chassis-1.0.1/tests/test_decimal_amount.py +178 -0
- django_chassis-1.0.1/tests/test_deleted_objects.py +89 -0
- django_chassis-1.0.1/tests/test_error_pages.py +256 -0
- django_chassis-1.0.1/tests/test_import_export.py +1023 -0
- django_chassis-1.0.1/tests/test_list_actions.py +221 -0
- django_chassis-1.0.1/tests/test_model_table_names.py +29 -0
- django_chassis-1.0.1/tests/test_navbar.py +504 -0
- django_chassis-1.0.1/tests/test_object_actions.py +119 -0
- django_chassis-1.0.1/tests/test_pagination_service.py +71 -0
- django_chassis-1.0.1/tests/test_permission_mixins.py +49 -0
- django_chassis-1.0.1/tests/test_permission_name_normalization.py +112 -0
- django_chassis-1.0.1/tests/test_permissions.py +106 -0
- django_chassis-1.0.1/tests/test_related_entities.py +143 -0
- django_chassis-1.0.1/tests/test_row_actions.py +57 -0
- django_chassis-1.0.1/tests/test_service_exports.py +10 -0
- django_chassis-1.0.1/tests/test_singleton.py +74 -0
- django_chassis-1.0.1/tests/test_source_conventions.py +261 -0
- django_chassis-1.0.1/tests/test_table_service.py +196 -0
- django_chassis-1.0.1/tests/test_timeline.py +142 -0
- django_chassis-1.0.1/tests/test_users_module.py +194 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 RDD Lab
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: django-chassis
|
|
3
|
+
Version: 1.0.1
|
|
4
|
+
Summary: Declarative Django Admin chassis: mixin, site, options, pages, and dashboard
|
|
5
|
+
Author-email: Raman Marozau <r.morozov@rdd-lab.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://django-chassis.rdd-lab.com/
|
|
8
|
+
Project-URL: Documentation, https://django-chassis.rdd-lab.com/
|
|
9
|
+
Project-URL: Issues, https://github.com/RDDLab/Django-Chassis/issues
|
|
10
|
+
Project-URL: Repository, https://github.com/RDDLab/Django-Chassis
|
|
11
|
+
Project-URL: Changelog, https://github.com/RDDLab/Django-Chassis/blob/main/CHANGELOG.md
|
|
12
|
+
Keywords: django,admin,dashboard,chassis
|
|
13
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Framework :: Django
|
|
18
|
+
Classifier: Framework :: Django :: 6.0
|
|
19
|
+
Classifier: Framework :: Django :: 6.1
|
|
20
|
+
Classifier: Programming Language :: Python
|
|
21
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
24
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
25
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
26
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
27
|
+
Classifier: Typing :: Typed
|
|
28
|
+
Requires-Python: <3.15,>=3.13
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
License-File: LICENSE
|
|
31
|
+
Requires-Dist: django>=6.0
|
|
32
|
+
Requires-Dist: pygments>=2.18
|
|
33
|
+
Requires-Dist: openpyxl>=3.1
|
|
34
|
+
Requires-Dist: geoip2>=4.8
|
|
35
|
+
Requires-Dist: netaddr>=1.3.0
|
|
36
|
+
Requires-Dist: device-detector>=6.4.0
|
|
37
|
+
Requires-Dist: gunicorn>=26.1.0
|
|
38
|
+
Provides-Extra: celery
|
|
39
|
+
Requires-Dist: celery>=5.3; extra == "celery"
|
|
40
|
+
Dynamic: license-file
|
|
41
|
+
|
|
42
|
+
<div align="center">
|
|
43
|
+
<img src="https://github.com/RDDLab/Django-Chassis/raw/main/docs/static/img/logo.svg" alt="Django-Chassis" width="560">
|
|
44
|
+
|
|
45
|
+
<p><strong>A declarative, fully typed chassis for building polished Django Admin applications.</strong></p>
|
|
46
|
+
|
|
47
|
+
<p>
|
|
48
|
+
<a href="https://django-chassis.rdd-lab.com/">Documentation</a> ·
|
|
49
|
+
<a href="https://django-chassis.rdd-lab.com/getting-started">Quick start</a> ·
|
|
50
|
+
<a href="https://django-chassis.rdd-lab.com/api-reference">API reference</a> ·
|
|
51
|
+
<a href="https://github.com/RDDLab/Django-Chassis/blob/main/CHANGELOG.md">Changelog</a>
|
|
52
|
+
</p>
|
|
53
|
+
|
|
54
|
+
<p>
|
|
55
|
+
<a href="https://pypi.org/project/django-chassis/"><img src="https://img.shields.io/badge/release-1.0.1-0f766e?style=flat-square" alt="Django-Chassis 1.0.1"></a>
|
|
56
|
+
<a href="https://pypi.org/project/django-chassis/"><img src="https://img.shields.io/pypi/pyversions/django-chassis.svg?style=flat-square" alt="Supported Python versions"></a>
|
|
57
|
+
<a href="https://pypi.org/project/django-chassis/"><img src="https://img.shields.io/pypi/djversions/django-chassis.svg?style=flat-square" alt="Supported Django versions"></a>
|
|
58
|
+
<a href="https://pypi.org/project/django-chassis/"><img src="https://img.shields.io/pypi/types/django-chassis.svg?style=flat-square" alt="Typed package"></a>
|
|
59
|
+
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square" alt="MIT license"></a>
|
|
60
|
+
</p>
|
|
61
|
+
|
|
62
|
+
<p>
|
|
63
|
+
<a href="https://github.com/RDDLab/Django-Chassis/actions/workflows/testing.yml"><img src="https://img.shields.io/github/actions/workflow/status/RDDLab/Django-Chassis/testing.yml?branch=main&label=tests&style=flat-square" alt="Test status"></a>
|
|
64
|
+
<a href="https://results.pre-commit.ci/latest/github/RDDLab/Django-Chassis/main"><img src="https://results.pre-commit.ci/badge/github/RDDLab/Django-Chassis/main.svg" alt="pre-commit.ci status"></a>
|
|
65
|
+
</p>
|
|
66
|
+
</div>
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
Django-Chassis gives a project a structured `AdminSite`, composable
|
|
71
|
+
`ModelAdmin` options, custom pages, dashboard contracts, and a complete template
|
|
72
|
+
overlay. Domain models and business rules stay in the project; Chassis provides
|
|
73
|
+
the reusable Admin application layer around them.
|
|
74
|
+
|
|
75
|
+
## Features
|
|
76
|
+
|
|
77
|
+
- **Declarative configuration** — compose the Admin with
|
|
78
|
+
`ChassisAdminSiteMixin`, `ChassisAdminMixin`, and immutable `options`.
|
|
79
|
+
- **A polished changelist** — search, filters, date hierarchy, tabs, badges,
|
|
80
|
+
pretty JSON, and decimal-amount presentation without ad-hoc template forks.
|
|
81
|
+
- **Row, list, and object actions** — permission-aware buttons, confirmation, and condition methods.
|
|
82
|
+
- **Related entities and generic tables** — independently paginated tables with `TableOption`.
|
|
83
|
+
- **Custom pages** — permission-aware pages, personal pages, information pages, and timelines.
|
|
84
|
+
- **Dashboard contracts** — metrics, charts, alerts, actions, a four-column grid, and live refresh at `dashboard/live/`.
|
|
85
|
+
- **Import/export** — JSON/XML in, JSON/XML/CSV/XLSX out, preview/apply, history, optional Celery.
|
|
86
|
+
- **Users and security** — profiles, sessions, login-attempt limits, GeoIP country detection, and an Admin audit journal.
|
|
87
|
+
- **Fully typed** — ships `py.typed` and is checked with Pyrefly in strict mode.
|
|
88
|
+
|
|
89
|
+
## Installation
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
pip install django-chassis
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Version `1.0.1` requires Python 3.13 or 3.14 and Django 6.0+.
|
|
96
|
+
|
|
97
|
+
Put `'django_chassis'` **before** `'django.contrib.admin'` so package templates overlay the stock Admin:
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
INSTALLED_APPS = [
|
|
101
|
+
'django_chassis',
|
|
102
|
+
'django.contrib.admin',
|
|
103
|
+
# ...
|
|
104
|
+
]
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Background import/export is optional:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
pip install 'django-chassis[celery]'
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
For a production HTTP server, Chassis also provides a Gunicorn management
|
|
114
|
+
command:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
python manage.py run_gunicorn --port=8000 --workers=2
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Quick start
|
|
121
|
+
|
|
122
|
+
Create a Chassis `AdminSite`, register a model, and mount the site in `urls.py`:
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
from django.contrib.admin import AdminSite, ModelAdmin
|
|
126
|
+
from django.urls import path
|
|
127
|
+
from django.utils.translation import gettext_lazy as _
|
|
128
|
+
|
|
129
|
+
from django_chassis.mixins import ChassisAdminMixin, ChassisAdminSiteMixin
|
|
130
|
+
from django_chassis.options import RowActionsOption, SearchOption
|
|
131
|
+
|
|
132
|
+
from catalog.models import Book
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
class CustomAdminSite(ChassisAdminSiteMixin, AdminSite):
|
|
136
|
+
chassis_brand_name = _('My project')
|
|
137
|
+
chassis_brand_logo_static_path = 'img/logo.png'
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
admin_site = CustomAdminSite(name='admin')
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class BookAdmin(ChassisAdminMixin, ModelAdmin):
|
|
144
|
+
options = [SearchOption(fields=['title', 'isbn']), RowActionsOption()]
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
admin_site.register(Book, BookAdmin)
|
|
148
|
+
|
|
149
|
+
urlpatterns = [path('admin/', admin_site.urls)]
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
> `ChassisAdminSiteMixin` and `ChassisAdminMixin` must come before their Django
|
|
153
|
+
> classes in the MRO.
|
|
154
|
+
|
|
155
|
+
## Documentation
|
|
156
|
+
|
|
157
|
+
Read the full guides, architecture notes, option reference, and dashboard
|
|
158
|
+
contracts at **[django-chassis.rdd-lab.com](https://django-chassis.rdd-lab.com/)**.
|
|
159
|
+
|
|
160
|
+
## Testing
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
uv sync --group dev
|
|
164
|
+
uv run pytest
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## License
|
|
168
|
+
|
|
169
|
+
Distributed under the [MIT License](https://opensource.org/licenses/MIT).
|
|
170
|
+
|
|
171
|
+
## Support the project
|
|
172
|
+
|
|
173
|
+
<a href="https://nowpayments.io/donation?api_key=7664bfa5-ea12-4ded-9c3b-8a498d437114" target="_blank" rel="noreferrer noopener">
|
|
174
|
+
<img src="https://nowpayments.io/images/embeds/donation-button-white.svg" alt="Cryptocurrency & Bitcoin donation button by NOWPayments">
|
|
175
|
+
</a>
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<img src="https://github.com/RDDLab/Django-Chassis/raw/main/docs/static/img/logo.svg" alt="Django-Chassis" width="560">
|
|
3
|
+
|
|
4
|
+
<p><strong>A declarative, fully typed chassis for building polished Django Admin applications.</strong></p>
|
|
5
|
+
|
|
6
|
+
<p>
|
|
7
|
+
<a href="https://django-chassis.rdd-lab.com/">Documentation</a> ·
|
|
8
|
+
<a href="https://django-chassis.rdd-lab.com/getting-started">Quick start</a> ·
|
|
9
|
+
<a href="https://django-chassis.rdd-lab.com/api-reference">API reference</a> ·
|
|
10
|
+
<a href="https://github.com/RDDLab/Django-Chassis/blob/main/CHANGELOG.md">Changelog</a>
|
|
11
|
+
</p>
|
|
12
|
+
|
|
13
|
+
<p>
|
|
14
|
+
<a href="https://pypi.org/project/django-chassis/"><img src="https://img.shields.io/badge/release-1.0.1-0f766e?style=flat-square" alt="Django-Chassis 1.0.1"></a>
|
|
15
|
+
<a href="https://pypi.org/project/django-chassis/"><img src="https://img.shields.io/pypi/pyversions/django-chassis.svg?style=flat-square" alt="Supported Python versions"></a>
|
|
16
|
+
<a href="https://pypi.org/project/django-chassis/"><img src="https://img.shields.io/pypi/djversions/django-chassis.svg?style=flat-square" alt="Supported Django versions"></a>
|
|
17
|
+
<a href="https://pypi.org/project/django-chassis/"><img src="https://img.shields.io/pypi/types/django-chassis.svg?style=flat-square" alt="Typed package"></a>
|
|
18
|
+
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square" alt="MIT license"></a>
|
|
19
|
+
</p>
|
|
20
|
+
|
|
21
|
+
<p>
|
|
22
|
+
<a href="https://github.com/RDDLab/Django-Chassis/actions/workflows/testing.yml"><img src="https://img.shields.io/github/actions/workflow/status/RDDLab/Django-Chassis/testing.yml?branch=main&label=tests&style=flat-square" alt="Test status"></a>
|
|
23
|
+
<a href="https://results.pre-commit.ci/latest/github/RDDLab/Django-Chassis/main"><img src="https://results.pre-commit.ci/badge/github/RDDLab/Django-Chassis/main.svg" alt="pre-commit.ci status"></a>
|
|
24
|
+
</p>
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
Django-Chassis gives a project a structured `AdminSite`, composable
|
|
30
|
+
`ModelAdmin` options, custom pages, dashboard contracts, and a complete template
|
|
31
|
+
overlay. Domain models and business rules stay in the project; Chassis provides
|
|
32
|
+
the reusable Admin application layer around them.
|
|
33
|
+
|
|
34
|
+
## Features
|
|
35
|
+
|
|
36
|
+
- **Declarative configuration** — compose the Admin with
|
|
37
|
+
`ChassisAdminSiteMixin`, `ChassisAdminMixin`, and immutable `options`.
|
|
38
|
+
- **A polished changelist** — search, filters, date hierarchy, tabs, badges,
|
|
39
|
+
pretty JSON, and decimal-amount presentation without ad-hoc template forks.
|
|
40
|
+
- **Row, list, and object actions** — permission-aware buttons, confirmation, and condition methods.
|
|
41
|
+
- **Related entities and generic tables** — independently paginated tables with `TableOption`.
|
|
42
|
+
- **Custom pages** — permission-aware pages, personal pages, information pages, and timelines.
|
|
43
|
+
- **Dashboard contracts** — metrics, charts, alerts, actions, a four-column grid, and live refresh at `dashboard/live/`.
|
|
44
|
+
- **Import/export** — JSON/XML in, JSON/XML/CSV/XLSX out, preview/apply, history, optional Celery.
|
|
45
|
+
- **Users and security** — profiles, sessions, login-attempt limits, GeoIP country detection, and an Admin audit journal.
|
|
46
|
+
- **Fully typed** — ships `py.typed` and is checked with Pyrefly in strict mode.
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pip install django-chassis
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Version `1.0.1` requires Python 3.13 or 3.14 and Django 6.0+.
|
|
55
|
+
|
|
56
|
+
Put `'django_chassis'` **before** `'django.contrib.admin'` so package templates overlay the stock Admin:
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
INSTALLED_APPS = [
|
|
60
|
+
'django_chassis',
|
|
61
|
+
'django.contrib.admin',
|
|
62
|
+
# ...
|
|
63
|
+
]
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Background import/export is optional:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
pip install 'django-chassis[celery]'
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
For a production HTTP server, Chassis also provides a Gunicorn management
|
|
73
|
+
command:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
python manage.py run_gunicorn --port=8000 --workers=2
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Quick start
|
|
80
|
+
|
|
81
|
+
Create a Chassis `AdminSite`, register a model, and mount the site in `urls.py`:
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
from django.contrib.admin import AdminSite, ModelAdmin
|
|
85
|
+
from django.urls import path
|
|
86
|
+
from django.utils.translation import gettext_lazy as _
|
|
87
|
+
|
|
88
|
+
from django_chassis.mixins import ChassisAdminMixin, ChassisAdminSiteMixin
|
|
89
|
+
from django_chassis.options import RowActionsOption, SearchOption
|
|
90
|
+
|
|
91
|
+
from catalog.models import Book
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class CustomAdminSite(ChassisAdminSiteMixin, AdminSite):
|
|
95
|
+
chassis_brand_name = _('My project')
|
|
96
|
+
chassis_brand_logo_static_path = 'img/logo.png'
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
admin_site = CustomAdminSite(name='admin')
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class BookAdmin(ChassisAdminMixin, ModelAdmin):
|
|
103
|
+
options = [SearchOption(fields=['title', 'isbn']), RowActionsOption()]
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
admin_site.register(Book, BookAdmin)
|
|
107
|
+
|
|
108
|
+
urlpatterns = [path('admin/', admin_site.urls)]
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
> `ChassisAdminSiteMixin` and `ChassisAdminMixin` must come before their Django
|
|
112
|
+
> classes in the MRO.
|
|
113
|
+
|
|
114
|
+
## Documentation
|
|
115
|
+
|
|
116
|
+
Read the full guides, architecture notes, option reference, and dashboard
|
|
117
|
+
contracts at **[django-chassis.rdd-lab.com](https://django-chassis.rdd-lab.com/)**.
|
|
118
|
+
|
|
119
|
+
## Testing
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
uv sync --group dev
|
|
123
|
+
uv run pytest
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## License
|
|
127
|
+
|
|
128
|
+
Distributed under the [MIT License](https://opensource.org/licenses/MIT).
|
|
129
|
+
|
|
130
|
+
## Support the project
|
|
131
|
+
|
|
132
|
+
<a href="https://nowpayments.io/donation?api_key=7664bfa5-ea12-4ded-9c3b-8a498d437114" target="_blank" rel="noreferrer noopener">
|
|
133
|
+
<img src="https://nowpayments.io/images/embeds/donation-button-white.svg" alt="Cryptocurrency & Bitcoin donation button by NOWPayments">
|
|
134
|
+
</a>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from django_chassis.admins.admin_audit_log import AdminAuditLogAdmin
|
|
2
|
+
from django_chassis.admins.group import GroupAdmin
|
|
3
|
+
from django_chassis.admins.login_attempt import LoginAttemptAdmin
|
|
4
|
+
from django_chassis.admins.login_attempt_schedule import LoginAttemptScheduleAdmin
|
|
5
|
+
from django_chassis.admins.user import UserAdmin
|
|
6
|
+
from django_chassis.admins.user_session import UserSessionAdmin
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
'AdminAuditLogAdmin',
|
|
10
|
+
'GroupAdmin',
|
|
11
|
+
'LoginAttemptAdmin',
|
|
12
|
+
'LoginAttemptScheduleAdmin',
|
|
13
|
+
'UserAdmin',
|
|
14
|
+
'UserSessionAdmin'
|
|
15
|
+
]
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
from django.contrib import admin
|
|
2
|
+
from django.db.models import Model
|
|
3
|
+
from django.http import HttpRequest
|
|
4
|
+
from django.utils.translation import gettext_lazy as _
|
|
5
|
+
|
|
6
|
+
from django_chassis.mixins.admin import ChassisAdminMixin
|
|
7
|
+
from django_chassis.mixins.read_only_admin import ReadOnlyAdminMixin
|
|
8
|
+
from django_chassis.options import FiltersOption, SearchOption
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class AdminAuditLogAdmin(ChassisAdminMixin, ReadOnlyAdminMixin, admin.ModelAdmin):
|
|
12
|
+
"""
|
|
13
|
+
Просматривать журнал HTTP-действий Django Admin.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
options = [
|
|
17
|
+
SearchOption(fields=['username', 'path', 'object_repr', 'client_ip']),
|
|
18
|
+
FiltersOption(fields=['action', 'result', 'is_superuser'])
|
|
19
|
+
]
|
|
20
|
+
fieldsets = [
|
|
21
|
+
(
|
|
22
|
+
_('Действие'),
|
|
23
|
+
{
|
|
24
|
+
'classes': ['wide'],
|
|
25
|
+
'fields': [
|
|
26
|
+
'id',
|
|
27
|
+
'user',
|
|
28
|
+
'username',
|
|
29
|
+
'is_superuser',
|
|
30
|
+
'action',
|
|
31
|
+
'result',
|
|
32
|
+
'action_name',
|
|
33
|
+
'created_at',
|
|
34
|
+
'completed_at',
|
|
35
|
+
'status_code',
|
|
36
|
+
'response_time_ms'
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
),
|
|
40
|
+
(
|
|
41
|
+
_('Объект'),
|
|
42
|
+
{
|
|
43
|
+
'classes': ['wide'],
|
|
44
|
+
'fields': ['app_label', 'model_name', 'object_id', 'object_repr', 'object_count', 'changes']
|
|
45
|
+
}
|
|
46
|
+
),
|
|
47
|
+
(
|
|
48
|
+
_('Запрос'),
|
|
49
|
+
{
|
|
50
|
+
'classes': ['wide'],
|
|
51
|
+
'fields': [
|
|
52
|
+
'method',
|
|
53
|
+
'path',
|
|
54
|
+
'route_name',
|
|
55
|
+
'query_params',
|
|
56
|
+
'client_ip',
|
|
57
|
+
'remote_ip',
|
|
58
|
+
'forwarded_for',
|
|
59
|
+
'user_agent',
|
|
60
|
+
'browser',
|
|
61
|
+
'operating_system',
|
|
62
|
+
'is_mobile',
|
|
63
|
+
'referer',
|
|
64
|
+
'session_hash'
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
)
|
|
68
|
+
]
|
|
69
|
+
readonly_fields = [
|
|
70
|
+
'id',
|
|
71
|
+
'user',
|
|
72
|
+
'username',
|
|
73
|
+
'is_superuser',
|
|
74
|
+
'action',
|
|
75
|
+
'result',
|
|
76
|
+
'action_name',
|
|
77
|
+
'created_at',
|
|
78
|
+
'completed_at',
|
|
79
|
+
'status_code',
|
|
80
|
+
'response_time_ms',
|
|
81
|
+
'app_label',
|
|
82
|
+
'model_name',
|
|
83
|
+
'object_id',
|
|
84
|
+
'object_repr',
|
|
85
|
+
'object_count',
|
|
86
|
+
'changes',
|
|
87
|
+
'method',
|
|
88
|
+
'path',
|
|
89
|
+
'route_name',
|
|
90
|
+
'query_params',
|
|
91
|
+
'client_ip',
|
|
92
|
+
'remote_ip',
|
|
93
|
+
'forwarded_for',
|
|
94
|
+
'user_agent',
|
|
95
|
+
'browser',
|
|
96
|
+
'operating_system',
|
|
97
|
+
'is_mobile',
|
|
98
|
+
'referer',
|
|
99
|
+
'session_hash'
|
|
100
|
+
]
|
|
101
|
+
|
|
102
|
+
def has_view_permission(self, request: HttpRequest, obj: Model | None = None) -> bool:
|
|
103
|
+
"""
|
|
104
|
+
Сохранить стандартную проверку view журнала.
|
|
105
|
+
"""
|
|
106
|
+
del obj
|
|
107
|
+
return getattr(request.user, 'has_perm')('django_chassis.view_adminauditlog')
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
from django.contrib.auth.admin import GroupAdmin as DjangoGroupAdmin
|
|
2
|
+
from django.db.models import Model
|
|
3
|
+
from django.http import HttpRequest
|
|
4
|
+
|
|
5
|
+
from django_chassis.mixins.admin import ChassisAdminMixin
|
|
6
|
+
from django_chassis.options import SearchOption
|
|
7
|
+
from django_chassis.protocols import cast_admin_user
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class GroupAdmin(ChassisAdminMixin, DjangoGroupAdmin):
|
|
11
|
+
"""
|
|
12
|
+
Управлять стандартными группами Django через Chassis Admin.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
options = [SearchOption(fields=['name'])]
|
|
16
|
+
|
|
17
|
+
@classmethod
|
|
18
|
+
def _is_active_staff_superuser(cls, request: HttpRequest) -> bool:
|
|
19
|
+
"""
|
|
20
|
+
Разрешить управление группами только полному суперпользователю.
|
|
21
|
+
"""
|
|
22
|
+
user = cast_admin_user(request.user)
|
|
23
|
+
return user.is_authenticated and user.is_active and user.is_staff and user.is_superuser
|
|
24
|
+
|
|
25
|
+
def has_module_permission(self, request: HttpRequest) -> bool:
|
|
26
|
+
"""
|
|
27
|
+
Скрыть раздел групп от несуперпользователей.
|
|
28
|
+
"""
|
|
29
|
+
return self._is_active_staff_superuser(request)
|
|
30
|
+
|
|
31
|
+
def has_view_permission(self, request: HttpRequest, obj: Model | None = None) -> bool:
|
|
32
|
+
"""
|
|
33
|
+
Закрыть список, карточку и прямые URL групп.
|
|
34
|
+
"""
|
|
35
|
+
del obj
|
|
36
|
+
return self._is_active_staff_superuser(request)
|
|
37
|
+
|
|
38
|
+
def has_add_permission(self, request: HttpRequest) -> bool:
|
|
39
|
+
"""
|
|
40
|
+
Запретить создание групп несуперпользователям.
|
|
41
|
+
"""
|
|
42
|
+
return self._is_active_staff_superuser(request)
|
|
43
|
+
|
|
44
|
+
def has_change_permission(self, request: HttpRequest, obj: Model | None = None) -> bool:
|
|
45
|
+
"""
|
|
46
|
+
Запретить изменение группы несуперпользователям.
|
|
47
|
+
"""
|
|
48
|
+
del obj
|
|
49
|
+
return self._is_active_staff_superuser(request)
|
|
50
|
+
|
|
51
|
+
def has_delete_permission(self, request: HttpRequest, obj: Model | None = None) -> bool:
|
|
52
|
+
"""
|
|
53
|
+
Запретить удаление группы несуперпользователям.
|
|
54
|
+
"""
|
|
55
|
+
del obj
|
|
56
|
+
return self._is_active_staff_superuser(request)
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
from django.contrib import admin, messages
|
|
2
|
+
from django.contrib.auth.base_user import AbstractBaseUser
|
|
3
|
+
from django.db.models import Model
|
|
4
|
+
from django.http import HttpRequest, HttpResponse
|
|
5
|
+
from django.utils.translation import gettext_lazy as _
|
|
6
|
+
|
|
7
|
+
from django_chassis.decorators import object_action
|
|
8
|
+
from django_chassis.enums import ButtonColor
|
|
9
|
+
from django_chassis.mixins.admin import ChassisAdminMixin
|
|
10
|
+
from django_chassis.mixins.read_only_admin import ReadOnlyAdminMixin
|
|
11
|
+
from django_chassis.models.login_attempt import LoginAttempt
|
|
12
|
+
from django_chassis.options import ObjectActionsOption, SearchOption
|
|
13
|
+
from django_chassis.services.login_attempt_limit_service import LoginAttemptLimitService
|
|
14
|
+
from django_chassis.validators.login_attempt_unlock import can_unlock_login_attempt
|
|
15
|
+
|
|
16
|
+
class LoginAttemptAdmin(ChassisAdminMixin, ReadOnlyAdminMixin, admin.ModelAdmin):
|
|
17
|
+
"""
|
|
18
|
+
Просматривать журнал попыток входа и снимать блокировку области.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
options = [SearchOption(fields=['username', 'client_ip', 'browser']), ObjectActionsOption(actions=['unlock_scope'])]
|
|
22
|
+
fieldsets = [
|
|
23
|
+
(_('Попытка'), {'classes': ['wide'], 'fields': [
|
|
24
|
+
'id',
|
|
25
|
+
'username',
|
|
26
|
+
'user',
|
|
27
|
+
'client_ip',
|
|
28
|
+
'browser',
|
|
29
|
+
'attempt_number',
|
|
30
|
+
'is_successful',
|
|
31
|
+
'is_unlock',
|
|
32
|
+
'created_at'
|
|
33
|
+
]})
|
|
34
|
+
]
|
|
35
|
+
readonly_fields = [
|
|
36
|
+
'id',
|
|
37
|
+
'username',
|
|
38
|
+
'user',
|
|
39
|
+
'client_ip',
|
|
40
|
+
'browser',
|
|
41
|
+
'attempt_number',
|
|
42
|
+
'is_successful',
|
|
43
|
+
'is_unlock',
|
|
44
|
+
'created_at'
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
@object_action(
|
|
48
|
+
description=_('Снять блокировку'),
|
|
49
|
+
permission='unlock_loginattempt',
|
|
50
|
+
confirmation=_('Снять блокировку входа для этой области логин/IP/браузер?'),
|
|
51
|
+
color=ButtonColor.WARNING,
|
|
52
|
+
condition=can_unlock_login_attempt
|
|
53
|
+
)
|
|
54
|
+
def unlock_scope(self, request: HttpRequest, obj: LoginAttempt) -> HttpResponse | None:
|
|
55
|
+
"""
|
|
56
|
+
Начать новый цикл ограничений для области этой записи.
|
|
57
|
+
"""
|
|
58
|
+
if not isinstance(request.user, AbstractBaseUser):
|
|
59
|
+
return None
|
|
60
|
+
LoginAttemptLimitService().unlock(username=obj.username, client_ip=obj.client_ip, browser=obj.browser)
|
|
61
|
+
messages.success(request, _('Блокировка входа снята.'))
|
|
62
|
+
return None
|
|
63
|
+
|
|
64
|
+
def has_view_permission(self, request: HttpRequest, obj: Model | None = None) -> bool:
|
|
65
|
+
"""
|
|
66
|
+
Сохранить стандартную проверку view журнала попыток.
|
|
67
|
+
"""
|
|
68
|
+
del obj
|
|
69
|
+
return getattr(request.user, 'has_perm')('django_chassis.view_loginattempt')
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from django.contrib import admin
|
|
2
|
+
from django.db.models import Model
|
|
3
|
+
from django.http import HttpRequest
|
|
4
|
+
from django.utils.translation import gettext_lazy as _
|
|
5
|
+
|
|
6
|
+
from django_chassis.mixins.admin import ChassisAdminMixin
|
|
7
|
+
from django_chassis.mixins.no_delete_admin import NoDeleteAdminMixin
|
|
8
|
+
from django_chassis.models.login_attempt_schedule import LoginAttemptSchedule
|
|
9
|
+
from django_chassis.options import SearchOption
|
|
10
|
+
from django_chassis.protocols import cast_admin_user
|
|
11
|
+
|
|
12
|
+
class LoginAttemptScheduleAdmin(ChassisAdminMixin, NoDeleteAdminMixin, admin.ModelAdmin):
|
|
13
|
+
"""
|
|
14
|
+
Настраивать задержки между попытками локального входа.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
options = [SearchOption(fields=['attempt_number'])]
|
|
18
|
+
fieldsets = [(_('Правило'), {'classes': ['wide'], 'fields': ['attempt_number', 'delay_seconds', 'is_active']})]
|
|
19
|
+
|
|
20
|
+
def has_module_permission(self, request: HttpRequest) -> bool:
|
|
21
|
+
"""
|
|
22
|
+
Показать расписание только суперпользователю.
|
|
23
|
+
"""
|
|
24
|
+
return bool(cast_admin_user(request.user).is_superuser)
|
|
25
|
+
|
|
26
|
+
def has_view_permission(self, request: HttpRequest, obj: Model | None = None) -> bool:
|
|
27
|
+
"""
|
|
28
|
+
Закрыть карточку расписания от несуперпользователей.
|
|
29
|
+
"""
|
|
30
|
+
del obj
|
|
31
|
+
return bool(cast_admin_user(request.user).is_superuser)
|
|
32
|
+
|
|
33
|
+
def has_add_permission(self, request: HttpRequest) -> bool:
|
|
34
|
+
"""
|
|
35
|
+
Разрешить создание правил только суперпользователю.
|
|
36
|
+
"""
|
|
37
|
+
return bool(cast_admin_user(request.user).is_superuser)
|
|
38
|
+
|
|
39
|
+
def has_change_permission(self, request: HttpRequest, obj: Model | None = None) -> bool:
|
|
40
|
+
"""
|
|
41
|
+
Разрешить изменение правил только суперпользователю.
|
|
42
|
+
"""
|
|
43
|
+
del obj
|
|
44
|
+
return bool(cast_admin_user(request.user).is_superuser)
|