bustapi 0.13.6__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.6 → bustapi-0.13.8}/CHANGELOG.md +14 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/Cargo.lock +4 -4
- {bustapi-0.13.6 → bustapi-0.13.8}/Cargo.toml +1 -1
- {bustapi-0.13.6 → bustapi-0.13.8}/PKG-INFO +1 -1
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/changelog.md +14 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/pyproject.toml +1 -1
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/__init__.py +1 -1
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/auth/decorators.py +47 -28
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/auth/login.py +11 -1
- bustapi-0.13.8/tests/test_discussion_28.py +87 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/- +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/.github/FUNDING.yml +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/.github/workflows/ci-multiplatform.yml +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/.github/workflows/ci.yml +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/.github/workflows/docs.yml +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/.github/workflows/manual-publish.yml +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/.gitignore +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/.python-version +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/AGENT_KNOWLEDGE.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/Dockerfile +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/LICENSE +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/README.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/benchmarks/CACHE_BENCHMARK.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/benchmarks/README.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/benchmarks/app.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/benchmarks/benchmark_all.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/benchmarks/benchmark_avg.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/benchmarks/benchmark_cache.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/benchmarks/benchmark_combined.png +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/benchmarks/bustapi.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/benchmarks/bustapi_bench.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/benchmarks/bustapi_internal.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/benchmarks/comparison_bench.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/benchmarks/comprehensive_benchmark.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/benchmarks/gen_graph.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/benchmarks/quick_bench.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/benchmarks/resource_bench.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/benchmarks/rps_comparison.png +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/benchmarks/run_comparison_auto.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/benchmarks/ws_benchmark.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/advanced/async.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/advanced/blueprints.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/advanced/dependency_injection.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/advanced/deployment.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/advanced/middleware.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/advanced/security.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/advanced/validation.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/api-reference.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/assets/logo.png +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/complete-api-reference.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/deployment-performance-guide.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/deployment.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/examples-guide.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/index.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/installation.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/overrides/.gitkeep +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/quickstart.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/release_track.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/site/advanced/async_support.html +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/site/advanced/blueprints.html +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/site/advanced/dependency_injection.html +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/site/advanced/middleware.html +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/site/advanced/validation.html +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/site/api/all.html +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/site/api/app.html +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/site/api/context.html +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/site/api/utilities.html +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/site/assets/logo.png +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/site/changelog.html +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/site/core_concepts/request_data.html +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/site/core_concepts/responses.html +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/site/core_concepts/routing.html +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/site/core_concepts/templates.html +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/site/examples/index.html +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/site/getting_started/index.html +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/site/getting_started/quickstart.html +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/site/index.html +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/site/script.js +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/site/style.css +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/stylesheets/extra.css +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/user-guide/authentication.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/user-guide/caching.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/user-guide/cli.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/user-guide/database.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/user-guide/documentation.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/user-guide/error_handling.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/user-guide/jwt.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/user-guide/logging.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/user-guide/multiprocessing.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/user-guide/request_data.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/user-guide/responses.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/user-guide/routing.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/user-guide/sessions.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/user-guide/static_files.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/user-guide/templates.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/user-guide/turbo-routes.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/user-guide/video-streaming.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/docs/websockets.md +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/advanced/08_auto_docs.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/advanced/12_test_modes.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/advanced/13_error_handling.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/advanced/14_middleware.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/advanced/16_middleware_session.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/advanced/20_file_uploads.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/advanced/24_body_and_depends.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/advanced/27_video_stream.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/advanced/28_websocket.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/advanced/29_turbo_websocket.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/basics/01_hello_world.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/basics/02_parameters.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/basics/03_async.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/basics/04_request_data.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/basics/19_all_types.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/database/07_database_raw.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/database/10_database_sqlmodel.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/routing/06_blueprints.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/routing/09_complex_routing.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/routing/21_path_validation.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/routing/22_path_docs.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/routing/23_query_validation.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/routing/blueprint_with_jwt.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/security/10_rate_limit_demo.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/security/11_security_demo.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/security/17_jwt_auth.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/security/17_safe_features.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/security/18_jwt_cookies.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/security/18_safe_advanced.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/security/18_session_login.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/templates/05_templates.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/templates/26_complex_template.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/templates/templates/index.html +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/turbo/cache_test.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/turbo/fair_benchmark.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/turbo/typed_turbo_example.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/ws/app.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/ws/templates/index.html +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/ws/websockets_demo.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/examples/ws/ws_limit.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/mkdocs.yml +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/app.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/auth/__init__.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/auth/csrf.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/auth/password.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/auth/tokens.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/auth/user.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/cli/__init__.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/cli/main.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/context.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/core/__init__.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/core/asgi.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/core/exceptions.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/core/helpers.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/core/logging.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/dependencies.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/dispatch.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/documentation/__init__.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/documentation/generator.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/extraction.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/fastapi_compat.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/hooks.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/http/__init__.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/http/request.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/http/response.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/jwt.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/logging.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/middleware.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/multiprocess.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/params.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/py.typed +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/responses.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/routing/__init__.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/routing/blueprints.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/routing/decorators.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/safe/__init__.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/safe/concurrency.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/safe/types.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/security/__init__.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/security/extension.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/security/rate_limit.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/server/__init__.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/server/runner.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/server/wsgi.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/sessions.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/templating/__init__.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/templating/engine.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/templating/mixin.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/testing/__init__.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/testing/client.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/utils.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/python/bustapi/websocket.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/run_all_examples.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/scratch/test_abort.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/scratch/test_headers.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/src/bindings/app.rs +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/src/bindings/converters.rs +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/src/bindings/handlers.rs +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/src/bindings/mod.rs +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/src/bindings/request.rs +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/src/bindings/typed_turbo.rs +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/src/bindings/websocket.rs +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/src/crypto.rs +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/src/jwt.rs +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/src/lib.rs +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/src/logger.rs +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/src/rate_limiter.rs +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/src/request/methods.rs +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/src/request/mod.rs +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/src/request/tests.rs +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/src/response/builders.rs +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/src/response/methods.rs +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/src/response/mod.rs +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/src/router/handlers.rs +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/src/router/matching.rs +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/src/router/middleware.rs +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/src/router/mod.rs +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/src/router/tests.rs +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/src/server/handlers.rs +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/src/server/mod.rs +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/src/server/startup.rs +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/src/server/stream.rs +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/src/static_files.rs +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/src/templating.rs +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/src/watcher.rs +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/src/websocket/config.rs +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/src/websocket/mod.rs +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/src/websocket/session.rs +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/src/websocket/turbo.rs +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/static/style.css +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/templates/base.html +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/templates/complex.html +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/tests/docs_test_all.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/tests/docs_test_api_reference.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/tests/docs_test_installation.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/tests/docs_test_quickstart.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/tests/docs_test_simple.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/tests/test_050_features.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/tests/test_async_hooks.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/tests/test_async_login.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/tests/test_auth.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/tests/test_discussion_21.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/tests/test_discussion_22.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/tests/test_examples.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/tests/test_hot_reload.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/tests/test_issue_18.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/tests/test_issue_23.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/tests/test_issue_24.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/tests/test_jwt.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/tests/test_jwt_cookies.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/tests/test_login_manager.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/tests/test_middleware.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/tests/test_multiprocess_stability.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/tests/test_new_examples.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/tests/test_orm_conflict.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/tests/test_path_standalone.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/tests/test_path_validation.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/tests/test_rate_limit_rust.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/tests/test_safe.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/tests/test_security_unit.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/tests/test_sessions.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/tests/test_zero_copy.py +0 -0
- {bustapi-0.13.6 → bustapi-0.13.8}/tests/verify_router.py +0 -0
|
@@ -2,6 +2,20 @@
|
|
|
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
|
+
|
|
5
19
|
## [0.13.6] - 2026-06-08
|
|
6
20
|
|
|
7
21
|
### Fixed
|
|
@@ -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",
|
|
@@ -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
|
]
|
|
@@ -2,6 +2,20 @@
|
|
|
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
|
+
|
|
5
19
|
## [0.13.6] - 2026-06-08
|
|
6
20
|
|
|
7
21
|
### Fixed
|
|
@@ -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,8 +107,18 @@ 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:
|
|
@@ -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
|
|
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
|
|
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
|