auth and token middleware context update

This commit is contained in:
berkay 2025-01-26 20:18:06 +03:00
parent 3d5a43220e
commit a7e48d8755
17 changed files with 265 additions and 345 deletions

View File

@ -17,6 +17,12 @@ class WagRedis:
)
class RedisAuthKeys:
AUTH: str = "AUTH"
OCCUPANT: str = "OCCUPANT"
EMPLOYEE: str = "EMPLOYEE"
class RedisCategoryKeys:
REBUILD: str = "REBUILD"
ENDPOINT2CLASS: str = "ENDPOINT2CLASS"
@ -28,6 +34,3 @@ class RedisCategoryKeys:
MENU_FIRST_LAYER: str = "MENU_FIRST_LAYER"
PAGE_MAPPER: str = "PAGE_MAPPER"
MENU_MAPPER: str = "MENU_MAPPER"
AUTH: str = "AUTH"
OCCUPANT: str = "OCCUPANT"
EMPLOYEE: str = "EMPLOYEE"

View File

@ -16,23 +16,17 @@ class CreateEndpointFromCluster:
def __init__(self, **kwargs):
self.router: CategoryCluster = kwargs.get("router")
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()
def attach_router(self):
method = getattr(self.router, self.method_endpoint.METHOD.lower())
# 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 = {
"path": self.method_endpoint.URL,
"summary": self.method_endpoint.SUMMARY,
"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:
kwargs["response_model"] = self.method_endpoint.RESPONSE_MODEL

View File

@ -1,6 +1,6 @@
"""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.ApiLibrary.common.line_number import get_line_number_for_error

View File

@ -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

View File

@ -15,6 +15,7 @@ from fastapi import Request, Response
from starlette.middleware.base import BaseHTTPMiddleware
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.AllConfigs.Token.config import Auth
from ApiLayers.ApiServices.Token.token_handler import TokenService
@ -87,20 +88,25 @@ class MiddlewareModule:
@wraps(func)
async def wrapper(request: Request, *args, **kwargs):
# Get and validate token context from request
auth_context = {
"is_employee": False,
"is_occupant": False,
"context": {}
}
endpoint_url = str(request.url.path)
auth_context = AuthContext(
auth={"token": {"access_token": "", "refresher_token": "", "context": {}}},
url=endpoint_url,
)
# 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
if inspect.iscoroutinefunction(func):
result = await func(request, *args, **kwargs)
else:
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 wrapper

View File

@ -5,110 +5,22 @@ Token event middleware for handling authentication and event tracking.
import inspect
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 pydantic import BaseModel
from ApiLayers.ApiLibrary.common.line_number import get_line_number_for_error
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.Schemas import Events, EndpointRestriction
from ApiLayers.AllConfigs.Redis.configs import RedisCategoryKeys
from Services.Redis.Actions.actions import RedisActions
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:
"""
Module containing token and event handling functionality.
@ -119,37 +31,18 @@ class TokenEventMiddleware:
"""
@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:
request_from_scope: The endpoint to match
request_from_scope: The FastAPI request object
Returns:
Dict containing the endpoint registration data
None if endpoint is not found in database
Tuple[str, list[str]]: The access token and a list of reachable event codes
"""
# Get token context from request
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:
raise HTTPExceptionApi(
error_code="",
@ -157,50 +50,60 @@ class TokenEventMiddleware:
loc=get_line_number_for_error(),
sys_msg="Token not found",
)
# Get token context from Redis by access token and collect reachable event codes
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",
)
return token_context, reachable_event_codes
db = EndpointRestriction.new_session()
restriction = EndpointRestriction.filter_one(
EndpointRestriction.endpoint_name == endpoint_from_scope,
db=db,
).data
if not restriction:
@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(
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:
# Intersect function codes with user accers objects available event codes
intersected_code = list(set(function_code_list_of_event) & set(reachable_event_codes))
if not len(intersected_code) == 1:
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": endpoint_from_scope,
"reachable_event_code": list(intersected_code)[0],
"class": an_event.function_class,
}
return endpoint_url, intersected_code[0]
@classmethod
def event_required(cls, func: Callable) -> Callable:
@ -216,88 +119,22 @@ class TokenEventMiddleware:
Returns:
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]:
# Get the endpoint URL for matching with events
endpoint_url = str(request.url.path)
# Set func_code first
func_code = "8aytr-"
setattr(wrapper, 'func_code', func_code)
# Get and validate token context from request
# token_context, reachable_event_codes = cls.retrieve_access_content(request)
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
auth_context = getattr(authenticated_func, 'auth', None)
print('auth_context', auth_context)
if auth_context is not None:
setattr(wrapper, 'auth', auth_context)
if token_context is not None:
setattr(wrapper, 'event_context', event_context)
setattr(func, 'event_context', event_context)
# 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):
result = await func(request, *args, **kwargs)
else:
@ -305,3 +142,41 @@ class TokenEventMiddleware:
return result
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

View File

@ -4,7 +4,10 @@ Handles dynamic route creation based on configurations.
"""
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):
@ -24,8 +27,11 @@ def get_all_routers() -> PrepareRouting:
Returns:
tuple: (routers, protected_routes)
"""
from Events.Engine.set_defaults.run import get_cluster_controller_group
cluster_list = get_cluster_controller_group()
prepare_routing = PrepareRouting(cluster_controller_group=cluster_list)
return prepare_routing
global routers
if not routers:
cluster_list = get_cluster_controller_group()
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 routers

View File

@ -4,7 +4,10 @@ Handles dynamic route creation based on configurations.
"""
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):
@ -24,10 +27,11 @@ def get_all_routers() -> PrepareRouting:
Returns:
tuple: (routers, protected_routes)
"""
from Events.Engine.set_defaults.run import get_cluster_controller_group
cluster_list = get_cluster_controller_group()
prepare_routing = PrepareRouting(cluster_controller_group=cluster_list)
return prepare_routing
global routers
if not routers:
cluster_list = get_cluster_controller_group()
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 routers

View File

@ -4,6 +4,7 @@ Authentication related API endpoints.
from typing import Union, Any, Dict
from ApiLayers.ApiValidations.Custom.wrapper_contexts import AuthContext, EventContext
from ApiLayers.Middleware import MiddlewareModule, TokenEventMiddleware
from ApiLayers.ApiValidations.Request import EmployeeSelection, OccupantSelection
@ -39,7 +40,7 @@ AuthenticationLoginEventMethods = MethodToEvent(
},
headers=[],
errors=[],
url="/authentication/login",
url="/login",
method="POST",
summary="Login via domain and 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,
data: EndpointBaseRequestModel,
) -> Dict[str, Any]:
function = AuthenticationLoginEventMethods.retrieve_event(
event_function_code=f"{authentication_login_super_user_event.key}"
)
function = AuthenticationLoginEventMethods.retrieve_event(event_function_code=f"{authentication_login_super_user_event.key}")
return function.endpoint_callable(request=request, data=data)
@ -65,7 +64,7 @@ AuthenticationSelectEventMethods = MethodToEvent(
decorators_list=[MiddlewareModule.auth_required],
headers=[],
errors=[],
url="/authentication/select",
url="/select",
method="POST",
summary="Select company or occupant type",
description="Select company or occupant type",
@ -95,7 +94,7 @@ AuthenticationCheckTokenEventMethods = MethodToEvent(
headers=[],
errors=[],
decorators_list=[MiddlewareModule.auth_required],
url="/authentication/check-token",
url="/check-token",
method="POST",
summary="Check if token is valid",
description="Check if access token is valid for user",
@ -118,7 +117,7 @@ AuthenticationRefreshEventMethods = MethodToEvent(
headers=[],
errors=[],
decorators_list=[MiddlewareModule.auth_required],
url="/authentication/refresh",
url="/refresh",
method="POST",
summary="Refresh user info",
description="Refresh user info using access token",
@ -143,7 +142,7 @@ AuthenticationChangePasswordEventMethods = MethodToEvent(
headers=[],
errors=[],
decorators_list=[MiddlewareModule.auth_required],
url="/authentication/change-password",
url="/change-password",
method="POST",
summary="Change password",
description="Change password with access token",
@ -166,7 +165,7 @@ AuthenticationCreatePasswordEventMethods = MethodToEvent(
},
headers=[],
errors=[],
url="/authentication/create-password",
url="/create-password",
method="POST",
summary="Create password",
description="Create password with password reset token requested via email",
@ -189,7 +188,7 @@ AuthenticationDisconnectUserEventMethods = MethodToEvent(
decorators_list=[MiddlewareModule.auth_required],
headers=[],
errors=[],
url="/authentication/disconnect",
url="/disconnect",
method="POST",
summary="Disconnect all sessions",
description="Disconnect all sessions of user in access token",
@ -210,28 +209,25 @@ AuthenticationLogoutEventMethods = MethodToEvent(
},
headers=[],
errors=[],
url="/authentication/logout",
decorators_list=[TokenEventMiddleware.event_required],
url="/logout",
method="POST",
summary="Logout user",
description="Logout only single session of user which domain is provided",
)
@TokenEventMiddleware.event_required
def authentication_logout_user(request: Request, data: EndpointBaseRequestModel):
function = AuthenticationLogoutEventMethods.retrieve_event(
event_function_code=f"{authentication_logout_user_event.key}"
)
print('authentication_logout_user', dict(
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)
event_context: EventContext = getattr(authentication_logout_user, "event_context", None)
print('event_context', event_context)
function = AuthenticationLogoutEventMethods.retrieve_event(event_function_code=f"{event_context.code}")
function.endpoint_callable.event_context = event_context
return function.endpoint_callable(request=request, data=data)
AuthenticationLogoutEventMethods.endpoint_callable = authentication_logout_user
AuthenticationRefreshTokenEventMethods = MethodToEvent(
name="AuthenticationRefreshTokenEventMethods",
events={
@ -239,19 +235,22 @@ AuthenticationRefreshTokenEventMethods = MethodToEvent(
},
headers=[],
errors=[],
decorators_list=[MiddlewareModule.auth_required, ],
url="/authentication/refresh-token",
decorators_list=[MiddlewareModule.auth_required],
url="/refresh-token",
method="POST",
summary="Refresh token",
description="Refresh access token with refresher token",
)
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(
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
@ -263,7 +262,7 @@ AuthenticationForgotPasswordEventMethods = MethodToEvent(
},
headers=[],
errors=[],
url="/authentication/forgot-password",
url="/forgot-password",
method="POST",
summary="Request password reset",
description="Send an email to user for a valid password reset token",
@ -289,7 +288,7 @@ AuthenticationResetPasswordEventMethods = MethodToEvent(
headers=[],
errors=[],
decorators_list=[MiddlewareModule.auth_required],
url="/authentication/reset-password",
url="/reset-password",
method="POST",
summary="Reset password",
description="Reset user password",
@ -314,7 +313,7 @@ AuthenticationDownloadAvatarEventMethods = MethodToEvent(
headers=[],
errors=[],
decorators_list=[],
url="/authentication/download-avatar",
url="/download-avatar",
method="POST",
summary="Download avatar",
description="Download avatar icon and profile info of user",

View File

@ -23,20 +23,20 @@ AuthCluster = CategoryCluster(
prefix="/authentication",
description="Authentication cluster",
pageinfo=authentication_page_info,
endpoints=[
AuthenticationLoginEventMethods,
AuthenticationLogoutEventMethods,
AuthenticationRefreshTokenEventMethods,
AuthenticationForgotPasswordEventMethods,
AuthenticationChangePasswordEventMethods,
AuthenticationCheckTokenEventMethods,
AuthenticationCreatePasswordEventMethods,
AuthenticationDisconnectUserEventMethods,
AuthenticationDownloadAvatarEventMethods,
AuthenticationResetPasswordEventMethods,
AuthenticationRefreshEventMethods,
AuthenticationSelectEventMethods,
],
endpoints={
"AuthenticationLoginEventMethods": AuthenticationLoginEventMethods,
"AuthenticationLogoutEventMethods": AuthenticationLogoutEventMethods,
"AuthenticationRefreshTokenEventMethods": AuthenticationRefreshTokenEventMethods,
"AuthenticationForgotPasswordEventMethods": AuthenticationForgotPasswordEventMethods,
"AuthenticationChangePasswordEventMethods": AuthenticationChangePasswordEventMethods,
"AuthenticationCheckTokenEventMethods": AuthenticationCheckTokenEventMethods,
"AuthenticationCreatePasswordEventMethods": AuthenticationCreatePasswordEventMethods,
"AuthenticationDisconnectUserEventMethods": AuthenticationDisconnectUserEventMethods,
"AuthenticationDownloadAvatarEventMethods": AuthenticationDownloadAvatarEventMethods,
"AuthenticationResetPasswordEventMethods": AuthenticationResetPasswordEventMethods,
"AuthenticationRefreshEventMethods": AuthenticationRefreshEventMethods,
"AuthenticationSelectEventMethods": AuthenticationSelectEventMethods,
},
include_in_schema=True,
sub_category=[],
)

View File

@ -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.Token.token_handler import TokenService
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.Schemas import (
BuildLivingSpace,
@ -372,14 +373,12 @@ def authentication_logout_user(request: Request, data: Any):
# selected_user.remove_refresher_token(domain=data.domain)
# return ResponseHandler.success("Session is logged out", data=token_user)
# return ResponseHandler.not_found("Logout is not successfully completed")
token_dict = authentication_logout_user.auth
print('token_dict', token_dict)
func_code = authentication_logout_user.func_code
print('func_code', func_code)
return
event_context: EventContext = getattr(authentication_logout_user, "event_context", None)
return event_context.model_dump()
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"""
# token_refresher = UsersTokens.filter_by_one(
# 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.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):

View File

@ -4,3 +4,10 @@ import Events.AllEvents.validations as 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)

View File

@ -135,11 +135,11 @@ class MethodToEvent:
return found_event
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, ...])
"""
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()}
@staticmethod
@ -156,8 +156,8 @@ class CategoryCluster:
PREFIX: str
PAGEINFO: PageInfo
DESCRIPTION: str
ENDPOINTS: list[MethodToEvent] # [MethodToEvent, ...]
SUBCATEGORY: Optional[List["CategoryCluster"]] # [CategoryCluster, ...]
ENDPOINTS: dict[str, MethodToEvent] # {"MethodToEvent": MethodToEvent, ...}
SUBCATEGORY: Optional[List["CategoryCluster"]] # [CategoryCluster, ...]
INCLUDE_IN_SCHEMA: Optional[bool] = True
def __init__(
@ -167,7 +167,7 @@ class CategoryCluster:
prefix: str,
description: str,
pageinfo: PageInfo,
endpoints: list[MethodToEvent],
endpoints: dict[str, MethodToEvent],
sub_category: list,
include_in_schema: Optional[bool] = True,
):
@ -176,7 +176,7 @@ class CategoryCluster:
self.PREFIX = prefix
self.PAGEINFO = pageinfo
self.DESCRIPTION = description
self.ENDPOINTS = endpoints or []
self.ENDPOINTS = endpoints or {}
self.SUBCATEGORY = sub_category or []
self.INCLUDE_IN_SCHEMA = include_in_schema
@ -189,7 +189,7 @@ class CategoryCluster:
RedisCategoryKeys.CLUSTER_2_METHOD_EVENT
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:
dict_cluster_2_method[endpoint_name] = self.name
dict_cluster_2_method[self.name] = list_endpoints
@ -200,7 +200,7 @@ class CategoryCluster:
Retrieves all function codes by iterating over the events list.
"""
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()])
return all_function_codes

View File

@ -1,4 +1,5 @@
from Events.AllEvents.events_file import events_list
from .category_cluster_models import cluster_controller
@ -7,10 +8,12 @@ def get_cluster_controller_group():
cluster_controller.import_all_category_clusters(cluster)
return cluster_controller
"""
prepare_routing = PrepareRouting(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(prepare_routing)
"""

View File

@ -38,7 +38,7 @@ class PrepareRouting(DecoratorModule):
return self.__safe_endpoint_list
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
applied_decorators_qualname = self.apply_decorators(method_endpoint)
# 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())
}
for method_endpoint in list(cluster.ENDPOINTS):
for method_endpoint in list(cluster.ENDPOINTS.values()):
# [SAVE]REDIS => ENDPOINT2CLASS = {MethodEvent: Endpoint("/.../.../..."), ...}
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(
{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, ...]
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()
def __str__(self):
self.std_out = f"\nSetItems2Redis:\n\n{self.std_out}"
return self.std_out
return f"\nSetItems2Redis:\n\n{self.std_out}"
def set_items(self):
from ApiLayers.AllConfigs.Redis.configs import RedisCategoryKeys
dict_prep = self.prepare_events.valid_redis_items.as_dict
RedisActions.delete(
list_keys=[
f"{RedisCategoryKeys.MENU_FIRST_LAYER}:*",
f"{RedisCategoryKeys.CLUSTER_INDEX}:*",
f"{RedisCategoryKeys.CLUSTER_FUNCTION_CODES}:*",
f"{RedisCategoryKeys.METHOD_FUNCTION_CODES}:*"
f"{RedisCategoryKeys.ENDPOINT2CLASS}:*",
]
)
for redis_values_to_delete, redis_key_type in RedisCategoryKeys.__annotations__.items():
if isinstance(redis_key_type, str):
continue
RedisActions.delete(list_keys=[f"{redis_values_to_delete}*"])
# Save MENU_FIRST_LAYER to Redis
redis_list = RedisList(redis_key=RedisCategoryKeys.MENU_FIRST_LAYER)
RedisActions.set_json(
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
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"
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,
}
)

View File

@ -58,9 +58,10 @@ class RedisResponse:
@property
def first(self) -> Union[RedisRow, None]:
print("self.data", self.data)
if self.data:
if isinstance(self.data, list):
if isinstance(self.data[0], RedisRow):
return self.data[0].row
return self.data[0]
elif isinstance(self.data, RedisRow):
return self.row

View File

@ -10,18 +10,22 @@ services:
dockerfile: DockerApiServices/AuthServiceApi/Dockerfile
ports:
- "41575:41575"
depends_on:
- init-service
event-service:
build:
context: .
dockerfile: DockerApiServices/EventServiceApi/Dockerfile
ports:
- "41576:41576"
# event-service:
# build:
# context: .
# dockerfile: DockerApiServices/EventServiceApi/Dockerfile
# ports:
# - "41576:41576"
# depends_on:
# - init-service
validation-service:
build:
context: .
dockerfile: DockerApiServices/ValidationServiceApi/Dockerfile
ports:
- "41577:41577"
# validation-service:
# build:
# context: .
# dockerfile: DockerApiServices/ValidationServiceApi/Dockerfile
# ports:
# - "41577:41577"
# and lets try to implement potry again in the dockerfile now we now that it is about copy of files