2# +==== BEGIN CatFeeder =================+
5# ...............)..(.')
7# ...............\(__)|
8# Inspired by Joan Stark
9# source https://www.asciiart.eu/
14# CREATION DATE: 23-01-2026
15# LAST Modified: 1:12:17 24-01-2026
17# This is the project in charge of making the connected cat feeder project work.
19# COPYRIGHT: (c) Cat Feeder
20# PURPOSE: Security decorators for API endpoint authentication and authorization.
23# +==== END CatFeeder =================+
26from functools
import wraps
27from typing
import Callable
29from .decorator_constants
import SecurityLevel, Environment
33 security_level: SecurityLevel = SecurityLevel.AUTHENTICATED,
34 environment: Environment = Environment.ALL
36 """Mark endpoint as requiring authentication.
39 security_level: Level of security required (default: AUTHENTICATED).
40 environment: Environment where this applies (default: ALL).
45 def decorator(func: Callable) -> Callable:
47 def wrapper(*args, **kwargs):
48 return func(*args, **kwargs)
50 setattr(wrapper,
"_requires_auth",
True)
51 setattr(wrapper,
"_security_level", security_level.value)
52 setattr(wrapper,
"_environment", environment.value)
61 security_level: SecurityLevel = SecurityLevel.ADMIN,
62 environment: Environment = Environment.ALL
64 """Mark endpoint as requiring admin privileges.
67 security_level: Level of admin access required (default: ADMIN).
68 environment: Environment where this applies (default: ALL).
73 def decorator(func: Callable) -> Callable:
75 def wrapper(*args, **kwargs):
76 return func(*args, **kwargs)
78 setattr(wrapper,
"_requires_admin",
True)
79 setattr(wrapper,
"_security_level", security_level.value)
80 setattr(wrapper,
"_environment", environment.value)
89 """Mark endpoint as public (no authentication required).
92 environment: Environment where this applies (default: ALL).
97 def decorator(func: Callable) -> Callable:
99 def wrapper(*args, **kwargs):
100 return func(*args, **kwargs)
102 setattr(wrapper,
"_public",
True)
103 setattr(wrapper,
"_security_level", SecurityLevel.PUBLIC.value)
104 setattr(wrapper,
"_environment", environment.value)
112def test_endpoint(environment: Environment = Environment.TESTING) -> Callable:
113 """Mark endpoint as testing-only.
116 environment: Environment where this applies (default: TESTING).
121 def decorator(func: Callable) -> Callable:
123 def wrapper(*args, **kwargs):
124 return func(*args, **kwargs)
126 setattr(wrapper,
"_testing_only",
True)
127 setattr(wrapper,
"_environment", environment.value)
136 """Helper function to preserve existing metadata attributes."""
138 '_requires_auth',
'_requires_admin',
'_public',
'_testing_only',
139 '_security_level',
'_environment',
'_description',
'_summary',
140 '_response_model',
'_tags'
143 for attr
in metadata_attrs:
144 if hasattr(func, attr):
145 setattr(wrapper, attr, getattr(func, attr))
Callable admin_endpoint(SecurityLevel security_level=SecurityLevel.ADMIN, Environment environment=Environment.ALL)
Callable public_endpoint(Environment environment=Environment.ALL)
Callable auth_endpoint(SecurityLevel security_level=SecurityLevel.AUTHENTICATED, Environment environment=Environment.ALL)
Callable test_endpoint(Environment environment=Environment.TESTING)
None _preserve_metadata(Callable func, Callable wrapper)