Source code for flask_more_smorest.perms.perms_blueprint

"""Blueprint Mixin to support method annotation for access control.

This module provides PermsBlueprintMixin which adds decorators for marking
endpoints as public or admin-only.
"""

from collections.abc import Callable

from flask.views import MethodView

from ..crud import CRUDBlueprint as CRUDBlueprintBase
from ..crud.crud_blueprint import MethodConfig


[docs] class PermsBlueprintMixin: """Blueprint mixin with added annotations for public and admin endpoints. This mixin extends Flask-Smorest's Blueprint to provide additional decorators for marking endpoints with special access levels: - public_endpoint: Accessible without authentication - admin_endpoint: Requires admin privileges Example: >>> class MyBlueprint(Blueprint, PermsBlueprintMixin): ... pass >>> bp = MyBlueprint('items', __name__) >>> @bp.route('/') >>> @bp.public_endpoint >>> def list_items(): ... return [] """ def _configure_endpoint( self, view_cls: type[MethodView], method_name: str, docstring: str, method_config: "MethodConfig", ) -> None: """Configure endpoint with admin/public decorators if needed. This method is called by CRUDBlueprint for each registered endpoint. When used via PermsBlueprint, both this mixin's implementation and CRUDBlueprint's implementation are called explicitly. Args: view_cls: MethodView class containing the endpoint method_name: Name of the method to configure docstring: Docstring to set on the method method_config: Configuration dict for the method """ if hasattr(view_cls, method_name): method = getattr(view_cls, method_name) if method_config.get("admin_only", False): self.admin_endpoint(method) if method_config.get("public", False): self.public_endpoint(method)
[docs] def public_endpoint(self, func: Callable) -> Callable: """Decorator to mark an endpoint as public. Public endpoints do not require authentication and can be accessed by anyone. Args: func: The endpoint function to mark as public Returns: The decorated function with public annotation Example: >>> @bp.route('/health') >>> @bp.public_endpoint >>> def health_check(): ... return {'status': 'ok'} """ func._is_public = True # type: ignore[attr-defined] if func.__doc__ is None: func.__doc__ = "Public endpoint" else: func.__doc__ += " | 🌐 Public" return func
[docs] def admin_endpoint(self, func: Callable) -> Callable: """Decorator to mark an endpoint as admin only. Admin endpoints require the user to have admin privileges. The Api class enforces this during request handling. Args: func: The endpoint function to mark as admin only Returns: The decorated function with admin annotation Example: >>> @bp.route('/users/<uuid:user_id>') >>> @bp.admin_endpoint >>> def delete_user(user_id): ... # Only admins can delete users ... pass """ func._is_admin = True # type: ignore[attr-defined] if func.__doc__ is None: func.__doc__ = "Admin only endpoint" else: func.__doc__ += " | 🔑 Admin only" return func
[docs] class PermsBlueprint(CRUDBlueprintBase, PermsBlueprintMixin): """CRUD Blueprint with permission annotations. Combines CRUDBlueprint functionality with PermsBlueprintMixin to provide automatic CRUD operations with permission checking support. """ def _configure_endpoint( self, view_cls: type[MethodView], method_name: str, docstring: str, method_config: MethodConfig, ) -> None: # Call each mixin's implementation explicitly PermsBlueprintMixin._configure_endpoint(self, view_cls, method_name, docstring, method_config) CRUDBlueprintBase._configure_endpoint(self, view_cls, method_name, docstring, method_config)