bustapi 0.13.5__tar.gz → 0.13.8__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.
- {bustapi-0.13.5 → bustapi-0.13.8}/CHANGELOG.md +20 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/Cargo.lock +28 -29
- {bustapi-0.13.5 → bustapi-0.13.8}/Cargo.toml +1 -1
- {bustapi-0.13.5 → bustapi-0.13.8}/PKG-INFO +1 -1
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/changelog.md +20 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/pyproject.toml +1 -1
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/__init__.py +1 -1
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/auth/decorators.py +47 -28
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/auth/login.py +13 -3
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/core/helpers.py +1 -3
- bustapi-0.13.8/tests/test_discussion_28.py +87 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/- +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/.github/FUNDING.yml +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/.github/workflows/ci-multiplatform.yml +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/.github/workflows/ci.yml +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/.github/workflows/docs.yml +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/.github/workflows/manual-publish.yml +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/.gitignore +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/.python-version +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/AGENT_KNOWLEDGE.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/Dockerfile +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/LICENSE +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/README.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/benchmarks/CACHE_BENCHMARK.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/benchmarks/README.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/benchmarks/app.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/benchmarks/benchmark_all.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/benchmarks/benchmark_avg.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/benchmarks/benchmark_cache.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/benchmarks/benchmark_combined.png +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/benchmarks/bustapi.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/benchmarks/bustapi_bench.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/benchmarks/bustapi_internal.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/benchmarks/comparison_bench.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/benchmarks/comprehensive_benchmark.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/benchmarks/gen_graph.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/benchmarks/quick_bench.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/benchmarks/resource_bench.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/benchmarks/rps_comparison.png +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/benchmarks/run_comparison_auto.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/benchmarks/ws_benchmark.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/advanced/async.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/advanced/blueprints.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/advanced/dependency_injection.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/advanced/deployment.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/advanced/middleware.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/advanced/security.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/advanced/validation.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/api-reference.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/assets/logo.png +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/complete-api-reference.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/deployment-performance-guide.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/deployment.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/examples-guide.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/index.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/installation.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/overrides/.gitkeep +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/quickstart.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/release_track.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/site/advanced/async_support.html +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/site/advanced/blueprints.html +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/site/advanced/dependency_injection.html +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/site/advanced/middleware.html +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/site/advanced/validation.html +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/site/api/all.html +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/site/api/app.html +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/site/api/context.html +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/site/api/utilities.html +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/site/assets/logo.png +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/site/changelog.html +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/site/core_concepts/request_data.html +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/site/core_concepts/responses.html +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/site/core_concepts/routing.html +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/site/core_concepts/templates.html +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/site/examples/index.html +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/site/getting_started/index.html +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/site/getting_started/quickstart.html +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/site/index.html +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/site/script.js +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/site/style.css +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/stylesheets/extra.css +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/user-guide/authentication.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/user-guide/caching.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/user-guide/cli.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/user-guide/database.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/user-guide/documentation.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/user-guide/error_handling.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/user-guide/jwt.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/user-guide/logging.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/user-guide/multiprocessing.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/user-guide/request_data.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/user-guide/responses.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/user-guide/routing.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/user-guide/sessions.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/user-guide/static_files.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/user-guide/templates.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/user-guide/turbo-routes.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/user-guide/video-streaming.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/docs/websockets.md +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/advanced/08_auto_docs.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/advanced/12_test_modes.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/advanced/13_error_handling.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/advanced/14_middleware.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/advanced/16_middleware_session.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/advanced/20_file_uploads.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/advanced/24_body_and_depends.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/advanced/27_video_stream.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/advanced/28_websocket.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/advanced/29_turbo_websocket.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/basics/01_hello_world.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/basics/02_parameters.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/basics/03_async.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/basics/04_request_data.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/basics/19_all_types.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/database/07_database_raw.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/database/10_database_sqlmodel.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/routing/06_blueprints.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/routing/09_complex_routing.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/routing/21_path_validation.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/routing/22_path_docs.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/routing/23_query_validation.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/routing/blueprint_with_jwt.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/security/10_rate_limit_demo.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/security/11_security_demo.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/security/17_jwt_auth.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/security/17_safe_features.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/security/18_jwt_cookies.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/security/18_safe_advanced.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/security/18_session_login.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/templates/05_templates.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/templates/26_complex_template.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/templates/templates/index.html +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/turbo/cache_test.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/turbo/fair_benchmark.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/turbo/typed_turbo_example.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/ws/app.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/ws/templates/index.html +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/ws/websockets_demo.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/examples/ws/ws_limit.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/mkdocs.yml +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/app.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/auth/__init__.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/auth/csrf.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/auth/password.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/auth/tokens.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/auth/user.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/cli/__init__.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/cli/main.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/context.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/core/__init__.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/core/asgi.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/core/exceptions.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/core/logging.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/dependencies.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/dispatch.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/documentation/__init__.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/documentation/generator.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/extraction.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/fastapi_compat.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/hooks.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/http/__init__.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/http/request.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/http/response.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/jwt.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/logging.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/middleware.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/multiprocess.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/params.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/py.typed +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/responses.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/routing/__init__.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/routing/blueprints.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/routing/decorators.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/safe/__init__.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/safe/concurrency.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/safe/types.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/security/__init__.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/security/extension.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/security/rate_limit.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/server/__init__.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/server/runner.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/server/wsgi.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/sessions.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/templating/__init__.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/templating/engine.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/templating/mixin.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/testing/__init__.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/testing/client.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/utils.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/python/bustapi/websocket.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/run_all_examples.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/scratch/test_abort.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/scratch/test_headers.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/src/bindings/app.rs +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/src/bindings/converters.rs +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/src/bindings/handlers.rs +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/src/bindings/mod.rs +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/src/bindings/request.rs +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/src/bindings/typed_turbo.rs +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/src/bindings/websocket.rs +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/src/crypto.rs +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/src/jwt.rs +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/src/lib.rs +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/src/logger.rs +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/src/rate_limiter.rs +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/src/request/methods.rs +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/src/request/mod.rs +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/src/request/tests.rs +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/src/response/builders.rs +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/src/response/methods.rs +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/src/response/mod.rs +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/src/router/handlers.rs +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/src/router/matching.rs +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/src/router/middleware.rs +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/src/router/mod.rs +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/src/router/tests.rs +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/src/server/handlers.rs +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/src/server/mod.rs +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/src/server/startup.rs +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/src/server/stream.rs +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/src/static_files.rs +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/src/templating.rs +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/src/watcher.rs +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/src/websocket/config.rs +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/src/websocket/mod.rs +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/src/websocket/session.rs +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/src/websocket/turbo.rs +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/static/style.css +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/templates/base.html +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/templates/complex.html +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/tests/docs_test_all.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/tests/docs_test_api_reference.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/tests/docs_test_installation.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/tests/docs_test_quickstart.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/tests/docs_test_simple.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/tests/test_050_features.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/tests/test_async_hooks.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/tests/test_async_login.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/tests/test_auth.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/tests/test_discussion_21.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/tests/test_discussion_22.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/tests/test_examples.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/tests/test_hot_reload.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/tests/test_issue_18.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/tests/test_issue_23.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/tests/test_issue_24.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/tests/test_jwt.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/tests/test_jwt_cookies.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/tests/test_login_manager.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/tests/test_middleware.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/tests/test_multiprocess_stability.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/tests/test_new_examples.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/tests/test_orm_conflict.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/tests/test_path_standalone.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/tests/test_path_validation.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/tests/test_rate_limit_rust.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/tests/test_safe.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/tests/test_security_unit.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/tests/test_sessions.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/tests/test_zero_copy.py +0 -0
- {bustapi-0.13.5 → bustapi-0.13.8}/tests/verify_router.py +0 -0
|
@@ -2,6 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented here.
|
|
4
4
|
|
|
5
|
+
## [0.13.8] - 2026-06-11
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- **Auth Decorators**: Added a `require_all` flag to `@roles_required` and `@permission_required` decorators, enabling explicit AND/OR logic for multi-role/permission checks.
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- **Auth Async Support**: Fixed a critical bug where `@roles_required` and `@permission_required` decorators failed to support `async def` routes.
|
|
12
|
+
|
|
13
|
+
## [0.13.7] - 2026-06-10
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
- **Login Manager ID Resolution**: Improved `login_user()` to gracefully handle non-string `get_id()` returns (e.g. integer IDs from Peewee ORM) and added support for a conflict-free `get_login_id()` method to prevent overriding built-in ORM properties.
|
|
17
|
+
- **Version Sync**: Synchronized package version in `__init__.py` which was previously out of sync with the package configuration.
|
|
18
|
+
|
|
19
|
+
## [0.13.6] - 2026-06-08
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
- **Auth Login Context**: Fixed `login_manager` extraction by correcting the attribute check on the request from `_app` to `app` ([#26](https://github.com/RUSTxPY/BustAPI/issues/26)).
|
|
23
|
+
- **Template Directory Handling**: Resolved duplicated fallback logic for template directories in `core/helpers.py` by streamlining the lookup against `current_app.template_folder` ([#25](https://github.com/RUSTxPY/BustAPI/issues/25)).
|
|
24
|
+
|
|
5
25
|
## [0.13.5] - 2026-06-04
|
|
6
26
|
|
|
7
27
|
### Added
|
|
@@ -372,9 +372,9 @@ checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06"
|
|
|
372
372
|
|
|
373
373
|
[[package]]
|
|
374
374
|
name = "bitflags"
|
|
375
|
-
version = "2.
|
|
375
|
+
version = "2.13.0"
|
|
376
376
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
377
|
-
checksum = "
|
|
377
|
+
checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8"
|
|
378
378
|
|
|
379
379
|
[[package]]
|
|
380
380
|
name = "blake2"
|
|
@@ -396,9 +396,9 @@ dependencies = [
|
|
|
396
396
|
|
|
397
397
|
[[package]]
|
|
398
398
|
name = "block-buffer"
|
|
399
|
-
version = "0.12.
|
|
399
|
+
version = "0.12.1"
|
|
400
400
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
401
|
-
checksum = "
|
|
401
|
+
checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa"
|
|
402
402
|
dependencies = [
|
|
403
403
|
"hybrid-array",
|
|
404
404
|
]
|
|
@@ -432,7 +432,7 @@ checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
|
|
|
432
432
|
|
|
433
433
|
[[package]]
|
|
434
434
|
name = "bustapi_core"
|
|
435
|
-
version = "0.13.
|
|
435
|
+
version = "0.13.8"
|
|
436
436
|
dependencies = [
|
|
437
437
|
"actix-files",
|
|
438
438
|
"actix-http",
|
|
@@ -526,9 +526,9 @@ dependencies = [
|
|
|
526
526
|
|
|
527
527
|
[[package]]
|
|
528
528
|
name = "chrono"
|
|
529
|
-
version = "0.4.
|
|
529
|
+
version = "0.4.45"
|
|
530
530
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
531
|
-
checksum = "
|
|
531
|
+
checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327"
|
|
532
532
|
dependencies = [
|
|
533
533
|
"iana-time-zone",
|
|
534
534
|
"js-sys",
|
|
@@ -779,7 +779,7 @@ version = "0.11.3"
|
|
|
779
779
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
780
780
|
checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2"
|
|
781
781
|
dependencies = [
|
|
782
|
-
"block-buffer 0.12.
|
|
782
|
+
"block-buffer 0.12.1",
|
|
783
783
|
"const-oid",
|
|
784
784
|
"crypto-common 0.2.2",
|
|
785
785
|
]
|
|
@@ -1329,13 +1329,12 @@ dependencies = [
|
|
|
1329
1329
|
|
|
1330
1330
|
[[package]]
|
|
1331
1331
|
name = "js-sys"
|
|
1332
|
-
version = "0.3.
|
|
1332
|
+
version = "0.3.100"
|
|
1333
1333
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1334
|
-
checksum = "
|
|
1334
|
+
checksum = "f2025f20d7a4fa7785846e7b63d10a76d3f1cee98ee5cb79ea59703f95e42162"
|
|
1335
1335
|
dependencies = [
|
|
1336
1336
|
"cfg-if",
|
|
1337
1337
|
"futures-util",
|
|
1338
|
-
"once_cell",
|
|
1339
1338
|
"wasm-bindgen",
|
|
1340
1339
|
]
|
|
1341
1340
|
|
|
@@ -1432,9 +1431,9 @@ dependencies = [
|
|
|
1432
1431
|
|
|
1433
1432
|
[[package]]
|
|
1434
1433
|
name = "log"
|
|
1435
|
-
version = "0.4.
|
|
1434
|
+
version = "0.4.32"
|
|
1436
1435
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1437
|
-
checksum = "
|
|
1436
|
+
checksum = "953f07c43838f8e6f9758cab68bf5bed85465e7587ebe0b823f1bcd81978ad3a"
|
|
1438
1437
|
|
|
1439
1438
|
[[package]]
|
|
1440
1439
|
name = "matchers"
|
|
@@ -1876,9 +1875,9 @@ dependencies = [
|
|
|
1876
1875
|
|
|
1877
1876
|
[[package]]
|
|
1878
1877
|
name = "regex"
|
|
1879
|
-
version = "1.12.
|
|
1878
|
+
version = "1.12.4"
|
|
1880
1879
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1881
|
-
checksum = "
|
|
1880
|
+
checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba"
|
|
1882
1881
|
dependencies = [
|
|
1883
1882
|
"aho-corasick",
|
|
1884
1883
|
"memchr",
|
|
@@ -1905,9 +1904,9 @@ checksum = "cab834c73d247e67f4fae452806d17d3c7501756d98c8808d7c9c7aa7d18f973"
|
|
|
1905
1904
|
|
|
1906
1905
|
[[package]]
|
|
1907
1906
|
name = "regex-syntax"
|
|
1908
|
-
version = "0.8.
|
|
1907
|
+
version = "0.8.11"
|
|
1909
1908
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1910
|
-
checksum = "
|
|
1909
|
+
checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
|
|
1911
1910
|
|
|
1912
1911
|
[[package]]
|
|
1913
1912
|
name = "rustc_version"
|
|
@@ -2457,9 +2456,9 @@ dependencies = [
|
|
|
2457
2456
|
|
|
2458
2457
|
[[package]]
|
|
2459
2458
|
name = "wasm-bindgen"
|
|
2460
|
-
version = "0.2.
|
|
2459
|
+
version = "0.2.123"
|
|
2461
2460
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2462
|
-
checksum = "
|
|
2461
|
+
checksum = "a254a4b10c19a76f09a27640e7ffbf9bc30bf67e16a3bf28aaefa4920fe81563"
|
|
2463
2462
|
dependencies = [
|
|
2464
2463
|
"cfg-if",
|
|
2465
2464
|
"once_cell",
|
|
@@ -2470,9 +2469,9 @@ dependencies = [
|
|
|
2470
2469
|
|
|
2471
2470
|
[[package]]
|
|
2472
2471
|
name = "wasm-bindgen-macro"
|
|
2473
|
-
version = "0.2.
|
|
2472
|
+
version = "0.2.123"
|
|
2474
2473
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2475
|
-
checksum = "
|
|
2474
|
+
checksum = "24a40fc75b0ec6f3746ceb10d36f53a93dcd68a93b11b6445983945d79eba0dc"
|
|
2476
2475
|
dependencies = [
|
|
2477
2476
|
"quote",
|
|
2478
2477
|
"wasm-bindgen-macro-support",
|
|
@@ -2480,9 +2479,9 @@ dependencies = [
|
|
|
2480
2479
|
|
|
2481
2480
|
[[package]]
|
|
2482
2481
|
name = "wasm-bindgen-macro-support"
|
|
2483
|
-
version = "0.2.
|
|
2482
|
+
version = "0.2.123"
|
|
2484
2483
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2485
|
-
checksum = "
|
|
2484
|
+
checksum = "908f34bd9b9ce3d4caf07b72dfab63d61504d156856c6bd3cd87fa350cf3985b"
|
|
2486
2485
|
dependencies = [
|
|
2487
2486
|
"bumpalo",
|
|
2488
2487
|
"proc-macro2",
|
|
@@ -2493,9 +2492,9 @@ dependencies = [
|
|
|
2493
2492
|
|
|
2494
2493
|
[[package]]
|
|
2495
2494
|
name = "wasm-bindgen-shared"
|
|
2496
|
-
version = "0.2.
|
|
2495
|
+
version = "0.2.123"
|
|
2497
2496
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2498
|
-
checksum = "
|
|
2497
|
+
checksum = "7acbf7616c27b194bbb550bf77ed0c2c3e5b7fd1260a93082b95fb7f47959b92"
|
|
2499
2498
|
dependencies = [
|
|
2500
2499
|
"unicode-ident",
|
|
2501
2500
|
]
|
|
@@ -2892,18 +2891,18 @@ dependencies = [
|
|
|
2892
2891
|
|
|
2893
2892
|
[[package]]
|
|
2894
2893
|
name = "zerocopy"
|
|
2895
|
-
version = "0.8.
|
|
2894
|
+
version = "0.8.52"
|
|
2896
2895
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2897
|
-
checksum = "
|
|
2896
|
+
checksum = "ce1022995ff5ff5d841ad7d994facc23098cd40152f2c1d11cd607c6f530653f"
|
|
2898
2897
|
dependencies = [
|
|
2899
2898
|
"zerocopy-derive",
|
|
2900
2899
|
]
|
|
2901
2900
|
|
|
2902
2901
|
[[package]]
|
|
2903
2902
|
name = "zerocopy-derive"
|
|
2904
|
-
version = "0.8.
|
|
2903
|
+
version = "0.8.52"
|
|
2905
2904
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2906
|
-
checksum = "
|
|
2905
|
+
checksum = "1ae7f38b72ec2a254e2b87ef277cf2cd4fb97cbebf944faa6f33354da0867930"
|
|
2907
2906
|
dependencies = [
|
|
2908
2907
|
"proc-macro2",
|
|
2909
2908
|
"quote",
|
|
@@ -2,6 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented here.
|
|
4
4
|
|
|
5
|
+
## [0.13.8] - 2026-06-11
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- **Auth Decorators**: Added a `require_all` flag to `@roles_required` and `@permission_required` decorators, enabling explicit AND/OR logic for multi-role/permission checks.
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- **Auth Async Support**: Fixed a critical bug where `@roles_required` and `@permission_required` decorators failed to support `async def` routes.
|
|
12
|
+
|
|
13
|
+
## [0.13.7] - 2026-06-10
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
- **Login Manager ID Resolution**: Improved `login_user()` to gracefully handle non-string `get_id()` returns (e.g. integer IDs from Peewee ORM) and added support for a conflict-free `get_login_id()` method to prevent overriding built-in ORM properties.
|
|
17
|
+
- **Version Sync**: Synchronized package version in `__init__.py` which was previously out of sync with the package configuration.
|
|
18
|
+
|
|
19
|
+
## [0.13.6] - 2026-06-08
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
- **Auth Login Context**: Fixed `login_manager` extraction by correcting the attribute check on the request from `_app` to `app` ([#26](https://github.com/RUSTxPY/BustAPI/issues/26)).
|
|
23
|
+
- **Template Directory Handling**: Resolved duplicated fallback logic for template directories in `core/helpers.py` by streamlining the lookup against `current_app.template_folder` ([#25](https://github.com/RUSTxPY/BustAPI/issues/25)).
|
|
24
|
+
|
|
5
25
|
## [0.13.5] - 2026-06-04
|
|
6
26
|
|
|
7
27
|
### Added
|
|
@@ -89,25 +89,17 @@ def fresh_login_required(fn: Callable) -> Callable:
|
|
|
89
89
|
return wrapper
|
|
90
90
|
|
|
91
91
|
|
|
92
|
-
def roles_required(*roles: str) -> Callable:
|
|
92
|
+
def roles_required(*roles: str, require_all: bool = False) -> Callable:
|
|
93
93
|
"""
|
|
94
94
|
Require user to have specific role(s).
|
|
95
95
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
def admin_panel():
|
|
100
|
-
...
|
|
101
|
-
|
|
102
|
-
@app.get("/moderator")
|
|
103
|
-
@roles_required("admin", "moderator")
|
|
104
|
-
def mod_panel():
|
|
105
|
-
...
|
|
96
|
+
Args:
|
|
97
|
+
roles: The roles to check.
|
|
98
|
+
require_all: If True, user must have ALL specified roles (AND). If False, ANY role is sufficient (OR).
|
|
106
99
|
"""
|
|
107
100
|
|
|
108
101
|
def decorator(fn: Callable) -> Callable:
|
|
109
|
-
|
|
110
|
-
def wrapper(*args, **kwargs):
|
|
102
|
+
def check_roles():
|
|
111
103
|
from ..core.exceptions import abort
|
|
112
104
|
from .login import current_user
|
|
113
105
|
|
|
@@ -123,10 +115,25 @@ def roles_required(*roles: str) -> Callable:
|
|
|
123
115
|
else:
|
|
124
116
|
user_roles = []
|
|
125
117
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
118
|
+
if require_all:
|
|
119
|
+
if not all(r in user_roles for r in roles):
|
|
120
|
+
abort(403, f"Roles required: {', '.join(roles)}")
|
|
121
|
+
else:
|
|
122
|
+
if not any(r in user_roles for r in roles):
|
|
123
|
+
abort(403, f"Role required: {', '.join(roles)}")
|
|
124
|
+
|
|
125
|
+
if inspect.iscoroutinefunction(fn):
|
|
129
126
|
|
|
127
|
+
@wraps(fn)
|
|
128
|
+
async def async_wrapper(*args, **kwargs):
|
|
129
|
+
check_roles()
|
|
130
|
+
return await fn(*args, **kwargs)
|
|
131
|
+
|
|
132
|
+
return async_wrapper
|
|
133
|
+
|
|
134
|
+
@wraps(fn)
|
|
135
|
+
def wrapper(*args, **kwargs):
|
|
136
|
+
check_roles()
|
|
130
137
|
return fn(*args, **kwargs)
|
|
131
138
|
|
|
132
139
|
return wrapper
|
|
@@ -134,20 +141,17 @@ def roles_required(*roles: str) -> Callable:
|
|
|
134
141
|
return decorator
|
|
135
142
|
|
|
136
143
|
|
|
137
|
-
def permission_required(*permissions: str) -> Callable:
|
|
144
|
+
def permission_required(*permissions: str, require_all: bool = True) -> Callable:
|
|
138
145
|
"""
|
|
139
146
|
Require user to have specific permission(s).
|
|
140
147
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
def delete_post():
|
|
145
|
-
...
|
|
148
|
+
Args:
|
|
149
|
+
permissions: The permissions to check.
|
|
150
|
+
require_all: If True, user must have ALL permissions (AND). If False, ANY permission is sufficient (OR).
|
|
146
151
|
"""
|
|
147
152
|
|
|
148
153
|
def decorator(fn: Callable) -> Callable:
|
|
149
|
-
|
|
150
|
-
def wrapper(*args, **kwargs):
|
|
154
|
+
def check_permissions():
|
|
151
155
|
from ..core.exceptions import abort
|
|
152
156
|
from .login import current_user
|
|
153
157
|
|
|
@@ -159,11 +163,26 @@ def permission_required(*permissions: str) -> Callable:
|
|
|
159
163
|
if callable(user_perms):
|
|
160
164
|
user_perms = user_perms()
|
|
161
165
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
+
if require_all:
|
|
167
|
+
for perm in permissions:
|
|
168
|
+
if perm not in user_perms:
|
|
169
|
+
abort(403, f"Permission required: {perm}")
|
|
170
|
+
else:
|
|
171
|
+
if not any(perm in user_perms for perm in permissions):
|
|
172
|
+
abort(403, f"Permission required: {', '.join(permissions)}")
|
|
173
|
+
|
|
174
|
+
if inspect.iscoroutinefunction(fn):
|
|
166
175
|
|
|
176
|
+
@wraps(fn)
|
|
177
|
+
async def async_wrapper(*args, **kwargs):
|
|
178
|
+
check_permissions()
|
|
179
|
+
return await fn(*args, **kwargs)
|
|
180
|
+
|
|
181
|
+
return async_wrapper
|
|
182
|
+
|
|
183
|
+
@wraps(fn)
|
|
184
|
+
def wrapper(*args, **kwargs):
|
|
185
|
+
check_permissions()
|
|
167
186
|
return fn(*args, **kwargs)
|
|
168
187
|
|
|
169
188
|
return wrapper
|
|
@@ -107,15 +107,25 @@ def login_user(user, remember: bool = False, fresh: bool = True) -> bool:
|
|
|
107
107
|
return False
|
|
108
108
|
|
|
109
109
|
# Get user ID
|
|
110
|
-
|
|
110
|
+
# 1. Support custom conflict-free get_login_id() first
|
|
111
|
+
user_id = getattr(user, "get_login_id", lambda: None)()
|
|
112
|
+
|
|
113
|
+
# 2. Fallback to standard get_id()
|
|
111
114
|
if user_id is None:
|
|
115
|
+
user_id = getattr(user, "get_id", lambda: None)()
|
|
116
|
+
|
|
117
|
+
# 3. Ensure string conversion (e.g., Peewee get_id() returns int)
|
|
118
|
+
if user_id is not None:
|
|
119
|
+
user_id = str(user_id)
|
|
120
|
+
else:
|
|
121
|
+
# 4. Final fallback to .id attribute
|
|
112
122
|
try:
|
|
113
123
|
user_id = str(user.id)
|
|
114
124
|
except AttributeError:
|
|
115
125
|
return False
|
|
116
126
|
|
|
117
127
|
# Get login manager config
|
|
118
|
-
login_manager = getattr(request, "
|
|
128
|
+
login_manager = getattr(request, "app", None)
|
|
119
129
|
if login_manager:
|
|
120
130
|
login_manager = getattr(login_manager, "login_manager", None)
|
|
121
131
|
|
|
@@ -153,7 +163,7 @@ def logout_user() -> bool:
|
|
|
153
163
|
return False
|
|
154
164
|
|
|
155
165
|
# Get login manager config
|
|
156
|
-
login_manager = getattr(request, "
|
|
166
|
+
login_manager = getattr(request, "app", None)
|
|
157
167
|
if login_manager:
|
|
158
168
|
login_manager = getattr(login_manager, "login_manager", None)
|
|
159
169
|
|
|
@@ -307,9 +307,7 @@ def render_template(template_name: str, **context) -> Response:
|
|
|
307
307
|
if template_dir is None:
|
|
308
308
|
try:
|
|
309
309
|
current_app = _get_current_object()
|
|
310
|
-
template_dir = (
|
|
311
|
-
getattr(current_app, "template_folder", None) or "templates"
|
|
312
|
-
)
|
|
310
|
+
template_dir = getattr(current_app, "template_folder", "templates")
|
|
313
311
|
except RuntimeError:
|
|
314
312
|
# No app context, use default
|
|
315
313
|
template_dir = "templates"
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from unittest.mock import patch
|
|
3
|
+
|
|
4
|
+
import pytest
|
|
5
|
+
from bustapi import BustAPI
|
|
6
|
+
from bustapi.auth.decorators import permission_required, roles_required
|
|
7
|
+
from bustapi.testing import BustTestClient
|
|
8
|
+
|
|
9
|
+
app = BustAPI()
|
|
10
|
+
app.secret_key = "test_secret"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class MockUser:
|
|
15
|
+
is_authenticated: bool = True
|
|
16
|
+
roles: list = None
|
|
17
|
+
permissions: list = None
|
|
18
|
+
|
|
19
|
+
def get_id(self):
|
|
20
|
+
return "123"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# Setup routes
|
|
24
|
+
@app.route("/sync-role-or")
|
|
25
|
+
@roles_required("admin", "editor")
|
|
26
|
+
def sync_role_or():
|
|
27
|
+
return "ok"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@app.route("/sync-role-and")
|
|
31
|
+
@roles_required("admin", "editor", require_all=True)
|
|
32
|
+
def sync_role_and():
|
|
33
|
+
return "ok"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@app.route("/async-perm-and")
|
|
37
|
+
@permission_required("read", "write")
|
|
38
|
+
async def async_perm_and():
|
|
39
|
+
return "ok"
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@app.route("/async-perm-or")
|
|
43
|
+
@permission_required("read", "write", require_all=False)
|
|
44
|
+
async def async_perm_or():
|
|
45
|
+
return "ok"
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def test_roles_or():
|
|
49
|
+
with patch("bustapi.auth.login.current_user", MockUser(roles=["editor"])):
|
|
50
|
+
with BustTestClient(app) as client:
|
|
51
|
+
assert client.get("/sync-role-or").status_code == 200
|
|
52
|
+
|
|
53
|
+
with patch("bustapi.auth.login.current_user", MockUser(roles=["user"])):
|
|
54
|
+
with BustTestClient(app) as client:
|
|
55
|
+
assert client.get("/sync-role-or").status_code == 403
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def test_roles_and():
|
|
59
|
+
with patch("bustapi.auth.login.current_user", MockUser(roles=["admin", "editor"])):
|
|
60
|
+
with BustTestClient(app) as client:
|
|
61
|
+
assert client.get("/sync-role-and").status_code == 200
|
|
62
|
+
|
|
63
|
+
with patch("bustapi.auth.login.current_user", MockUser(roles=["admin"])):
|
|
64
|
+
with BustTestClient(app) as client:
|
|
65
|
+
assert client.get("/sync-role-and").status_code == 403
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def test_perms_and():
|
|
69
|
+
with patch(
|
|
70
|
+
"bustapi.auth.login.current_user", MockUser(permissions=["read", "write"])
|
|
71
|
+
):
|
|
72
|
+
with BustTestClient(app) as client:
|
|
73
|
+
assert client.get("/async-perm-and").status_code == 200
|
|
74
|
+
|
|
75
|
+
with patch("bustapi.auth.login.current_user", MockUser(permissions=["read"])):
|
|
76
|
+
with BustTestClient(app) as client:
|
|
77
|
+
assert client.get("/async-perm-and").status_code == 403
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def test_perms_or():
|
|
81
|
+
with patch("bustapi.auth.login.current_user", MockUser(permissions=["read"])):
|
|
82
|
+
with BustTestClient(app) as client:
|
|
83
|
+
assert client.get("/async-perm-or").status_code == 200
|
|
84
|
+
|
|
85
|
+
with patch("bustapi.auth.login.current_user", MockUser(permissions=["delete"])):
|
|
86
|
+
with BustTestClient(app) as client:
|
|
87
|
+
assert client.get("/async-perm-or").status_code == 403
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|