auth and token middleware context update
This commit is contained in:
parent
3d5a43220e
commit
a7e48d8755
|
|
@ -17,6 +17,12 @@ class WagRedis:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class RedisAuthKeys:
|
||||||
|
AUTH: str = "AUTH"
|
||||||
|
OCCUPANT: str = "OCCUPANT"
|
||||||
|
EMPLOYEE: str = "EMPLOYEE"
|
||||||
|
|
||||||
|
|
||||||
class RedisCategoryKeys:
|
class RedisCategoryKeys:
|
||||||
REBUILD: str = "REBUILD"
|
REBUILD: str = "REBUILD"
|
||||||
ENDPOINT2CLASS: str = "ENDPOINT2CLASS"
|
ENDPOINT2CLASS: str = "ENDPOINT2CLASS"
|
||||||
|
|
@ -28,6 +34,3 @@ class RedisCategoryKeys:
|
||||||
MENU_FIRST_LAYER: str = "MENU_FIRST_LAYER"
|
MENU_FIRST_LAYER: str = "MENU_FIRST_LAYER"
|
||||||
PAGE_MAPPER: str = "PAGE_MAPPER"
|
PAGE_MAPPER: str = "PAGE_MAPPER"
|
||||||
MENU_MAPPER: str = "MENU_MAPPER"
|
MENU_MAPPER: str = "MENU_MAPPER"
|
||||||
AUTH: str = "AUTH"
|
|
||||||
OCCUPANT: str = "OCCUPANT"
|
|
||||||
EMPLOYEE: str = "EMPLOYEE"
|
|
||||||
|
|
@ -16,23 +16,17 @@ class CreateEndpointFromCluster:
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
self.router: CategoryCluster = kwargs.get("router")
|
self.router: CategoryCluster = kwargs.get("router")
|
||||||
self.method_endpoint: MethodToEvent = kwargs.get("method_endpoint")
|
self.method_endpoint: MethodToEvent = kwargs.get("method_endpoint")
|
||||||
self.unique_id = str(uuid.uuid4())[:8] # Use first 8 chars of UUID for brevity
|
|
||||||
self.attach_router()
|
self.attach_router()
|
||||||
|
|
||||||
def attach_router(self):
|
def attach_router(self):
|
||||||
method = getattr(self.router, self.method_endpoint.METHOD.lower())
|
method = getattr(self.router, self.method_endpoint.METHOD.lower())
|
||||||
|
|
||||||
# Create a unique operation ID based on the endpoint path, method, and a unique identifier
|
# Create a unique operation ID based on the endpoint path, method, and a unique identifier
|
||||||
base_path = self.method_endpoint.URL.strip('/').replace('/', '_').replace('-', '_')
|
|
||||||
operation_id = f"{base_path}_{self.method_endpoint.METHOD.lower()}_{self.unique_id}"
|
|
||||||
|
|
||||||
kwargs = {
|
kwargs = {
|
||||||
"path": self.method_endpoint.URL,
|
"path": self.method_endpoint.URL,
|
||||||
"summary": self.method_endpoint.SUMMARY,
|
"summary": self.method_endpoint.SUMMARY,
|
||||||
"description": self.method_endpoint.DESCRIPTION,
|
"description": self.method_endpoint.DESCRIPTION,
|
||||||
"operation_id": operation_id
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if hasattr(self.method_endpoint, 'RESPONSE_MODEL') and self.method_endpoint.RESPONSE_MODEL is not None:
|
if hasattr(self.method_endpoint, 'RESPONSE_MODEL') and self.method_endpoint.RESPONSE_MODEL is not None:
|
||||||
kwargs["response_model"] = self.method_endpoint.RESPONSE_MODEL
|
kwargs["response_model"] = self.method_endpoint.RESPONSE_MODEL
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
"""Token service for handling authentication tokens and user sessions."""
|
"""Token service for handling authentication tokens and user sessions."""
|
||||||
|
|
||||||
from typing import List, Union, TypeVar, Dict, Any, Optional, TYPE_CHECKING
|
from typing import List, Union, TypeVar, Dict, Any, TYPE_CHECKING
|
||||||
|
|
||||||
from ApiLayers.AllConfigs.Token.config import Auth
|
from ApiLayers.AllConfigs.Token.config import Auth
|
||||||
from ApiLayers.ApiLibrary.common.line_number import get_line_number_for_error
|
from ApiLayers.ApiLibrary.common.line_number import get_line_number_for_error
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
from typing import Optional, Any
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
|
class DefaultContext(BaseModel):
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
class EventContext(DefaultContext):
|
||||||
|
|
||||||
|
auth: Any
|
||||||
|
code: str
|
||||||
|
url: str
|
||||||
|
|
||||||
|
|
||||||
|
class AuthContext(DefaultContext):
|
||||||
|
auth: Any
|
||||||
|
url: str
|
||||||
|
|
@ -15,6 +15,7 @@ from fastapi import Request, Response
|
||||||
from starlette.middleware.base import BaseHTTPMiddleware
|
from starlette.middleware.base import BaseHTTPMiddleware
|
||||||
|
|
||||||
from ApiLayers.ApiLibrary.common.line_number import get_line_number_for_error
|
from ApiLayers.ApiLibrary.common.line_number import get_line_number_for_error
|
||||||
|
from ApiLayers.ApiValidations.Custom.wrapper_contexts import AuthContext
|
||||||
from ApiLayers.ErrorHandlers.ErrorHandlers.api_exc_handler import HTTPExceptionApi
|
from ApiLayers.ErrorHandlers.ErrorHandlers.api_exc_handler import HTTPExceptionApi
|
||||||
from ApiLayers.AllConfigs.Token.config import Auth
|
from ApiLayers.AllConfigs.Token.config import Auth
|
||||||
from ApiLayers.ApiServices.Token.token_handler import TokenService
|
from ApiLayers.ApiServices.Token.token_handler import TokenService
|
||||||
|
|
@ -87,14 +88,15 @@ class MiddlewareModule:
|
||||||
@wraps(func)
|
@wraps(func)
|
||||||
async def wrapper(request: Request, *args, **kwargs):
|
async def wrapper(request: Request, *args, **kwargs):
|
||||||
# Get and validate token context from request
|
# Get and validate token context from request
|
||||||
auth_context = {
|
endpoint_url = str(request.url.path)
|
||||||
"is_employee": False,
|
auth_context = AuthContext(
|
||||||
"is_occupant": False,
|
auth={"token": {"access_token": "", "refresher_token": "", "context": {}}},
|
||||||
"context": {}
|
url=endpoint_url,
|
||||||
}
|
)
|
||||||
|
|
||||||
# Set auth context on the wrapper function itself
|
# Set auth context on the wrapper function itself
|
||||||
setattr(wrapper, 'auth', auth_context)
|
setattr(func, 'auth_context', auth_context)
|
||||||
|
setattr(wrapper, 'auth_context', auth_context)
|
||||||
|
|
||||||
# Call the original endpoint function
|
# Call the original endpoint function
|
||||||
if inspect.iscoroutinefunction(func):
|
if inspect.iscoroutinefunction(func):
|
||||||
|
|
@ -102,6 +104,10 @@ class MiddlewareModule:
|
||||||
else:
|
else:
|
||||||
result = func(request, *args, **kwargs)
|
result = func(request, *args, **kwargs)
|
||||||
|
|
||||||
|
# Set auth context on the wrapper function itself
|
||||||
|
setattr(func, 'auth_context', auth_context)
|
||||||
|
setattr(wrapper, 'auth_context', auth_context)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,110 +5,22 @@ Token event middleware for handling authentication and event tracking.
|
||||||
import inspect
|
import inspect
|
||||||
|
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from typing import Callable, Dict, Any, Optional, Union
|
from typing import Callable, Dict, Any, Optional, Tuple, Union
|
||||||
from fastapi import Request
|
from fastapi import Request
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
from ApiLayers.ApiLibrary.common.line_number import get_line_number_for_error
|
from ApiLayers.ApiLibrary.common.line_number import get_line_number_for_error
|
||||||
from ApiLayers.ApiServices.Token.token_handler import TokenService
|
from ApiLayers.ApiServices.Token.token_handler import TokenService
|
||||||
|
from ApiLayers.ApiValidations.Custom.wrapper_contexts import EventContext
|
||||||
from ApiLayers.ErrorHandlers.Exceptions.api_exc import HTTPExceptionApi
|
from ApiLayers.ErrorHandlers.Exceptions.api_exc import HTTPExceptionApi
|
||||||
from ApiLayers.Schemas import Events, EndpointRestriction
|
from ApiLayers.Schemas import Events, EndpointRestriction
|
||||||
|
from ApiLayers.AllConfigs.Redis.configs import RedisCategoryKeys
|
||||||
|
|
||||||
|
from Services.Redis.Actions.actions import RedisActions
|
||||||
|
|
||||||
from .auth_middleware import MiddlewareModule
|
from .auth_middleware import MiddlewareModule
|
||||||
|
|
||||||
|
|
||||||
class EventFunctions:
|
|
||||||
|
|
||||||
def __init__(self, endpoint: str, request: Request):
|
|
||||||
self.endpoint = endpoint
|
|
||||||
self.request = request
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def retrieve_function_dict(self) -> Optional[Dict[str, Any]]:
|
|
||||||
"""
|
|
||||||
Retrieve function dictionary for a given endpoint.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
endpoint: The endpoint to retrieve the function dictionary for
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Dictionary containing the function dictionary
|
|
||||||
None if endpoint is not found
|
|
||||||
"""
|
|
||||||
access_token = TokenService.get_access_token_from_request(self.request)
|
|
||||||
token_context = TokenService.get_object_via_access_key(
|
|
||||||
access_token=access_token
|
|
||||||
)
|
|
||||||
if token_context.is_employee:
|
|
||||||
reachable_event_codes: list[str] = (
|
|
||||||
token_context.selected_company.reachable_event_codes
|
|
||||||
)
|
|
||||||
elif token_context.is_occupant:
|
|
||||||
reachable_event_codes: list[str] = (
|
|
||||||
token_context.selected_occupant.reachable_event_codes
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
raise HTTPExceptionApi(
|
|
||||||
error_code="",
|
|
||||||
lang="en",
|
|
||||||
loc=get_line_number_for_error(),
|
|
||||||
sys_msg="Token not found",
|
|
||||||
)
|
|
||||||
|
|
||||||
if not access_token:
|
|
||||||
raise HTTPExceptionApi(
|
|
||||||
error_code="",
|
|
||||||
lang="en",
|
|
||||||
loc=get_line_number_for_error(),
|
|
||||||
sys_msg="Token not found",
|
|
||||||
)
|
|
||||||
|
|
||||||
db = EndpointRestriction.new_session()
|
|
||||||
restriction = EndpointRestriction.filter_one(
|
|
||||||
EndpointRestriction.endpoint_name == self.endpoint,
|
|
||||||
db=db,
|
|
||||||
).data
|
|
||||||
if not restriction:
|
|
||||||
raise HTTPExceptionApi(
|
|
||||||
error_code="",
|
|
||||||
lang="en",
|
|
||||||
loc=get_line_number_for_error(),
|
|
||||||
sys_msg="Function code not found",
|
|
||||||
)
|
|
||||||
|
|
||||||
event_related = Events.filter_all(
|
|
||||||
Events.endpoint_id == restriction.id,
|
|
||||||
db=db,
|
|
||||||
).data
|
|
||||||
if not event_related:
|
|
||||||
raise HTTPExceptionApi(
|
|
||||||
error_code="",
|
|
||||||
lang="en",
|
|
||||||
loc=get_line_number_for_error(),
|
|
||||||
sys_msg="No event is registered for this user.",
|
|
||||||
)
|
|
||||||
an_event = event_related[0]
|
|
||||||
event_related_codes: list[str] = [
|
|
||||||
event.function_code for event in event_related
|
|
||||||
]
|
|
||||||
intersected_code: set = set(reachable_event_codes).intersection(
|
|
||||||
set(event_related_codes)
|
|
||||||
)
|
|
||||||
if not len(list(intersected_code)) == 1:
|
|
||||||
raise HTTPExceptionApi(
|
|
||||||
error_code="",
|
|
||||||
lang="en",
|
|
||||||
loc=get_line_number_for_error(),
|
|
||||||
sys_msg="No event is registered for this user.",
|
|
||||||
)
|
|
||||||
return {
|
|
||||||
"endpoint_url": self.endpoint,
|
|
||||||
"reachable_event_code": list(intersected_code)[0],
|
|
||||||
"class": an_event.function_class,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class TokenEventMiddleware:
|
class TokenEventMiddleware:
|
||||||
"""
|
"""
|
||||||
Module containing token and event handling functionality.
|
Module containing token and event handling functionality.
|
||||||
|
|
@ -119,37 +31,18 @@ class TokenEventMiddleware:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def match_endpoint_with_accessible_event(request_from_scope, endpoint_from_scope) -> Optional[Dict[str, Any]]:
|
def retrieve_access_content(request_from_scope: Request) -> Tuple[str, list[str]]:
|
||||||
"""
|
"""
|
||||||
Match an endpoint with accessible events.
|
Retrieves the access token and validates it.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
request_from_scope: The endpoint to match
|
request_from_scope: The FastAPI request object
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Dict containing the endpoint registration data
|
Tuple[str, list[str]]: The access token and a list of reachable event codes
|
||||||
None if endpoint is not found in database
|
|
||||||
"""
|
"""
|
||||||
|
# Get token context from request
|
||||||
access_token = TokenService.get_access_token_from_request(request_from_scope)
|
access_token = TokenService.get_access_token_from_request(request_from_scope)
|
||||||
token_context = TokenService.get_object_via_access_key(
|
|
||||||
access_token=access_token
|
|
||||||
)
|
|
||||||
if token_context.is_employee:
|
|
||||||
reachable_event_codes: list[str] = (
|
|
||||||
token_context.selected_company.reachable_event_codes
|
|
||||||
)
|
|
||||||
elif token_context.is_occupant:
|
|
||||||
reachable_event_codes: list[str] = (
|
|
||||||
token_context.selected_occupant.reachable_event_codes
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
raise HTTPExceptionApi(
|
|
||||||
error_code="",
|
|
||||||
lang="en",
|
|
||||||
loc=get_line_number_for_error(),
|
|
||||||
sys_msg="Token not found",
|
|
||||||
)
|
|
||||||
|
|
||||||
if not access_token:
|
if not access_token:
|
||||||
raise HTTPExceptionApi(
|
raise HTTPExceptionApi(
|
||||||
error_code="",
|
error_code="",
|
||||||
|
|
@ -158,12 +51,42 @@ class TokenEventMiddleware:
|
||||||
sys_msg="Token not found",
|
sys_msg="Token not found",
|
||||||
)
|
)
|
||||||
|
|
||||||
db = EndpointRestriction.new_session()
|
# Get token context from Redis by access token and collect reachable event codes
|
||||||
restriction = EndpointRestriction.filter_one(
|
token_context = TokenService.get_object_via_access_key(access_token=access_token)
|
||||||
EndpointRestriction.endpoint_name == endpoint_from_scope,
|
if token_context.is_employee:
|
||||||
db=db,
|
reachable_event_codes: list[str] = token_context.selected_company.reachable_event_codes
|
||||||
).data
|
elif token_context.is_occupant:
|
||||||
if not restriction:
|
reachable_event_codes: list[str] = token_context.selected_occupant.reachable_event_codes
|
||||||
|
else:
|
||||||
|
raise HTTPExceptionApi(
|
||||||
|
error_code="",
|
||||||
|
lang="en",
|
||||||
|
loc=get_line_number_for_error(),
|
||||||
|
sys_msg="Token not found",
|
||||||
|
)
|
||||||
|
return token_context, reachable_event_codes
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def retrieve_intersected_event_code(request: Request, reachable_event_codes: list[str]) -> str:
|
||||||
|
"""
|
||||||
|
Match an endpoint with accessible events.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request: The endpoint to match
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dict containing the endpoint registration data
|
||||||
|
None if endpoint is not found in database
|
||||||
|
"""
|
||||||
|
endpoint_url = str(request.url.path)
|
||||||
|
# Get the endpoint URL for matching with events
|
||||||
|
function_codes_of_endpoint = RedisActions.get_json(
|
||||||
|
list_keys=[
|
||||||
|
RedisCategoryKeys.METHOD_FUNCTION_CODES, "*", endpoint_url
|
||||||
|
]
|
||||||
|
)
|
||||||
|
function_code_list_of_event = function_codes_of_endpoint.first
|
||||||
|
if not function_codes_of_endpoint.status:
|
||||||
raise HTTPExceptionApi(
|
raise HTTPExceptionApi(
|
||||||
error_code="",
|
error_code="",
|
||||||
lang="en",
|
lang="en",
|
||||||
|
|
@ -171,36 +94,16 @@ class TokenEventMiddleware:
|
||||||
sys_msg="Function code not found",
|
sys_msg="Function code not found",
|
||||||
)
|
)
|
||||||
|
|
||||||
event_related = Events.filter_all(
|
# Intersect function codes with user accers objects available event codes
|
||||||
Events.endpoint_id == restriction.id,
|
intersected_code = list(set(function_code_list_of_event) & set(reachable_event_codes))
|
||||||
db=db,
|
if not len(intersected_code) == 1:
|
||||||
).data
|
|
||||||
if not event_related:
|
|
||||||
raise HTTPExceptionApi(
|
raise HTTPExceptionApi(
|
||||||
error_code="",
|
error_code="",
|
||||||
lang="en",
|
lang="en",
|
||||||
loc=get_line_number_for_error(),
|
loc=get_line_number_for_error(),
|
||||||
sys_msg="No event is registered for this user.",
|
sys_msg="No event is registered for this user.",
|
||||||
)
|
)
|
||||||
an_event = event_related[0]
|
return endpoint_url, intersected_code[0]
|
||||||
event_related_codes: list[str] = [
|
|
||||||
event.function_code for event in event_related
|
|
||||||
]
|
|
||||||
intersected_code: set = set(reachable_event_codes).intersection(
|
|
||||||
set(event_related_codes)
|
|
||||||
)
|
|
||||||
if not len(list(intersected_code)) == 1:
|
|
||||||
raise HTTPExceptionApi(
|
|
||||||
error_code="",
|
|
||||||
lang="en",
|
|
||||||
loc=get_line_number_for_error(),
|
|
||||||
sys_msg="No event is registered for this user.",
|
|
||||||
)
|
|
||||||
return {
|
|
||||||
"endpoint_url": endpoint_from_scope,
|
|
||||||
"reachable_event_code": list(intersected_code)[0],
|
|
||||||
"class": an_event.function_class,
|
|
||||||
}
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def event_required(cls, func: Callable) -> Callable:
|
def event_required(cls, func: Callable) -> Callable:
|
||||||
|
|
@ -216,88 +119,22 @@ class TokenEventMiddleware:
|
||||||
Returns:
|
Returns:
|
||||||
Callable: The wrapped function with both auth and event handling
|
Callable: The wrapped function with both auth and event handling
|
||||||
"""
|
"""
|
||||||
# First apply authentication
|
|
||||||
authenticated_func = MiddlewareModule.auth_required(func)
|
|
||||||
|
|
||||||
@wraps(authenticated_func)
|
@wraps(func)
|
||||||
async def wrapper(request: Request, *args, **kwargs) -> Dict[str, Any]:
|
async def wrapper(request: Request, *args, **kwargs) -> Dict[str, Any]:
|
||||||
# Get the endpoint URL for matching with events
|
|
||||||
endpoint_url = str(request.url.path)
|
|
||||||
|
|
||||||
# Set func_code first
|
# Get and validate token context from request
|
||||||
func_code = "8aytr-"
|
# token_context, reachable_event_codes = cls.retrieve_access_content(request)
|
||||||
setattr(wrapper, 'func_code', func_code)
|
token_context, reachable_event_codes = {"token": "context", "context": {}}, ["g1j8i6j7-9k4h-0h6l-4i3j-2j0k1k0j0i0k"]
|
||||||
|
endpoint_url, reachable_event_code = cls.retrieve_intersected_event_code(request, reachable_event_codes)
|
||||||
|
event_context = EventContext(auth=token_context, code=reachable_event_code, url=endpoint_url)
|
||||||
|
|
||||||
# Get auth context from the authenticated function's wrapper
|
# Get auth context from the authenticated function's wrapper
|
||||||
auth_context = getattr(authenticated_func, 'auth', None)
|
if token_context is not None:
|
||||||
print('auth_context', auth_context)
|
setattr(wrapper, 'event_context', event_context)
|
||||||
if auth_context is not None:
|
setattr(func, 'event_context', event_context)
|
||||||
setattr(wrapper, 'auth', auth_context)
|
|
||||||
|
|
||||||
# Execute the authenticated function and get its result
|
# Execute the authenticated function and get its result
|
||||||
if inspect.iscoroutinefunction(authenticated_func):
|
|
||||||
result = await authenticated_func(request, *args, **kwargs)
|
|
||||||
else:
|
|
||||||
result = authenticated_func(request, *args, **kwargs)
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
# Copy any existing attributes from the authenticated function
|
|
||||||
for attr in dir(authenticated_func):
|
|
||||||
if not attr.startswith('__'):
|
|
||||||
setattr(wrapper, attr, getattr(authenticated_func, attr))
|
|
||||||
|
|
||||||
return wrapper
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def validation_required(
|
|
||||||
func: Callable[..., Dict[str, Any]]
|
|
||||||
) -> Callable[..., Dict[str, Any]]:
|
|
||||||
"""
|
|
||||||
Decorator for endpoints with token and event requirements.
|
|
||||||
This decorator:
|
|
||||||
1. First validates authentication using MiddlewareModule.auth_required
|
|
||||||
2. Then adds event tracking context
|
|
||||||
|
|
||||||
Args:
|
|
||||||
func: The function to be decorated
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Callable: The wrapped function with both auth and event handling
|
|
||||||
"""
|
|
||||||
# First apply authentication
|
|
||||||
# authenticated_func = MiddlewareModule.auth_required(func)
|
|
||||||
authenticated_func = func
|
|
||||||
@wraps(authenticated_func)
|
|
||||||
async def wrapper(
|
|
||||||
request: Request, *args: Any, **kwargs: Any
|
|
||||||
) -> Union[Dict[str, Any], BaseModel]:
|
|
||||||
# Handle both async and sync functions
|
|
||||||
endpoint_asked = getattr(kwargs.get("data", None), "data", None).get(
|
|
||||||
"endpoint", None
|
|
||||||
)
|
|
||||||
if not endpoint_asked:
|
|
||||||
raise HTTPExceptionApi(
|
|
||||||
error_code="",
|
|
||||||
lang="en",
|
|
||||||
loc=get_line_number_for_error(),
|
|
||||||
sys_msg="Endpoint not found",
|
|
||||||
)
|
|
||||||
func.func_code = cls.match_endpoint_with_accessible_event(
|
|
||||||
endpoint_url, request
|
|
||||||
)
|
|
||||||
if inspect.iscoroutinefunction(authenticated_func):
|
|
||||||
result = await authenticated_func(request, *args, **kwargs)
|
|
||||||
else:
|
|
||||||
result = authenticated_func(request, *args, **kwargs)
|
|
||||||
function_auth = getattr(authenticated_func, "auth", None)
|
|
||||||
wrapper.auth = function_auth
|
|
||||||
func.auth = function_auth
|
|
||||||
authenticated_func.auth = function_auth
|
|
||||||
if inspect.iscoroutinefunction(authenticated_func):
|
|
||||||
result = await authenticated_func(request, *args, **kwargs)
|
|
||||||
else:
|
|
||||||
result = authenticated_func(request, *args, **kwargs)
|
|
||||||
if inspect.iscoroutinefunction(func):
|
if inspect.iscoroutinefunction(func):
|
||||||
result = await func(request, *args, **kwargs)
|
result = await func(request, *args, **kwargs)
|
||||||
else:
|
else:
|
||||||
|
|
@ -305,3 +142,41 @@ class TokenEventMiddleware:
|
||||||
return result
|
return result
|
||||||
|
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
# event_required is already sets function_code state to wrapper
|
||||||
|
# @classmethod
|
||||||
|
# def validation_required(cls, func: Callable[..., Dict[str, Any]]) -> Callable[..., Dict[str, Any]]:
|
||||||
|
# """
|
||||||
|
# Decorator for endpoints with token and event requirements.
|
||||||
|
# This decorator:
|
||||||
|
# 1. First validates authentication using MiddlewareModule.auth_required
|
||||||
|
# 2. Then adds event tracking context
|
||||||
|
|
||||||
|
# Args:
|
||||||
|
# func: The function to be decorated
|
||||||
|
|
||||||
|
# Returns:
|
||||||
|
# Callable: The wrapped function with both auth and event handling
|
||||||
|
# """
|
||||||
|
|
||||||
|
# @wraps(func)
|
||||||
|
# async def wrapper(request: Request, *args: Any, **kwargs: Any) -> Union[Dict[str, Any], BaseModel]:
|
||||||
|
|
||||||
|
# # Get and validate token context from request
|
||||||
|
# token_context, reachable_event_codes = cls.retrieve_access_content(request)
|
||||||
|
# endpoint_url, reachable_event_code = cls.retrieve_intersected_event_code(request, reachable_event_codes)
|
||||||
|
|
||||||
|
# # Get auth context from the authenticated function's wrapper
|
||||||
|
# if token_context is not None:
|
||||||
|
# setattr(wrapper, 'auth', token_context)
|
||||||
|
# setattr(wrapper, 'url', endpoint_url)
|
||||||
|
# setattr(wrapper, 'func_code', reachable_event_code)
|
||||||
|
|
||||||
|
# # Execute the authenticated function and get its result
|
||||||
|
# if inspect.iscoroutinefunction(func):
|
||||||
|
# result = await func(request, *args, **kwargs)
|
||||||
|
# else:
|
||||||
|
# result = func(request, *args, **kwargs)
|
||||||
|
# return result
|
||||||
|
|
||||||
|
# return wrapper
|
||||||
|
|
@ -4,7 +4,10 @@ Handles dynamic route creation based on configurations.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from fastapi import Request
|
from fastapi import Request
|
||||||
from Events.Engine.set_defaults.setClusters import PrepareRouting
|
from Events.Engine.set_defaults.run import get_cluster_controller_group
|
||||||
|
from Events.Engine.set_defaults.setClusters import PrepareRouting, SetItems2Redis, PrepareEvents
|
||||||
|
|
||||||
|
routers = None
|
||||||
|
|
||||||
|
|
||||||
async def health_check(request: Request):
|
async def health_check(request: Request):
|
||||||
|
|
@ -24,8 +27,11 @@ def get_all_routers() -> PrepareRouting:
|
||||||
Returns:
|
Returns:
|
||||||
tuple: (routers, protected_routes)
|
tuple: (routers, protected_routes)
|
||||||
"""
|
"""
|
||||||
from Events.Engine.set_defaults.run import get_cluster_controller_group
|
global routers
|
||||||
|
if not routers:
|
||||||
cluster_list = get_cluster_controller_group()
|
cluster_list = get_cluster_controller_group()
|
||||||
prepare_routing = PrepareRouting(cluster_controller_group=cluster_list)
|
prepare_routing = PrepareRouting(cluster_controller_group=cluster_list)
|
||||||
|
prepare_events = PrepareEvents(cluster_controller_group=cluster_list)
|
||||||
|
set_items_2_redis = SetItems2Redis(prepare_events=prepare_events)
|
||||||
return prepare_routing
|
return prepare_routing
|
||||||
|
return routers
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,10 @@ Handles dynamic route creation based on configurations.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from fastapi import Request
|
from fastapi import Request
|
||||||
from Events.Engine.set_defaults.setClusters import PrepareRouting
|
from Events.Engine.set_defaults.run import get_cluster_controller_group
|
||||||
|
from Events.Engine.set_defaults.setClusters import PrepareRouting, SetItems2Redis, PrepareEvents
|
||||||
|
|
||||||
|
routers = None
|
||||||
|
|
||||||
|
|
||||||
async def health_check(request: Request):
|
async def health_check(request: Request):
|
||||||
|
|
@ -24,10 +27,11 @@ def get_all_routers() -> PrepareRouting:
|
||||||
Returns:
|
Returns:
|
||||||
tuple: (routers, protected_routes)
|
tuple: (routers, protected_routes)
|
||||||
"""
|
"""
|
||||||
from Events.Engine.set_defaults.run import get_cluster_controller_group
|
global routers
|
||||||
|
if not routers:
|
||||||
cluster_list = get_cluster_controller_group()
|
cluster_list = get_cluster_controller_group()
|
||||||
prepare_routing = PrepareRouting(cluster_controller_group=cluster_list)
|
prepare_routing = PrepareRouting(cluster_controller_group=cluster_list)
|
||||||
|
prepare_events = PrepareEvents(cluster_controller_group=cluster_list)
|
||||||
|
set_items_2_redis = SetItems2Redis(prepare_events=prepare_events)
|
||||||
return prepare_routing
|
return prepare_routing
|
||||||
|
return routers
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ Authentication related API endpoints.
|
||||||
|
|
||||||
from typing import Union, Any, Dict
|
from typing import Union, Any, Dict
|
||||||
|
|
||||||
|
from ApiLayers.ApiValidations.Custom.wrapper_contexts import AuthContext, EventContext
|
||||||
from ApiLayers.Middleware import MiddlewareModule, TokenEventMiddleware
|
from ApiLayers.Middleware import MiddlewareModule, TokenEventMiddleware
|
||||||
from ApiLayers.ApiValidations.Request import EmployeeSelection, OccupantSelection
|
from ApiLayers.ApiValidations.Request import EmployeeSelection, OccupantSelection
|
||||||
|
|
||||||
|
|
@ -39,7 +40,7 @@ AuthenticationLoginEventMethods = MethodToEvent(
|
||||||
},
|
},
|
||||||
headers=[],
|
headers=[],
|
||||||
errors=[],
|
errors=[],
|
||||||
url="/authentication/login",
|
url="/login",
|
||||||
method="POST",
|
method="POST",
|
||||||
summary="Login via domain and access key : [email] | [phone]",
|
summary="Login via domain and access key : [email] | [phone]",
|
||||||
description="Login to the system via domain, access key : [email] | [phone]",
|
description="Login to the system via domain, access key : [email] | [phone]",
|
||||||
|
|
@ -49,9 +50,7 @@ def authentication_login_with_domain_and_creds(
|
||||||
request: Request,
|
request: Request,
|
||||||
data: EndpointBaseRequestModel,
|
data: EndpointBaseRequestModel,
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
function = AuthenticationLoginEventMethods.retrieve_event(
|
function = AuthenticationLoginEventMethods.retrieve_event(event_function_code=f"{authentication_login_super_user_event.key}")
|
||||||
event_function_code=f"{authentication_login_super_user_event.key}"
|
|
||||||
)
|
|
||||||
return function.endpoint_callable(request=request, data=data)
|
return function.endpoint_callable(request=request, data=data)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -65,7 +64,7 @@ AuthenticationSelectEventMethods = MethodToEvent(
|
||||||
decorators_list=[MiddlewareModule.auth_required],
|
decorators_list=[MiddlewareModule.auth_required],
|
||||||
headers=[],
|
headers=[],
|
||||||
errors=[],
|
errors=[],
|
||||||
url="/authentication/select",
|
url="/select",
|
||||||
method="POST",
|
method="POST",
|
||||||
summary="Select company or occupant type",
|
summary="Select company or occupant type",
|
||||||
description="Select company or occupant type",
|
description="Select company or occupant type",
|
||||||
|
|
@ -95,7 +94,7 @@ AuthenticationCheckTokenEventMethods = MethodToEvent(
|
||||||
headers=[],
|
headers=[],
|
||||||
errors=[],
|
errors=[],
|
||||||
decorators_list=[MiddlewareModule.auth_required],
|
decorators_list=[MiddlewareModule.auth_required],
|
||||||
url="/authentication/check-token",
|
url="/check-token",
|
||||||
method="POST",
|
method="POST",
|
||||||
summary="Check if token is valid",
|
summary="Check if token is valid",
|
||||||
description="Check if access token is valid for user",
|
description="Check if access token is valid for user",
|
||||||
|
|
@ -118,7 +117,7 @@ AuthenticationRefreshEventMethods = MethodToEvent(
|
||||||
headers=[],
|
headers=[],
|
||||||
errors=[],
|
errors=[],
|
||||||
decorators_list=[MiddlewareModule.auth_required],
|
decorators_list=[MiddlewareModule.auth_required],
|
||||||
url="/authentication/refresh",
|
url="/refresh",
|
||||||
method="POST",
|
method="POST",
|
||||||
summary="Refresh user info",
|
summary="Refresh user info",
|
||||||
description="Refresh user info using access token",
|
description="Refresh user info using access token",
|
||||||
|
|
@ -143,7 +142,7 @@ AuthenticationChangePasswordEventMethods = MethodToEvent(
|
||||||
headers=[],
|
headers=[],
|
||||||
errors=[],
|
errors=[],
|
||||||
decorators_list=[MiddlewareModule.auth_required],
|
decorators_list=[MiddlewareModule.auth_required],
|
||||||
url="/authentication/change-password",
|
url="/change-password",
|
||||||
method="POST",
|
method="POST",
|
||||||
summary="Change password",
|
summary="Change password",
|
||||||
description="Change password with access token",
|
description="Change password with access token",
|
||||||
|
|
@ -166,7 +165,7 @@ AuthenticationCreatePasswordEventMethods = MethodToEvent(
|
||||||
},
|
},
|
||||||
headers=[],
|
headers=[],
|
||||||
errors=[],
|
errors=[],
|
||||||
url="/authentication/create-password",
|
url="/create-password",
|
||||||
method="POST",
|
method="POST",
|
||||||
summary="Create password",
|
summary="Create password",
|
||||||
description="Create password with password reset token requested via email",
|
description="Create password with password reset token requested via email",
|
||||||
|
|
@ -189,7 +188,7 @@ AuthenticationDisconnectUserEventMethods = MethodToEvent(
|
||||||
decorators_list=[MiddlewareModule.auth_required],
|
decorators_list=[MiddlewareModule.auth_required],
|
||||||
headers=[],
|
headers=[],
|
||||||
errors=[],
|
errors=[],
|
||||||
url="/authentication/disconnect",
|
url="/disconnect",
|
||||||
method="POST",
|
method="POST",
|
||||||
summary="Disconnect all sessions",
|
summary="Disconnect all sessions",
|
||||||
description="Disconnect all sessions of user in access token",
|
description="Disconnect all sessions of user in access token",
|
||||||
|
|
@ -210,28 +209,25 @@ AuthenticationLogoutEventMethods = MethodToEvent(
|
||||||
},
|
},
|
||||||
headers=[],
|
headers=[],
|
||||||
errors=[],
|
errors=[],
|
||||||
url="/authentication/logout",
|
decorators_list=[TokenEventMiddleware.event_required],
|
||||||
|
url="/logout",
|
||||||
method="POST",
|
method="POST",
|
||||||
summary="Logout user",
|
summary="Logout user",
|
||||||
description="Logout only single session of user which domain is provided",
|
description="Logout only single session of user which domain is provided",
|
||||||
)
|
)
|
||||||
|
|
||||||
@TokenEventMiddleware.event_required
|
|
||||||
def authentication_logout_user(request: Request, data: EndpointBaseRequestModel):
|
def authentication_logout_user(request: Request, data: EndpointBaseRequestModel):
|
||||||
function = AuthenticationLogoutEventMethods.retrieve_event(
|
event_context: EventContext = getattr(authentication_logout_user, "event_context", None)
|
||||||
event_function_code=f"{authentication_logout_user_event.key}"
|
print('event_context', event_context)
|
||||||
)
|
function = AuthenticationLogoutEventMethods.retrieve_event(event_function_code=f"{event_context.code}")
|
||||||
print('authentication_logout_user', dict(
|
function.endpoint_callable.event_context = event_context
|
||||||
auth=getattr(authentication_logout_user, "auth", None),
|
|
||||||
func_code=getattr(authentication_logout_user, "func_code", None),
|
|
||||||
))
|
|
||||||
function.endpoint_callable.auth = getattr(authentication_logout_user, "auth", None)
|
|
||||||
function.endpoint_callable.func_code = getattr(authentication_logout_user, "func_code", None)
|
|
||||||
return function.endpoint_callable(request=request, data=data)
|
return function.endpoint_callable(request=request, data=data)
|
||||||
|
|
||||||
|
|
||||||
AuthenticationLogoutEventMethods.endpoint_callable = authentication_logout_user
|
AuthenticationLogoutEventMethods.endpoint_callable = authentication_logout_user
|
||||||
|
|
||||||
|
|
||||||
AuthenticationRefreshTokenEventMethods = MethodToEvent(
|
AuthenticationRefreshTokenEventMethods = MethodToEvent(
|
||||||
name="AuthenticationRefreshTokenEventMethods",
|
name="AuthenticationRefreshTokenEventMethods",
|
||||||
events={
|
events={
|
||||||
|
|
@ -239,19 +235,22 @@ AuthenticationRefreshTokenEventMethods = MethodToEvent(
|
||||||
},
|
},
|
||||||
headers=[],
|
headers=[],
|
||||||
errors=[],
|
errors=[],
|
||||||
decorators_list=[MiddlewareModule.auth_required, ],
|
decorators_list=[MiddlewareModule.auth_required],
|
||||||
url="/authentication/refresh-token",
|
url="/refresh-token",
|
||||||
method="POST",
|
method="POST",
|
||||||
summary="Refresh token",
|
summary="Refresh token",
|
||||||
description="Refresh access token with refresher token",
|
description="Refresh access token with refresher token",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def authentication_refresher_token(request: Request, data: EndpointBaseRequestModel):
|
def authentication_refresher_token(request: Request, data: EndpointBaseRequestModel):
|
||||||
token_dict = authentication_refresher_token.auth
|
auth_context: AuthContext = getattr(authentication_refresher_token, "auth_context", None)
|
||||||
function = AuthenticationRefreshTokenEventMethods.retrieve_event(
|
function = AuthenticationRefreshTokenEventMethods.retrieve_event(
|
||||||
event_function_code=f"{authentication_refresher_token_event.key}"
|
event_function_code=f"{authentication_refresher_token_event.key}"
|
||||||
)
|
)
|
||||||
return function.endpoint_callable(data=data, request=request, token_dict=token_dict)
|
function.endpoint_callable.auth_context = auth_context
|
||||||
|
return function.endpoint_callable(data=data, request=request)
|
||||||
|
|
||||||
|
|
||||||
AuthenticationRefreshTokenEventMethods.endpoint_callable = authentication_refresher_token
|
AuthenticationRefreshTokenEventMethods.endpoint_callable = authentication_refresher_token
|
||||||
|
|
||||||
|
|
@ -263,7 +262,7 @@ AuthenticationForgotPasswordEventMethods = MethodToEvent(
|
||||||
},
|
},
|
||||||
headers=[],
|
headers=[],
|
||||||
errors=[],
|
errors=[],
|
||||||
url="/authentication/forgot-password",
|
url="/forgot-password",
|
||||||
method="POST",
|
method="POST",
|
||||||
summary="Request password reset",
|
summary="Request password reset",
|
||||||
description="Send an email to user for a valid password reset token",
|
description="Send an email to user for a valid password reset token",
|
||||||
|
|
@ -289,7 +288,7 @@ AuthenticationResetPasswordEventMethods = MethodToEvent(
|
||||||
headers=[],
|
headers=[],
|
||||||
errors=[],
|
errors=[],
|
||||||
decorators_list=[MiddlewareModule.auth_required],
|
decorators_list=[MiddlewareModule.auth_required],
|
||||||
url="/authentication/reset-password",
|
url="/reset-password",
|
||||||
method="POST",
|
method="POST",
|
||||||
summary="Reset password",
|
summary="Reset password",
|
||||||
description="Reset user password",
|
description="Reset user password",
|
||||||
|
|
@ -314,7 +313,7 @@ AuthenticationDownloadAvatarEventMethods = MethodToEvent(
|
||||||
headers=[],
|
headers=[],
|
||||||
errors=[],
|
errors=[],
|
||||||
decorators_list=[],
|
decorators_list=[],
|
||||||
url="/authentication/download-avatar",
|
url="/download-avatar",
|
||||||
method="POST",
|
method="POST",
|
||||||
summary="Download avatar",
|
summary="Download avatar",
|
||||||
description="Download avatar icon and profile info of user",
|
description="Download avatar icon and profile info of user",
|
||||||
|
|
|
||||||
|
|
@ -23,20 +23,20 @@ AuthCluster = CategoryCluster(
|
||||||
prefix="/authentication",
|
prefix="/authentication",
|
||||||
description="Authentication cluster",
|
description="Authentication cluster",
|
||||||
pageinfo=authentication_page_info,
|
pageinfo=authentication_page_info,
|
||||||
endpoints=[
|
endpoints={
|
||||||
AuthenticationLoginEventMethods,
|
"AuthenticationLoginEventMethods": AuthenticationLoginEventMethods,
|
||||||
AuthenticationLogoutEventMethods,
|
"AuthenticationLogoutEventMethods": AuthenticationLogoutEventMethods,
|
||||||
AuthenticationRefreshTokenEventMethods,
|
"AuthenticationRefreshTokenEventMethods": AuthenticationRefreshTokenEventMethods,
|
||||||
AuthenticationForgotPasswordEventMethods,
|
"AuthenticationForgotPasswordEventMethods": AuthenticationForgotPasswordEventMethods,
|
||||||
AuthenticationChangePasswordEventMethods,
|
"AuthenticationChangePasswordEventMethods": AuthenticationChangePasswordEventMethods,
|
||||||
AuthenticationCheckTokenEventMethods,
|
"AuthenticationCheckTokenEventMethods": AuthenticationCheckTokenEventMethods,
|
||||||
AuthenticationCreatePasswordEventMethods,
|
"AuthenticationCreatePasswordEventMethods": AuthenticationCreatePasswordEventMethods,
|
||||||
AuthenticationDisconnectUserEventMethods,
|
"AuthenticationDisconnectUserEventMethods": AuthenticationDisconnectUserEventMethods,
|
||||||
AuthenticationDownloadAvatarEventMethods,
|
"AuthenticationDownloadAvatarEventMethods": AuthenticationDownloadAvatarEventMethods,
|
||||||
AuthenticationResetPasswordEventMethods,
|
"AuthenticationResetPasswordEventMethods": AuthenticationResetPasswordEventMethods,
|
||||||
AuthenticationRefreshEventMethods,
|
"AuthenticationRefreshEventMethods": AuthenticationRefreshEventMethods,
|
||||||
AuthenticationSelectEventMethods,
|
"AuthenticationSelectEventMethods": AuthenticationSelectEventMethods,
|
||||||
],
|
},
|
||||||
include_in_schema=True,
|
include_in_schema=True,
|
||||||
sub_category=[],
|
sub_category=[],
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ from ApiLayers.ApiLibrary.common.line_number import get_line_number_for_error
|
||||||
from ApiLayers.ApiServices.Login.user_login_handler import UserLoginModule
|
from ApiLayers.ApiServices.Login.user_login_handler import UserLoginModule
|
||||||
from ApiLayers.ApiServices.Token.token_handler import TokenService
|
from ApiLayers.ApiServices.Token.token_handler import TokenService
|
||||||
from ApiLayers.ApiValidations.Custom.token_objects import CompanyToken, OccupantToken
|
from ApiLayers.ApiValidations.Custom.token_objects import CompanyToken, OccupantToken
|
||||||
|
from ApiLayers.ApiValidations.Custom.wrapper_contexts import AuthContext, EventContext
|
||||||
from ApiLayers.ErrorHandlers import HTTPExceptionApi
|
from ApiLayers.ErrorHandlers import HTTPExceptionApi
|
||||||
from ApiLayers.Schemas import (
|
from ApiLayers.Schemas import (
|
||||||
BuildLivingSpace,
|
BuildLivingSpace,
|
||||||
|
|
@ -372,14 +373,12 @@ def authentication_logout_user(request: Request, data: Any):
|
||||||
# selected_user.remove_refresher_token(domain=data.domain)
|
# selected_user.remove_refresher_token(domain=data.domain)
|
||||||
# return ResponseHandler.success("Session is logged out", data=token_user)
|
# return ResponseHandler.success("Session is logged out", data=token_user)
|
||||||
# return ResponseHandler.not_found("Logout is not successfully completed")
|
# return ResponseHandler.not_found("Logout is not successfully completed")
|
||||||
token_dict = authentication_logout_user.auth
|
|
||||||
print('token_dict', token_dict)
|
event_context: EventContext = getattr(authentication_logout_user, "event_context", None)
|
||||||
func_code = authentication_logout_user.func_code
|
return event_context.model_dump()
|
||||||
print('func_code', func_code)
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
def authentication_refresher_token(request: Request, token_dict: TokenDictType, data: Any):
|
def authentication_refresher_token(request: Request, data: Any):
|
||||||
"""Refresh access token with refresher token"""
|
"""Refresh access token with refresher token"""
|
||||||
# token_refresher = UsersTokens.filter_by_one(
|
# token_refresher = UsersTokens.filter_by_one(
|
||||||
# token=data.refresh_token,
|
# token=data.refresh_token,
|
||||||
|
|
@ -402,7 +401,8 @@ def authentication_refresher_token(request: Request, token_dict: TokenDictType,
|
||||||
# }
|
# }
|
||||||
# return ResponseHandler.success("User is logged in successfully via refresher token", data=response_data)
|
# return ResponseHandler.success("User is logged in successfully via refresher token", data=response_data)
|
||||||
# return ResponseHandler.not_found("Invalid data")
|
# return ResponseHandler.not_found("Invalid data")
|
||||||
return
|
auth_context: AuthContext = getattr(authentication_refresher_token, "auth_context", None)
|
||||||
|
return auth_context.model_dump()
|
||||||
|
|
||||||
|
|
||||||
def authentication_forgot_password(request: Request, data: Any):
|
def authentication_forgot_password(request: Request, data: Any):
|
||||||
|
|
|
||||||
|
|
@ -4,3 +4,10 @@ import Events.AllEvents.validations as validations_events
|
||||||
|
|
||||||
|
|
||||||
events_list = (auths_events, events_events, validations_events)
|
events_list = (auths_events, events_events, validations_events)
|
||||||
|
|
||||||
|
|
||||||
|
def retrieve_cluster_by_name(cluster_name: str):
|
||||||
|
for module in events_list:
|
||||||
|
if hasattr(module, cluster_name, None):
|
||||||
|
return getattr(module, cluster_name, None)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -135,11 +135,11 @@ class MethodToEvent:
|
||||||
return found_event
|
return found_event
|
||||||
raise ValueError(f"Event with function code {event_function_code} not found")
|
raise ValueError(f"Event with function code {event_function_code} not found")
|
||||||
|
|
||||||
def retrieve_redis_value(self, cluster_name: str) -> Dict:
|
def retrieve_redis_value(self, cluster: "CategoryCluster") -> Dict:
|
||||||
"""
|
"""
|
||||||
Key("METHOD_FUNCTION_CODES:{ClusterToMethod}:MethodEvent:Endpoint") : Value([FUNCTION_CODE, ...])
|
Key("METHOD_FUNCTION_CODES:{ClusterToMethod}:MethodEvent:Endpoint") : Value([FUNCTION_CODE, ...])
|
||||||
"""
|
"""
|
||||||
redis_key = f"{RedisCategoryKeys.METHOD_FUNCTION_CODES}:{cluster_name}:{self.name}:{self.URL}"
|
redis_key = f"{RedisCategoryKeys.METHOD_FUNCTION_CODES}:{cluster.name}:{self.name}:{f"{cluster.PREFIX}{self.URL}"}"
|
||||||
return {redis_key: self.retrieve_all_event_keys()}
|
return {redis_key: self.retrieve_all_event_keys()}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
@ -156,7 +156,7 @@ class CategoryCluster:
|
||||||
PREFIX: str
|
PREFIX: str
|
||||||
PAGEINFO: PageInfo
|
PAGEINFO: PageInfo
|
||||||
DESCRIPTION: str
|
DESCRIPTION: str
|
||||||
ENDPOINTS: list[MethodToEvent] # [MethodToEvent, ...]
|
ENDPOINTS: dict[str, MethodToEvent] # {"MethodToEvent": MethodToEvent, ...}
|
||||||
SUBCATEGORY: Optional[List["CategoryCluster"]] # [CategoryCluster, ...]
|
SUBCATEGORY: Optional[List["CategoryCluster"]] # [CategoryCluster, ...]
|
||||||
INCLUDE_IN_SCHEMA: Optional[bool] = True
|
INCLUDE_IN_SCHEMA: Optional[bool] = True
|
||||||
|
|
||||||
|
|
@ -167,7 +167,7 @@ class CategoryCluster:
|
||||||
prefix: str,
|
prefix: str,
|
||||||
description: str,
|
description: str,
|
||||||
pageinfo: PageInfo,
|
pageinfo: PageInfo,
|
||||||
endpoints: list[MethodToEvent],
|
endpoints: dict[str, MethodToEvent],
|
||||||
sub_category: list,
|
sub_category: list,
|
||||||
include_in_schema: Optional[bool] = True,
|
include_in_schema: Optional[bool] = True,
|
||||||
):
|
):
|
||||||
|
|
@ -176,7 +176,7 @@ class CategoryCluster:
|
||||||
self.PREFIX = prefix
|
self.PREFIX = prefix
|
||||||
self.PAGEINFO = pageinfo
|
self.PAGEINFO = pageinfo
|
||||||
self.DESCRIPTION = description
|
self.DESCRIPTION = description
|
||||||
self.ENDPOINTS = endpoints or []
|
self.ENDPOINTS = endpoints or {}
|
||||||
self.SUBCATEGORY = sub_category or []
|
self.SUBCATEGORY = sub_category or []
|
||||||
self.INCLUDE_IN_SCHEMA = include_in_schema
|
self.INCLUDE_IN_SCHEMA = include_in_schema
|
||||||
|
|
||||||
|
|
@ -189,7 +189,7 @@ class CategoryCluster:
|
||||||
RedisCategoryKeys.CLUSTER_2_METHOD_EVENT
|
RedisCategoryKeys.CLUSTER_2_METHOD_EVENT
|
||||||
Returns the class name and function codes for the class.
|
Returns the class name and function codes for the class.
|
||||||
"""
|
"""
|
||||||
dict_cluster_2_method, list_endpoints = {}, [i.name for i in self.ENDPOINTS]
|
dict_cluster_2_method, list_endpoints = {}, [i.name for i in self.ENDPOINTS.values()]
|
||||||
for endpoint_name in list_endpoints:
|
for endpoint_name in list_endpoints:
|
||||||
dict_cluster_2_method[endpoint_name] = self.name
|
dict_cluster_2_method[endpoint_name] = self.name
|
||||||
dict_cluster_2_method[self.name] = list_endpoints
|
dict_cluster_2_method[self.name] = list_endpoints
|
||||||
|
|
@ -200,7 +200,7 @@ class CategoryCluster:
|
||||||
Retrieves all function codes by iterating over the events list.
|
Retrieves all function codes by iterating over the events list.
|
||||||
"""
|
"""
|
||||||
all_function_codes = []
|
all_function_codes = []
|
||||||
for event_method in self.ENDPOINTS:
|
for event_method in self.ENDPOINTS.values():
|
||||||
all_function_codes.extend([str(event_key) for event_key in event_method.EVENTS.keys()])
|
all_function_codes.extend([str(event_key) for event_key in event_method.EVENTS.keys()])
|
||||||
return all_function_codes
|
return all_function_codes
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
from Events.AllEvents.events_file import events_list
|
from Events.AllEvents.events_file import events_list
|
||||||
|
|
||||||
from .category_cluster_models import cluster_controller
|
from .category_cluster_models import cluster_controller
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -7,10 +8,12 @@ def get_cluster_controller_group():
|
||||||
cluster_controller.import_all_category_clusters(cluster)
|
cluster_controller.import_all_category_clusters(cluster)
|
||||||
return cluster_controller
|
return cluster_controller
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
prepare_routing = PrepareRouting(cluster_controller_group=cluster_controller)
|
prepare_routing = PrepareRouting(cluster_controller_group=cluster_controller)
|
||||||
prepare_events = PrepareEvents(cluster_controller_group=cluster_controller)
|
prepare_events = PrepareEvents(cluster_controller_group=cluster_controller)
|
||||||
set_items_2_redis = SetItems2Redis(prepare_events=prepare_events)
|
|
||||||
print(set_items_2_redis)
|
print(set_items_2_redis)
|
||||||
print(prepare_routing)
|
print(prepare_routing)
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ class PrepareRouting(DecoratorModule):
|
||||||
return self.__safe_endpoint_list
|
return self.__safe_endpoint_list
|
||||||
|
|
||||||
def create_endpoints(self, cluster: CategoryCluster, created_router):
|
def create_endpoints(self, cluster: CategoryCluster, created_router):
|
||||||
for method_endpoint in list(cluster.ENDPOINTS):
|
for method_endpoint in list(cluster.ENDPOINTS.values()):
|
||||||
# Filter out the original function and apply decorators
|
# Filter out the original function and apply decorators
|
||||||
applied_decorators_qualname = self.apply_decorators(method_endpoint)
|
applied_decorators_qualname = self.apply_decorators(method_endpoint)
|
||||||
# Register the endpoint with FastAPI router
|
# Register the endpoint with FastAPI router
|
||||||
|
|
@ -89,17 +89,17 @@ class PrepareEvents(DecoratorModule):
|
||||||
f"{self.valid_redis_items.CLUSTER_FUNCTION_CODES_KEY}:{cluster.name}" : tuple(cluster.retrieve_all_function_codes())
|
f"{self.valid_redis_items.CLUSTER_FUNCTION_CODES_KEY}:{cluster.name}" : tuple(cluster.retrieve_all_function_codes())
|
||||||
}
|
}
|
||||||
|
|
||||||
for method_endpoint in list(cluster.ENDPOINTS):
|
for method_endpoint in list(cluster.ENDPOINTS.values()):
|
||||||
# [SAVE]REDIS => ENDPOINT2CLASS = {MethodEvent: Endpoint("/.../.../..."), ...}
|
# [SAVE]REDIS => ENDPOINT2CLASS = {MethodEvent: Endpoint("/.../.../..."), ...}
|
||||||
self.valid_redis_items.ENDPOINT2CLASS_VALUE.update(
|
self.valid_redis_items.ENDPOINT2CLASS_VALUE.update(
|
||||||
{f"{cluster.name}:{method_endpoint.name}": method_endpoint.URL}
|
{f"{cluster.name}:{method_endpoint.name}": f"{cluster.PREFIX}{method_endpoint.URL}"}
|
||||||
)
|
)
|
||||||
self.valid_redis_items.ENDPOINT2CLASS_VALUE.update(
|
self.valid_redis_items.ENDPOINT2CLASS_VALUE.update(
|
||||||
{method_endpoint.URL :f"{cluster.name}:{method_endpoint.name}"}
|
{f"{cluster.PREFIX}{method_endpoint.URL}" :f"{cluster.name}:{method_endpoint.name}"}
|
||||||
)
|
)
|
||||||
# [SAVE]REDIS => METHOD_FUNCTION_CODES:MethodEvent:Endpoint = [FUNCTION_CODE, ...]
|
# [SAVE]REDIS => METHOD_FUNCTION_CODES:MethodEvent:Endpoint = [FUNCTION_CODE, ...]
|
||||||
self.valid_redis_items.METHOD_FUNCTION_CODES_VALUE.update(
|
self.valid_redis_items.METHOD_FUNCTION_CODES_VALUE.update(
|
||||||
method_endpoint.retrieve_redis_value(cluster_name=cluster.name)
|
method_endpoint.retrieve_redis_value(cluster=cluster)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -112,28 +112,22 @@ class SetItems2Redis:
|
||||||
self.set_items()
|
self.set_items()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
self.std_out = f"\nSetItems2Redis:\n\n{self.std_out}"
|
return f"\nSetItems2Redis:\n\n{self.std_out}"
|
||||||
return self.std_out
|
|
||||||
|
|
||||||
def set_items(self):
|
def set_items(self):
|
||||||
from ApiLayers.AllConfigs.Redis.configs import RedisCategoryKeys
|
from ApiLayers.AllConfigs.Redis.configs import RedisCategoryKeys
|
||||||
dict_prep = self.prepare_events.valid_redis_items.as_dict
|
dict_prep = self.prepare_events.valid_redis_items.as_dict
|
||||||
RedisActions.delete(
|
for redis_values_to_delete, redis_key_type in RedisCategoryKeys.__annotations__.items():
|
||||||
list_keys=[
|
if isinstance(redis_key_type, str):
|
||||||
f"{RedisCategoryKeys.MENU_FIRST_LAYER}:*",
|
continue
|
||||||
f"{RedisCategoryKeys.CLUSTER_INDEX}:*",
|
RedisActions.delete(list_keys=[f"{redis_values_to_delete}*"])
|
||||||
f"{RedisCategoryKeys.CLUSTER_FUNCTION_CODES}:*",
|
|
||||||
f"{RedisCategoryKeys.METHOD_FUNCTION_CODES}:*"
|
|
||||||
f"{RedisCategoryKeys.ENDPOINT2CLASS}:*",
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
# Save MENU_FIRST_LAYER to Redis
|
# Save MENU_FIRST_LAYER to Redis
|
||||||
redis_list = RedisList(redis_key=RedisCategoryKeys.MENU_FIRST_LAYER)
|
redis_list = RedisList(redis_key=RedisCategoryKeys.MENU_FIRST_LAYER)
|
||||||
RedisActions.set_json(
|
RedisActions.set_json(
|
||||||
list_keys=redis_list.to_list(), value=dict_prep.get(RedisCategoryKeys.MENU_FIRST_LAYER)
|
list_keys=redis_list.to_list(), value=dict_prep.get(RedisCategoryKeys.MENU_FIRST_LAYER)
|
||||||
)
|
)
|
||||||
self.std_out = f"{RedisCategoryKeys.MENU_FIRST_LAYER}: {dict_prep.get(RedisCategoryKeys.MENU_FIRST_LAYER)}\n"
|
self.std_out += f"{RedisCategoryKeys.MENU_FIRST_LAYER}: {dict_prep.get(RedisCategoryKeys.MENU_FIRST_LAYER)}\n"
|
||||||
|
|
||||||
# Save CLUSTER_INDEX to Redis
|
# Save CLUSTER_INDEX to Redis
|
||||||
redis_list = RedisList(redis_key=RedisCategoryKeys.CLUSTER_INDEX)
|
redis_list = RedisList(redis_key=RedisCategoryKeys.CLUSTER_INDEX)
|
||||||
|
|
@ -167,5 +161,11 @@ class SetItems2Redis:
|
||||||
self.std_out += f"\n{RedisCategoryKeys.ENDPOINT2CLASS}: {dict_prep.get(RedisCategoryKeys.ENDPOINT2CLASS)}\n"
|
self.std_out += f"\n{RedisCategoryKeys.ENDPOINT2CLASS}: {dict_prep.get(RedisCategoryKeys.ENDPOINT2CLASS)}\n"
|
||||||
|
|
||||||
RedisActions.set_json(
|
RedisActions.set_json(
|
||||||
list_keys=[f"{RedisCategoryKeys.REBUILD}:*"], value=False
|
list_keys=[f"{RedisCategoryKeys.REBUILD}:*"], value={
|
||||||
|
f"{RedisCategoryKeys.MENU_FIRST_LAYER}": True,
|
||||||
|
f"{RedisCategoryKeys.CLUSTER_INDEX}": True,
|
||||||
|
f"{RedisCategoryKeys.CLUSTER_FUNCTION_CODES}": True,
|
||||||
|
f"{RedisCategoryKeys.METHOD_FUNCTION_CODES}": True,
|
||||||
|
f"{RedisCategoryKeys.ENDPOINT2CLASS}": True,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -58,9 +58,10 @@ class RedisResponse:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def first(self) -> Union[RedisRow, None]:
|
def first(self) -> Union[RedisRow, None]:
|
||||||
print("self.data", self.data)
|
|
||||||
if self.data:
|
if self.data:
|
||||||
if isinstance(self.data, list):
|
if isinstance(self.data, list):
|
||||||
|
if isinstance(self.data[0], RedisRow):
|
||||||
|
return self.data[0].row
|
||||||
return self.data[0]
|
return self.data[0]
|
||||||
elif isinstance(self.data, RedisRow):
|
elif isinstance(self.data, RedisRow):
|
||||||
return self.row
|
return self.row
|
||||||
|
|
|
||||||
|
|
@ -10,18 +10,22 @@ services:
|
||||||
dockerfile: DockerApiServices/AuthServiceApi/Dockerfile
|
dockerfile: DockerApiServices/AuthServiceApi/Dockerfile
|
||||||
ports:
|
ports:
|
||||||
- "41575:41575"
|
- "41575:41575"
|
||||||
|
depends_on:
|
||||||
|
- init-service
|
||||||
|
|
||||||
event-service:
|
# event-service:
|
||||||
build:
|
# build:
|
||||||
context: .
|
# context: .
|
||||||
dockerfile: DockerApiServices/EventServiceApi/Dockerfile
|
# dockerfile: DockerApiServices/EventServiceApi/Dockerfile
|
||||||
ports:
|
# ports:
|
||||||
- "41576:41576"
|
# - "41576:41576"
|
||||||
|
# depends_on:
|
||||||
|
# - init-service
|
||||||
|
|
||||||
validation-service:
|
# validation-service:
|
||||||
build:
|
# build:
|
||||||
context: .
|
# context: .
|
||||||
dockerfile: DockerApiServices/ValidationServiceApi/Dockerfile
|
# dockerfile: DockerApiServices/ValidationServiceApi/Dockerfile
|
||||||
ports:
|
# ports:
|
||||||
- "41577:41577"
|
# - "41577:41577"
|
||||||
# and lets try to implement potry again in the dockerfile now we now that it is about copy of files
|
# and lets try to implement potry again in the dockerfile now we now that it is about copy of files
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue