From 5d3f94664282994f24f9293f1543aeb5d7abc641 Mon Sep 17 00:00:00 2001 From: berkay Date: Tue, 28 Jan 2025 17:11:59 +0300 Subject: [PATCH] language models and set defaults are updated --- .idea/workspace.xml | 8 +- ApiLayers/AllConfigs/Redis/configs.py | 8 +- ApiLayers/AllConfigs/main.py | 6 + .../ApiServices/Login/user_login_handler.py | 14 +- ApiLayers/ApiServices/Token/token_handler.py | 10 +- .../Response/default_response.py | 38 +++-- .../ErrorHandlers/api_exc_handler.py | 25 ++- ApiLayers/LanguageModels/Errors/all_errors.py | 4 + .../LanguageModels/Errors/defualt_error.py | 98 ++++++++++++ .../LanguageModels/Request/Auth/login.py | 17 +++ ApiLayers/LanguageModels/Request/__init__.py | 5 + .../LanguageModels/Response/all_responses.py | 3 + .../Response/authentication/auth.py | 18 +++ ApiLayers/LanguageModels/default_template.py | 10 ++ .../set_defaults/language_setters.py | 144 ++++++++++++++++++ ApiLayers/Middleware/auth_middleware.py | 4 +- .../Middleware/token_event_middleware.py | 7 +- ApiLayers/Schemas/event/event.py | 1 + ApiLayers/Schemas/identity/identity.py | 4 +- .../AuthServiceApi/app_handler.py | 4 +- .../AuthServiceApi/create_routes.py | 20 +-- DockerApiServices/InitServiceApi/Dockerfile | 42 ++--- DockerApiServices/InitServiceApi/app.py | 5 + DockerApiServices/InitServiceApi/config.py | 71 +++++++++ .../InitServiceApi/create_all_dependecies.py | 41 +++++ .../authentication/auth/api_events.py | 19 ++- Events/AllEvents/authentication/auth/auth.py | 23 ++- .../authentication/auth/function_handlers.py | 73 +++++---- .../AllEvents/authentication/auth/models.py | 14 +- Events/AllEvents/validations/__init__.py | 5 + Events/Engine/abstract_class.py | 11 ++ Events/Engine/set_defaults/setClusters.py | 2 +- Services/Redis/Models/access.py | 6 +- Services/Redis/Models/response.py | 4 +- 34 files changed, 638 insertions(+), 126 deletions(-) create mode 100644 ApiLayers/LanguageModels/Errors/all_errors.py create mode 100644 ApiLayers/LanguageModels/Errors/defualt_error.py create mode 100644 ApiLayers/LanguageModels/Request/Auth/login.py create mode 100644 ApiLayers/LanguageModels/Request/__init__.py create mode 100644 ApiLayers/LanguageModels/Response/all_responses.py create mode 100644 ApiLayers/LanguageModels/Response/authentication/auth.py create mode 100644 ApiLayers/LanguageModels/default_template.py create mode 100644 ApiLayers/LanguageModels/set_defaults/language_setters.py create mode 100644 DockerApiServices/InitServiceApi/app.py create mode 100644 DockerApiServices/InitServiceApi/config.py create mode 100644 DockerApiServices/InitServiceApi/create_all_dependecies.py diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 390fadd..8dc4e64 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -7,20 +7,24 @@ + - + + + + + - diff --git a/ApiLayers/AllConfigs/Redis/configs.py b/ApiLayers/AllConfigs/Redis/configs.py index 9ac900d..0f80abd 100644 --- a/ApiLayers/AllConfigs/Redis/configs.py +++ b/ApiLayers/AllConfigs/Redis/configs.py @@ -16,15 +16,19 @@ class WagRedis: ) -# VALIDATION_USER: str = "VALIDATION_USER" class RedisValidationKeys: ENDPOINTS: str = "ENDPOINTS" VALIDATIONS: str = "VALIDATIONS" HEADERS: str = "HEADERS" ERRORCODES: str = "ERRORCODES" RESPONSES: str = "RESPONSES" + REQUESTS: str = "REQUESTS" + RESPONSE: str = "RESPONSE" LANGUAGE_MODELS: str = "LANGUAGE_MODELS" - + STATIC: str = "STATIC" + DYNAMIC: str = "DYNAMIC" + # REQUEST: str = "REQUEST" + # VALIDATION_USER: str = "VALIDATION_USER" class RedisAuthKeys: AUTH: str = "AUTH" diff --git a/ApiLayers/AllConfigs/main.py b/ApiLayers/AllConfigs/main.py index 1c68cc4..d39fd18 100644 --- a/ApiLayers/AllConfigs/main.py +++ b/ApiLayers/AllConfigs/main.py @@ -17,3 +17,9 @@ 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 + + +class LanguageConfig: + + SUPPORTED_LANGUAGES = ["en", "tr"] + DEFAULT_LANGUAGE = "tr" diff --git a/ApiLayers/ApiServices/Login/user_login_handler.py b/ApiLayers/ApiServices/Login/user_login_handler.py index 949d036..aec97ce 100644 --- a/ApiLayers/ApiServices/Login/user_login_handler.py +++ b/ApiLayers/ApiServices/Login/user_login_handler.py @@ -50,6 +50,7 @@ class UserLoginModule: 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. """ @@ -65,12 +66,17 @@ class UserLoginModule: ) # 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, ): # 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, + 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() @@ -78,7 +84,7 @@ class UserLoginModule: 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", {}) + "selection_list": token_response.get("selection_list", {}), } return None raise HTTPExceptionApi( diff --git a/ApiLayers/ApiServices/Token/token_handler.py b/ApiLayers/ApiServices/Token/token_handler.py index ea5f736..e10bfc2 100644 --- a/ApiLayers/ApiServices/Token/token_handler.py +++ b/ApiLayers/ApiServices/Token/token_handler.py @@ -285,10 +285,14 @@ class TokenService: cls.remove_token_with_domain(user=user, domain=domain) Users.client_arrow = DateTimeLocal(is_client=True, timezone=user.local_timezone) login_dict, db_session = {}, UsersTokens.new_session() - if user.is_occupant: # Handle login based on user type - login_dict = cls.do_occupant_login(request=request, user=user, domain=domain) + if user.is_occupant: # Handle login based on user type + login_dict = cls.do_occupant_login( + request=request, user=user, domain=domain + ) elif user.is_employee: - login_dict = cls.do_employee_login(request=request, user=user, domain=domain) + login_dict = cls.do_employee_login( + request=request, user=user, domain=domain + ) # Handle remember me functionality if remember: diff --git a/ApiLayers/ApiValidations/Response/default_response.py b/ApiLayers/ApiValidations/Response/default_response.py index 590abf5..4803019 100644 --- a/ApiLayers/ApiValidations/Response/default_response.py +++ b/ApiLayers/ApiValidations/Response/default_response.py @@ -14,14 +14,18 @@ class BaseEndpointResponse: from Services.Redis import RedisActions 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_key = ( + f"{RedisValidationKeys.LANGUAGE_MODELS}:{RedisValidationKeys.RESPONSES}" + ) + language_model = RedisActions.get_json( + list_keys=[language_model_key, self.code, self.lang] + ) if language_model.status: return language_model.first.as_dict return {"message": f"{self.code} -> Language model not found"} -class EndpointSuccessResponse(BaseEndpointResponse): # 200 OK +class EndpointSuccessResponse(BaseEndpointResponse): # 200 OK def as_dict(self, data: Optional[dict] = None): return JSONResponse( @@ -30,7 +34,7 @@ class EndpointSuccessResponse(BaseEndpointResponse): # 200 OK ) -class EndpointCreatedResponse(BaseEndpointResponse): # 201 Created +class EndpointCreatedResponse(BaseEndpointResponse): # 201 Created def as_dict(self, data: Optional[dict] = None): return JSONResponse( @@ -39,7 +43,7 @@ class EndpointCreatedResponse(BaseEndpointResponse): # 201 Create ) -class EndpointAcceptedResponse(BaseEndpointResponse): # 202 Accepted +class EndpointAcceptedResponse(BaseEndpointResponse): # 202 Accepted def as_dict(self, data: Optional[dict] = None): return JSONResponse( @@ -48,7 +52,7 @@ class EndpointAcceptedResponse(BaseEndpointResponse): # 202 Accep ) -class EndpointNotModifiedResponse(BaseEndpointResponse): # 304 Not Modified +class EndpointNotModifiedResponse(BaseEndpointResponse): # 304 Not Modified def as_dict(self): return JSONResponse( @@ -57,7 +61,7 @@ class EndpointNotModifiedResponse(BaseEndpointResponse): # 304 Not ) -class EndpointBadRequestResponse(BaseEndpointResponse): # 400 Bad Request +class EndpointBadRequestResponse(BaseEndpointResponse): # 400 Bad Request def as_dict(self, data: Optional[dict] = None): return JSONResponse( @@ -66,7 +70,7 @@ class EndpointBadRequestResponse(BaseEndpointResponse): # 400 Bad R ) -class EndpointUnauthorizedResponse(BaseEndpointResponse): # 401 Unauthorized +class EndpointUnauthorizedResponse(BaseEndpointResponse): # 401 Unauthorized def as_dict(self): return JSONResponse( @@ -75,7 +79,7 @@ class EndpointUnauthorizedResponse(BaseEndpointResponse): # 401 Unaut ) -class EndpointForbiddenResponse(BaseEndpointResponse): # 403 Forbidden +class EndpointForbiddenResponse(BaseEndpointResponse): # 403 Forbidden def as_dict(self): return JSONResponse( @@ -84,7 +88,7 @@ class EndpointForbiddenResponse(BaseEndpointResponse): # 403 Forbi ) -class EndpointNotFoundResponse(BaseEndpointResponse): # 404 Not Found +class EndpointNotFoundResponse(BaseEndpointResponse): # 404 Not Found def as_dict(self): return JSONResponse( @@ -93,7 +97,7 @@ class EndpointNotFoundResponse(BaseEndpointResponse): # 404 Not F ) -class EndpointMethodNotAllowedResponse(BaseEndpointResponse): # 405 Method Not Allowed +class EndpointMethodNotAllowedResponse(BaseEndpointResponse): # 405 Method Not Allowed def as_dict(self): return JSONResponse( @@ -102,7 +106,7 @@ class EndpointMethodNotAllowedResponse(BaseEndpointResponse): # 405 Metho ) -class EndpointNotAcceptableResponse(BaseEndpointResponse): # 406 Not Acceptable +class EndpointNotAcceptableResponse(BaseEndpointResponse): # 406 Not Acceptable def as_dict(self): return JSONResponse( @@ -111,7 +115,7 @@ class EndpointNotAcceptableResponse(BaseEndpointResponse): # 406 Not A ) -class EndpointConflictResponse(BaseEndpointResponse): # 409 Conflict +class EndpointConflictResponse(BaseEndpointResponse): # 409 Conflict def as_dict(self): return JSONResponse( @@ -120,7 +124,9 @@ class EndpointConflictResponse(BaseEndpointResponse): # 409 Confli ) -class EndpointUnprocessableEntityResponse(BaseEndpointResponse): # 422 Unprocessable Entity +class EndpointUnprocessableEntityResponse( + BaseEndpointResponse +): # 422 Unprocessable Entity def as_dict(self, data: Optional[dict] = None): return JSONResponse( @@ -129,7 +135,7 @@ class EndpointUnprocessableEntityResponse(BaseEndpointResponse): # 422 Unpro ) -class EndpointTooManyRequestsResponse(BaseEndpointResponse): # 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) @@ -143,7 +149,7 @@ class EndpointTooManyRequestsResponse(BaseEndpointResponse): # 429 Too M ) -class EndpointInternalErrorResponse(BaseEndpointResponse): # 500 Internal Server Error +class EndpointInternalErrorResponse(BaseEndpointResponse): # 500 Internal Server Error def as_dict(self): return JSONResponse( diff --git a/ApiLayers/ErrorHandlers/ErrorHandlers/api_exc_handler.py b/ApiLayers/ErrorHandlers/ErrorHandlers/api_exc_handler.py index 8bac6be..2dbb61d 100644 --- a/ApiLayers/ErrorHandlers/ErrorHandlers/api_exc_handler.py +++ b/ApiLayers/ErrorHandlers/ErrorHandlers/api_exc_handler.py @@ -4,7 +4,9 @@ from pydantic import ValidationError from fastapi import Request, WebSocket, status from fastapi.responses import Response, JSONResponse -from ApiLayers.LanguageModels.Errors.merge_all_error_languages import MergedErrorLanguageModels +from ApiLayers.LanguageModels.Errors.merge_all_error_languages import ( + MergedErrorLanguageModels, +) from ApiLayers.ErrorHandlers.Exceptions.api_exc import HTTPExceptionApi from ApiLayers.ErrorHandlers.bases import BaseErrorModelClass @@ -20,13 +22,19 @@ def validation_exception_handler(request, exc: ValidationError) -> JSONResponse: """ validation_messages, validation_list = exc.errors() or [], [] for validation in validation_messages: - validation_list.append({ - "type": dict(validation).get("type"), - "location": dict(validation).get("loc"), - "message": dict(validation).get("msg"), # todo change message with language message - "input": dict(validation).get("input"), - }) - error_response_dict = dict(message=validation_list, request=str(request.url.path), title=exc.title) + validation_list.append( + { + "type": dict(validation).get("type"), + "location": dict(validation).get("loc"), + "message": dict(validation).get( + "msg" + ), # todo change message with language message + "input": dict(validation).get("input"), + } + ) + error_response_dict = dict( + message=validation_list, request=str(request.url.path), title=exc.title + ) return JSONResponse( content=error_response_dict, status_code=status.HTTP_422_UNPROCESSABLE_ENTITY ) @@ -46,6 +54,7 @@ class HTTPExceptionApiHandler: @staticmethod def retrieve_error_message(exc: HTTPExceptionApi, error_languages) -> str: from ApiLayers.ErrorHandlers import DEFAULT_ERROR + return error_languages.get(str(exc.error_code).upper(), DEFAULT_ERROR) async def handle_exception( diff --git a/ApiLayers/LanguageModels/Errors/all_errors.py b/ApiLayers/LanguageModels/Errors/all_errors.py new file mode 100644 index 0000000..1f9e19d --- /dev/null +++ b/ApiLayers/LanguageModels/Errors/all_errors.py @@ -0,0 +1,4 @@ +from .defualt_error import default_errors + + +all_errors_list = [default_errors] diff --git a/ApiLayers/LanguageModels/Errors/defualt_error.py b/ApiLayers/LanguageModels/Errors/defualt_error.py new file mode 100644 index 0000000..d79f47f --- /dev/null +++ b/ApiLayers/LanguageModels/Errors/defualt_error.py @@ -0,0 +1,98 @@ +default_errors = { + "NOT_CREATED": { + "tr": { + "message": "Kayıt oluşturulamadı. Lütfen tekrar deneyiniz.", + }, + "en": { + "message": "Record could not be created. Please try again.", + }, + }, + "NOT_DELETED": { + "tr": { + "message": "Kayıt silinemedi. Lütfen tekrar deneyiniz.", + }, + "en": { + "message": "Record could not be deleted. Please try again.", + }, + }, + "NOT_UPDATED": { + "tr": { + "message": "Kayıt güncellenemedi. Lütfen tekrar deneyiniz.", + }, + "en": { + "message": "Record could not be updated. Please try again.", + }, + }, + "NOT_LISTED": { + "tr": { + "message": "Kayıt listelenemedi. Lütfen tekrar deneyiniz.", + }, + "en": { + "message": "Record could not be listed. Please try again.", + }, + }, + "NOT_FOUND": { + "tr": { + "message": "Kayıt bulunamadı. Lütfen tekrar deneyiniz.", + }, + "en": { + "message": "Record could not be found. Please try again.", + }, + }, + "ALREADY_EXISTS": { + "tr": { + "message": "Kayıt zaten mevcut. Lütfen tekrar deneyiniz.", + }, + "en": { + "message": "Record already exists. Please try again.", + }, + }, + "IS_NOT_CONFIRMED": { + "tr": { + "message": "Kayıt onaylanmadı. Lütfen tekrar deneyiniz.", + }, + "en": { + "message": "Record is not confirmed. Please try again.", + }, + }, + "NOT_AUTHORIZED": { + "tr": { + "message": "Yetkisiz kullanıcı. Lütfen tekrar deneyiniz.", + }, + "en": { + "message": "Unauthorized user. Please try again.", + }, + }, + "NOT_VALID": { + "tr": { + "message": "Geçersiz veri. Lütfen tekrar deneyiniz.", + }, + "en": { + "message": "Invalid data. Please try again.", + }, + }, + "NOT_ACCEPTABLE": { + "tr": { + "message": "Geçersiz veri. Lütfen tekrar deneyiniz.", + }, + "en": { + "message": "Invalid data. Please try again.", + }, + }, + "INVALID_DATA": { + "tr": { + "message": "Geçersiz veri. Lütfen tekrar deneyiniz.", + }, + "en": { + "message": "Invalid data. Please try again.", + }, + }, + "UNKNOWN_ERROR": { + "tr": { + "message": "Bilinmeyen bir hata oluştu. Lütfen tekrar deneyiniz.", + }, + "en": { + "message": "An unknown error occured. Please try again.", + }, + }, +} diff --git a/ApiLayers/LanguageModels/Request/Auth/login.py b/ApiLayers/LanguageModels/Request/Auth/login.py new file mode 100644 index 0000000..6c7178d --- /dev/null +++ b/ApiLayers/LanguageModels/Request/Auth/login.py @@ -0,0 +1,17 @@ +from typing import Dict + + +LoginRequestLanguageModel: Dict[str, Dict[str, str]] = { + "tr": { + "domain": "Domain", + "access_key": "Erişim Anahtarı", + "password": "Parola", + "remember_me": "Beni Hatırla", + }, + "en": { + "domain": "Domain", + "access_key": "Access Key", + "password": "Password", + "remember_me": "Remember Me", + }, +} \ No newline at end of file diff --git a/ApiLayers/LanguageModels/Request/__init__.py b/ApiLayers/LanguageModels/Request/__init__.py new file mode 100644 index 0000000..8885794 --- /dev/null +++ b/ApiLayers/LanguageModels/Request/__init__.py @@ -0,0 +1,5 @@ +from .Auth.login import LoginRequestLanguageModel + +__all__ = [ + "LoginRequestLanguageModel" + ] \ No newline at end of file diff --git a/ApiLayers/LanguageModels/Response/all_responses.py b/ApiLayers/LanguageModels/Response/all_responses.py new file mode 100644 index 0000000..adb6edc --- /dev/null +++ b/ApiLayers/LanguageModels/Response/all_responses.py @@ -0,0 +1,3 @@ +from .authentication.auth import authResponses + +all_response_list = [authResponses] diff --git a/ApiLayers/LanguageModels/Response/authentication/auth.py b/ApiLayers/LanguageModels/Response/authentication/auth.py new file mode 100644 index 0000000..d126d2d --- /dev/null +++ b/ApiLayers/LanguageModels/Response/authentication/auth.py @@ -0,0 +1,18 @@ +authResponses = { + "LOGIN_SELECT": { + "tr": { + "message": "Şirket/Görev başarılı bir şekilde seçildi.", + }, + "en": { + "message": "Company/Duty selected successfully.", + }, + }, + "LOGIN_SUCCESS": { + "tr": { + "message": "Giriş başırı ile tamamlandı. Devam etmek için bir şirket/görev seçiniz.", + }, + "en": { + "message": "Login successful. Please select an company/duty to continue.", + }, + }, +} diff --git a/ApiLayers/LanguageModels/default_template.py b/ApiLayers/LanguageModels/default_template.py new file mode 100644 index 0000000..905a8df --- /dev/null +++ b/ApiLayers/LanguageModels/default_template.py @@ -0,0 +1,10 @@ +responses = { + "LOGIN_SELECT": { + "tr": { + "": "", + }, + "en": { + "": "", + }, + }, +} diff --git a/ApiLayers/LanguageModels/set_defaults/language_setters.py b/ApiLayers/LanguageModels/set_defaults/language_setters.py new file mode 100644 index 0000000..35975ad --- /dev/null +++ b/ApiLayers/LanguageModels/set_defaults/language_setters.py @@ -0,0 +1,144 @@ +from ApiLayers.AllConfigs.Redis.configs import RedisValidationKeys +from ApiLayers.AllConfigs.main import LanguageConfig +from Events.Engine.set_defaults.category_cluster_models import CategoryClusterController +from Services.Redis.Actions.actions import RedisActions + + +class SetDefaultLanguageModelsRedis: + + std_out: str = "" + + def __init__( + self, + set_response_languages_list: list[dict], + set_errors_languages_list: list[dict], + ): + self.responses_list: list[dict] = set_response_languages_list + self.errors_list: list[dict] = set_errors_languages_list + + def __str__(self): + return f"\nPrepareLanguageModels:\n\n{self.std_out}" + + def set_all(self): + + # RedisActions.delete(list_keys=["*"]) + RedisActions.delete(list_keys=[f"{RedisValidationKeys.LANGUAGE_MODELS}:*"]) + + for response in self.responses_list: + for lang in list(LanguageConfig.SUPPORTED_LANGUAGES): + for code, dict_to_set in response.items(): + # [SAVE]REDIS => LANGUAGE_MODELS:STATIC:RESPONSES:{ResponseCode}:tr = {...} + redis_key = f"{RedisValidationKeys.LANGUAGE_MODELS}:{RedisValidationKeys.STATIC}" + set_key = f"{redis_key}:{RedisValidationKeys.RESPONSES}:{code}:{lang}" + RedisActions.set_json(list_keys=[set_key], value=dict_to_set) + + self.std_out += f"Language Response Models are set to Redis\n" + for response in self.errors_list: + for lang in list(LanguageConfig.SUPPORTED_LANGUAGES): + for code, dict_to_set in response.items(): + # [SAVE]REDIS => LANGUAGE_MODELS:STATIC:ERRORCODES:{ErrorCode}:en = {...} + redis_key = f"{RedisValidationKeys.LANGUAGE_MODELS}:{RedisValidationKeys.STATIC}" + set_key = f"{redis_key}:{code}:{lang}" + RedisActions.set_json(list_keys=[set_key], value=dict_to_set) + + self.std_out += f"Language Error Models are set to Redis\n" + + +class SetClusterLanguageModelsRedis: + + std_out: str = "" + events_lm_dict: dict[str, dict[str, dict]] = {} + events_rq_dict: dict[str, dict[str, dict]] = {} + events_rs_dict: dict[str, dict[str, dict]] = {} + + def __init__(self, cluster_controller_group: CategoryClusterController): + self.cluster_controller_group = cluster_controller_group + + def __str__(self): + return f"\nPrepareLanguageModels:\n\n{self.std_out}" + + @staticmethod + def merge_language_dicts(list_of_lang_models: list[dict]): + """ + Merges the language models of the events to a single dictionary. + """ + merged_lang_models: dict[str, dict] = {} + for lang_model in list_of_lang_models: + for lang in list(LanguageConfig.SUPPORTED_LANGUAGES): + if not lang_model.get(lang, None): + raise ValueError(f"Language model for {lang} not found in {lang_model}") + if lang not in merged_lang_models: + merged_lang_models[lang] = lang_model[lang] + else: + merged_lang_models[lang].update(lang_model[lang]) + return merged_lang_models + + def set_models_from_cluster(self): + # iterate(ClusterToMethod) to set all models by pairing function codes + for cluster_control in self.cluster_controller_group.imports: + self.std_out += f"Setting models from cluster : {cluster_control.name}\n" + for endpoint in cluster_control.category_cluster.ENDPOINTS.values(): + for key_event, event in endpoint.EVENTS.items(): + merged_language_dict = self.merge_language_dicts(event.LANGUAGE_MODELS) + request_validation = getattr(event.REQUEST_VALIDATOR, 'model_fields', None) + response_validation = getattr(event.RESPONSE_VALIDATOR, 'model_fields', None) + objects_missing = bool(request_validation) and bool(response_validation) and bool(merged_language_dict) + if not objects_missing: + continue + if merged_language_dict: + self.events_lm_dict[key_event] = merged_language_dict + if request_validation: + self.events_rq_dict[key_event] = request_validation + if response_validation: + self.events_rs_dict[key_event] = response_validation + self.std_out += f"Request/Response/Language validation model is set {key_event}\n" + + def set_all(self): + # Set all language models from cluster list by pairing event code and models + self.set_models_from_cluster() + if self.events_lm_dict and self.events_rq_dict: + """ + [SAVE]REDIS => LANGUAGE_MODELS:DYNAMIC:HEADERS:REQUEST:{FunctionCode}:tr = {...} + Get Request BaseModel pydantic model_fields of each event and set headers which are included in model_fields + """ + for lang in list(LanguageConfig.SUPPORTED_LANGUAGES): # Iterate(languages ["tr", "en"]) + for key_field in self.events_rq_dict.keys(): # Iterate(function_code) + request_model = self.events_rq_dict[key_field] + if not request_model: + self.std_out += f"Request validation model not found for {key_field}\n" + continue + if key_field not in self.events_rq_dict or key_field not in self.events_lm_dict: + self.std_out += f"Request language model not found for {key_field}\n" + continue + + value_to_set = {} + redis_key = f"{RedisValidationKeys.LANGUAGE_MODELS}:{RedisValidationKeys.DYNAMIC}" + set_key = f"{redis_key}:{key_field}:{lang}" + for key in request_model.keys(): + value_to_set[key] = self.events_lm_dict[key_field][lang][key] + RedisActions.set_json(list_keys=[set_key], value=value_to_set) + + self.std_out += f"Language Request Headers are set to Redis\n" + if self.events_lm_dict and self.events_rs_dict: + """ + [SAVE]REDIS => LANGUAGE_MODELS:DYNAMIC:HEADERS:RESPONSE:{FunctionCode}:en = {...} + Get Response BaseModel pydantic model_fields of each event and set headers which are included in model_fields + """ + for lang in list(LanguageConfig.SUPPORTED_LANGUAGES): # Iterate(languages ["tr", "en"]) + for key_field in self.events_rs_dict.keys(): # Iterate(function_code) + response_model = self.events_rs_dict[key_field] + if not response_model: + self.std_out += f"Response validation model not found for {key_field}\n" + continue + if key_field not in self.events_rs_dict or key_field not in self.events_lm_dict: + self.std_out += f"Response language model not found for {key_field}\n" + continue + + value_to_set = {} + redis_key = f"{RedisValidationKeys.LANGUAGE_MODELS}:{RedisValidationKeys.DYNAMIC}" + set_key = f"{redis_key}:{key_field}:{lang}" + for key in response_model.keys(): + value_to_set[key] = self.events_lm_dict[key_field][lang][key] + RedisActions.set_json(list_keys=[set_key], value=value_to_set) + + self.std_out += f"Language Response Headers are set to Redis\n" diff --git a/ApiLayers/Middleware/auth_middleware.py b/ApiLayers/Middleware/auth_middleware.py index 030a966..c42cba5 100644 --- a/ApiLayers/Middleware/auth_middleware.py +++ b/ApiLayers/Middleware/auth_middleware.py @@ -87,7 +87,9 @@ class MiddlewareModule: # Get and validate token context from request endpoint_url = str(request.url.path) token_context = cls.get_user_from_request(request=request) - auth_context = AuthContext(auth=token_context, url=endpoint_url, request=request) + auth_context = AuthContext( + auth=token_context, url=endpoint_url, request=request + ) # Set auth context on the wrapper function itself setattr(func, "auth_context", auth_context) diff --git a/ApiLayers/Middleware/token_event_middleware.py b/ApiLayers/Middleware/token_event_middleware.py index 5885a1b..ac1c688 100644 --- a/ApiLayers/Middleware/token_event_middleware.py +++ b/ApiLayers/Middleware/token_event_middleware.py @@ -135,12 +135,15 @@ class TokenEventMiddleware: # Get and validate token context from request # token_context, reachable_event_codes = cls.retrieve_access_content(request) reachable_event_codes = ["g1j8i6j7-9k4h-0h6l-4i3j-2j0k1k0j0i0k"] - token_context = {"token": "context","context": {}} + 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, + auth=token_context, + code=reachable_event_code, + url=endpoint_url, + request=request, ) # Get auth context from the authenticated function's wrapper diff --git a/ApiLayers/Schemas/event/event.py b/ApiLayers/Schemas/event/event.py index 23cc197..f8f1707 100644 --- a/ApiLayers/Schemas/event/event.py +++ b/ApiLayers/Schemas/event/event.py @@ -313,6 +313,7 @@ class Event2Employee(CrudCollection): # return [event.endpoint_name for event in endpoint_restrictions] # + class Event2Occupant(CrudCollection): """ Occupant2Event class based on declarative_base and BaseMixin via session diff --git a/ApiLayers/Schemas/identity/identity.py b/ApiLayers/Schemas/identity/identity.py index 9ec3ad9..d7e9608 100644 --- a/ApiLayers/Schemas/identity/identity.py +++ b/ApiLayers/Schemas/identity/identity.py @@ -148,7 +148,9 @@ class Users(CrudCollection, UserLoginModule, SelectAction): @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 + 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, diff --git a/DockerApiServices/AuthServiceApi/app_handler.py b/DockerApiServices/AuthServiceApi/app_handler.py index b84b32d..e46c2c9 100644 --- a/DockerApiServices/AuthServiceApi/app_handler.py +++ b/DockerApiServices/AuthServiceApi/app_handler.py @@ -65,7 +65,9 @@ def setup_exception_handlers(app: FastAPI) -> None: """ custom_exception_handler = HTTPExceptionApiHandler(response_model=JSONResponse) app.add_exception_handler(ValidationError, validation_exception_handler) - app.add_exception_handler(HTTPExceptionApi, custom_exception_handler.handle_exception) + app.add_exception_handler( + HTTPExceptionApi, custom_exception_handler.handle_exception + ) app.add_exception_handler(Exception, generic_exception_handler) diff --git a/DockerApiServices/AuthServiceApi/create_routes.py b/DockerApiServices/AuthServiceApi/create_routes.py index 43488df..080ba67 100644 --- a/DockerApiServices/AuthServiceApi/create_routes.py +++ b/DockerApiServices/AuthServiceApi/create_routes.py @@ -16,16 +16,6 @@ from Events.Engine.set_defaults.setClusters import ( routers: Optional[PrepareRouting] = None -# async def health_check(request: Request): -# """Default health check endpoint.""" -# return {"status": "healthy", "message": "Service is running"} -# -# -# async def ping_test(request: Request, service_name: str = "base-router"): -# """Default ping test endpoint.""" -# return {"ping": "pong", "service": service_name} - - def get_all_routers() -> PrepareRouting: """ Get all routers and protected routes from route configurations. @@ -41,3 +31,13 @@ def get_all_routers() -> PrepareRouting: prepare_events = PrepareEvents(cluster_controller_group=cluster_list) SetItems2Redis(prepare_events=prepare_events) return prepare_routing + + +# async def health_check(request: Request): +# """Default health check endpoint.""" +# return {"status": "healthy", "message": "Service is running"} +# +# +# async def ping_test(request: Request, service_name: str = "base-router"): +# """Default ping test endpoint.""" +# return {"ping": "pong", "service": service_name} diff --git a/DockerApiServices/InitServiceApi/Dockerfile b/DockerApiServices/InitServiceApi/Dockerfile index 36f3401..34acace 100644 --- a/DockerApiServices/InitServiceApi/Dockerfile +++ b/DockerApiServices/InitServiceApi/Dockerfile @@ -12,29 +12,29 @@ RUN apt-get update \ # Copy Poetry configuration COPY DockerApiServices/pyproject.toml ./pyproject.toml -# # Configure Poetry and install dependencies with optimizations -# RUN poetry config virtualenvs.create false \ -# && poetry install --no-interaction --no-ansi --no-root --only main \ -# && pip cache purge \ -# && rm -rf ~/.cache/pypoetry +# Configure Poetry and install dependencies with optimizations +RUN poetry config virtualenvs.create false \ + && poetry install --no-interaction --no-ansi --no-root --only main \ + && pip cache purge \ + && rm -rf ~/.cache/pypoetry -# # Copy application code -# COPY DockerApiServices/EventServiceApi /app +# Copy application code +COPY DockerApiServices/InitServiceApi /app -# # Copy application code -# COPY ApiLayers /app/ApiLayers -# COPY Services /app/Services +# Copy application code +COPY ApiLayers /app/ApiLayers +COPY Services /app/Services -# # Events -# # COPY Events/base_request_model.py /app/Events/base_request_model.py -# COPY Events/Engine /app/Events/Engine -# COPY Events/AllEvents/events /app/Events/AllEvents/events -# COPY DockerApiServices/EventServiceApi/events_file.py /app/Events/AllEvents/events_file.py +# Events +# COPY Events/base_request_model.py /app/Events/base_request_model.py +COPY Events/Engine /app/Events/Engine +COPY Events/AllEvents /app/Events/AllEvents +COPY Events/base_request_model.py /app/Events/base_request_model.py -# # Set Python path to include app directory -# ENV PYTHONPATH=/app \ -# PYTHONUNBUFFERED=1 \ -# PYTHONDONTWRITEBYTECODE=1 +# Set Python path to include app directory +ENV PYTHONPATH=/app \ + PYTHONUNBUFFERED=1 \ + PYTHONDONTWRITEBYTECODE=1 -# # Run the application using the configured uvicorn server -# CMD ["poetry", "run", "python", "app.py"] +# Run the application using the configured uvicorn server +CMD ["poetry", "run", "python", "app.py"] diff --git a/DockerApiServices/InitServiceApi/app.py b/DockerApiServices/InitServiceApi/app.py new file mode 100644 index 0000000..c17a3ed --- /dev/null +++ b/DockerApiServices/InitServiceApi/app.py @@ -0,0 +1,5 @@ +from create_all_dependecies import SetRedisDefaults + + +if __name__ == "__main__": + SetRedisDefaults.set_all() diff --git a/DockerApiServices/InitServiceApi/config.py b/DockerApiServices/InitServiceApi/config.py new file mode 100644 index 0000000..b8dd8f9 --- /dev/null +++ b/DockerApiServices/InitServiceApi/config.py @@ -0,0 +1,71 @@ +class DefaultApiConfig: + app: str + host: str + port: int + log_level: str + reload: bool + + @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), + } + + +class ApiStatic: + PLACEHOLDER = "https://s.tmimgcdn.com/scr/800x500/276800/building-home-nature-logo-vector-template-3_276851-original.jpg" + FORGOT_LINK = "https://www.evyos.com.tr/password/create?tokenUrl=" + BLACKLIST_LINK = "https://www.evyos.com.tr/support/unknown-login-notice/" + APP_DIR = "/home/berkay/git-evyos/api-managment-backend/" + + @classmethod + def forgot_link(cls, forgot_key): + return cls.FORGOT_LINK + forgot_key + + @classmethod + def blacklist_login(cls, record_id): + return cls.BLACKLIST_LINK + record_id + + +class HostConfig: + MAIN_HOST = "10.10.2.36" # http://10.10.2.36 + EMAIL_HOST = "10.10.2.34" # http://10.10.2.34 + + +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." + ) + APP_URL = "https://www.auth.eys.gen.tr" + + # Server Configuration + app = "app:app" + host = "0.0.0.0" + port = 41575 + log_level = "info" + reload = True + + +class MainConfig: + + # Date and Time Configuration + DATETIME_FORMAT = "YYYY-MM-DD HH:mm:ss Z" + DATETIME_FORMAT_JS = "YYYY-MM-DD HH:mm:ss +0" + + # Timezone Configuration + 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 + + +class LanguageConfig: + + SUPPORTED_LANGUAGES = ["en", "tr"] + DEFAULT_LANGUAGE = "tr" diff --git a/DockerApiServices/InitServiceApi/create_all_dependecies.py b/DockerApiServices/InitServiceApi/create_all_dependecies.py new file mode 100644 index 0000000..b971d75 --- /dev/null +++ b/DockerApiServices/InitServiceApi/create_all_dependecies.py @@ -0,0 +1,41 @@ +""" +Route configuration and factory module. +Handles dynamic route creation based on configurations. +""" + +from Events.Engine.set_defaults.run import get_cluster_controller_group +from Events.Engine.set_defaults.setClusters import SetItems2Redis, PrepareEvents + +from ApiLayers.LanguageModels.set_defaults.language_setters import SetClusterLanguageModelsRedis, SetDefaultLanguageModelsRedis +from ApiLayers.LanguageModels.Response.all_responses import all_response_list +from ApiLayers.LanguageModels.Errors.all_errors import all_errors_list + + +class SetRedisDefaults: + + @classmethod + def set_all(cls) -> None: + """ + Get all routers and protected routes from route configurations. + + Returns: + None + """ + cluster_list = get_cluster_controller_group() + default_dict = dict( + set_response_languages_list=all_response_list, set_errors_languages_list=all_errors_list, + ) + prepare_events = PrepareEvents(cluster_controller_group=cluster_list) + SetItems2Redis(prepare_events=prepare_events) + SetDefaultLanguageModelsRedis(**default_dict).set_all() + SetClusterLanguageModelsRedis(cluster_controller_group=cluster_list).set_all() + + +# async def health_check(request: Request): +# """Default health check endpoint.""" +# return {"status": "healthy", "message": "Service is running"} +# +# +# async def ping_test(request: Request, service_name: str = "base-router"): +# """Default ping test endpoint.""" +# return {"ping": "pong", "service": service_name} diff --git a/Events/AllEvents/authentication/auth/api_events.py b/Events/AllEvents/authentication/auth/api_events.py index 5e54e57..12adb42 100644 --- a/Events/AllEvents/authentication/auth/api_events.py +++ b/Events/AllEvents/authentication/auth/api_events.py @@ -1,15 +1,17 @@ from Events.Engine.abstract_class import Event +from ApiLayers.Schemas import Users from .models import AuthenticationRequestModels, AuthenticationResponseModels from .function_handlers import AuthenticationFunctions - +from ApiLayers.LanguageModels.Request import LoginRequestLanguageModel # Auth Login authentication_login_super_user_event = Event( name="authentication_login_super_user_event", key="a5d2d0d1-3e9b-4b0f-8c7d-6d4a4b4c4d4e", request_validator=AuthenticationRequestModels.LoginSuperUserRequestModel, - # response_validator=LoginSuperUserResponseModel, + language_models=[], + response_validator=AuthenticationResponseModels.LoginSuperUserResponseModel, description="Login super user", ) @@ -24,7 +26,8 @@ authentication_select_super_user_event = Event( name="authentication_select_super_user_event", key="a5d2d0d1-3e9b-4b0f-8c7d-6d4a4b4c4d4e", request_validator=AuthenticationRequestModels.SelectCompanyOrOccupantTypeSuperUserRequestModel, - # response_validator=SelectCompanyOrOccupantTypeSuperUserResponseModel, + language_models=[], + response_validator=AuthenticationResponseModels.SelectCompanyOrOccupantTypeSuperUserResponseModel, description="Select company or occupant type super user", ) @@ -39,6 +42,7 @@ authentication_check_token_event = Event( name="authentication_check_token_event", key="b6e3d1e2-4f9c-5c1g-9d8e-7e5f6f5e5d5f", request_validator=None, # TODO: Add request validator + language_models=[Users.__language_model__], # response_validator=None, # TODO: Add response validator description="Check if token is valid", ) @@ -54,6 +58,7 @@ authentication_refresh_user_info_event = Event( name="authentication_refresh_user_info_event", key="c7f4e2f3-5g0d-6d2h-0e9f-8f6g7g6f6e6g", request_validator=None, # TODO: Add request validator + language_models=[Users.__language_model__], # response_validator=None, # TODO: Add response validator description="Refresh user information", ) @@ -69,6 +74,7 @@ authentication_change_password_event = Event( name="authentication_change_password_event", key="d8g5f3g4-6h1e-7e3i-1f0g-9g7h8h7g7f7h", request_validator=None, # TODO: Add request validator + language_models=[Users.__language_model__], # response_validator=None, # TODO: Add response validator description="Change user password", ) @@ -84,6 +90,7 @@ authentication_create_password_event = Event( name="authentication_create_password_event", key="e9h6g4h5-7i2f-8f4j-2g1h-0h8i9i8h8g8i", request_validator=None, # TODO: Add request validator + language_models=[Users.__language_model__], # response_validator=None, # TODO: Add response validator description="Create new password", ) @@ -99,6 +106,7 @@ authentication_disconnect_user_event = Event( name="authentication_disconnect_user_event", key="f0i7h5i6-8j3g-9g5k-3h2i-1i9j0j9i9h9j", request_validator=None, # TODO: Add request validator + language_models=[Users.__language_model__], # response_validator=None, # TODO: Add response validator description="Disconnect all user sessions", ) @@ -114,6 +122,7 @@ authentication_logout_user_event = Event( name="authentication_logout_user_event", key="g1j8i6j7-9k4h-0h6l-4i3j-2j0k1k0j0i0k", request_validator=None, # TODO: Add request validator + language_models=[Users.__language_model__], # response_validator=None, # TODO: Add response validator description="Logout user session", ) @@ -129,6 +138,7 @@ authentication_refresher_token_event = Event( name="authentication_refresher_token_event", key="h2k9j7k8-0l5i-1i7m-5j4k-3k1l2l1k1j1l", request_validator=None, # TODO: Add request validator + language_models=[Users.__language_model__], # response_validator=None, # TODO: Add response validator description="Refresh authentication token", ) @@ -144,6 +154,7 @@ authentication_forgot_password_event = Event( name="authentication_forgot_password_event", key="i3l0k8l9-1m6j-2j8n-6k5l-4l2m3m2l2k2m", request_validator=None, # TODO: Add request validator + language_models=[Users.__language_model__], # response_validator=None, # TODO: Add response validator description="Request password reset", ) @@ -159,6 +170,7 @@ authentication_reset_password_event = Event( name="authentication_reset_password_event", key="j4m1l9m0-2n7k-3k9o-7l6m-5m3n4n3m3l3n", request_validator=None, # TODO: Add request validator + language_models=[Users.__language_model__], # response_validator=None, # TODO: Add response validator description="Reset user password", ) @@ -174,6 +186,7 @@ authentication_download_avatar_event = Event( name="authentication_download_avatar_event", key="k5n2m0n1-3o8l-4l0p-8m7n-6n4o5o4n4m4o", request_validator=None, # TODO: Add request validator + language_models=[Users.__language_model__], # response_validator=None, # TODO: Add response validator description="Download user avatar and profile info", ) diff --git a/Events/AllEvents/authentication/auth/auth.py b/Events/AllEvents/authentication/auth/auth.py index 70296ba..c60654b 100644 --- a/Events/AllEvents/authentication/auth/auth.py +++ b/Events/AllEvents/authentication/auth/auth.py @@ -1,6 +1,7 @@ """ Authentication related API endpoints. """ + from typing import Any, Dict from fastapi import Request @@ -40,7 +41,7 @@ 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}" @@ -70,21 +71,27 @@ AuthenticationSelectEventMethods = MethodToEvent( def authentication_select_company_or_occupant_type( - request: Request, data: EndpointBaseRequestModel + request: Request, data: EndpointBaseRequestModel ) -> Dict[str, Any]: """ Select company or occupant type. """ - context_retriever = ContextRetrievers(func=authentication_select_company_or_occupant_type) + context_retriever = ContextRetrievers( + func=authentication_select_company_or_occupant_type + ) function = AuthenticationSelectEventMethods.retrieve_event( event_function_code=f"{authentication_select_super_user_event.key}" ) AuthenticationFunctions.context_retriever = context_retriever data_model = None if context_retriever.token.is_employee: - data_model = function.REQUEST_VALIDATOR.get('EmployeeSelection', None)(**data.data) + data_model = function.REQUEST_VALIDATOR.get("EmployeeSelection", None)( + **data.data + ) elif context_retriever.token.is_occupant: - data_model = function.REQUEST_VALIDATOR.get('OccupantSelection', None)(**data.data) + data_model = function.REQUEST_VALIDATOR.get("OccupantSelection", None)( + **data.data + ) return function.endpoint_callable(data=data_model) @@ -163,7 +170,9 @@ AuthenticationChangePasswordEventMethods = MethodToEvent( def authentication_change_password_event_callable(data: EndpointBaseRequestModel): - context_retriever = ContextRetrievers(func=authentication_change_password_event_callable) + context_retriever = ContextRetrievers( + func=authentication_change_password_event_callable + ) function = AuthenticationChangePasswordEventMethods.retrieve_event( event_function_code=f"{authentication_change_password_event.key}" ) @@ -177,7 +186,7 @@ AuthenticationChangePasswordEventMethods.endpoint_callable = ( AuthenticationCreatePasswordEventMethods = MethodToEvent( name="AuthenticationCreatePasswordEventMethods", - events={authentication_create_password_event: authentication_create_password_event}, + events={authentication_create_password_event.key: authentication_create_password_event}, headers=[], errors=[], url="/create-password", diff --git a/Events/AllEvents/authentication/auth/function_handlers.py b/Events/AllEvents/authentication/auth/function_handlers.py index f03d18d..f3fb4df 100644 --- a/Events/AllEvents/authentication/auth/function_handlers.py +++ b/Events/AllEvents/authentication/auth/function_handlers.py @@ -28,8 +28,10 @@ from Events.base_request_model import ContextRetrievers, TokenDictType class Handlers: """Class for handling authentication functions""" - @classmethod # Requires no auth context - def handle_employee_selection(cls, request: Request, data: Any, token_dict: TokenDictType): + @classmethod # Requires no auth context + def handle_employee_selection( + cls, request: Request, data: Any, token_dict: TokenDictType + ): db = Users.new_session() if data.company_uu_id not in token_dict.companies_uu_id_list: raise HTTPExceptionApi( @@ -66,7 +68,8 @@ class Handlers: # Get employee employee: Employees = Employees.filter_one( Employees.people_id == token_dict.person_id, - Employees.staff_id.in_(staff_ids), db=db + Employees.staff_id.in_(staff_ids), + db=db, ).data if not employee: @@ -123,8 +126,10 @@ class Handlers: sys_msg=f"{e}", ) - @classmethod # Requires no auth context - def handle_occupant_selection(cls, request: Request, data: Any, token_dict: TokenDictType): + @classmethod # Requires no auth context + def handle_occupant_selection( + cls, request: Request, data: Any, token_dict: TokenDictType + ): """Handle occupant type selection""" db = BuildLivingSpace.new_session() # Get selected occupant type @@ -207,7 +212,7 @@ class AuthenticationFunctions: context_retriever: Union[ContextRetrievers] = None - @classmethod # Requires no auth context + @classmethod # Requires no auth context def authentication_login_with_domain_and_creds(cls, request: Request, data: Any): """ Authenticate user with domain and credentials. @@ -215,12 +220,10 @@ class AuthenticationFunctions: 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 - } + { + "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 """ @@ -235,7 +238,7 @@ class AuthenticationFunctions: code="LOGIN_SUCCESS", lang=user_login_module.language ).as_dict(data=user_login_module.as_dict) - @classmethod # Requires auth context + @classmethod # Requires auth context def authentication_select_company_or_occupant_type(cls, data: Any): """ Handle selection of company or occupant type @@ -243,25 +246,31 @@ class AuthenticationFunctions: """ if cls.context_retriever.token.is_employee: if Handlers.handle_employee_selection( - request=cls.context_retriever.request, data=data, token_dict=cls.context_retriever.token + request=cls.context_retriever.request, + data=data, + token_dict=cls.context_retriever.token, ): return EndpointSuccessResponse( code="LOGIN_SELECT", lang=cls.context_retriever.token.lang - ).as_dict(data={ - "selected": data.company_uu_id, **cls.context_retriever.base - }) + ).as_dict( + data={"selected": data.company_uu_id, **cls.context_retriever.base} + ) elif cls.context_retriever.token.is_occupant: if Handlers.handle_occupant_selection( - request=cls.context_retriever.request, data=data, token_dict=cls.context_retriever.token + request=cls.context_retriever.request, + data=data, + token_dict=cls.context_retriever.token, ): return EndpointSuccessResponse( code="LOGIN_SELECT", lang=cls.context_retriever.token.lang - ).as_dict(data={ - "selected": data.build_living_space_uu_id, **cls.context_retriever.base - }) - return {"completed": False, "selected": None, **cls.context_retriever.base} + ).as_dict( + data={ + "selected": data.build_living_space_uu_id, + **cls.context_retriever.base, + } + ) - @classmethod # Requires not auth context + @classmethod # Requires not auth context def authentication_check_token_is_valid(cls, data: Any): """Check if token is valid for user""" # try: @@ -271,7 +280,7 @@ class AuthenticationFunctions: # return ResponseHandler.unauthorized("Access Token is NOT valid") return - @classmethod # Requires not auth context + @classmethod # Requires not auth context def authentication_refresh_user_info(cls, data: Any): """Refresh user info using access token""" # try: @@ -300,7 +309,7 @@ class AuthenticationFunctions: # return ResponseHandler.error(str(e)) return - @classmethod # Requires no auth context + @classmethod # Requires no auth context def authentication_change_password(cls, data: Any): """Change password with access token""" # try: @@ -320,7 +329,7 @@ class AuthenticationFunctions: # return ResponseHandler.error(str(e)) return - @classmethod # Requires not auth context + @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: @@ -333,7 +342,7 @@ class AuthenticationFunctions: # return ResponseHandler.not_found("Record not found") return - @classmethod # Requires auth context + @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 @@ -348,7 +357,7 @@ class AuthenticationFunctions: # return ResponseHandler.not_found("Invalid data") return - @classmethod # Requires auth context + @classmethod # Requires auth context def authentication_logout_user(cls, data: Any): """Logout only single session of user which domain is provided""" # token_user = None @@ -364,7 +373,7 @@ class AuthenticationFunctions: context_retriever = ContextRetrievers(func=cls.authentication_logout_user) return context_retriever.base - @classmethod # Requires not auth context + @classmethod # Requires not auth context def authentication_refresher_token(cls, data: Any): """Refresh access token with refresher token""" # token_refresher = UsersTokens.filter_by_one( @@ -391,7 +400,7 @@ class AuthenticationFunctions: context_retriever = ContextRetrievers(func=cls.authentication_refresher_token) return context_retriever.base - @classmethod # Requires not auth context + @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) @@ -410,7 +419,7 @@ class AuthenticationFunctions: # return ResponseHandler.success("Password is change link is sent to your email or phone", data={}) return - @classmethod # Requires not auth context + @classmethod # Requires not auth context def authentication_reset_password(cls, data: Any): """Reset password with forgot password token""" # from sqlalchemy import or_ @@ -439,7 +448,7 @@ class AuthenticationFunctions: # return ResponseHandler.success("Password change link is sent to your email or phone", data=found_user.get_dict()) return - @classmethod # Requires not auth context + @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: diff --git a/Events/AllEvents/authentication/auth/models.py b/Events/AllEvents/authentication/auth/models.py index 78e4689..9bb98be 100644 --- a/Events/AllEvents/authentication/auth/models.py +++ b/Events/AllEvents/authentication/auth/models.py @@ -6,10 +6,6 @@ from ApiLayers.ApiValidations.Request import ( ) -class LoginSuperUserRequestModel(Login): - pass - - class LoginSuperUserResponseModel(BaseModel): pass @@ -37,14 +33,12 @@ class OccupantSelectionSuperUserRequestModel(BaseModel): class OccupantSelectionSuperUserResponseModel(BaseModel): pass -""" -EmployeeSelection, -OccupantSelection, -""" + class AuthenticationRequestModels: - LoginSuperUserRequestModel = LoginSuperUserRequestModel + LoginSuperUserRequestModel = Login SelectCompanyOrOccupantTypeSuperUserRequestModel = { - "EmployeeSelection": EmployeeSelection, "OccupantSelection":OccupantSelection + "EmployeeSelection": EmployeeSelection, + "OccupantSelection": OccupantSelection, } EmployeeSelectionSuperUserRequestModel = EmployeeSelectionSuperUserRequestModel OccupantSelectionSuperUserRequestModel = OccupantSelectionSuperUserRequestModel diff --git a/Events/AllEvents/validations/__init__.py b/Events/AllEvents/validations/__init__.py index e69de29..d8ca65a 100644 --- a/Events/AllEvents/validations/__init__.py +++ b/Events/AllEvents/validations/__init__.py @@ -0,0 +1,5 @@ +""" +Validations package initialization. +""" + +__all__ = [] diff --git a/Events/Engine/abstract_class.py b/Events/Engine/abstract_class.py index 6ac4267..13abf88 100644 --- a/Events/Engine/abstract_class.py +++ b/Events/Engine/abstract_class.py @@ -34,6 +34,7 @@ class Event: RESPONSE_VALIDATOR: Optional[Any] REQUEST_VALIDATOR: Optional[Any] DESCRIPTION: str + LANGUAGE_MODELS: list EXTRA_OPTIONS: Optional[Dict[str, Any]] = None endpoint_callable: Any @@ -42,6 +43,7 @@ class Event: name: str, key: str | UUID, description: str, + language_models: list[Dict[str, Dict]], request_validator: Optional[Any] = None, response_validator: Optional[Any] = None, extra_options: Optional[Dict[str, Any]] = None, @@ -50,9 +52,18 @@ class Event: self.KEY_ = key self.REQUEST_VALIDATOR = request_validator self.RESPONSE_VALIDATOR = response_validator + self.LANGUAGE_MODELS = language_models self.DESCRIPTION = description self.EXTRA_OPTIONS = extra_options + @property + def request_headers(self): + return self.LANGUAGE_MODELS + + @property + def response_headers(self): + return self.LANGUAGE_MODELS + @property def description(self): return f"This is an event of {self.name}. Description: {self.DESCRIPTION}" diff --git a/Events/Engine/set_defaults/setClusters.py b/Events/Engine/set_defaults/setClusters.py index e8daa8b..c9ad749 100644 --- a/Events/Engine/set_defaults/setClusters.py +++ b/Events/Engine/set_defaults/setClusters.py @@ -4,6 +4,7 @@ from ApiLayers.ApiServices.Cluster.create_router import ( CreateRouterFromCluster, CreateEndpointFromCluster, ) +from ApiLayers.AllConfigs.Redis.configs import RedisCategoryKeys from Events.Engine.abstract_class import CategoryCluster from Services.Redis.Actions.actions import RedisActions from Services.Redis.Models.cluster import RedisList @@ -123,7 +124,6 @@ class SetItems2Redis: return f"\nSetItems2Redis:\n\n{self.std_out}" def set_items(self): - from ApiLayers.AllConfigs.Redis.configs import RedisCategoryKeys dict_prep = self.prepare_events.valid_redis_items.as_dict for ( diff --git a/Services/Redis/Models/access.py b/Services/Redis/Models/access.py index ddbcf8e..c886b7a 100644 --- a/Services/Redis/Models/access.py +++ b/Services/Redis/Models/access.py @@ -21,7 +21,11 @@ class AccessToken(BaseRedisModel): def to_list(self): """Convert to list for Redis storage.""" - return [self.auth_key, self.accessToken, str(self.userUUID) if self.userUUID else None] + return [ + self.auth_key, + self.accessToken, + str(self.userUUID) if self.userUUID else None, + ] @property def count(self): diff --git a/Services/Redis/Models/response.py b/Services/Redis/Models/response.py index ffc86a0..72497bf 100644 --- a/Services/Redis/Models/response.py +++ b/Services/Redis/Models/response.py @@ -29,7 +29,9 @@ class RedisResponse: def as_dict(self) -> Dict: data = self.all main_dict = { - "status": self.status, "message": self.message, "count": self.count, + "status": self.status, + "message": self.message, + "count": self.count, "dataType": getattr(self, "data_type", None), } if isinstance(data, RedisRow):