fastapi-admin-kit 0.1.2__tar.gz → 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/PKG-INFO +19 -3
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/README.md +16 -1
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/__init__.py +3 -1
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/actions/base.py +2 -6
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/actions/registry.py +1 -3
- fastapi_admin_kit-0.2.0/fastapi_admin_kit/admin/admin_database.py +249 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/admin/admin_router.py +2 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/admin/admin_template.py +19 -30
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/admin/builtin_models.py +70 -50
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/admin/core.py +64 -71
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/admin.py +54 -66
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/api/auth.py +30 -43
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/api/crud.py +9 -8
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/api/deps.py +2 -6
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/api/roles.py +7 -11
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/audit/context.py +1 -1
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/audit/diff.py +6 -6
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/audit/event_bus.py +1 -3
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/audit/models.py +1 -3
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/auth/__init__.py +15 -8
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/auth/backend.py +38 -20
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/auth/csrf.py +30 -9
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/auth/dependencies.py +3 -7
- fastapi_admin_kit-0.2.0/fastapi_admin_kit/auth/hasher.py +43 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/auth/identity.py +9 -11
- fastapi_admin_kit-0.2.0/fastapi_admin_kit/auth/mixins.py +87 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/auth/models.py +56 -65
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/auth/password.py +3 -1
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/auth/permissions.py +11 -10
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/auth/protocol.py +1 -1
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/auth/router.py +1 -1
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/auth/session.py +1 -3
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/auth/totp.py +10 -7
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/auth/views.py +65 -20
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/cli/__init__.py +19 -15
- fastapi_admin_kit-0.2.0/fastapi_admin_kit/cli/helpers.py +103 -0
- fastapi_admin_kit-0.2.0/fastapi_admin_kit/cli/migrate.py +247 -0
- fastapi_admin_kit-0.2.0/fastapi_admin_kit/cli/permissions.py +184 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/cli/scaffold.py +10 -10
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/cli/user.py +36 -56
- fastapi_admin_kit-0.2.0/fastapi_admin_kit/config/auth.py +99 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/config/behavior.py +2 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/config/nav.py +1 -3
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/dashboard/__init__.py +6 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/filters/registry.py +3 -9
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/flash.py +2 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/form/pipeline.py +2 -7
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/inspection/__init__.py +1 -3
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/inspection/registry.py +2 -6
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/inspection.py +1 -3
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/modeladmin.py +7 -20
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/nav.py +6 -12
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/registry/core.py +18 -14
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/registry/validation.py +2 -6
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/router.py +98 -53
- fastapi_admin_kit-0.2.0/fastapi_admin_kit/search_utils.py +71 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/static/css/admin.css +17 -18
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/static/js/admin.js +70 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/templates/macros/form_fields.html +1 -1
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/templates/macros/widgets.html +33 -33
- fastapi_admin_kit-0.2.0/fastapi_admin_kit/templates/pages/403.html +37 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/templates/pages/dashboard.html +31 -4
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/templates/pages/form.html +1 -4
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/templates/pages/login.html +14 -3
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/templates/pages/role_form.html +2 -2
- fastapi_admin_kit-0.2.0/fastapi_admin_kit/templates/pages/search.html +120 -0
- fastapi_admin_kit-0.2.0/fastapi_admin_kit/templates/pages/users/form.html +249 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/templates/partials/_inline_edit_row.html +1 -1
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/templates/partials/field_wrapper.html +1 -1
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/templates/partials/head.html +1 -1
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/templates/partials/head_minimal.html +1 -1
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/templates/partials/list_table.html +1 -1
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/templates/partials/mobile_backdrop.html +1 -1
- fastapi_admin_kit-0.2.0/fastapi_admin_kit/templates/partials/perm_select_widget.html +46 -0
- fastapi_admin_kit-0.2.0/fastapi_admin_kit/templates/partials/permission_widget.html +113 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/templates/partials/scripts.html +1 -1
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/types.py +3 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/validation.py +2 -6
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/views/audit.py +30 -24
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/views/bulk.py +1 -3
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/views/class_views.py +113 -147
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/views/context.py +25 -80
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/views/dashboard.py +63 -26
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/views/delete.py +1 -3
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/views/factory.py +29 -70
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/views/form.py +11 -9
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/views/profile.py +10 -15
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/views/protocols.py +1 -3
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/views/renderers.py +37 -65
- fastapi_admin_kit-0.2.0/fastapi_admin_kit/views/roles.py +310 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/views/search.py +1 -3
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/views/settings.py +1 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/views/sidebar.py +21 -18
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/views/totp.py +7 -16
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/views/users.py +24 -32
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/views.py +15 -15
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/widgets/inputs.py +2 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/widgets/registry.py +1 -3
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/widgets/relation.py +11 -1
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/pyproject.toml +3 -1
- fastapi_admin_kit-0.1.2/fastapi_admin_kit/admin/admin_database.py +0 -147
- fastapi_admin_kit-0.1.2/fastapi_admin_kit/config/auth.py +0 -54
- fastapi_admin_kit-0.1.2/fastapi_admin_kit/templates/pages/users/form.html +0 -229
- fastapi_admin_kit-0.1.2/fastapi_admin_kit/templates/partials/permission_widget.html +0 -86
- fastapi_admin_kit-0.1.2/fastapi_admin_kit/views/roles.py +0 -259
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/.gitignore +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/LICENSE +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/actions/__init__.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/admin/__init__.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/admin/admin_config.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/admin/decorators.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/admin/state.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/api/__init__.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/api/schema_generator.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/api/schemas.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/api/search.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/audit/__init__.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/audit/events.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/audit/listener.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/audit/logger.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/audit/middleware.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/audit/sqlalchemy_logger.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/auth/ratelimit.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/cli/__main__.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/config/__init__.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/config/audit.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/config/database.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/config/storage.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/config/theme.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/config/ui.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/db.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/exceptions.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/field_types.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/filters/__init__.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/filters/base.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/form/__init__.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/models/__init__.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/models/base.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/pagination/__init__.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/pagination/base.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/pagination/cursor.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/pagination/dynamic.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/pagination/offset.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/plugins/__init__.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/py.typed +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/registry/__init__.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/registry.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/static/css/presets.css +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/static/css/tokens.css +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/static/css/variables.css +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/static/icons/heroicons.svg +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/static/js/htmx-config.js +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/storage/__init__.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/storage/base.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/storage/local.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/templates/base.html +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/templates/macros/icons.html +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/templates/macros/table.html +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/templates/pages/2fa/setup.html +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/templates/pages/2fa/verify.html +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/templates/pages/audit_detail.html +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/templates/pages/audit_log.html +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/templates/pages/detail.html +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/templates/pages/list.html +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/templates/pages/profile/password.html +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/templates/pages/profile/profile.html +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/templates/pages/roles/form.html +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/templates/pages/roles/list.html +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/templates/pages/roles.html +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/templates/pages/settings/theme.html +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/templates/pages/users/list.html +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/templates/partials/command_palette.html +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/templates/partials/flash_messages.html +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/templates/partials/inline_edit_form.html +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/templates/partials/pagination.html +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/templates/partials/sidebar.html +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/templates/partials/topbar.html +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/views/__init__.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/views/extra.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/views/list.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/widgets/__init__.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/widgets/base.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/widgets/resolver.py +0 -0
- {fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/mkdocs.yml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fastapi-admin-kit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Drop-in admin panel for FastAPI + SQLAlchemy + SQLModel apps
|
|
5
5
|
Project-URL: Homepage, https://github.com/borhanst/fastapi-admin-kit
|
|
6
6
|
Project-URL: Documentation, https://borhanst.github.io/fastapi-admin-kit/
|
|
@@ -25,7 +25,7 @@ Classifier: Typing :: Typed
|
|
|
25
25
|
Requires-Python: >=3.11
|
|
26
26
|
Requires-Dist: aiosqlite>=0.20.0
|
|
27
27
|
Requires-Dist: bcrypt>=4.0.0
|
|
28
|
-
Requires-Dist: fastapi>=0.
|
|
28
|
+
Requires-Dist: fastapi>=0.100.0
|
|
29
29
|
Requires-Dist: itsdangerous>=2.2.0
|
|
30
30
|
Requires-Dist: jinja2>=3.1.0
|
|
31
31
|
Requires-Dist: pyjwt>=2.13.0
|
|
@@ -35,6 +35,7 @@ Requires-Dist: uvicorn>=0.30.0
|
|
|
35
35
|
Provides-Extra: dev
|
|
36
36
|
Requires-Dist: hatch>=1.13.0; extra == 'dev'
|
|
37
37
|
Requires-Dist: httpx>=0.27.0; extra == 'dev'
|
|
38
|
+
Requires-Dist: pre-commit>=3.5.0; extra == 'dev'
|
|
38
39
|
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
|
|
39
40
|
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
40
41
|
Requires-Dist: ruff>=0.5.0; extra == 'dev'
|
|
@@ -92,16 +93,29 @@ from contextlib import asynccontextmanager
|
|
|
92
93
|
from fastapi import FastAPI
|
|
93
94
|
from sqlalchemy import Column, Float, Integer, String
|
|
94
95
|
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
|
|
95
|
-
from sqlalchemy.orm import DeclarativeBase, sessionmaker
|
|
96
|
+
from sqlalchemy.orm import DeclarativeBase, relationship, sessionmaker
|
|
96
97
|
|
|
97
98
|
from fastapi_admin_kit import Admin
|
|
98
99
|
from fastapi_admin_kit.auth.backend import BuiltinAuthBackend
|
|
100
|
+
from fastapi_admin_kit.auth.mixins import AuthModelMixin
|
|
101
|
+
from fastapi_admin_kit.auth.models import Role, admin_user_roles
|
|
99
102
|
|
|
100
103
|
|
|
101
104
|
class Base(DeclarativeBase):
|
|
102
105
|
pass
|
|
103
106
|
|
|
104
107
|
|
|
108
|
+
class User(AuthModelMixin, Base):
|
|
109
|
+
__tablename__ = "users"
|
|
110
|
+
id = Column(Integer, primary_key=True)
|
|
111
|
+
email = Column(String(255), unique=True, nullable=False)
|
|
112
|
+
full_name = Column(String(255))
|
|
113
|
+
|
|
114
|
+
roles = relationship(
|
|
115
|
+
"Role", secondary=admin_user_roles, back_populates="users"
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
|
|
105
119
|
class Product(Base):
|
|
106
120
|
__tablename__ = "products"
|
|
107
121
|
id = Column(Integer, primary_key=True)
|
|
@@ -120,6 +134,7 @@ async_session = sessionmaker(engine, class_=AsyncSession)
|
|
|
120
134
|
async def lifespan(app: FastAPI):
|
|
121
135
|
async with engine.begin() as conn:
|
|
122
136
|
await conn.run_sync(Base.metadata.create_all)
|
|
137
|
+
await admin.setup()
|
|
123
138
|
yield
|
|
124
139
|
await engine.dispose()
|
|
125
140
|
|
|
@@ -130,6 +145,7 @@ admin = Admin(
|
|
|
130
145
|
engine=engine,
|
|
131
146
|
base=Base,
|
|
132
147
|
secret_key=SECRET_KEY,
|
|
148
|
+
auth_model=User,
|
|
133
149
|
auth_backend=BuiltinAuthBackend(),
|
|
134
150
|
)
|
|
135
151
|
admin.register(Product)
|
|
@@ -40,16 +40,29 @@ from contextlib import asynccontextmanager
|
|
|
40
40
|
from fastapi import FastAPI
|
|
41
41
|
from sqlalchemy import Column, Float, Integer, String
|
|
42
42
|
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
|
|
43
|
-
from sqlalchemy.orm import DeclarativeBase, sessionmaker
|
|
43
|
+
from sqlalchemy.orm import DeclarativeBase, relationship, sessionmaker
|
|
44
44
|
|
|
45
45
|
from fastapi_admin_kit import Admin
|
|
46
46
|
from fastapi_admin_kit.auth.backend import BuiltinAuthBackend
|
|
47
|
+
from fastapi_admin_kit.auth.mixins import AuthModelMixin
|
|
48
|
+
from fastapi_admin_kit.auth.models import Role, admin_user_roles
|
|
47
49
|
|
|
48
50
|
|
|
49
51
|
class Base(DeclarativeBase):
|
|
50
52
|
pass
|
|
51
53
|
|
|
52
54
|
|
|
55
|
+
class User(AuthModelMixin, Base):
|
|
56
|
+
__tablename__ = "users"
|
|
57
|
+
id = Column(Integer, primary_key=True)
|
|
58
|
+
email = Column(String(255), unique=True, nullable=False)
|
|
59
|
+
full_name = Column(String(255))
|
|
60
|
+
|
|
61
|
+
roles = relationship(
|
|
62
|
+
"Role", secondary=admin_user_roles, back_populates="users"
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
53
66
|
class Product(Base):
|
|
54
67
|
__tablename__ = "products"
|
|
55
68
|
id = Column(Integer, primary_key=True)
|
|
@@ -68,6 +81,7 @@ async_session = sessionmaker(engine, class_=AsyncSession)
|
|
|
68
81
|
async def lifespan(app: FastAPI):
|
|
69
82
|
async with engine.begin() as conn:
|
|
70
83
|
await conn.run_sync(Base.metadata.create_all)
|
|
84
|
+
await admin.setup()
|
|
71
85
|
yield
|
|
72
86
|
await engine.dispose()
|
|
73
87
|
|
|
@@ -78,6 +92,7 @@ admin = Admin(
|
|
|
78
92
|
engine=engine,
|
|
79
93
|
base=Base,
|
|
80
94
|
secret_key=SECRET_KEY,
|
|
95
|
+
auth_model=User,
|
|
81
96
|
auth_backend=BuiltinAuthBackend(),
|
|
82
97
|
)
|
|
83
98
|
admin.register(Product)
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from fastapi_admin_kit.admin import Admin
|
|
4
4
|
from fastapi_admin_kit.admin.decorators import column
|
|
5
|
+
from fastapi_admin_kit.auth.mixins import AuthModelMixin
|
|
5
6
|
from fastapi_admin_kit.config import DatabaseConfig, DatabaseType
|
|
6
7
|
from fastapi_admin_kit.exceptions import ConfigError
|
|
7
8
|
from fastapi_admin_kit.nav import (
|
|
@@ -40,6 +41,7 @@ from fastapi_admin_kit.views import (
|
|
|
40
41
|
__all__ = [
|
|
41
42
|
"Admin",
|
|
42
43
|
"AdminRegistry",
|
|
44
|
+
"AuthModelMixin",
|
|
43
45
|
"ConfigError",
|
|
44
46
|
"DatabaseConfig",
|
|
45
47
|
"DatabaseType",
|
|
@@ -73,4 +75,4 @@ __all__ = [
|
|
|
73
75
|
# Per-model assets
|
|
74
76
|
"AdminExtra",
|
|
75
77
|
]
|
|
76
|
-
__version__ = "0.
|
|
78
|
+
__version__ = "0.2.0"
|
|
@@ -36,9 +36,7 @@ class Action(ABC):
|
|
|
36
36
|
self.description = description
|
|
37
37
|
|
|
38
38
|
@abstractmethod
|
|
39
|
-
async def execute(
|
|
40
|
-
self, objects: list[Any], request: Request | None
|
|
41
|
-
) -> None:
|
|
39
|
+
async def execute(self, objects: list[Any], request: Request | None) -> None:
|
|
42
40
|
"""Run the action against the selected objects."""
|
|
43
41
|
...
|
|
44
42
|
|
|
@@ -58,9 +56,7 @@ class Action(ABC):
|
|
|
58
56
|
class ModelAction(Action):
|
|
59
57
|
"""Action that operates on a single model instance (row/detail actions)."""
|
|
60
58
|
|
|
61
|
-
async def execute_single(
|
|
62
|
-
self, obj: Any, request: Request | None
|
|
63
|
-
) -> None:
|
|
59
|
+
async def execute_single(self, obj: Any, request: Request | None) -> None:
|
|
64
60
|
"""Run the action on a single object.
|
|
65
61
|
|
|
66
62
|
Override this instead of execute for single-object actions.
|
|
@@ -19,9 +19,7 @@ class DeleteSelectedAction(Action):
|
|
|
19
19
|
confirmation_message="Are you sure you want to delete the selected items?",
|
|
20
20
|
)
|
|
21
21
|
|
|
22
|
-
async def execute(
|
|
23
|
-
self, objects: list[Any], request: Request | None
|
|
24
|
-
) -> None:
|
|
22
|
+
async def execute(self, objects: list[Any], request: Request | None) -> None:
|
|
25
23
|
# Actual deletion is handled by the existing bulk handler in views/factory.py
|
|
26
24
|
pass
|
|
27
25
|
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
"""Admin database setup and initialization."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from fastapi_admin_kit.config.database import DatabaseConfig
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class AdminDatabase:
|
|
11
|
+
"""Handles database setup, table creation, and role seeding."""
|
|
12
|
+
|
|
13
|
+
def __init__(
|
|
14
|
+
self,
|
|
15
|
+
engine: Any | None = None,
|
|
16
|
+
base: Any | None = None,
|
|
17
|
+
database_config: DatabaseConfig | None = None,
|
|
18
|
+
):
|
|
19
|
+
self.engine = engine
|
|
20
|
+
self.base = base
|
|
21
|
+
self.database_config = database_config
|
|
22
|
+
|
|
23
|
+
def _ensure_engine(self) -> Any:
|
|
24
|
+
"""
|
|
25
|
+
Create the async engine from ``database_config`` if no engine is set.
|
|
26
|
+
"""
|
|
27
|
+
if self.engine is None and self.database_config is not None:
|
|
28
|
+
self.engine = self.database_config.create_engine()
|
|
29
|
+
return self.engine
|
|
30
|
+
|
|
31
|
+
async def _create_tables(self) -> None:
|
|
32
|
+
"""Create all admin database tables (async-safe)."""
|
|
33
|
+
from sqlalchemy.ext.asyncio import AsyncEngine
|
|
34
|
+
|
|
35
|
+
from fastapi_admin_kit.audit import (
|
|
36
|
+
models as _audit_models, # noqa: F401
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
# Import models to register them with metadata
|
|
40
|
+
from fastapi_admin_kit.auth import models as _auth_models # noqa: F401
|
|
41
|
+
from fastapi_admin_kit.models.base import Base as AdminBase
|
|
42
|
+
|
|
43
|
+
if isinstance(self.engine, AsyncEngine):
|
|
44
|
+
# Async engine - use run_sync
|
|
45
|
+
async with self.engine.begin() as conn:
|
|
46
|
+
# Create admin tables
|
|
47
|
+
await conn.run_sync(AdminBase.metadata.create_all)
|
|
48
|
+
# Create user tables if Base is provided
|
|
49
|
+
if self.base is not None:
|
|
50
|
+
await conn.run_sync(self.base.metadata.create_all)
|
|
51
|
+
# Auto-migrate: add missing columns
|
|
52
|
+
await conn.run_sync(self._auto_migrate, AdminBase.metadata)
|
|
53
|
+
if self.base is not None:
|
|
54
|
+
await conn.run_sync(self._auto_migrate, self.base.metadata)
|
|
55
|
+
else:
|
|
56
|
+
# Sync engine - direct call
|
|
57
|
+
AdminBase.metadata.create_all(bind=self.engine)
|
|
58
|
+
if self.base is not None:
|
|
59
|
+
self.base.metadata.create_all(bind=self.engine)
|
|
60
|
+
# Auto-migrate: add missing columns
|
|
61
|
+
self._auto_migrate_sync(AdminBase.metadata)
|
|
62
|
+
if self.base is not None:
|
|
63
|
+
self._auto_migrate_sync(self.base.metadata)
|
|
64
|
+
|
|
65
|
+
def _auto_migrate_sync(self, metadata: Any) -> None:
|
|
66
|
+
"""Sync version of auto-migrate."""
|
|
67
|
+
from sqlalchemy import inspect as sa_inspect
|
|
68
|
+
from sqlalchemy import text
|
|
69
|
+
|
|
70
|
+
inspector = sa_inspect(self.engine)
|
|
71
|
+
for table_name, table in metadata.tables.items():
|
|
72
|
+
if not inspector.has_table(table_name):
|
|
73
|
+
continue
|
|
74
|
+
existing_cols = {c["name"] for c in inspector.get_columns(table_name)}
|
|
75
|
+
for col in table.columns:
|
|
76
|
+
if col.name not in existing_cols:
|
|
77
|
+
col_type = col.type.compile(self.engine.dialect)
|
|
78
|
+
nullable = "NULL" if col.nullable else "NOT NULL"
|
|
79
|
+
default = ""
|
|
80
|
+
if col.server_default is not None:
|
|
81
|
+
default_sql = col.server_default.arg
|
|
82
|
+
if hasattr(default_sql, "text"):
|
|
83
|
+
default_sql = default_sql.text
|
|
84
|
+
default = f" DEFAULT {default_sql}"
|
|
85
|
+
elif col.default is not None and col.default.is_seq:
|
|
86
|
+
pass
|
|
87
|
+
sql = text(
|
|
88
|
+
f"""ALTER TABLE {table_name}
|
|
89
|
+
ADD COLUMN {col.name} {col_type}
|
|
90
|
+
{nullable}{default}"""
|
|
91
|
+
)
|
|
92
|
+
with self.engine.begin() as conn:
|
|
93
|
+
conn.execute(sql)
|
|
94
|
+
|
|
95
|
+
def _auto_migrate(self, sync_conn: Any, metadata: Any) -> None:
|
|
96
|
+
"""
|
|
97
|
+
Add missing columns to existing tables (sync, called via run_sync).
|
|
98
|
+
"""
|
|
99
|
+
from sqlalchemy import inspect as sa_inspect
|
|
100
|
+
from sqlalchemy import text
|
|
101
|
+
|
|
102
|
+
dialect = sync_conn.dialect if hasattr(sync_conn, "dialect") else None
|
|
103
|
+
if dialect is None:
|
|
104
|
+
return
|
|
105
|
+
|
|
106
|
+
inspector = sa_inspect(sync_conn)
|
|
107
|
+
for table_name, table in metadata.tables.items():
|
|
108
|
+
if not inspector.has_table(table_name):
|
|
109
|
+
continue
|
|
110
|
+
existing_cols = {c["name"] for c in inspector.get_columns(table_name)}
|
|
111
|
+
for col in table.columns:
|
|
112
|
+
if col.name not in existing_cols:
|
|
113
|
+
col_type = col.type.compile(dialect)
|
|
114
|
+
nullable = "NULL" if col.nullable else "NOT NULL"
|
|
115
|
+
default = ""
|
|
116
|
+
if col.server_default is not None:
|
|
117
|
+
default_sql = col.server_default.arg
|
|
118
|
+
if hasattr(default_sql, "text"):
|
|
119
|
+
default_sql = default_sql.text
|
|
120
|
+
default = f" DEFAULT {default_sql}"
|
|
121
|
+
elif not col.nullable:
|
|
122
|
+
# SQLite requires a default for NOT NULL columns being added
|
|
123
|
+
type_defaults = {
|
|
124
|
+
"VARCHAR": "''", "TEXT": "''", "INTEGER": "0",
|
|
125
|
+
"FLOAT": "0.0", "BOOLEAN": "0", "DATETIME": "''",
|
|
126
|
+
}
|
|
127
|
+
sql_type = col_type.upper().split("(")[0]
|
|
128
|
+
temp_val = type_defaults.get(sql_type, "''")
|
|
129
|
+
default = f" DEFAULT {temp_val}"
|
|
130
|
+
sql = text(
|
|
131
|
+
f"""ALTER TABLE {table_name}
|
|
132
|
+
ADD COLUMN
|
|
133
|
+
{col.name} {col_type} {nullable}{default}
|
|
134
|
+
"""
|
|
135
|
+
)
|
|
136
|
+
sync_conn.execute(sql)
|
|
137
|
+
|
|
138
|
+
async def _seed_roles(self, seed_roles: list, seed_roles_overwrite: bool = False) -> None:
|
|
139
|
+
"""Seed default roles if none exist (or if overwrite is enabled)."""
|
|
140
|
+
from sqlalchemy import select
|
|
141
|
+
from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession
|
|
142
|
+
from sqlalchemy.orm import Session, sessionmaker
|
|
143
|
+
|
|
144
|
+
from fastapi_admin_kit.auth.models import Permission, Role
|
|
145
|
+
|
|
146
|
+
is_async = isinstance(self.engine, AsyncEngine)
|
|
147
|
+
|
|
148
|
+
if is_async:
|
|
149
|
+
# Use AsyncSession for async engine
|
|
150
|
+
session_local = sessionmaker(self.engine, class_=AsyncSession, expire_on_commit=False)
|
|
151
|
+
async with session_local() as session:
|
|
152
|
+
# Check existing count
|
|
153
|
+
result = await session.execute(select(Role))
|
|
154
|
+
existing_count = len(result.scalars().all())
|
|
155
|
+
|
|
156
|
+
if existing_count > 0 and not seed_roles_overwrite:
|
|
157
|
+
return
|
|
158
|
+
|
|
159
|
+
if seed_roles_overwrite:
|
|
160
|
+
await session.execute(select(Role).delete())
|
|
161
|
+
|
|
162
|
+
for role_spec in seed_roles:
|
|
163
|
+
role = Role(name=role_spec.name, description=role_spec.description)
|
|
164
|
+
session.add(role)
|
|
165
|
+
await session.flush() # get role.id
|
|
166
|
+
# Eagerly load M2M relationship for async session
|
|
167
|
+
await session.refresh(role, ["permissions"])
|
|
168
|
+
|
|
169
|
+
if role_spec.permissions:
|
|
170
|
+
for table_name, perms in role_spec.permissions.items():
|
|
171
|
+
# Find or create permission for this table
|
|
172
|
+
from sqlalchemy import select as sa_select
|
|
173
|
+
|
|
174
|
+
result = await session.execute(
|
|
175
|
+
sa_select(Permission).filter_by(table_name=table_name)
|
|
176
|
+
)
|
|
177
|
+
existing = result.scalar_one_or_none()
|
|
178
|
+
if existing is None:
|
|
179
|
+
perm = Permission(
|
|
180
|
+
name=table_name,
|
|
181
|
+
table_name=table_name,
|
|
182
|
+
can_view=perms.get("view", False),
|
|
183
|
+
can_create=perms.get("create", False),
|
|
184
|
+
can_edit=perms.get("edit", False),
|
|
185
|
+
can_delete=perms.get("delete", False),
|
|
186
|
+
)
|
|
187
|
+
session.add(perm)
|
|
188
|
+
await session.flush()
|
|
189
|
+
else:
|
|
190
|
+
perm = existing
|
|
191
|
+
# Link permission to role via M2M
|
|
192
|
+
role.permissions.append(perm)
|
|
193
|
+
|
|
194
|
+
await session.commit()
|
|
195
|
+
else:
|
|
196
|
+
# Use sync Session for sync engine
|
|
197
|
+
session = Session(bind=self.engine)
|
|
198
|
+
try:
|
|
199
|
+
existing_count = session.query(Role).count()
|
|
200
|
+
|
|
201
|
+
if existing_count > 0 and not seed_roles_overwrite:
|
|
202
|
+
return
|
|
203
|
+
|
|
204
|
+
if seed_roles_overwrite:
|
|
205
|
+
session.query(Role).delete()
|
|
206
|
+
|
|
207
|
+
for role_spec in seed_roles:
|
|
208
|
+
role = Role(name=role_spec.name, description=role_spec.description)
|
|
209
|
+
session.add(role)
|
|
210
|
+
session.flush() # get role.id
|
|
211
|
+
|
|
212
|
+
if role_spec.permissions:
|
|
213
|
+
for table_name, perms in role_spec.permissions.items():
|
|
214
|
+
# Find or create permission for this table
|
|
215
|
+
existing = (
|
|
216
|
+
session.query(Permission).filter_by(table_name=table_name).first()
|
|
217
|
+
)
|
|
218
|
+
if existing is None:
|
|
219
|
+
perm = Permission(
|
|
220
|
+
name=table_name,
|
|
221
|
+
table_name=table_name,
|
|
222
|
+
can_view=perms.get("view", False),
|
|
223
|
+
can_create=perms.get("create", False),
|
|
224
|
+
can_edit=perms.get("edit", False),
|
|
225
|
+
can_delete=perms.get("delete", False),
|
|
226
|
+
)
|
|
227
|
+
session.add(perm)
|
|
228
|
+
session.flush()
|
|
229
|
+
else:
|
|
230
|
+
perm = existing
|
|
231
|
+
# Link permission to role via M2M
|
|
232
|
+
role.permissions.append(perm)
|
|
233
|
+
|
|
234
|
+
session.commit()
|
|
235
|
+
finally:
|
|
236
|
+
session.close()
|
|
237
|
+
|
|
238
|
+
def _init_session_backend(
|
|
239
|
+
self, secret_key: str, session_ttl: int, cookie_name: str, secure: bool
|
|
240
|
+
) -> Any:
|
|
241
|
+
"""Create and store the signed-cookie session backend."""
|
|
242
|
+
from fastapi_admin_kit.auth.session import SignedCookieSessionBackend
|
|
243
|
+
|
|
244
|
+
return SignedCookieSessionBackend(
|
|
245
|
+
secret_key=secret_key,
|
|
246
|
+
session_ttl=session_ttl,
|
|
247
|
+
cookie_name=cookie_name,
|
|
248
|
+
secure=secure,
|
|
249
|
+
)
|
|
@@ -29,6 +29,8 @@ class AdminRouter:
|
|
|
29
29
|
registry = AdminRegistry()
|
|
30
30
|
|
|
31
31
|
for registered in registry.all():
|
|
32
|
+
if getattr(registered.admin, "skip_auto_routes", False):
|
|
33
|
+
continue
|
|
32
34
|
model_router = build_model_router(registered)
|
|
33
35
|
app.include_router(model_router, prefix=self.admin_path)
|
|
34
36
|
|
{fastapi_admin_kit-0.1.2 → fastapi_admin_kit-0.2.0}/fastapi_admin_kit/admin/admin_template.py
RENAMED
|
@@ -84,48 +84,41 @@ class AdminTemplate:
|
|
|
84
84
|
|
|
85
85
|
if user and not is_superuser:
|
|
86
86
|
role_ids = (
|
|
87
|
-
snapshot.get("role_ids", [])
|
|
88
|
-
if snapshot
|
|
89
|
-
else getattr(user, "role_ids", [])
|
|
87
|
+
snapshot.get("role_ids", []) if snapshot else getattr(user, "role_ids", [])
|
|
90
88
|
)
|
|
91
89
|
if role_ids:
|
|
92
90
|
try:
|
|
93
91
|
from sqlalchemy import select
|
|
94
92
|
from sqlalchemy.orm import Session
|
|
95
93
|
|
|
96
|
-
from fastapi_admin_kit.auth.models import
|
|
94
|
+
from fastapi_admin_kit.auth.models import Permission, admin_role_permissions
|
|
97
95
|
|
|
98
96
|
engine = request.app.state.admin_engine
|
|
99
97
|
with Session(engine) as s:
|
|
100
98
|
result = s.execute(
|
|
101
|
-
select(
|
|
102
|
-
|
|
99
|
+
select(Permission)
|
|
100
|
+
.join(
|
|
101
|
+
admin_role_permissions,
|
|
102
|
+
Permission.id == admin_role_permissions.c.permission_id,
|
|
103
103
|
)
|
|
104
|
+
.filter(admin_role_permissions.c.role_id.in_(role_ids))
|
|
104
105
|
)
|
|
105
106
|
rows = result.scalars().all()
|
|
106
107
|
for perm in rows:
|
|
107
108
|
if perm.table_name in permissions_map:
|
|
108
109
|
existing = permissions_map[perm.table_name]
|
|
109
|
-
permissions_map[perm.table_name] = (
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
or perm.can_create,
|
|
115
|
-
can_edit=existing.can_edit
|
|
116
|
-
or perm.can_edit,
|
|
117
|
-
can_delete=existing.can_delete
|
|
118
|
-
or perm.can_delete,
|
|
119
|
-
)
|
|
110
|
+
permissions_map[perm.table_name] = PermissionSet(
|
|
111
|
+
can_view=existing.can_view or perm.can_view,
|
|
112
|
+
can_create=existing.can_create or perm.can_create,
|
|
113
|
+
can_edit=existing.can_edit or perm.can_edit,
|
|
114
|
+
can_delete=existing.can_delete or perm.can_delete,
|
|
120
115
|
)
|
|
121
116
|
else:
|
|
122
|
-
permissions_map[perm.table_name] = (
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
can_delete=perm.can_delete,
|
|
128
|
-
)
|
|
117
|
+
permissions_map[perm.table_name] = PermissionSet(
|
|
118
|
+
can_view=perm.can_view,
|
|
119
|
+
can_create=perm.can_create,
|
|
120
|
+
can_edit=perm.can_edit,
|
|
121
|
+
can_delete=perm.can_delete,
|
|
129
122
|
)
|
|
130
123
|
except Exception:
|
|
131
124
|
pass
|
|
@@ -147,9 +140,7 @@ class AdminTemplate:
|
|
|
147
140
|
for item in items:
|
|
148
141
|
if not _item_visible(item):
|
|
149
142
|
continue
|
|
150
|
-
filtered_children = (
|
|
151
|
-
_filter_items(item.children) if item.children else []
|
|
152
|
-
)
|
|
143
|
+
filtered_children = _filter_items(item.children) if item.children else []
|
|
153
144
|
result.append(replace(item, children=filtered_children))
|
|
154
145
|
return result
|
|
155
146
|
|
|
@@ -195,9 +186,7 @@ class AdminTemplate:
|
|
|
195
186
|
"settings_visible": settings_visible,
|
|
196
187
|
}
|
|
197
188
|
|
|
198
|
-
def apply_sidebar_context(
|
|
199
|
-
self, request: Any, user: Any, context: dict
|
|
200
|
-
) -> dict:
|
|
189
|
+
def apply_sidebar_context(self, request: Any, user: Any, context: dict) -> dict:
|
|
201
190
|
"""Inject nav_groups + permissions_map into a template context dict."""
|
|
202
191
|
context.update(self.build_sidebar_context(request, user=user))
|
|
203
192
|
return context
|