middleware and respnse models updated

This commit is contained in:
berkay 2025-01-27 17:25:49 +03:00
parent e403993d24
commit b88f910a43
54 changed files with 1125 additions and 808 deletions

View File

@ -6,14 +6,59 @@
<component name="ChangeListManager">
<list default="true" id="b5202e0c-6ddf-4a56-a13a-e18798c4c7cf" name="Changes" comment="">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ApiLayers/AllConfigs/Redis/configs.py" beforeDir="false" afterPath="$PROJECT_DIR$/ApiLayers/AllConfigs/Redis/configs.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ApiLayers/ApiLibrary/token/password_module.py" beforeDir="false" afterPath="$PROJECT_DIR$/ApiLayers/ApiLibrary/token/password_module.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ApiLayers/ApiServices/Cluster/create_router.py" beforeDir="false" afterPath="$PROJECT_DIR$/ApiLayers/ApiServices/Cluster/create_router.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ApiLayers/ApiServices/Cluster/handle_cluster.py" beforeDir="false" afterPath="$PROJECT_DIR$/ApiLayers/ApiServices/Cluster/handle_cluster.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ApiLayers/ApiServices/Login/user_login_handler.py" beforeDir="false" afterPath="$PROJECT_DIR$/ApiLayers/ApiServices/Login/user_login_handler.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ApiLayers/ApiServices/Token/token_handler.py" beforeDir="false" afterPath="$PROJECT_DIR$/ApiLayers/ApiServices/Token/token_handler.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ApiLayers/ApiValidations/Custom/wrapper_contexts.py" beforeDir="false" afterPath="$PROJECT_DIR$/ApiLayers/ApiValidations/Custom/wrapper_contexts.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ApiLayers/ApiValidations/Request/decision_book.py" beforeDir="false" afterPath="$PROJECT_DIR$/ApiLayers/ApiValidations/Request/decision_book.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ApiLayers/ApiValidations/Response/default_response.py" beforeDir="false" afterPath="$PROJECT_DIR$/ApiLayers/ApiValidations/Response/default_response.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ApiLayers/ErrorHandlers/Exceptions/api_exc.py" beforeDir="false" afterPath="$PROJECT_DIR$/ApiLayers/ErrorHandlers/Exceptions/api_exc.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ApiLayers/LanguageModels/Database/__init__.py" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/ApiLayers/LanguageModels/Database/account/account.py" beforeDir="false" afterPath="$PROJECT_DIR$/ApiLayers/LanguageModels/Database/account/account.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ApiLayers/LanguageModels/Database/account/iban.py" beforeDir="false" afterPath="$PROJECT_DIR$/ApiLayers/LanguageModels/Database/account/iban.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ApiLayers/LanguageModels/Database/building/budget.py" beforeDir="false" afterPath="$PROJECT_DIR$/ApiLayers/LanguageModels/Database/building/budget.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ApiLayers/LanguageModels/Database/building/build.py" beforeDir="false" afterPath="$PROJECT_DIR$/ApiLayers/LanguageModels/Database/building/build.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ApiLayers/LanguageModels/Database/building/decision_book.py" beforeDir="false" afterPath="$PROJECT_DIR$/ApiLayers/LanguageModels/Database/building/decision_book.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ApiLayers/LanguageModels/Database/company/company.py" beforeDir="false" afterPath="$PROJECT_DIR$/ApiLayers/LanguageModels/Database/company/company.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ApiLayers/LanguageModels/Database/company/department.py" beforeDir="false" afterPath="$PROJECT_DIR$/ApiLayers/LanguageModels/Database/company/department.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ApiLayers/LanguageModels/Database/company/employee.py" beforeDir="false" afterPath="$PROJECT_DIR$/ApiLayers/LanguageModels/Database/company/employee.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ApiLayers/LanguageModels/Database/event/event.py" beforeDir="false" afterPath="$PROJECT_DIR$/ApiLayers/LanguageModels/Database/event/event.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ApiLayers/LanguageModels/Database/identity/identity.py" beforeDir="false" afterPath="$PROJECT_DIR$/ApiLayers/LanguageModels/Database/identity/identity.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ApiLayers/LanguageModels/Database/rules/rules.py" beforeDir="false" afterPath="$PROJECT_DIR$/ApiLayers/LanguageModels/Database/rules/rules.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ApiLayers/LanguageModels/Errors/__init__.py" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/ApiLayers/Middleware/auth_middleware.py" beforeDir="false" afterPath="$PROJECT_DIR$/ApiLayers/Middleware/auth_middleware.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ApiLayers/Middleware/token_event_middleware.py" beforeDir="false" afterPath="$PROJECT_DIR$/ApiLayers/Middleware/token_event_middleware.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ApiLayers/Schemas/building/build.py" beforeDir="false" afterPath="$PROJECT_DIR$/ApiLayers/Schemas/building/build.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ApiLayers/Schemas/identity/identity.py" beforeDir="false" afterPath="$PROJECT_DIR$/ApiLayers/Schemas/identity/identity.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ApiLayers/Schemas/rules/rules.py" beforeDir="false" afterPath="$PROJECT_DIR$/ApiLayers/Schemas/rules/rules.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/DockerApiServices/AuthServiceApi/app_handler.py" beforeDir="false" afterPath="$PROJECT_DIR$/DockerApiServices/AuthServiceApi/app_handler.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/DockerApiServices/AuthServiceApi/config.py" beforeDir="false" afterPath="$PROJECT_DIR$/DockerApiServices/AuthServiceApi/config.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/DockerApiServices/AuthServiceApi/create_routes.py" beforeDir="false" afterPath="$PROJECT_DIR$/DockerApiServices/AuthServiceApi/create_routes.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/DockerApiServices/AuthServiceApi/open_api_creator.py" beforeDir="false" afterPath="$PROJECT_DIR$/DockerApiServices/AuthServiceApi/open_api_creator.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/DockerApiServices/EventServiceApi/app_handler.py" beforeDir="false" afterPath="$PROJECT_DIR$/DockerApiServices/EventServiceApi/app_handler.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/DockerApiServices/EventServiceApi/config.py" beforeDir="false" afterPath="$PROJECT_DIR$/DockerApiServices/EventServiceApi/config.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/DockerApiServices/EventServiceApi/create_routes.py" beforeDir="false" afterPath="$PROJECT_DIR$/DockerApiServices/EventServiceApi/create_routes.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/DockerApiServices/EventServiceApi/open_api_creator.py" beforeDir="false" afterPath="$PROJECT_DIR$/DockerApiServices/EventServiceApi/open_api_creator.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/DockerApiServices/ValidationServiceApi/app_handler.py" beforeDir="false" afterPath="$PROJECT_DIR$/DockerApiServices/ValidationServiceApi/app_handler.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/DockerApiServices/ValidationServiceApi/config.py" beforeDir="false" afterPath="$PROJECT_DIR$/DockerApiServices/ValidationServiceApi/config.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/DockerApiServices/ValidationServiceApi/create_routes.py" beforeDir="false" afterPath="$PROJECT_DIR$/DockerApiServices/ValidationServiceApi/create_routes.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/DockerApiServices/ValidationServiceApi/open_api_creator.py" beforeDir="false" afterPath="$PROJECT_DIR$/DockerApiServices/ValidationServiceApi/open_api_creator.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Events/AllEvents/authentication/auth/api_events.py" beforeDir="false" afterPath="$PROJECT_DIR$/Events/AllEvents/authentication/auth/api_events.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Events/AllEvents/authentication/auth/auth.py" beforeDir="false" afterPath="$PROJECT_DIR$/Events/AllEvents/authentication/auth/auth.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Events/AllEvents/authentication/auth/function_handlers.py" beforeDir="false" afterPath="$PROJECT_DIR$/Events/AllEvents/authentication/auth/function_handlers.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Events/AllEvents/authentication/auth/models.py" beforeDir="false" afterPath="$PROJECT_DIR$/Events/AllEvents/authentication/auth/models.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Events/AllEvents/events/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/Events/AllEvents/events/__init__.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Events/AllEvents/events_file.py" beforeDir="false" afterPath="$PROJECT_DIR$/Events/AllEvents/events_file.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Events/Engine/abstract_class.py" beforeDir="false" afterPath="$PROJECT_DIR$/Events/Engine/abstract_class.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Events/Engine/set_defaults/category_cluster_models.py" beforeDir="false" afterPath="$PROJECT_DIR$/Events/Engine/set_defaults/category_cluster_models.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Events/Engine/set_defaults/prepare_redis_items.py" beforeDir="false" afterPath="$PROJECT_DIR$/Events/Engine/set_defaults/prepare_redis_items.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Events/Engine/set_defaults/run.py" beforeDir="false" afterPath="$PROJECT_DIR$/Events/Engine/set_defaults/run.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Events/Engine/set_defaults/setClusters.py" beforeDir="false" afterPath="$PROJECT_DIR$/Events/Engine/set_defaults/setClusters.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Events/base_request_model.py" beforeDir="false" afterPath="$PROJECT_DIR$/Events/base_request_model.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Services/PostgresDb/Models/filter_functions.py" beforeDir="false" afterPath="$PROJECT_DIR$/Services/PostgresDb/Models/filter_functions.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Services/PostgresDb/Models/mixin.py" beforeDir="false" afterPath="$PROJECT_DIR$/Services/PostgresDb/Models/mixin.py" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />

View File

@ -13,7 +13,7 @@ class PasswordModule:
return str(uuid.uuid4()) if str_std else uuid.uuid4()
@staticmethod
def generate_token(length=32):
def generate_token(length=32) -> str:
letters = "abcdefghijklmnopqrstuvwxyz"
merged_letters = [letter for letter in letters] + [
letter.upper() for letter in letters
@ -27,17 +27,17 @@ class PasswordModule:
return token_generated
@staticmethod
def generate_access_token():
def generate_access_token() -> str:
return secrets.token_urlsafe(Auth.ACCESS_TOKEN_LENGTH)
@staticmethod
def generate_refresher_token():
def generate_refresher_token() -> str:
return secrets.token_urlsafe(Auth.REFRESHER_TOKEN_LENGTH)
@staticmethod
def create_hashed_password(domain: str, id_: str, password: str):
def create_hashed_password(domain: str, id_: str, password: str) -> str:
return hashlib.sha256(f"{domain}:{id_}:{password}".encode("utf-8")).hexdigest()
@classmethod
def check_password(cls, domain, id_, password, password_hashed):
def check_password(cls, domain, id_, password, password_hashed) -> bool:
return cls.create_hashed_password(domain, id_, password) == password_hashed

View File

@ -20,14 +20,17 @@ class CreateEndpointFromCluster:
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
kwargs = {
"path": self.method_endpoint.URL,
"summary": self.method_endpoint.SUMMARY,
"description": self.method_endpoint.DESCRIPTION,
}
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
method(**kwargs)(self.method_endpoint.endpoint_callable)

View File

@ -2,4 +2,3 @@ from Services.Redis import RedisActions, AccessToken
from Services.Redis.Models.cluster import RedisList
redis_list = RedisList(redis_key="test")

View File

@ -1,9 +1,7 @@
from typing import Any, Dict
from ApiLayers.ErrorHandlers import HTTPExceptionApi
from ApiLayers.ApiValidations.Request.authentication import Login
from ApiLayers.ApiLibrary.token.password_module import PasswordModule
from ApiLayers.ApiLibrary.common.line_number import get_line_number_for_error
from ApiLayers.ErrorHandlers import HTTPExceptionApi
class UserLoginModule:
@ -11,13 +9,27 @@ class UserLoginModule:
def __init__(self, request: "Request"):
self.request = request
self.user = None
self.access_object = None
self.access_token = None
self.refresh_token = None
@property
def as_dict(self) -> dict:
return {
"user": self.user,
"access_object": self.access_object,
"access_token": self.access_token,
"refresh_token": self.refresh_token,
}
@staticmethod
def check_user_exists(access_key: str):
from ApiLayers.Schemas import Users
"""Check if user exists."""
db_session = Users.new_session()
"""
Check if the user exists in the database.
"""
db_session = Users.new_session() # Check if user exists.
if "@" in access_key:
found_user: Users = Users.filter_one(
Users.email == access_key.lower(), db=db_session
@ -31,39 +43,48 @@ class UserLoginModule:
error_code="HTTP_400_BAD_REQUEST",
lang="en",
loc=get_line_number_for_error(),
sys_msg="User not found",
sys_msg="check_user_exists: User not found",
)
return found_user
def login_user_via_credentials(self, access_data: "Login") -> Dict[str, Any]:
def login_user_via_credentials(self, access_data: "Login") -> None:
from ApiLayers.ApiServices.Token.token_handler import TokenService
from ApiLayers.Schemas import Users
"""
Login the user via the credentials.
"""
# Get the actual data from the BaseRequestModel if needed
found_user: Users = self.check_user_exists(access_key=access_data.access_key)
self.user = found_user
if len(found_user.hash_password) < 5:
raise HTTPExceptionApi(
error_code="HTTP_400_BAD_REQUEST",
lang=found_user.lang,
loc=get_line_number_for_error(),
sys_msg="Invalid password create a password to user first",
sys_msg="login_user_via_credentials: Invalid password create a password to user first",
)
# Check if the password is correct
if PasswordModule.check_password(
domain=access_data.domain,
id_=found_user.uu_id,
password=access_data.password,
password_hashed=found_user.hash_password,
domain=access_data.domain, id_=found_user.uu_id,
password=access_data.password, password_hashed=found_user.hash_password,
):
return TokenService.set_access_token_to_redis(
request=self.request,
user=found_user,
domain=access_data.domain,
remember=access_data.remember_me,
# Set the access token to the redis
token_response = TokenService.set_access_token_to_redis(
request=self.request, user=found_user, domain=access_data.domain, remember=access_data.remember_me,
)
# Set the user and token information to the instance
self.user = found_user.get_dict()
self.access_token = token_response.get("access_token")
self.refresh_token = token_response.get("refresh_token")
self.access_object = {
"user_type": token_response.get("user_type", None),
"selection_list": token_response.get("selection_list", {})
}
return None
raise HTTPExceptionApi(
error_code="HTTP_400_BAD_REQUEST",
lang=found_user.lang,
lang="tr",
loc=get_line_number_for_error(),
sys_msg="login_user_via_credentials raised error",
sys_msg="login_user_via_credentials: raised an unknown error",
)

View File

@ -250,7 +250,7 @@ class TokenService:
return {
"access_token": access_token,
"user_type": UserType.employee.name,
"companies_list": companies_list,
"selection_list": companies_list,
}
raise HTTPExceptionApi(
error_code="",
@ -264,8 +264,8 @@ class TokenService:
"""Remove all tokens for a user with specific domain."""
redis_rows = cls._get_user_tokens(user)
for redis_row in redis_rows.all:
if redis_row.data.get("domain") == domain:
RedisActions.delete_key(redis_row.key)
if redis_row.row.get("domain") == domain:
redis_row.delete()
@classmethod
def remove_all_token(cls, user: Users) -> None:

View File

@ -2,17 +2,27 @@ from typing import Optional, Any
from pydantic import BaseModel
class DefaultContext(BaseModel):
...
class DefaultContext(BaseModel): ...
class EventContext(DefaultContext):
auth: Any
code: str
url: str
request: Optional[Any] = None
@property
def base(self) -> dict[str, Any]:
return {"url": self.url, "code": self.code}
class AuthContext(DefaultContext):
auth: Any
url: str
request: Optional[Any] = None
@property
def base(self) -> dict[str, Any]:
return {"url": self.url}

View File

@ -1,5 +1,9 @@
from typing import Optional
from ApiLayers.ApiValidations.Request import BaseModelRegular, PydanticBaseModel, ListOptions
from ApiLayers.ApiValidations.Request import (
BaseModelRegular,
PydanticBaseModel,
ListOptions,
)
class DecisionBookDecisionBookInvitations(BaseModelRegular):

View File

@ -15,85 +15,85 @@ class BaseEndpointResponse:
from ApiLayers.AllConfigs.Redis.configs import RedisValidationKeys
language_model_key = f"{RedisValidationKeys.LANGUAGE_MODELS}:{RedisValidationKeys.RESPONSES}"
language_model = RedisActions.get_json(list_keys=[language_model_key, self.code , self.lang])
language_model = RedisActions.get_json(list_keys=[language_model_key, self.code, self.lang])
if language_model.status:
return language_model.first.as_dict
raise ValueError("Language model not found")
return {"message": f"{self.code} -> Language model not found"}
class EndpointSuccessResponse(BaseEndpointResponse): # 1. 200 OK
class EndpointSuccessResponse(BaseEndpointResponse): # 200 OK
def as_dict(self, data: Optional[dict] = None):
return JSONResponse(
status_code=status.HTTP_200_OK,
content=dict(completed=True, lang=self.lang, data=data, **self.response)
content=dict(completed=True, **self.response, lang=self.lang, data=data),
)
class EndpointCreatedResponse(BaseEndpointResponse): # 2. 201 Created
class EndpointCreatedResponse(BaseEndpointResponse): # 201 Created
def as_dict(self, data: Optional[dict] = None):
return JSONResponse(
status_code=status.HTTP_201_CREATED,
content=dict(completed=True, lang=self.lang, data=data, **self.response)
content=dict(completed=True, **self.response, lang=self.lang, data=data),
)
class EndpointAcceptedResponse(BaseEndpointResponse): # 3. 202 Accepted
class EndpointAcceptedResponse(BaseEndpointResponse): # 202 Accepted
def as_dict(self, data: Optional[dict] = None):
return JSONResponse(
status_code=status.HTTP_202_ACCEPTED,
content=dict(completed=True, lang=self.lang, data=data, **self.response)
content=dict(completed=True, **self.response, lang=self.lang, data=data),
)
class EndpointBadRequestResponse(BaseEndpointResponse): # 4. 400 Bad Request
class EndpointBadRequestResponse(BaseEndpointResponse): # 400 Bad Request
def as_dict(self, data: Optional[dict] = None):
return JSONResponse(
status_code=status.HTTP_400_BAD_REQUEST,
content=dict(completed=False, lang=self.lang, data=data, **self.response)
content=dict(completed=False, **self.response, lang=self.lang, data=data),
)
class EndpointUnauthorizedResponse(BaseEndpointResponse): # 5. 401 Unauthorized
class EndpointUnauthorizedResponse(BaseEndpointResponse): # 401 Unauthorized
def as_dict(self):
return JSONResponse(
status_code=status.HTTP_401_UNAUTHORIZED,
content=dict(completed=False, lang=self.lang, **self.response)
content=dict(completed=False, **self.response, lang=self.lang),
)
class EndpointNotFoundResponse(BaseEndpointResponse): # 6. 404 Not Found
class EndpointNotFoundResponse(BaseEndpointResponse): # 404 Not Found
def as_dict(self):
return JSONResponse(
status_code=status.HTTP_404_NOT_FOUND,
content=dict(completed=False, lang=self.lang, **self.response)
content=dict(completed=False, **self.response, lang=self.lang),
)
class EndpointForbiddenResponse(BaseEndpointResponse): # 3. 403 Forbidden
class EndpointForbiddenResponse(BaseEndpointResponse): # 403 Forbidden
def as_dict(self):
return JSONResponse(
status_code=status.HTTP_403_FORBIDDEN,
content=dict(completed=False, lang=self.lang, **self.response)
content=dict(completed=False, **self.response, lang=self.lang),
)
class EndpointConflictResponse(BaseEndpointResponse): # 6. 409 Conflict
class EndpointConflictResponse(BaseEndpointResponse): # 409 Conflict
def as_dict(self):
return JSONResponse(
status_code=status.HTTP_409_CONFLICT,
content=dict(completed=False, lang=self.lang, **self.response)
content=dict(completed=False, **self.response, lang=self.lang),
)
class EndpointTooManyRequestsResponse(BaseEndpointResponse): # 7. 429 Too Many Requests
class EndpointTooManyRequestsResponse(BaseEndpointResponse): # 429 Too Many Requests
def __init__(self, retry_after: int, lang: str, code: str):
super().__init__(lang=lang, code=code)
@ -103,16 +103,16 @@ class EndpointTooManyRequestsResponse(BaseEndpointResponse): # 7. 429 Too Ma
return JSONResponse(
status_code=status.HTTP_429_TOO_MANY_REQUESTS,
headers={"Retry-After": str(self.retry_after)},
content=dict(completed=False, lang=self.lang, **self.response)
content=dict(completed=False, **self.response, lang=self.lang),
)
class EndpointInternalErrorResponse(BaseEndpointResponse): # 7. 500 Internal Server Error
class EndpointInternalErrorResponse(BaseEndpointResponse): # 500 Internal Server Error
def as_dict(self):
return JSONResponse(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
content=dict(completed=False, lang=self.lang, **self.response)
content=dict(completed=False, **self.response, lang=self.lang),
)
@ -121,5 +121,5 @@ class EndpointErrorResponse(BaseEndpointResponse):
def as_dict(self):
return JSONResponse(
status_code=status.HTTP_304_NOT_MODIFIED,
content=dict(completed=False, lang=self.lang, **self.response)
content=dict(completed=False, **self.response, lang=self.lang),
)

View File

@ -1,9 +1,17 @@
from Services.Redis.Actions.actions import RedisActions
from ApiLayers.AllConfigs.Redis.configs import RedisValidationKeys
class HTTPExceptionApi(Exception):
def __init__(self, error_code: str, lang: str, loc: str = "", sys_msg: str = ""):
"""
Initialize the HTTPExceptionApi class.
:param error_code: The error code. To retrieve the error message.
:param lang: The language. Catch error msg from redis.
:param loc: The location. To log where error occurred.
:param sys_msg: The system message. To log the error message.
"""
self.error_code = error_code
self.lang = lang
self.loc = loc
@ -13,6 +21,12 @@ class HTTPExceptionApi(Exception):
"""
Retrieve the error message from the redis by the error code.
"""
error_msg = RedisActions.get_json(list_keys=["LANGUAGE_MODELS", "ERRORCODES", self.lang])
if error_msg.status:
return error_msg.first
error_redis_key = (
f"{RedisValidationKeys.LANGUAGE_MODELS}:{RedisValidationKeys.ERRORCODES}"
)
error_message = RedisActions.get_json(list_keys=[error_redis_key, self.lang])
if error_message.status:
error_message_dict = error_message.first.as_dict
if error_message_dict.get(self.error_code, None):
return error_message_dict.get(self.error_code)
return f"System Message -> {self.sys_msg}"

View File

@ -1,4 +1,6 @@
from ApiLayers.LanguageModels.Database.Mixins.crud_mixin import CrudCollectionLanguageModel
from ApiLayers.LanguageModels.Database.Mixins.crud_mixin import (
CrudCollectionLanguageModel,
)
AccountBooksLanguageModel = dict(
tr={

View File

@ -1,4 +1,6 @@
from ApiLayers.LanguageModels.Database.Mixins.crud_mixin import CrudCollectionLanguageModel
from ApiLayers.LanguageModels.Database.Mixins.crud_mixin import (
CrudCollectionLanguageModel,
)
BuildIbansLanguageModel = dict(
tr={

View File

@ -1,4 +1,6 @@
from ApiLayers.LanguageModels.Database.Mixins.crud_mixin import CrudCollectionLanguageModel
from ApiLayers.LanguageModels.Database.Mixins.crud_mixin import (
CrudCollectionLanguageModel,
)
DecisionBookBudgetBooksLanguageModel = dict(
tr={

View File

@ -1,4 +1,6 @@
from ApiLayers.LanguageModels.Database.Mixins.crud_mixin import CrudCollectionLanguageModel
from ApiLayers.LanguageModels.Database.Mixins.crud_mixin import (
CrudCollectionLanguageModel,
)
BuildTypesLanguageModel = dict(
tr={

View File

@ -1,4 +1,6 @@
from ApiLayers.LanguageModels.Database.Mixins.crud_mixin import CrudCollectionLanguageModel
from ApiLayers.LanguageModels.Database.Mixins.crud_mixin import (
CrudCollectionLanguageModel,
)
BuildDecisionBookLanguageModel = dict(
tr={

View File

@ -1,4 +1,6 @@
from ApiLayers.LanguageModels.Database.Mixins.crud_mixin import CrudCollectionLanguageModel
from ApiLayers.LanguageModels.Database.Mixins.crud_mixin import (
CrudCollectionLanguageModel,
)
RelationshipDutyCompanyLanguageModel = dict(
tr={

View File

@ -1,4 +1,6 @@
from ApiLayers.LanguageModels.Database.Mixins.crud_mixin import CrudCollectionLanguageModel
from ApiLayers.LanguageModels.Database.Mixins.crud_mixin import (
CrudCollectionLanguageModel,
)
DepartmentsLanguageModel = dict(
tr={

View File

@ -1,4 +1,6 @@
from ApiLayers.LanguageModels.Database.Mixins.crud_mixin import CrudCollectionLanguageModel
from ApiLayers.LanguageModels.Database.Mixins.crud_mixin import (
CrudCollectionLanguageModel,
)
StaffLanguageModel = dict(
tr={

View File

@ -1,4 +1,6 @@
from ApiLayers.LanguageModels.Database.Mixins.crud_mixin import CrudCollectionLanguageModel
from ApiLayers.LanguageModels.Database.Mixins.crud_mixin import (
CrudCollectionLanguageModel,
)
EventsLanguageModel = dict(

View File

@ -1,4 +1,6 @@
from ApiLayers.LanguageModels.Database.Mixins.crud_mixin import CrudCollectionLanguageModel
from ApiLayers.LanguageModels.Database.Mixins.crud_mixin import (
CrudCollectionLanguageModel,
)
UsersTokensLanguageModel = dict(
tr={

View File

@ -1,4 +1,6 @@
from ApiLayers.LanguageModels.Database.Mixins.crud_mixin import CrudCollectionLanguageModel
from ApiLayers.LanguageModels.Database.Mixins.crud_mixin import (
CrudCollectionLanguageModel,
)
EndpointRestrictionLanguageModel = dict(
tr={

View File

@ -1,3 +0,0 @@
from .merge_all_error_languages import MergedErrorLanguageModels
__all__ = ["MergedErrorLanguageModels"]

View File

@ -92,11 +92,12 @@ class MiddlewareModule:
auth_context = AuthContext(
auth={"token": {"access_token": "", "refresher_token": "", "context": {}}},
url=endpoint_url,
request=request,
)
# Set auth context on the wrapper function itself
setattr(func, 'auth_context', auth_context)
setattr(wrapper, 'auth_context', auth_context)
setattr(func, "auth_context", auth_context)
setattr(wrapper, "auth_context", auth_context)
# Call the original endpoint function
if inspect.iscoroutinefunction(func):
@ -105,10 +106,11 @@ class MiddlewareModule:
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)
setattr(func, "auth_context", auth_context)
setattr(wrapper, "auth_context", auth_context)
return result
return wrapper

View File

@ -41,7 +41,7 @@ class TokenEventMiddleware:
Returns:
Tuple[str, list[str]]: The access token and a list of reachable event codes
"""
# Get token context from request
# Get token context from request
access_token = TokenService.get_access_token_from_request(request_from_scope)
if not access_token:
raise HTTPExceptionApi(
@ -50,13 +50,19 @@ 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)
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
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
reachable_event_codes: list[str] = (
token_context.selected_occupant.reachable_event_codes
)
else:
raise HTTPExceptionApi(
error_code="",
@ -67,12 +73,15 @@ class TokenEventMiddleware:
return token_context, reachable_event_codes
@staticmethod
def retrieve_intersected_event_code(request: Request, reachable_event_codes: list[str]) -> str:
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
reachable_event_codes: The list of event codes accessible to the user
Returns:
Dict containing the endpoint registration data
@ -81,9 +90,7 @@ class TokenEventMiddleware:
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
]
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:
@ -93,9 +100,11 @@ class TokenEventMiddleware:
loc=get_line_number_for_error(),
sys_msg="Function code not found",
)
# Intersect function codes with user accers objects available event codes
intersected_code = list(set(function_code_list_of_event) & set(reachable_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="",
@ -122,18 +131,23 @@ class TokenEventMiddleware:
@wraps(func)
async def wrapper(request: Request, *args, **kwargs) -> Dict[str, Any]:
# 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)
reachable_event_codes = ["g1j8i6j7-9k4h-0h6l-4i3j-2j0k1k0j0i0k"]
token_context = {"token": "context","context": {}}
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, request=request,
)
# Get auth context from the authenticated function's wrapper
if token_context is not None:
setattr(wrapper, 'event_context', event_context)
setattr(func, 'event_context', event_context)
setattr(wrapper, "event_context", event_context)
setattr(func, "event_context", event_context)
# Execute the authenticated function and get its result
if inspect.iscoroutinefunction(func):
result = await func(request, *args, **kwargs)
@ -179,4 +193,4 @@ class TokenEventMiddleware:
# result = func(request, *args, **kwargs)
# return result
# return wrapper
# return wrapper

View File

@ -24,7 +24,10 @@ from ApiLayers.ApiValidations.Request import (
UpdateBuild,
)
from ApiLayers.ApiValidations.Custom.token_objects import EmployeeTokenObject, OccupantTokenObject
from ApiLayers.ApiValidations.Custom.token_objects import (
EmployeeTokenObject,
OccupantTokenObject,
)
from ApiLayers.LanguageModels.Database.building.build import (
BuildTypesLanguageModel,
Part2EmployeeLanguageModel,

View File

@ -17,7 +17,10 @@ from sqlalchemy import (
from sqlalchemy.orm import mapped_column, relationship, Mapped
from ApiLayers.ApiLibrary.date_time_actions.date_functions import system_arrow
from ApiLayers.ApiLibrary.extensions.select import SelectAction, SelectActionWithEmployee
from ApiLayers.ApiLibrary.extensions.select import (
SelectAction,
SelectActionWithEmployee,
)
from ApiLayers.AllConfigs.Token.config import Auth
from ApiLayers.ApiServices.Login.user_login_handler import UserLoginModule
@ -138,6 +141,24 @@ class Users(CrudCollection, UserLoginModule, SelectAction):
def is_employee(self):
return str(self.email).split("@")[1] == Auth.ACCESS_EMAIL_EXT
@property
def user_type(self):
return "Occupant" if self.is_occupant else "Employee"
@classmethod
def credentials(cls):
db_session = cls.new_session()
person_object: People = People.filter_by_one(db=db_session, system=True, id=cls.person_id).data
if person_object:
return {
"person_id": person_object.id,
"person_uu_id": str(person_object.uu_id),
}
return {
"person_id": None,
"person_uu_id": None,
}
@property
def password_expiry_ends(self):
"""Calculates the expiry end date based on expiry begins and expires day"""
@ -153,16 +174,6 @@ class Users(CrudCollection, UserLoginModule, SelectAction):
)
)
@property
def is_super_user(self):
"""Checks if the user is a superuser based on priority code"""
return getattr(self.priority, "priority_code", 0) == 78
@property
def is_user(self):
"""Checks if the user is a regular user based on priority code"""
return getattr(self.priority, "priority_code", 0) == 0
@classmethod
def create_action(cls, create_user: InsertUsers, token_dict):
db_session = cls.new_session()
@ -192,21 +203,7 @@ class Users(CrudCollection, UserLoginModule, SelectAction):
created_user.reset_password_token(found_user=created_user)
return created_user
@classmethod
def credentials(cls):
db_session = cls.new_session()
person_object = People.filter_by_one(
db=db_session, system=True, id=cls.person_id
).data
if person_object:
return {
"person_id": person_object.id,
"person_uu_id": str(person_object.uu_id),
}
return {
"person_id": None,
"person_uu_id": None,
}
def get_employee_and_duty_details(self):
from Schemas import Employees, Duties

View File

@ -1,7 +1,9 @@
from sqlalchemy import String
from sqlalchemy.orm import mapped_column, Mapped
from ApiLayers.LanguageModels.Database.rules.rules import EndpointRestrictionLanguageModel
from ApiLayers.LanguageModels.Database.rules.rules import (
EndpointRestrictionLanguageModel,
)
from Services.PostgresDb import CrudCollection

View File

@ -12,7 +12,10 @@ from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from ApiLayers.ErrorHandlers.Exceptions.api_exc import HTTPExceptionApi
from ApiLayers.Middleware.auth_middleware import RequestTimingMiddleware, LoggerTimingMiddleware
from ApiLayers.Middleware.auth_middleware import (
RequestTimingMiddleware,
LoggerTimingMiddleware,
)
def setup_cors_middleware(app: FastAPI) -> None:
@ -55,7 +58,9 @@ def setup_exception_handlers(app: FastAPI) -> None:
Args:
app: FastAPI application instance
"""
from ApiLayers.ErrorHandlers.ErrorHandlers.api_exc_handler import HTTPExceptionApiHandler
from ApiLayers.ErrorHandlers.ErrorHandlers.api_exc_handler import (
HTTPExceptionApiHandler,
)
custom_exception_handler = HTTPExceptionApiHandler(response_model=JSONResponse)
app.add_exception_handler(

View File

@ -1,4 +1,3 @@
class DefaultApiConfig:
app: str
host: str
@ -9,12 +8,12 @@ class DefaultApiConfig:
@classmethod
def as_dict(cls):
return {
"app": cls.app,
"host": cls.host,
"port": int(cls.port),
"log_level": cls.log_level,
"reload": bool(cls.reload),
}
"app": cls.app,
"host": cls.host,
"port": int(cls.port),
"log_level": cls.log_level,
"reload": bool(cls.reload),
}
class ApiStatic:
@ -41,7 +40,9 @@ class ApiConfig(DefaultApiConfig):
# Application Information
APP_NAME = "evyos-auth-api-gateway"
TITLE = "WAG API Auth Api Gateway"
DESCRIPTION = "This api is serves as web auth api gateway only to evyos web services."
DESCRIPTION = (
"This api is serves as web auth api gateway only to evyos web services."
)
APP_URL = "https://www.auth.eys.gen.tr"
# Server Configuration
@ -65,6 +66,6 @@ class MainConfig:
class LanguageConfig:
SUPPORTED_LANGUAGES = ["en", "tr"]
DEFAULT_LANGUAGE = "tr"

View File

@ -2,10 +2,15 @@
Route configuration and factory module.
Handles dynamic route creation based on configurations.
"""
from typing import Optional
from Events.Engine.set_defaults.run import get_cluster_controller_group
from Events.Engine.set_defaults.setClusters import PrepareRouting, SetItems2Redis, PrepareEvents
from Events.Engine.set_defaults.setClusters import (
PrepareRouting,
SetItems2Redis,
PrepareEvents,
)
routers: Optional[PrepareRouting] = None

View File

@ -32,7 +32,11 @@ class OpenAPISchemaCreator:
"""
self.app = app
self.cluster = get_all_routers()
self.safe_endpoint_list = self.cluster.safe_endpoints if hasattr(self.cluster, 'safe_endpoints') else []
self.safe_endpoint_list = (
self.cluster.safe_endpoints
if hasattr(self.cluster, "safe_endpoints")
else []
)
def _create_security_schemes(self) -> Dict[str, Any]:
"""
@ -42,6 +46,7 @@ class OpenAPISchemaCreator:
Dict[str, Any]: Security scheme configurations
"""
from ApiLayers.AllConfigs.Token.config import Auth
return {
"BearerAuth": {
"type": "apiKey",
@ -191,12 +196,12 @@ class OpenAPISchemaCreator:
# Check if endpoint is in safe list
endpoint_path = f"{path}:{method}"
if endpoint_path not in [f"{e.URL}:{e.METHOD.lower()}" for e in self.safe_endpoint_list]:
if endpoint_path not in [
f"{e.URL}:{e.METHOD.lower()}" for e in self.safe_endpoint_list
]:
if "security" not in schema["paths"][path][method]:
schema["paths"][path][method]["security"] = []
schema["paths"][path][method]["security"].append(
{"BearerAuth": []}
)
schema["paths"][path][method]["security"].append({"BearerAuth": []})
def create_schema(self) -> Dict[str, Any]:
"""
@ -216,8 +221,10 @@ class OpenAPISchemaCreator:
if "components" not in openapi_schema:
openapi_schema["components"] = {}
openapi_schema["components"]["securitySchemes"] = self._create_security_schemes()
openapi_schema["components"][
"securitySchemes"
] = self._create_security_schemes()
# Configure route security and responses
for route in self.app.routes:
if isinstance(route, APIRoute) and route.include_in_schema:

View File

@ -12,7 +12,10 @@ from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from ApiLayers.ErrorHandlers.Exceptions.api_exc import HTTPExceptionApi
from ApiLayers.Middleware.auth_middleware import RequestTimingMiddleware, LoggerTimingMiddleware
from ApiLayers.Middleware.auth_middleware import (
RequestTimingMiddleware,
LoggerTimingMiddleware,
)
def setup_cors_middleware(app: FastAPI) -> None:
@ -55,7 +58,9 @@ def setup_exception_handlers(app: FastAPI) -> None:
Args:
app: FastAPI application instance
"""
from ApiLayers.ErrorHandlers.ErrorHandlers.api_exc_handler import HTTPExceptionApiHandler
from ApiLayers.ErrorHandlers.ErrorHandlers.api_exc_handler import (
HTTPExceptionApiHandler,
)
custom_exception_handler = HTTPExceptionApiHandler(response_model=JSONResponse)
app.add_exception_handler(

View File

@ -1,4 +1,3 @@
class DefaultApiConfig:
app: str
host: str
@ -9,12 +8,12 @@ class DefaultApiConfig:
@classmethod
def as_dict(cls):
return {
"app": cls.app,
"host": cls.host,
"port": int(cls.port),
"log_level": cls.log_level,
"reload": bool(cls.reload),
}
"app": cls.app,
"host": cls.host,
"port": int(cls.port),
"log_level": cls.log_level,
"reload": bool(cls.reload),
}
class ApiStatic:
@ -32,12 +31,13 @@ class ApiStatic:
return cls.BLACKLIST_LINK + record_id
class ApiConfig(DefaultApiConfig):
# Api configuration
APP_NAME = "evyos-event-api-gateway"
TITLE = "WAG API Event Api Gateway"
DESCRIPTION = "This api is serves as web event api gateway only to evyos web services."
DESCRIPTION = (
"This api is serves as web event api gateway only to evyos web services."
)
APP_URL = "https://www.event.eys.gen.tr"
# Uvicorn server configuration
@ -57,4 +57,3 @@ class MainConfig:
DEFAULT_TIMEZONE = "GMT+3" # Default timezone for the application
SYSTEM_TIMEZONE = "GMT+0" # System timezone (used for internal operations)
SUPPORTED_TIMEZONES = ["GMT+0", "GMT+3"] # List of supported timezones

View File

@ -5,7 +5,11 @@ Handles dynamic route creation based on configurations.
from fastapi import Request
from Events.Engine.set_defaults.run import get_cluster_controller_group
from Events.Engine.set_defaults.setClusters import PrepareRouting, SetItems2Redis, PrepareEvents
from Events.Engine.set_defaults.setClusters import (
PrepareRouting,
SetItems2Redis,
PrepareEvents,
)
routers = None

View File

@ -32,7 +32,11 @@ class OpenAPISchemaCreator:
"""
self.app = app
self.cluster = get_all_routers()
self.safe_endpoint_list = self.cluster.safe_endpoints if hasattr(self.cluster, 'safe_endpoints') else []
self.safe_endpoint_list = (
self.cluster.safe_endpoints
if hasattr(self.cluster, "safe_endpoints")
else []
)
def _create_security_schemes(self) -> Dict[str, Any]:
"""
@ -42,6 +46,7 @@ class OpenAPISchemaCreator:
Dict[str, Any]: Security scheme configurations
"""
from ApiLayers.AllConfigs.Token.config import Auth
return {
"BearerAuth": {
"type": "apiKey",
@ -191,12 +196,12 @@ class OpenAPISchemaCreator:
# Check if endpoint is in safe list
endpoint_path = f"{path}:{method}"
if endpoint_path not in [f"{e.URL}:{e.METHOD.lower()}" for e in self.safe_endpoint_list]:
if endpoint_path not in [
f"{e.URL}:{e.METHOD.lower()}" for e in self.safe_endpoint_list
]:
if "security" not in schema["paths"][path][method]:
schema["paths"][path][method]["security"] = []
schema["paths"][path][method]["security"].append(
{"BearerAuth": []}
)
schema["paths"][path][method]["security"].append({"BearerAuth": []})
def create_schema(self) -> Dict[str, Any]:
"""
@ -216,8 +221,10 @@ class OpenAPISchemaCreator:
if "components" not in openapi_schema:
openapi_schema["components"] = {}
openapi_schema["components"]["securitySchemes"] = self._create_security_schemes()
openapi_schema["components"][
"securitySchemes"
] = self._create_security_schemes()
# Configure route security and responses
for route in self.app.routes:
if isinstance(route, APIRoute) and route.include_in_schema:

View File

@ -12,7 +12,10 @@ from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from ApiLayers.ErrorHandlers.Exceptions.api_exc import HTTPExceptionApi
from ApiLayers.Middleware.auth_middleware import RequestTimingMiddleware, LoggerTimingMiddleware
from ApiLayers.Middleware.auth_middleware import (
RequestTimingMiddleware,
LoggerTimingMiddleware,
)
def setup_cors_middleware(app: FastAPI) -> None:
@ -55,7 +58,9 @@ def setup_exception_handlers(app: FastAPI) -> None:
Args:
app: FastAPI application instance
"""
from ApiLayers.ErrorHandlers.ErrorHandlers.api_exc_handler import HTTPExceptionApiHandler
from ApiLayers.ErrorHandlers.ErrorHandlers.api_exc_handler import (
HTTPExceptionApiHandler,
)
custom_exception_handler = HTTPExceptionApiHandler(response_model=JSONResponse)
app.add_exception_handler(

View File

@ -1,4 +1,3 @@
class DefaultApiConfig:
app: str
host: str
@ -9,12 +8,12 @@ class DefaultApiConfig:
@classmethod
def as_dict(cls):
return {
"app": cls.app,
"host": cls.host,
"port": int(cls.port),
"log_level": cls.log_level,
"reload": bool(cls.reload),
}
"app": cls.app,
"host": cls.host,
"port": int(cls.port),
"log_level": cls.log_level,
"reload": bool(cls.reload),
}
class ApiStatic:
@ -36,7 +35,9 @@ class ApiConfig(DefaultApiConfig):
# Api configuration
APP_NAME = "evyos-validation-api-gateway"
TITLE = "WAG API Validation Api Gateway"
DESCRIPTION = "This api is serves as web validation api gateway only to evyos web services."
DESCRIPTION = (
"This api is serves as web validation api gateway only to evyos web services."
)
APP_URL = "https://www.validation.eys.gen.tr"
# App configuration
app = "app:app"
@ -55,4 +56,3 @@ class MainConfig:
DEFAULT_TIMEZONE = "GMT+3" # Default timezone for the application
SYSTEM_TIMEZONE = "GMT+0" # System timezone (used for internal operations)
SUPPORTED_TIMEZONES = ["GMT+0", "GMT+3"] # List of supported timezones

View File

@ -29,5 +29,3 @@ def get_all_routers() -> PrepareRouting:
cluster_list = get_cluster_controller_group()
prepare_routing = PrepareRouting(cluster_controller_group=cluster_list)
return prepare_routing

View File

@ -32,7 +32,11 @@ class OpenAPISchemaCreator:
"""
self.app = app
self.cluster = get_all_routers()
self.safe_endpoint_list = self.cluster.safe_endpoints if hasattr(self.cluster, 'safe_endpoints') else []
self.safe_endpoint_list = (
self.cluster.safe_endpoints
if hasattr(self.cluster, "safe_endpoints")
else []
)
def _create_security_schemes(self) -> Dict[str, Any]:
"""
@ -42,6 +46,7 @@ class OpenAPISchemaCreator:
Dict[str, Any]: Security scheme configurations
"""
from ApiLayers.AllConfigs.Token.config import Auth
return {
"BearerAuth": {
"type": "apiKey",
@ -191,12 +196,12 @@ class OpenAPISchemaCreator:
# Check if endpoint is in safe list
endpoint_path = f"{path}:{method}"
if endpoint_path not in [f"{e.URL}:{e.METHOD.lower()}" for e in self.safe_endpoint_list]:
if endpoint_path not in [
f"{e.URL}:{e.METHOD.lower()}" for e in self.safe_endpoint_list
]:
if "security" not in schema["paths"][path][method]:
schema["paths"][path][method]["security"] = []
schema["paths"][path][method]["security"].append(
{"BearerAuth": []}
)
schema["paths"][path][method]["security"].append({"BearerAuth": []})
def create_schema(self) -> Dict[str, Any]:
"""
@ -216,8 +221,10 @@ class OpenAPISchemaCreator:
if "components" not in openapi_schema:
openapi_schema["components"] = {}
openapi_schema["components"]["securitySchemes"] = self._create_security_schemes()
openapi_schema["components"][
"securitySchemes"
] = self._create_security_schemes()
# Configure route security and responses
for route in self.app.routes:
if isinstance(route, APIRoute) and route.include_in_schema:

View File

@ -1,56 +1,39 @@
from Events.Engine.abstract_class import Event
from .models import (
LoginSuperUserRequestModel,
LoginSuperUserResponseModel,
SelectCompanyOrOccupantTypeSuperUserRequestModel,
SelectCompanyOrOccupantTypeSuperUserResponseModel,
EmployeeSelectionSuperUserRequestModel,
EmployeeSelectionSuperUserResponseModel,
OccupantSelectionSuperUserRequestModel,
OccupantSelectionSuperUserResponseModel,
)
from .function_handlers import (
authentication_login_with_domain_and_creds,
authentication_select_company_or_occupant_type,
authentication_check_token_is_valid,
authentication_refresh_user_info,
authentication_change_password,
authentication_create_password,
authentication_disconnect_user,
authentication_logout_user,
authentication_refresher_token,
authentication_forgot_password,
authentication_reset_password,
authentication_download_avatar,
)
from .models import AuthenticationRequestModels, AuthenticationResponseModels
from .function_handlers import AuthenticationFunctions
# Auth Login
authentication_login_super_user_event = Event(
name="authentication_login_super_user_event",
key="a5d2d0d1-3e9b-4b0f-8c7d-6d4a4b4c4d4e",
request_validator=LoginSuperUserRequestModel,
request_validator=AuthenticationRequestModels.LoginSuperUserRequestModel,
# response_validator=LoginSuperUserResponseModel,
description="Login super user",
)
authentication_login_super_user_event.endpoint_callable = (
authentication_login_with_domain_and_creds
AuthenticationFunctions.authentication_login_with_domain_and_creds
)
# Auth Select Company or Occupant Type
authentication_select_company_or_occupant_type_super_user_event = Event(
name="authentication_select_company_or_occupant_type_super_user_event",
authentication_select_super_user_event = Event(
name="authentication_select_super_user_event",
key="a5d2d0d1-3e9b-4b0f-8c7d-6d4a4b4c4d4e",
request_validator=SelectCompanyOrOccupantTypeSuperUserRequestModel,
request_validator=AuthenticationRequestModels.SelectCompanyOrOccupantTypeSuperUserRequestModel,
# response_validator=SelectCompanyOrOccupantTypeSuperUserResponseModel,
description="Select company or occupant type super user",
)
authentication_select_company_or_occupant_type_super_user_event.endpoint_callable = (
authentication_select_company_or_occupant_type
authentication_select_super_user_event.endpoint_callable = (
AuthenticationFunctions.authentication_select_company_or_occupant_type
)
# Check Token Validity
authentication_check_token_event = Event(
name="authentication_check_token_event",
@ -59,7 +42,12 @@ authentication_check_token_event = Event(
# response_validator=None, # TODO: Add response validator
description="Check if token is valid",
)
authentication_check_token_event.endpoint_callable = authentication_check_token_is_valid
authentication_check_token_event.endpoint_callable = (
AuthenticationFunctions.authentication_check_token_is_valid
)
# Refresh User Info
authentication_refresh_user_info_event = Event(
@ -69,10 +57,13 @@ authentication_refresh_user_info_event = Event(
# response_validator=None, # TODO: Add response validator
description="Refresh user information",
)
authentication_refresh_user_info_event.endpoint_callable = (
authentication_refresh_user_info
AuthenticationFunctions.authentication_refresh_user_info
)
# Change Password
authentication_change_password_event = Event(
name="authentication_change_password_event",
@ -81,7 +72,12 @@ authentication_change_password_event = Event(
# response_validator=None, # TODO: Add response validator
description="Change user password",
)
authentication_change_password_event.endpoint_callable = authentication_change_password
authentication_change_password_event.endpoint_callable = (
AuthenticationFunctions.authentication_change_password
)
# Create Password
authentication_create_password_event = Event(
@ -91,7 +87,12 @@ authentication_create_password_event = Event(
# response_validator=None, # TODO: Add response validator
description="Create new password",
)
authentication_create_password_event.endpoint_callable = authentication_create_password
authentication_create_password_event.endpoint_callable = (
AuthenticationFunctions.authentication_create_password
)
# Disconnect User
authentication_disconnect_user_event = Event(
@ -101,7 +102,12 @@ authentication_disconnect_user_event = Event(
# response_validator=None, # TODO: Add response validator
description="Disconnect all user sessions",
)
authentication_disconnect_user_event.endpoint_callable = authentication_disconnect_user
authentication_disconnect_user_event.endpoint_callable = (
AuthenticationFunctions.authentication_disconnect_user
)
# Logout User
authentication_logout_user_event = Event(
@ -111,7 +117,12 @@ authentication_logout_user_event = Event(
# response_validator=None, # TODO: Add response validator
description="Logout user session",
)
authentication_logout_user_event.endpoint_callable = authentication_logout_user
authentication_logout_user_event.endpoint_callable = (
AuthenticationFunctions.authentication_logout_user
)
# Refresh Token
authentication_refresher_token_event = Event(
@ -121,7 +132,12 @@ authentication_refresher_token_event = Event(
# response_validator=None, # TODO: Add response validator
description="Refresh authentication token",
)
authentication_refresher_token_event.endpoint_callable = authentication_refresher_token
authentication_refresher_token_event.endpoint_callable = (
AuthenticationFunctions.authentication_refresher_token
)
# Forgot Password
authentication_forgot_password_event = Event(
@ -131,7 +147,12 @@ authentication_forgot_password_event = Event(
# response_validator=None, # TODO: Add response validator
description="Request password reset",
)
authentication_forgot_password_event.endpoint_callable = authentication_forgot_password
authentication_forgot_password_event.endpoint_callable = (
AuthenticationFunctions.authentication_forgot_password
)
# Reset Password
authentication_reset_password_event = Event(
@ -141,7 +162,12 @@ authentication_reset_password_event = Event(
# response_validator=None, # TODO: Add response validator
description="Reset user password",
)
authentication_reset_password_event.endpoint_callable = authentication_reset_password
authentication_reset_password_event.endpoint_callable = (
AuthenticationFunctions.authentication_reset_password
)
# Download Avatar
authentication_download_avatar_event = Event(
@ -151,4 +177,8 @@ authentication_download_avatar_event = Event(
# response_validator=None, # TODO: Add response validator
description="Download user avatar and profile info",
)
authentication_download_avatar_event.endpoint_callable = authentication_download_avatar
authentication_download_avatar_event.endpoint_callable = (
AuthenticationFunctions.authentication_download_avatar
)

View File

@ -1,19 +1,16 @@
"""
Authentication related API endpoints.
"""
from typing import Any, Dict
from fastapi import Request
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
from ApiLayers.Middleware import MiddlewareModule
from Events.Engine.abstract_class import MethodToEvent
from Events.base_request_model import EndpointBaseRequestModel
from Events.base_request_model import EndpointBaseRequestModel, ContextRetrievers
from .api_events import (
authentication_login_super_user_event,
authentication_select_company_or_occupant_type_super_user_event,
authentication_select_super_user_event,
authentication_check_token_event,
authentication_refresh_user_info_event,
authentication_change_password_event,
@ -26,12 +23,6 @@ from .api_events import (
authentication_download_avatar_event,
)
from fastapi import Request
# Type aliases for common types
TokenDictType = Union["EmployeeTokenObject", "OccupantTokenObject"]
AuthenticationLoginEventMethods = MethodToEvent(
name="AuthenticationLoginEventMethods",
@ -48,20 +39,24 @@ AuthenticationLoginEventMethods = MethodToEvent(
def authentication_login_with_domain_and_creds_endpoint(
request: Request,
data: EndpointBaseRequestModel,
request: Request, data: EndpointBaseRequestModel,
) -> Dict[str, Any]:
event_2_catch = AuthenticationLoginEventMethods.retrieve_event(event_function_code=f"{authentication_login_super_user_event.key}")
event_2_catch = AuthenticationLoginEventMethods.retrieve_event(
event_function_code=f"{authentication_login_super_user_event.key}"
)
data = event_2_catch.REQUEST_VALIDATOR(**data.data)
return event_2_catch.endpoint_callable(request=request, data=data)
AuthenticationLoginEventMethods.endpoint_callable = authentication_login_with_domain_and_creds_endpoint
AuthenticationLoginEventMethods.endpoint_callable = (
authentication_login_with_domain_and_creds_endpoint
)
AuthenticationSelectEventMethods = MethodToEvent(
name="AuthenticationSelectEventMethods",
events={
authentication_select_company_or_occupant_type_super_user_event.key: authentication_select_company_or_occupant_type_super_user_event,
authentication_select_super_user_event.key: authentication_select_super_user_event,
},
decorators_list=[MiddlewareModule.auth_required],
headers=[],
@ -72,28 +67,27 @@ AuthenticationSelectEventMethods = MethodToEvent(
description="Select company or occupant type",
)
def authentication_select_company_or_occupant_type(
request: Request,
data: EndpointBaseRequestModel,
) -> Dict[str, Any]:
def authentication_select_company_or_occupant_type(data: EndpointBaseRequestModel) -> Dict[str, Any]:
"""
Select company or occupant type.
"""
auth_context = authentication_select_company_or_occupant_type.auth_context
context_retriever = ContextRetrievers(func=authentication_select_company_or_occupant_type)
function = AuthenticationSelectEventMethods.retrieve_event(
event_function_code=f"{authentication_select_company_or_occupant_type_super_user_event.key}"
event_function_code=f"{authentication_select_super_user_event.key}"
)
function.endpoint_callable.auth_context = auth_context
return function.endpoint_callable(request=request, data=data)
setattr(function.endpoint_callable, context_retriever.key, context_retriever.context)
return function.endpoint_callable(data=data)
AuthenticationSelectEventMethods.endpoint_callable = authentication_select_company_or_occupant_type
AuthenticationSelectEventMethods.endpoint_callable = (
authentication_select_company_or_occupant_type
)
AuthenticationCheckTokenEventMethods = MethodToEvent(
name="AuthenticationCheckTokenEventMethods",
events={
authentication_check_token_event.key: authentication_check_token_event
},
events={authentication_check_token_event.key: authentication_check_token_event},
headers=[],
errors=[],
decorators_list=[MiddlewareModule.auth_required],
@ -103,14 +97,20 @@ AuthenticationCheckTokenEventMethods = MethodToEvent(
description="Check if access token is valid for user",
)
def authentication_check_token_is_valid(request: Request):
def authentication_check_token_is_valid():
context_retriever = ContextRetrievers(func=authentication_check_token_is_valid)
function = AuthenticationCheckTokenEventMethods.retrieve_event(
event_function_code=f"{authentication_check_token_event.key}"
)
return function.endpoint_callable(request=request)
setattr(function.endpoint_callable, context_retriever.key, context_retriever.context)
return function.endpoint_callable()
AuthenticationCheckTokenEventMethods.endpoint_callable = authentication_check_token_is_valid
AuthenticationCheckTokenEventMethods.endpoint_callable = (
authentication_check_token_is_valid
)
AuthenticationRefreshEventMethods = MethodToEvent(
name="AuthenticationRefreshEventMethods",
@ -127,16 +127,18 @@ AuthenticationRefreshEventMethods = MethodToEvent(
)
def authentication_refresh_user_info(request: Request):
token_dict = authentication_refresh_user_info.auth
def authentication_refresh_user_info():
context_retriever = ContextRetrievers(func=authentication_refresh_user_info)
function = AuthenticationRefreshEventMethods.retrieve_event(
event_function_code=f"{authentication_refresh_user_info_event.key}"
)
return function.endpoint_callable(request=request, token_dict=token_dict)
setattr(function.endpoint_callable, context_retriever.key, context_retriever.context)
return function.endpoint_callable()
AuthenticationRefreshEventMethods.endpoint_callable = authentication_refresh_user_info
AuthenticationChangePasswordEventMethods = MethodToEvent(
name="AuthenticationChangePasswordEventMethods",
events={
@ -151,21 +153,23 @@ AuthenticationChangePasswordEventMethods = MethodToEvent(
description="Change password with access token",
)
def authentication_change_password_event_callable(request: Request, data: EndpointBaseRequestModel):
token_dict = authentication_change_password_event_callable.auth
def authentication_change_password_event_callable(data: EndpointBaseRequestModel):
context_retriever = ContextRetrievers(func=authentication_change_password_event_callable)
function = AuthenticationChangePasswordEventMethods.retrieve_event(
event_function_code=f"{authentication_change_password_event.key}"
)
return function.endpoint_callable(data=data, token_dict=token_dict)
setattr(function.endpoint_callable, context_retriever.key, context_retriever.context)
return function.endpoint_callable(data=data)
AuthenticationChangePasswordEventMethods.endpoint_callable = authentication_change_password_event_callable
AuthenticationChangePasswordEventMethods.endpoint_callable = (
authentication_change_password_event_callable
)
AuthenticationCreatePasswordEventMethods = MethodToEvent(
name="AuthenticationCreatePasswordEventMethods",
events={
authentication_create_password_event: authentication_create_password_event
},
events={authentication_create_password_event: authentication_create_password_event},
headers=[],
errors=[],
url="/create-password",
@ -174,14 +178,20 @@ AuthenticationCreatePasswordEventMethods = MethodToEvent(
description="Create password with password reset token requested via email",
)
def authentication_create_password(data: EndpointBaseRequestModel):
context_retriever = ContextRetrievers(func=authentication_create_password)
function = AuthenticationCreatePasswordEventMethods.retrieve_event(
event_function_code=f"{authentication_create_password_event.key}"
)
setattr(function.endpoint_callable, context_retriever.key, context_retriever.context)
return function.endpoint_callable(data=data)
AuthenticationCreatePasswordEventMethods.endpoint_callable = authentication_create_password
AuthenticationCreatePasswordEventMethods.endpoint_callable = (
authentication_create_password
)
AuthenticationDisconnectUserEventMethods = MethodToEvent(
name="AuthenticationDisconnectUserEventMethods",
@ -197,22 +207,22 @@ AuthenticationDisconnectUserEventMethods = MethodToEvent(
description="Disconnect all sessions of user in access token",
)
def authentication_disconnect_user(request: Request, data: EndpointBaseRequestModel):
token_dict = authentication_disconnect_user.auth
def authentication_disconnect_user(data: EndpointBaseRequestModel):
context_retriever = ContextRetrievers(func=authentication_disconnect_user)
function = AuthenticationDisconnectUserEventMethods.retrieve_event(
event_function_code=f"{authentication_disconnect_user_event.key}"
)
return function.endpoint_callable(data=data, token_dict=token_dict)
setattr(function.endpoint_callable, context_retriever.key, context_retriever.context)
return function.endpoint_callable(data=data)
AuthenticationLogoutEventMethods = MethodToEvent(
name="AuthenticationLogoutEventMethods",
events={
authentication_logout_user_event.key: authentication_logout_user_event
},
events={authentication_logout_user_event.key: authentication_logout_user_event},
headers=[],
errors=[],
decorators_list=[TokenEventMiddleware.event_required],
decorators_list=[MiddlewareModule.auth_required],
url="/logout",
method="POST",
summary="Logout user",
@ -220,12 +230,13 @@ AuthenticationLogoutEventMethods = MethodToEvent(
)
def authentication_logout_user(request: Request, data: EndpointBaseRequestModel):
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)
def authentication_logout_user(data: EndpointBaseRequestModel):
context_retriever = ContextRetrievers(func=authentication_logout_user)
function = AuthenticationLogoutEventMethods.retrieve_event(
event_function_code=f"{authentication_logout_user_event.key}"
)
setattr(function.endpoint_callable, context_retriever.key, context_retriever.context)
return function.endpoint_callable(data=data)
AuthenticationLogoutEventMethods.endpoint_callable = authentication_logout_user
@ -246,16 +257,18 @@ AuthenticationRefreshTokenEventMethods = MethodToEvent(
)
def authentication_refresher_token(request: Request, data: EndpointBaseRequestModel):
auth_context: AuthContext = getattr(authentication_refresher_token, "auth_context", None)
def authentication_refresher_token(data: EndpointBaseRequestModel):
context_retriever = ContextRetrievers(func=authentication_refresher_token)
function = AuthenticationRefreshTokenEventMethods.retrieve_event(
event_function_code=f"{authentication_refresher_token_event.key}"
)
function.endpoint_callable.auth_context = auth_context
return function.endpoint_callable(data=data, request=request)
setattr(function.endpoint_callable, context_retriever.key, context_retriever.context)
return function.endpoint_callable(data=data)
AuthenticationRefreshTokenEventMethods.endpoint_callable = authentication_refresher_token
AuthenticationRefreshTokenEventMethods.endpoint_callable = (
authentication_refresher_token
)
AuthenticationForgotPasswordEventMethods = MethodToEvent(
@ -272,15 +285,18 @@ AuthenticationForgotPasswordEventMethods = MethodToEvent(
)
def authentication_forgot_password(request: Request, data: EndpointBaseRequestModel):
token_dict = authentication_forgot_password.auth
def authentication_forgot_password(data: EndpointBaseRequestModel):
context_retriever = ContextRetrievers(func=authentication_forgot_password)
function = AuthenticationForgotPasswordEventMethods.retrieve_event(
event_function_code=f"{authentication_forgot_password_event.key}"
)
return function.endpoint_callable(data=data, token_dict=token_dict)
setattr(function.endpoint_callable, context_retriever.key, context_retriever.context)
return function.endpoint_callable(data=data)
AuthenticationForgotPasswordEventMethods.endpoint_callable = authentication_forgot_password
AuthenticationForgotPasswordEventMethods.endpoint_callable = (
authentication_forgot_password
)
AuthenticationResetPasswordEventMethods = MethodToEvent(
@ -299,14 +315,18 @@ AuthenticationResetPasswordEventMethods = MethodToEvent(
def authentication_reset_password(data: EndpointBaseRequestModel):
# token_dict = authentication_reset_password.auth
context_retriever = ContextRetrievers(func=authentication_reset_password)
function = AuthenticationResetPasswordEventMethods.retrieve_event(
event_function_code=f"{authentication_reset_password_event.key}"
)
setattr(function.endpoint_callable, context_retriever.key, context_retriever.context)
return function.endpoint_callable(data=data)
AuthenticationResetPasswordEventMethods.endpoint_callable = authentication_reset_password
AuthenticationResetPasswordEventMethods.endpoint_callable = (
authentication_reset_password
)
AuthenticationDownloadAvatarEventMethods = MethodToEvent(
name="AuthenticationDownloadAvatarEventMethods",
@ -315,7 +335,7 @@ AuthenticationDownloadAvatarEventMethods = MethodToEvent(
},
headers=[],
errors=[],
decorators_list=[],
decorators_list=[MiddlewareModule.auth_required],
url="/download-avatar",
method="POST",
summary="Download avatar",
@ -323,13 +343,15 @@ AuthenticationDownloadAvatarEventMethods = MethodToEvent(
)
@MiddlewareModule.auth_required
def authentication_download_avatar(request: Request):
token_dict = authentication_download_avatar.auth
def authentication_download_avatar():
context_retriever = ContextRetrievers(func=authentication_download_avatar)
function = AuthenticationDownloadAvatarEventMethods.retrieve_event(
event_function_code=f"{authentication_download_avatar_event.key}"
)
return function.endpoint_callable(token_dict=token_dict)
setattr(function.endpoint_callable, context_retriever.key, context_retriever.context)
return function.endpoint_callable()
AuthenticationDownloadAvatarEventMethods.endpoint_callable = authentication_download_avatar
AuthenticationDownloadAvatarEventMethods.endpoint_callable = (
authentication_download_avatar
)

View File

@ -1,11 +1,11 @@
from typing import Any, TYPE_CHECKING, Union, Dict
from typing import Any
from fastapi import Request
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.ApiValidations.Response.default_response import EndpointSuccessResponse
from ApiLayers.ErrorHandlers import HTTPExceptionApi
from ApiLayers.Schemas import (
BuildLivingSpace,
@ -22,462 +22,452 @@ from ApiLayers.Schemas import (
OccupantTypes,
Users,
)
from ApiLayers.ApiValidations.Response.default_response import EndpointSuccessResponse
from fastapi import Request
from Events.base_request_model import ContextRetrievers, TokenDictType
# Type aliases for common types
TokenDictType = Union["EmployeeTokenObject", "OccupantTokenObject"]
class Handlers:
"""Class for handling authentication functions"""
def authentication_login_with_domain_and_creds(request: Request, data: Any):
"""
Authenticate user with domain and credentials.
Args:
request: FastAPI request object
data: Request body containing login credentials
{
"domain": "evyos.com.tr",
"access_key": "karatay.berkay.sup@evyos.com.tr",
"password": "string",
"remember_me": false
}
Returns:
SuccessResponse containing authentication token and user info
"""
# Get token from login module
user_login_module = UserLoginModule(request=request)
token = user_login_module.login_user_via_credentials(access_data=data)
# Return response with token and headers
user_login_module.language = "tr"
success_response = EndpointSuccessResponse(
code="LoginSuccess", lang=user_login_module.language
)
return success_response.as_dict(
data={
"access_token": token.get("access_token"),
"refresh_token": token.get("refresher_token"),
"access_object": {"user_type": token.get("user_type"), "companies_list": token.get("companies_list")},
"user": token.get("user"),
}
)
# return {
# "completed": True,
# "message": "User is logged in successfully",
# "access_token": token.get("access_token"),
# "refresh_token": token.get("refresher_token"),
# "access_object": {
# "user_type": token.get("user_type"), "companies_list": token.get("companies_list")
# },
# "user": token.get("user"),
# }
def handle_employee_selection(request: Request, data: Any, token_dict: TokenDictType):
Users.set_user_define_properties(token=token_dict)
db_session = Users.new_session()
if data.company_uu_id not in token_dict.companies_uu_id_list:
raise HTTPExceptionApi(
error_code="HTTP_400_BAD_REQUEST",
lang=token_dict.lang,
loc=get_line_number_for_error(),
sys_msg="Company not found in token",
)
selected_company = Companies.filter_one(
Companies.uu_id == data.company_uu_id,
db=db_session,
).first
if not selected_company:
raise HTTPExceptionApi(
error_code="HTTP_400_BAD_REQUEST",
lang=token_dict.lang,
loc=get_line_number_for_error(),
sys_msg="Company not found in token",
)
# Get department IDs for the company
department_ids = [
dept.id
for dept in Departments.filter_all(
Departments.company_id == selected_company.id,
db=db_session,
@classmethod # Requires no auth context
def handle_employee_selection(cls, request: Request, data: Any, token_dict: TokenDictType):
Users.set_user_define_properties(token=token_dict)
db = Users.new_session()
if data.company_uu_id not in token_dict.companies_uu_id_list:
raise HTTPExceptionApi(
error_code="HTTP_400_BAD_REQUEST",
lang=token_dict.lang,
loc=get_line_number_for_error(),
sys_msg="Company not found in token",
)
selected_company: Companies = Companies.filter_one(
Companies.uu_id == data.company_uu_id,
db=db,
).data
]
if not selected_company:
raise HTTPExceptionApi(
error_code="HTTP_400_BAD_REQUEST",
lang=token_dict.lang,
loc=get_line_number_for_error(),
sys_msg="Company not found in token",
)
# Get duties IDs for the company
duties_ids = [
duty.id
for duty in Duties.filter_all(
Duties.company_id == selected_company.id, db=db_session
# Get department IDs for the company
department_ids = [
dept.id
for dept in Departments.filter_all(
Departments.company_id == selected_company.id,
db=db,
).data
]
# Get duties IDs for the company
duties_ids = [
duty.id
for duty in Duties.filter_all(
Duties.company_id == selected_company.id, db=db
).data
]
# Get staff IDs
staff_ids = [
staff.id
for staff in Staff.filter_all(Staff.duties_id.in_(duties_ids), db=db).data
]
# Get employee
employee: Employees = Employees.filter_one(
Employees.people_id == token_dict.person_id,
Employees.staff_id.in_(staff_ids),
db=db,
).data
]
# Get staff IDs
staff_ids = [
staff.id
for staff in Staff.filter_all(
Staff.duties_id.in_(duties_ids), db=db_session
if not employee:
raise HTTPExceptionApi(
error_code="HTTP_400_BAD_REQUEST",
lang=token_dict.lang,
loc=get_line_number_for_error(),
sys_msg="Employee not found in token",
)
# Get reachable events
reachable_event_codes = Event2Employee.get_event_codes(employee_id=employee.id)
reachable_event_endpoints = Event2Employee.get_event_endpoints(
employee_id=employee.id
)
# Get staff and duties
staff = Staff.filter_one(Staff.id == employee.staff_id, db=db).data
duties = Duties.filter_one(Duties.id == staff.duties_id, db=db).data
department = Departments.filter_one(
Departments.id == duties.department_id, db=db
).data
]
# Get employee
employee = Employees.filter_one(
Employees.people_id == token_dict.person_id,
Employees.staff_id.in_(staff_ids),
db=db_session,
).first
# Get bulk duty
bulk_id = Duty.filter_by_one(system=True, duty_code="BULK", db=db).data
bulk_duty_id = Duties.filter_by_one(
company_id=selected_company.id,
duties_id=bulk_id.id,
**Duties.valid_record_dict,
db=db,
).data
if not employee:
raise HTTPExceptionApi(
error_code="HTTP_400_BAD_REQUEST",
lang=token_dict.lang,
loc=get_line_number_for_error(),
sys_msg="Employee not found in token",
# Create company token
company_token = CompanyToken(
company_uu_id=selected_company.uu_id.__str__(),
company_id=selected_company.id,
department_id=department.id,
department_uu_id=department.uu_id.__str__(),
duty_id=duties.id,
duty_uu_id=duties.uu_id.__str__(),
bulk_duties_id=bulk_duty_id.id,
staff_id=staff.id,
staff_uu_id=staff.uu_id.__str__(),
employee_id=employee.id,
employee_uu_id=employee.uu_id.__str__(),
reachable_event_codes=reachable_event_codes,
reachable_event_endpoints=reachable_event_endpoints,
)
# Get reachable events
reachable_event_codes = Event2Employee.get_event_codes(employee_id=employee.id)
reachable_event_endpoints = Event2Employee.get_event_endpoints(
employee_id=employee.id
)
try: # Update Redis
return TokenService.update_token_at_redis(
request=request, add_payload=company_token
)
except Exception as e:
raise HTTPExceptionApi(
error_code="",
lang="en",
loc=get_line_number_for_error(),
sys_msg=f"{e}",
)
# Get staff and duties
staff = Staff.filter_one(Staff.id == employee.staff_id, db=db_session).data
duties = Duties.filter_one(Duties.id == staff.duties_id, db=db_session).data
department = Departments.filter_one(
Departments.id == duties.department_id, db=db_session
).data
@classmethod # Requires no auth context
def handle_occupant_selection(cls, request: Request, data: Any, token_dict: TokenDictType):
"""Handle occupant type selection"""
Users.set_user_define_properties(token=token_dict)
db = BuildLivingSpace.new_session()
# Get selected occupant type
selected_build_living_space: BuildLivingSpace = BuildLivingSpace.filter_one(
BuildLivingSpace.uu_id == data.build_living_space_uu_id,
db=db,
).data
if not selected_build_living_space:
raise HTTPExceptionApi(
error_code="HTTP_400_BAD_REQUEST",
lang=token_dict.lang,
loc=get_line_number_for_error(),
sys_msg="Selected occupant type not found",
)
# Get bulk duty
bulk_id = Duty.filter_by_one(system=True, duty_code="BULK", db=db_session).data
bulk_duty_id = Duties.filter_by_one(
company_id=selected_company.id,
duties_id=bulk_id.id,
**Duties.valid_record_dict,
db=db_session,
).data
# Create company token
company_token = CompanyToken(
company_uu_id=selected_company.uu_id.__str__(),
company_id=selected_company.id,
department_id=department.id,
department_uu_id=department.uu_id.__str__(),
duty_id=duties.id,
duty_uu_id=duties.uu_id.__str__(),
bulk_duties_id=bulk_duty_id.id,
staff_id=staff.id,
staff_uu_id=staff.uu_id.__str__(),
employee_id=employee.id,
employee_uu_id=employee.uu_id.__str__(),
reachable_event_codes=reachable_event_codes,
reachable_event_endpoints=reachable_event_endpoints,
)
try: # Update Redis
update_token = TokenService.update_token_at_redis(
request=request, add_payload=company_token
# Get reachable events
reachable_event_codes = Event2Occupant.get_event_codes(
build_living_space_id=selected_build_living_space.id
)
return update_token
except Exception as e:
raise HTTPExceptionApi(
error_code="",
lang="en",
loc=get_line_number_for_error(),
sys_msg=f"{e}",
reachable_event_endpoints = Event2Occupant.get_event_endpoints(
build_living_space_id=selected_build_living_space.id
)
occupant_type = OccupantTypes.filter_one(
OccupantTypes.id == selected_build_living_space.occupant_type_id,
db=db,
system=True,
).data
build_part = BuildParts.filter_one(
BuildParts.id == selected_build_living_space.build_parts_id,
db=db,
).data
build = BuildParts.filter_one(
BuildParts.id == build_part.build_id,
db=db,
).data
responsible_employee = Employees.filter_one(
Employees.id == build_part.responsible_employee_id,
db=db,
).data
related_company = RelationshipEmployee2Build.filter_one(
RelationshipEmployee2Build.member_id == build.id,
db=db,
).data
# Get company
company_related = Companies.filter_one(
Companies.id == related_company.company_id,
db=db,
).data
# Create occupant token
occupant_token = OccupantToken(
living_space_id=selected_build_living_space.id,
living_space_uu_id=selected_build_living_space.uu_id.__str__(),
occupant_type_id=occupant_type.id,
occupant_type_uu_id=occupant_type.uu_id.__str__(),
occupant_type=occupant_type.occupant_type,
build_id=build.id,
build_uuid=build.uu_id.__str__(),
build_part_id=build_part.id,
build_part_uuid=build_part.uu_id.__str__(),
responsible_employee_id=responsible_employee.id,
responsible_employee_uuid=responsible_employee.uu_id.__str__(),
responsible_company_id=company_related.id,
responsible_company_uuid=company_related.uu_id.__str__(),
reachable_event_codes=reachable_event_codes,
reachable_event_endpoints=reachable_event_endpoints,
)
def handle_occupant_selection(request: Request, data: Any, token_dict: TokenDictType):
"""Handle occupant type selection"""
db = BuildLivingSpace.new_session()
# Get selected occupant type
selected_build_living_space = BuildLivingSpace.filter_one(
BuildLivingSpace.uu_id == data.build_living_space_uu_id,
db=db,
).data
if not selected_build_living_space:
raise HTTPExceptionApi(
error_code="HTTP_400_BAD_REQUEST",
lang=token_dict.lang,
loc=get_line_number_for_error(),
sys_msg="Selected occupant type not found",
)
# Get reachable events
reachable_event_codes = Event2Occupant.get_event_codes(
build_living_space_id=selected_build_living_space.id
)
reachable_event_endpoints = Event2Occupant.get_event_endpoints(
build_living_space_id=selected_build_living_space.id
)
occupant_type = OccupantTypes.filter_one(
OccupantTypes.id == selected_build_living_space.occupant_type_id,
db=db,
system=True,
).data
build_part = BuildParts.filter_one(
BuildParts.id == selected_build_living_space.build_parts_id,
db=db,
).data
build = BuildParts.filter_one(
BuildParts.id == build_part.build_id,
db=db,
).data
responsible_employee = Employees.filter_one(
Employees.id == build_part.responsible_employee_id,
db=db,
).data
related_company = RelationshipEmployee2Build.filter_one(
RelationshipEmployee2Build.member_id == build.id,
db=db,
).data
# Get company
company_related = Companies.filter_one(
Companies.id == related_company.company_id,
db=db,
).data
# Create occupant token
occupant_token = OccupantToken(
living_space_id=selected_build_living_space.id,
living_space_uu_id=selected_build_living_space.uu_id.__str__(),
occupant_type_id=occupant_type.id,
occupant_type_uu_id=occupant_type.uu_id.__str__(),
occupant_type=occupant_type.occupant_type,
build_id=build.id,
build_uuid=build.uu_id.__str__(),
build_part_id=build_part.id,
build_part_uuid=build_part.uu_id.__str__(),
responsible_employee_id=responsible_employee.id,
responsible_employee_uuid=responsible_employee.uu_id.__str__(),
responsible_company_id=company_related.id,
responsible_company_uuid=company_related.uu_id.__str__(),
reachable_event_codes=reachable_event_codes,
reachable_event_endpoints=reachable_event_endpoints,
)
try: # Update Redis
update_token = TokenService.update_token_at_redis(
request=request, add_payload=occupant_token
)
return update_token
except Exception as e:
raise HTTPExceptionApi(
error_code="",
lang="en",
loc=get_line_number_for_error(),
sys_msg=f"{e}",
)
try: # Update Redis
return TokenService.update_token_at_redis(
request=request, add_payload=occupant_token
)
except Exception as e:
raise HTTPExceptionApi(
error_code="",
lang="en",
loc=get_line_number_for_error(),
sys_msg=f"{e}",
)
def authentication_select_company_or_occupant_type(request: Request, data: Any):
"""Handle selection of company or occupant type"""
token_dict: TokenDictType = authentication_select_company_or_occupant_type.auth_context
if token_dict.is_employee:
if handle_employee_selection(data, token_dict, request):
return {"selected_occupant": None, "selected_company": data.company_uu_id}
elif token_dict.is_occupant:
if handle_occupant_selection(data, token_dict, request):
return {"selected_company": None, "selected_occupant": data.build_living_space_uu_id}
return {"completed": False, "selected_company": None, "selected_occupant": None}
class AuthenticationFunctions:
"""Class for handling authentication functions"""
@classmethod # Requires auth context
def authentication_select_company_or_occupant_type(cls, data: Any):
"""Handle selection of company or occupant type"""
context_retriever = ContextRetrievers(func=cls.authentication_select_company_or_occupant_type)
if context_retriever.token.is_employee:
if Handlers.handle_employee_selection(
request=context_retriever.request, data=data, token_dict=context_retriever.token
):
return {
"completed": True, "selected": data.company_uu_id, **context_retriever.base,
}
elif context_retriever.token.is_occupant:
if Handlers.handle_occupant_selection(
request=context_retriever.request, data=data, token_dict=context_retriever.token
):
return {
"completed": True, "selected": data.build_living_space_uu_id, **context_retriever.base,
}
return {"completed": False, "selected": None, **context_retriever.base}
def authentication_check_token_is_valid(request: Request, data: Any):
"""Check if token is valid for user"""
# try:
# if RedisActions.get_object_via_access_key(request=request):
# return ResponseHandler.success("Access Token is valid")
# except HTTPException:
# return ResponseHandler.unauthorized("Access Token is NOT valid")
return
@classmethod # Requires no auth context
def authentication_login_with_domain_and_creds(cls, request: Request, data: Any):
"""
Authenticate user with domain and credentials.
Args:
request: FastAPI request object
data: Request body containing login credentials
{
"domain": "evyos.com.tr",
"access_key": "karatay.berkay.sup@evyos.com.tr",
"password": "string",
"remember_me": false
}
Returns:
SuccessResponse containing authentication token and user info
"""
def authentication_refresh_user_info(request: Request, token_dict: TokenDictType, data: Any):
"""Refresh user info using access token"""
# try:
# access_token = request.headers.get(Auth.ACCESS_TOKEN_TAG)
# if not access_token:
# return ResponseHandler.unauthorized()
# Get token from login module
user_login_module = UserLoginModule(request=request)
user_login_module.login_user_via_credentials(access_data=data)
user_login_module.language = "tr"
# found_user = Users.filter_one(Users.uu_id == token_dict.user_uu_id).data
# if not found_user:
# return ResponseHandler.not_found("User not found")
# user_token = UsersTokens.filter_one(
# UsersTokens.domain == found_user.domain_name,
# UsersTokens.user_id == found_user.id,
# UsersTokens.token_type == "RememberMe",
# ).data
# response_data = {
# "access_token": access_token,
# "refresh_token": getattr(user_token, "token", None),
# "user": found_user.get_dict(),
# }
# return ResponseHandler.success(
# "User info refreshed successfully",
# data=response_data,
# )
# except Exception as e:
# return ResponseHandler.error(str(e))
return
# Return response with token and headers
return EndpointSuccessResponse(
code="LOGIN_SUCCESS", lang=user_login_module.language
).as_dict(data=user_login_module.as_dict)
@classmethod # Requires not auth context
def authentication_check_token_is_valid(cls, data: Any):
"""Check if token is valid for user"""
# try:
# if RedisActions.get_object_via_access_key(request=request):
# return ResponseHandler.success("Access Token is valid")
# except HTTPException:
# return ResponseHandler.unauthorized("Access Token is NOT valid")
return
def authentication_change_password(request: Request, token_dict: TokenDictType, data: Any):
"""Change password with access token"""
# try:
# if not isinstance(token_dict, EmployeeTokenObject):
# return ResponseHandler.unauthorized("Only employees can change password")
@classmethod # Requires not auth context
def authentication_refresh_user_info(cls, data: Any):
"""Refresh user info using access token"""
# try:
# access_token = request.headers.get(Auth.ACCESS_TOKEN_TAG)
# if not access_token:
# return ResponseHandler.unauthorized()
# found_user = Users.filter_one(Users.uu_id == token_dict.user_uu_id).data
# if not found_user:
# return ResponseHandler.not_found("User not found")
# found_user = Users.filter_one(Users.uu_id == token_dict.user_uu_id).data
# if not found_user:
# return ResponseHandler.not_found("User not found")
# user_token = UsersTokens.filter_one(
# UsersTokens.domain == found_user.domain_name,
# UsersTokens.user_id == found_user.id,
# UsersTokens.token_type == "RememberMe",
# ).data
# response_data = {
# "access_token": access_token,
# "refresh_token": getattr(user_token, "token", None),
# "user": found_user.get_dict(),
# }
# return ResponseHandler.success(
# "User info refreshed successfully",
# data=response_data,
# )
# except Exception as e:
# return ResponseHandler.error(str(e))
return
# if not found_user.check_password(data.old_password):
# return ResponseHandler.unauthorized("Old password is incorrect")
@classmethod # Requires no auth context
def authentication_change_password(cls, data: Any):
"""Change password with access token"""
# try:
# if not isinstance(token_dict, EmployeeTokenObject):
# return ResponseHandler.unauthorized("Only employees can change password")
# found_user.set_password(data.new_password)
# return ResponseHandler.success("Password changed successfully")
# except Exception as e:
# return ResponseHandler.error(str(e))
return
# found_user = Users.filter_one(Users.uu_id == token_dict.user_uu_id).data
# if not found_user:
# return ResponseHandler.not_found("User not found")
# if not found_user.check_password(data.old_password):
# return ResponseHandler.unauthorized("Old password is incorrect")
def authentication_create_password(request: Request, data: Any):
"""Create password with password reset token requested via email"""
# if not data.re_password == data.password:
# raise HTTPException(status_code=status.HTTP_406_NOT_ACCEPTABLE, detail="Password must match")
# if found_user := Users.filter_one(Users.password_token == data.password_token).data:
# found_user.create_password(found_user=found_user, password=data.password)
# found_user.password_token = ""
# found_user.save()
# return ResponseHandler.success("Password is created successfully", data=found_user.get_dict())
# return ResponseHandler.not_found("Record not found")
return
# found_user.set_password(data.new_password)
# return ResponseHandler.success("Password changed successfully")
# except Exception as e:
# return ResponseHandler.error(str(e))
return
@classmethod # Requires not auth context
def authentication_create_password(cls, data: Any):
"""Create password with password reset token requested via email"""
# if not data.re_password == data.password:
# raise HTTPException(status_code=status.HTTP_406_NOT_ACCEPTABLE, detail="Password must match")
# if found_user := Users.filter_one(Users.password_token == data.password_token).data:
# found_user.create_password(found_user=found_user, password=data.password)
# found_user.password_token = ""
# found_user.save()
# return ResponseHandler.success("Password is created successfully", data=found_user.get_dict())
# return ResponseHandler.not_found("Record not found")
return
def authentication_disconnect_user(request: Request, token_dict: TokenDictType, data: Any):
"""Disconnect all sessions of user in access token"""
# found_user = Users.filter_one(Users.uu_id == token_dict.user_uu_id).data
# if not found_user:
# return ResponseHandler.not_found("User not found")
# if already_tokens := RedisActions.get_object_via_user_uu_id(user_id=str(found_user.uu_id)):
# for key, token_user in already_tokens.items():
# RedisActions.delete(key)
# selected_user = Users.filter_one(Users.uu_id == token_user.get("uu_id")).data
# selected_user.remove_refresher_token(domain=data.domain, disconnect=True)
# return ResponseHandler.success("All sessions are disconnected", data=selected_user.get_dict())
# return ResponseHandler.not_found("Invalid data")
return
@classmethod # Requires auth context
def authentication_disconnect_user(cls, data: Any):
"""Disconnect all sessions of user in access token"""
# found_user = Users.filter_one(Users.uu_id == token_dict.user_uu_id).data
# if not found_user:
# return ResponseHandler.not_found("User not found")
# if already_tokens := RedisActions.get_object_via_user_uu_id(user_id=str(found_user.uu_id)):
# for key, token_user in already_tokens.items():
# RedisActions.delete(key)
# selected_user = Users.filter_one(Users.uu_id == token_user.get("uu_id")).data
# selected_user.remove_refresher_token(domain=data.domain, disconnect=True)
# return ResponseHandler.success("All sessions are disconnected", data=selected_user.get_dict())
# return ResponseHandler.not_found("Invalid data")
return
@classmethod # Requires auth context
def authentication_logout_user(cls, data: Any):
"""Logout only single session of user which domain is provided"""
# token_user = None
# if already_tokens := RedisActions.get_object_via_access_key(request=request):
# for key in already_tokens:
# token_user = RedisActions.get_json(key)
# if token_user.get("domain") == data.domain:
# RedisActions.delete(key)
# selected_user = Users.filter_one(Users.uu_id == token_user.get("uu_id")).data
# 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")
context_retriever = ContextRetrievers(func=cls.authentication_logout_user)
return context_retriever.base
def authentication_logout_user(request: Request, data: Any):
"""Logout only single session of user which domain is provided"""
# token_user = None
# if already_tokens := RedisActions.get_object_via_access_key(request=request):
# for key in already_tokens:
# token_user = RedisActions.get_json(key)
# if token_user.get("domain") == data.domain:
# RedisActions.delete(key)
# selected_user = Users.filter_one(Users.uu_id == token_user.get("uu_id")).data
# 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")
@classmethod # Requires not auth context
def authentication_refresher_token(cls, data: Any):
"""Refresh access token with refresher token"""
# token_refresher = UsersTokens.filter_by_one(
# token=data.refresh_token,
# domain=data.domain,
# **UsersTokens.valid_record_dict,
# ).data
# if not token_refresher:
# return ResponseHandler.not_found("Invalid data")
# if found_user := Users.filter_one(Users.id == token_refresher.user_id).data:
# access_key = AuthActions.save_access_token_to_redis(
# request=request, found_user=found_user, domain=data.domain
# )
# found_user.last_agent = request.headers.get("User-Agent", None)
# found_user.last_platform = request.headers.get("Origin", None)
# found_user.last_remote_addr = getattr(request, "remote_addr", None) or request.headers.get("X-Forwarded-For", None)
# found_user.last_seen = str(system_arrow.now())
# response_data = {
# "access_token": access_key,
# "refresh_token": data.refresh_token,
# }
# return ResponseHandler.success("User is logged in successfully via refresher token", data=response_data)
# return ResponseHandler.not_found("Invalid data")
context_retriever = ContextRetrievers(func=cls.authentication_refresher_token)
return context_retriever.base
event_context: EventContext = getattr(authentication_logout_user, "event_context", None)
return event_context.model_dump()
@classmethod # Requires not auth context
def authentication_forgot_password(cls, data: Any):
"""Send an email to user for a valid password reset token"""
# found_user: Users = Users.check_user_exits(access_key=data.access_key, domain=data.domain)
# forgot_key = AuthActions.save_access_token_to_redis(request=request, found_user=found_user, domain=data.domain)
# forgot_link = ApiStatic.forgot_link(forgot_key=forgot_key)
# send_email_completed = send_email(
# subject=f"Dear {found_user.user_tag}, your forgot password link has been sent.",
# receivers=[str(found_user.email)],
# html=change_your_password_template(user_name=found_user.user_tag, forgot_link=forgot_link),
# )
# if not send_email_completed:
# raise HTTPException(status_code=400, detail="Email can not be sent. Try again later")
# found_user.password_token = forgot_key
# found_user.password_token_is_valid = str(system_arrow.shift(days=1))
# found_user.save()
# return ResponseHandler.success("Password is change link is sent to your email or phone", data={})
return
@classmethod # Requires not auth context
def authentication_reset_password(cls, data: Any):
"""Reset password with forgot password token"""
# from sqlalchemy import or_
# found_user = Users.query.filter(
# or_(
# Users.email == str(data.access_key).lower(),
# Users.phone_number == str(data.access_key).replace(" ", ""),
# ),
# ).first()
# if not found_user:
# raise HTTPException(
# status_code=status.HTTP_400_BAD_REQUEST,
# detail="Given access key or domain is not matching with the any user record.",
# )
# reset_password_token = found_user.reset_password_token(found_user=found_user)
# send_email_completed = send_email(
# subject=f"Dear {found_user.user_tag}, a password reset request has been received.",
# receivers=[str(found_user.email)],
# html=change_your_password_template(
# user_name=found_user.user_tag,
# forgot_link=ApiStatic.forgot_link(forgot_key=reset_password_token),
# ),
# )
# if not send_email_completed:
# raise found_user.raise_http_exception(status_code=400, message="Email can not be sent. Try again later")
# return ResponseHandler.success("Password change link is sent to your email or phone", data=found_user.get_dict())
return
def authentication_refresher_token(request: Request, data: Any):
"""Refresh access token with refresher token"""
# token_refresher = UsersTokens.filter_by_one(
# token=data.refresh_token,
# domain=data.domain,
# **UsersTokens.valid_record_dict,
# ).data
# if not token_refresher:
# return ResponseHandler.not_found("Invalid data")
# if found_user := Users.filter_one(Users.id == token_refresher.user_id).data:
# access_key = AuthActions.save_access_token_to_redis(
# request=request, found_user=found_user, domain=data.domain
# )
# found_user.last_agent = request.headers.get("User-Agent", None)
# found_user.last_platform = request.headers.get("Origin", None)
# found_user.last_remote_addr = getattr(request, "remote_addr", None) or request.headers.get("X-Forwarded-For", None)
# found_user.last_seen = str(system_arrow.now())
# response_data = {
# "access_token": access_key,
# "refresh_token": data.refresh_token,
# }
# return ResponseHandler.success("User is logged in successfully via refresher token", data=response_data)
# return ResponseHandler.not_found("Invalid data")
auth_context: AuthContext = getattr(authentication_refresher_token, "auth_context", None)
return auth_context.model_dump()
def authentication_forgot_password(request: Request, data: Any):
"""Send an email to user for a valid password reset token"""
# found_user: Users = Users.check_user_exits(access_key=data.access_key, domain=data.domain)
# forgot_key = AuthActions.save_access_token_to_redis(request=request, found_user=found_user, domain=data.domain)
# forgot_link = ApiStatic.forgot_link(forgot_key=forgot_key)
# send_email_completed = send_email(
# subject=f"Dear {found_user.user_tag}, your forgot password link has been sent.",
# receivers=[str(found_user.email)],
# html=change_your_password_template(user_name=found_user.user_tag, forgot_link=forgot_link),
# )
# if not send_email_completed:
# raise HTTPException(status_code=400, detail="Email can not be sent. Try again later")
# found_user.password_token = forgot_key
# found_user.password_token_is_valid = str(system_arrow.shift(days=1))
# found_user.save()
# return ResponseHandler.success("Password is change link is sent to your email or phone", data={})
return
def authentication_reset_password(request: Request, data: Any):
"""Reset password with forgot password token"""
# from sqlalchemy import or_
# found_user = Users.query.filter(
# or_(
# Users.email == str(data.access_key).lower(),
# Users.phone_number == str(data.access_key).replace(" ", ""),
# ),
# ).first()
# if not found_user:
# raise HTTPException(
# status_code=status.HTTP_400_BAD_REQUEST,
# detail="Given access key or domain is not matching with the any user record.",
# )
# reset_password_token = found_user.reset_password_token(found_user=found_user)
# send_email_completed = send_email(
# subject=f"Dear {found_user.user_tag}, a password reset request has been received.",
# receivers=[str(found_user.email)],
# html=change_your_password_template(
# user_name=found_user.user_tag,
# forgot_link=ApiStatic.forgot_link(forgot_key=reset_password_token),
# ),
# )
# if not send_email_completed:
# raise found_user.raise_http_exception(status_code=400, message="Email can not be sent. Try again later")
# return ResponseHandler.success("Password change link is sent to your email or phone", data=found_user.get_dict())
return
def authentication_download_avatar(request: Request, data: Any, token_dict: TokenDictType):
"""Download avatar icon and profile info of user"""
# if found_user := Users.filter_one(Users.id == token_dict.user_id).data:
# expired_starts = str(system_arrow.now() - system_arrow.get(str(found_user.expiry_ends)))
# expired_int = (system_arrow.now() - system_arrow.get(str(found_user.expiry_ends))).days
# user_info = {
# "lang": token_dict.lang,
# "full_name": found_user.person.full_name,
# "avatar": found_user.avatar,
# "remember_me": found_user.remember_me,
# "expiry_ends": str(found_user.expiry_ends),
# "expired_str": expired_starts,
# "expired_int": int(expired_int),
# }
# return ResponseHandler.success("Avatar and profile is shared via user credentials", data=user_info)
# return ResponseHandler.not_found("Invalid data")
return
@classmethod # Requires not auth context
def authentication_download_avatar(cls, data: Any):
"""Download avatar icon and profile info of user"""
# if found_user := Users.filter_one(Users.id == token_dict.user_id).data:
# expired_starts = str(system_arrow.now() - system_arrow.get(str(found_user.expiry_ends)))
# expired_int = (system_arrow.now() - system_arrow.get(str(found_user.expiry_ends))).days
# user_info = {
# "lang": token_dict.lang,
# "full_name": found_user.person.full_name,
# "avatar": found_user.avatar,
# "remember_me": found_user.remember_me,
# "expiry_ends": str(found_user.expiry_ends),
# "expired_str": expired_starts,
# "expired_int": int(expired_int),
# }
# return ResponseHandler.success("Avatar and profile is shared via user credentials", data=user_info)
# return ResponseHandler.not_found("Invalid data")
return

View File

@ -1,7 +1,6 @@
from pydantic import BaseModel
from ApiLayers.ApiValidations.Request import (
Login,
)
from ApiLayers.ApiValidations.Request import Login
class LoginSuperUserRequestModel(Login):
pass
@ -33,3 +32,21 @@ class OccupantSelectionSuperUserRequestModel(BaseModel):
class OccupantSelectionSuperUserResponseModel(BaseModel):
pass
class AuthenticationRequestModels:
LoginSuperUserRequestModel = LoginSuperUserRequestModel
SelectCompanyOrOccupantTypeSuperUserRequestModel = (
SelectCompanyOrOccupantTypeSuperUserRequestModel
)
EmployeeSelectionSuperUserRequestModel = EmployeeSelectionSuperUserRequestModel
OccupantSelectionSuperUserRequestModel = OccupantSelectionSuperUserRequestModel
class AuthenticationResponseModels:
LoginSuperUserResponseModel = LoginSuperUserResponseModel
SelectCompanyOrOccupantTypeSuperUserResponseModel = (
SelectCompanyOrOccupantTypeSuperUserResponseModel
)
EmployeeSelectionSuperUserResponseModel = EmployeeSelectionSuperUserResponseModel
OccupantSelectionSuperUserResponseModel = OccupantSelectionSuperUserResponseModel

View File

@ -2,6 +2,4 @@
Events package initialization.
"""
__all__ = [
]
__all__ = []

View File

@ -10,4 +10,3 @@ 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

@ -62,7 +62,7 @@ class Event:
return self.NAME
@property
def key(self):
def key(self) -> str:
return str(self.KEY_)
@abstractmethod
@ -156,8 +156,8 @@ class CategoryCluster:
PREFIX: str
PAGEINFO: PageInfo
DESCRIPTION: str
ENDPOINTS: dict[str, MethodToEvent] # {"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__(
@ -189,7 +189,9 @@ 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.values()]
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
@ -201,7 +203,9 @@ class CategoryCluster:
"""
all_function_codes = []
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
def retrieve_redis_value(self) -> Dict:

View File

@ -23,14 +23,17 @@ class CategoryClusterController:
{ "category_cluster_name": "category_cluster_module" }
"""
if not hasattr(category_clusters, "__all__"):
raise ValueError(f"Given module {str(category_clusters)} does not have __all__ attribute")
raise ValueError(
f"Given module {str(category_clusters)} does not have __all__ attribute"
)
for iter_module in [str(item) for item in category_clusters.__all__]:
# CategoryCluster which represent api routers for each category
cls.imports_dict.append(
CategoryBulk(
category_cluster=getattr(category_clusters, iter_module, None),
name=iter_module
))
name=iter_module,
)
)
@classmethod
def as_dict(cls):
@ -39,4 +42,5 @@ class CategoryClusterController:
to_dict[cluster.name] = cluster.category_cluster
return to_dict
cluster_controller = CategoryClusterController()
cluster_controller = CategoryClusterController()

View File

@ -35,24 +35,32 @@ class DecoratorModule:
"""
decorators = []
current_func = func
original_qualname = getattr(func, '__qualname__', '')
original_qualname = getattr(func, "__qualname__", "")
while hasattr(current_func, '__wrapped__'):
if hasattr(current_func, '__closure__') and current_func.__closure__:
while hasattr(current_func, "__wrapped__"):
if hasattr(current_func, "__closure__") and current_func.__closure__:
for cell in current_func.__closure__:
decorator = cell.cell_contents
# Only add if it's a callable and not the original function
if callable(decorator) and getattr(decorator, '__qualname__', '') != original_qualname:
if (
callable(decorator)
and getattr(decorator, "__qualname__", "") != original_qualname
):
decorators.append(decorator)
current_func = current_func.__wrapped__
return list(dict.fromkeys(decorators)) # Remove duplicates while preserving order
return list(
dict.fromkeys(decorators)
) # Remove duplicates while preserving order
@staticmethod
def get_actual_decorators(method_endpoint):
original_qualname = getattr(method_endpoint.endpoint_callable, '__qualname__', '')
original_qualname = getattr(
method_endpoint.endpoint_callable, "__qualname__", ""
)
actual_decorators = [
d for d in method_endpoint.DECORATORS_LIST or []
if callable(d) and getattr(d, '__qualname__', '') != original_qualname
d
for d in method_endpoint.DECORATORS_LIST or []
if callable(d) and getattr(d, "__qualname__", "") != original_qualname
]
return actual_decorators
@ -68,17 +76,27 @@ class DecoratorModule:
try:
function_callable = decorator(function_callable)
except Exception as e:
print(f"Warning: Failed to apply decorator {decorator.__qualname__}: {str(e)}")
print(
f"Warning: Failed to apply decorator {decorator.__qualname__}: {str(e)}"
)
method_endpoint.endpoint_callable = function_callable
# Get the final list of applied decorators (for debugging)
applied_decorators = cls.get_all_decorators(method_endpoint.endpoint_callable)
applied_decorators_qualname = [getattr(d, '__qualname__', str(d)) for d in applied_decorators]
applied_decorators_qualname = [
getattr(d, "__qualname__", str(d)) for d in applied_decorators
]
if applied_decorators:
print(f"Applied decorators for {method_endpoint.name}:", applied_decorators_qualname)
print(
f"Applied decorators for {method_endpoint.name}:",
applied_decorators_qualname,
)
return applied_decorators_qualname
@classmethod
def list_qualname(cls, method_endpoint_list):
return [getattr(method_endpoint, '__qualname__', '') for method_endpoint in method_endpoint_list]
return [
getattr(method_endpoint, "__qualname__", "")
for method_endpoint in method_endpoint_list
]

View File

@ -9,8 +9,6 @@ def get_cluster_controller_group():
return cluster_controller
"""
prepare_routing = PrepareRouting(cluster_controller_group=cluster_controller)
prepare_events = PrepareEvents(cluster_controller_group=cluster_controller)

View File

@ -2,7 +2,7 @@ from typing import Any
from ApiLayers.ApiServices.Cluster.create_router import (
CreateRouterFromCluster,
CreateEndpointFromCluster
CreateEndpointFromCluster,
)
from Events.Engine.abstract_class import CategoryCluster
from Services.Redis.Actions.actions import RedisActions
@ -83,19 +83,27 @@ class PrepareEvents(DecoratorModule):
# [SAVE]REDIS => MENU_FIRST_LAYER = [ClusterToMethod, ...]
self.valid_redis_items.MENU_FIRST_LAYER_VALUE.add(cluster.name)
# [SAVE]REDIS => CLUSTER_INDEX = {ClusterToMethod: [MethodEvent, ...], "MethodEvent": "ClusterToMethod"}
self.valid_redis_items.CLUSTER_INDEX_VALUE.update(cluster.get_redis_cluster_index_value())
self.valid_redis_items.CLUSTER_INDEX_VALUE.update(
cluster.get_redis_cluster_index_value()
)
# [SAVE]REDIS => CLUSTER_FUNCTION_CODES = {"ClusterToMethod"} : [FUNCTION_CODE, ...]}
self.valid_redis_items.CLUSTER_FUNCTION_CODES_VALUE = {
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.values()):
# [SAVE]REDIS => ENDPOINT2CLASS = {MethodEvent: Endpoint("/.../.../..."), ...}
self.valid_redis_items.ENDPOINT2CLASS_VALUE.update(
{f"{cluster.name}:{method_endpoint.name}": f"{cluster.PREFIX}{method_endpoint.URL}"}
{
f"{cluster.name}:{method_endpoint.name}": f"{cluster.PREFIX}{method_endpoint.URL}"
}
)
self.valid_redis_items.ENDPOINT2CLASS_VALUE.update(
{f"{cluster.PREFIX}{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(
@ -116,8 +124,12 @@ class SetItems2Redis:
def set_items(self):
from ApiLayers.AllConfigs.Redis.configs import RedisCategoryKeys
dict_prep = self.prepare_events.valid_redis_items.as_dict
for redis_values_to_delete, redis_key_type in RedisCategoryKeys.__annotations__.items():
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}*"])
@ -125,19 +137,23 @@ class SetItems2Redis:
# 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)
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"
# Save CLUSTER_INDEX to Redis
redis_list = RedisList(redis_key=RedisCategoryKeys.CLUSTER_INDEX)
RedisActions.set_json(
list_keys=redis_list.to_list(), value=dict_prep.get(RedisCategoryKeys.CLUSTER_INDEX)
list_keys=redis_list.to_list(),
value=dict_prep.get(RedisCategoryKeys.CLUSTER_INDEX),
)
self.std_out += f"\n{RedisCategoryKeys.CLUSTER_INDEX}: {dict_prep.get(RedisCategoryKeys.CLUSTER_INDEX)}\n"
# Save CLUSTER_FUNCTION_CODES to Redis by iterating over the dict
for redis_key, redis_value in dict_prep.get(RedisCategoryKeys.CLUSTER_FUNCTION_CODES).items():
for redis_key, redis_value in dict_prep.get(
RedisCategoryKeys.CLUSTER_FUNCTION_CODES
).items():
redis_list = RedisList(redis_key=redis_key)
RedisActions.set_json(
list_keys=redis_list.to_list(), value=list(redis_value)
@ -145,7 +161,9 @@ class SetItems2Redis:
self.std_out += f"\n{RedisCategoryKeys.CLUSTER_FUNCTION_CODES}: {dict_prep.get(RedisCategoryKeys.CLUSTER_FUNCTION_CODES)}\n"
# Save METHOD_FUNCTION_CODES to Redis by iterating over the dict
for redis_key, redis_value in dict_prep.get(RedisCategoryKeys.METHOD_FUNCTION_CODES).items():
for redis_key, redis_value in dict_prep.get(
RedisCategoryKeys.METHOD_FUNCTION_CODES
).items():
redis_list = RedisList(redis_key=redis_key)
RedisActions.set_json(
list_keys=redis_list.to_list(), value=list(redis_value)
@ -153,19 +171,22 @@ class SetItems2Redis:
self.std_out += f"\n{RedisCategoryKeys.METHOD_FUNCTION_CODES}: {dict_prep.get(RedisCategoryKeys.METHOD_FUNCTION_CODES)}\n"
# Save ENDPOINT2CLASS to Redis by iterating over the dict
for redis_key, redis_value in dict_prep.get(RedisCategoryKeys.ENDPOINT2CLASS).items():
redis_list = RedisList(redis_key=f"{RedisCategoryKeys.ENDPOINT2CLASS}:{redis_key}\n")
RedisActions.set_json(
list_keys=redis_list.to_list(), value=redis_value
for redis_key, redis_value in dict_prep.get(
RedisCategoryKeys.ENDPOINT2CLASS
).items():
redis_list = RedisList(
redis_key=f"{RedisCategoryKeys.ENDPOINT2CLASS}:{redis_key}\n"
)
RedisActions.set_json(list_keys=redis_list.to_list(), value=redis_value)
self.std_out += f"\n{RedisCategoryKeys.ENDPOINT2CLASS}: {dict_prep.get(RedisCategoryKeys.ENDPOINT2CLASS)}\n"
RedisActions.set_json(
list_keys=[f"{RedisCategoryKeys.REBUILD}:*"], value={
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

@ -5,11 +5,19 @@ This module provides base request models that can be used across different endpo
to ensure consistent request handling and validation.
"""
from typing import Dict, Any, TypeVar
from pydantic import BaseModel, Field, ConfigDict
from typing import Union, Optional, Any
from pydantic import BaseModel, Field
from ApiLayers.ApiValidations.Custom.token_objects import (
EmployeeTokenObject,
OccupantTokenObject,
)
from ApiLayers.ApiValidations.Custom.wrapper_contexts import AuthContext, EventContext
T = TypeVar("T")
TokenDictType = Union[
EmployeeTokenObject, OccupantTokenObject
] # Type aliases for common types
class EndpointBaseRequestModel(BaseModel):
@ -17,35 +25,63 @@ class EndpointBaseRequestModel(BaseModel):
data: dict = Field(..., description="Data to be sent with the request")
class Config:
json_schema_extra = {
"data": {
"key": "value",
}
}
json_schema_extra = {"data": {"key": "value"}}
class SuccessResponse(BaseModel):
"""Standard success response model."""
class ContextRetrievers:
"""Utility class to retrieve context from functions."""
data: Dict[str, Any] = Field(
...,
example={
"id": "123",
"username": "john.doe",
"email": "john@example.com",
"role": "user",
},
)
is_auth: bool = False
is_event: bool = False
key_: str = ""
model_config = ConfigDict(
json_schema_extra={
"example": {
"data": {
"id": "123",
"username": "john.doe",
"email": "john@example.com",
"role": "user",
},
}
}
)
def __init__(self, func):
self.func = func
if hasattr(self.func, "auth_context"):
self.is_auth = True
self.key_ = "auth_context"
elif hasattr(self.func, "event_context"):
self.is_event = hasattr(self.func, "event_context")
self.key_ = "event_context"
@property
def key(self) -> Union[str, None]:
"""Retrieve key context from a function."""
return self.key_
@property
def context(self) -> Union[AuthContext, EventContext, None]:
"""Retrieve authentication or event context from a function."""
if self.is_auth:
return getattr(self.func, "auth_context", None)
elif self.is_event:
return getattr(self.func, "event_context", None)
return None
@property
def request(self) -> Union[Any, None]:
"""Retrieve request context from a function."""
return getattr(self.context, "request", None)
@property
def token(self) -> TokenDictType:
"""Retrieve token context from a function."""
if self.is_auth or self.is_event:
return getattr(self.context, "auth", None)
@property
def url(self) -> Union[str, None]:
"""Retrieve URL context from a function."""
return getattr(self.context, "url", None)
@property
def code(self) -> Union[str, None]:
"""Retrieve code context from a function."""
if self.is_event:
return getattr(self.context, "code", None)
return None
@property
def base(self) -> Optional[dict[str, Any]]:
"""Retrieve base request model from a function."""
return getattr(self.context, "base", None)

View File

@ -125,7 +125,9 @@ class QueryModel(ArgumentModel):
if not expired:
args = cls.get_not_expired_query_arg(args)
query = cls._query(db=db).filter(*args)
return PostgresResponse(pre_query=cls._query(db=db), query=query, is_array=False)
return PostgresResponse(
pre_query=cls._query(db=db), query=query, is_array=False
)
@classmethod
def filter_all_system(

View File

@ -26,7 +26,9 @@ class BasicMixin(Base, BaseAlchemyModel):
__repr__ = ReprMixin.__repr__
class CrudMixin(BasicMixin, CRUDModel, SerializeMixin, ReprMixin, SmartQueryMixin, QueryModel ):
class CrudMixin(
BasicMixin, CRUDModel, SerializeMixin, ReprMixin, SmartQueryMixin, QueryModel
):
"""
Base mixin providing CRUD operations and common fields for PostgreSQL models.