updated login/select

This commit is contained in:
berkay 2025-01-27 21:43:36 +03:00
parent b88f910a43
commit c0bd9c1685
18 changed files with 257 additions and 275 deletions

View File

@ -6,59 +6,23 @@
<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/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/AllConfigs/Redis/configs.py" beforeDir="false" afterPath="$PROJECT_DIR$/ApiLayers/AllConfigs/Redis/configs.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/Custom/token_objects.py" beforeDir="false" afterPath="$PROJECT_DIR$/ApiLayers/ApiValidations/Custom/token_objects.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/ErrorHandlers/ErrorHandlers/api_exc_handler.py" beforeDir="false" afterPath="$PROJECT_DIR$/ApiLayers/ErrorHandlers/ErrorHandlers/api_exc_handler.py" afterDir="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/event/event.py" beforeDir="false" afterPath="$PROJECT_DIR$/ApiLayers/Schemas/event/event.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" />
<change beforePath="$PROJECT_DIR$/Services/Redis/Models/access.py" beforeDir="false" afterPath="$PROJECT_DIR$/Services/Redis/Models/access.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Services/Redis/Models/response.py" beforeDir="false" afterPath="$PROJECT_DIR$/Services/Redis/Models/response.py" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />

View File

@ -2,6 +2,7 @@ from ApiLayers.AllConfigs import HostConfig
class WagRedis:
REDIS_HOST = HostConfig.MAIN_HOST
REDIS_PASSWORD: str = "commercial_redis_password"
REDIS_PORT: int = 11222
@ -10,10 +11,8 @@ class WagRedis:
@classmethod
def as_dict(cls):
return dict(
host=WagRedis.REDIS_HOST,
password=WagRedis.REDIS_PASSWORD,
port=WagRedis.REDIS_PORT,
db=WagRedis.REDIS_DB,
host=WagRedis.REDIS_HOST, password=WagRedis.REDIS_PASSWORD,
port=WagRedis.REDIS_PORT, db=WagRedis.REDIS_DB,
)

View File

@ -50,7 +50,6 @@ 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.
"""

View File

@ -265,7 +265,7 @@ class TokenService:
redis_rows = cls._get_user_tokens(user)
for redis_row in redis_rows.all:
if redis_row.row.get("domain") == domain:
redis_row.delete()
RedisActions.delete([redis_row.key])
@classmethod
def remove_all_token(cls, user: Users) -> None:
@ -284,16 +284,11 @@ class TokenService:
"""Set access token to redis and handle user session."""
cls.remove_token_with_domain(user=user, domain=domain)
Users.client_arrow = DateTimeLocal(is_client=True, timezone=user.local_timezone)
db_session = UsersTokens.new_session()
# Handle login based on user type
if user.is_occupant:
login_dict = cls.do_occupant_login(
request=request, user=user, domain=domain
)
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)
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:
@ -321,10 +316,7 @@ class TokenService:
).query.delete(synchronize_session=False)
user.remember_me = False
user.save(db=db_session)
return {
**login_dict,
"user": user.get_dict(),
}
return {**login_dict, "user": user.get_dict()}
@classmethod
def update_token_at_redis(
@ -424,9 +416,8 @@ class TokenService:
sys_msg="Access token token is not found or unable to retrieve",
)
if redis_object := redis_response.first:
redis_object_dict = redis_object.data
access_token_obj.userUUID = redis_object_dict.get("user_uu_id")
return cls._process_redis_object(redis_object_dict)
access_token_obj.userUUID = redis_object.get("user_uu_id")
return cls._process_redis_object(redis_object)
@classmethod
def get_object_via_user_uu_id(cls, user_id: str) -> T:
@ -434,7 +425,7 @@ class TokenService:
access_token = AccessToken(userUUID=user_id)
redis_response = RedisActions.get_json(list_keys=access_token.to_list())
if redis_object := redis_response.first.data:
if redis_object := redis_response.first.row:
access_token.userUUID = redis_object.get("user_uu_id")
return cls._process_redis_object(redis_object)

View File

@ -59,11 +59,10 @@ class OccupantToken(BaseModel):
responsible_employee_uuid: Optional[str] = None
reachable_event_codes: Optional[list[str]] = None # ID list of reachable modules
reachable_event_endpoints: Optional[list[str]] = None
class CompanyToken(BaseModel): # Required Company Object for an employee
class CompanyToken(BaseModel):
# Selection of the company for an employee is made by the user
company_id: int
company_uu_id: str
@ -82,14 +81,12 @@ class CompanyToken(BaseModel): # Required Company Object for an employee
bulk_duties_id: int
reachable_event_codes: Optional[list[str]] = None # ID list of reachable modules
reachable_event_endpoints: Optional[list[str]] = None
class OccupantTokenObject(ApplicationToken):
# Occupant Token Object -> Requires selection of the occupant type for a specific build part
available_occupants: dict = None
selected_occupant: Optional[OccupantToken] = None # Selected Occupant Type
@property

View File

@ -21,7 +21,7 @@ class BaseEndpointResponse:
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 +30,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 +39,7 @@ class EndpointCreatedResponse(BaseEndpointResponse): # 201 Created
)
class EndpointAcceptedResponse(BaseEndpointResponse): # 202 Accepted
class EndpointAcceptedResponse(BaseEndpointResponse): # 202 Accepted
def as_dict(self, data: Optional[dict] = None):
return JSONResponse(
@ -48,7 +48,16 @@ class EndpointAcceptedResponse(BaseEndpointResponse): # 202 Accepted
)
class EndpointBadRequestResponse(BaseEndpointResponse): # 400 Bad Request
class EndpointNotModifiedResponse(BaseEndpointResponse): # 304 Not Modified
def as_dict(self):
return JSONResponse(
status_code=status.HTTP_304_NOT_MODIFIED,
content=dict(completed=False, **self.response, lang=self.lang),
)
class EndpointBadRequestResponse(BaseEndpointResponse): # 400 Bad Request
def as_dict(self, data: Optional[dict] = None):
return JSONResponse(
@ -57,7 +66,7 @@ class EndpointBadRequestResponse(BaseEndpointResponse): # 400 Bad Reques
)
class EndpointUnauthorizedResponse(BaseEndpointResponse): # 401 Unauthorized
class EndpointUnauthorizedResponse(BaseEndpointResponse): # 401 Unauthorized
def as_dict(self):
return JSONResponse(
@ -66,16 +75,7 @@ class EndpointUnauthorizedResponse(BaseEndpointResponse): # 401 Unauthoriz
)
class EndpointNotFoundResponse(BaseEndpointResponse): # 404 Not Found
def as_dict(self):
return JSONResponse(
status_code=status.HTTP_404_NOT_FOUND,
content=dict(completed=False, **self.response, lang=self.lang),
)
class EndpointForbiddenResponse(BaseEndpointResponse): # 403 Forbidden
class EndpointForbiddenResponse(BaseEndpointResponse): # 403 Forbidden
def as_dict(self):
return JSONResponse(
@ -84,7 +84,34 @@ class EndpointForbiddenResponse(BaseEndpointResponse): # 403 Forbidden
)
class EndpointConflictResponse(BaseEndpointResponse): # 409 Conflict
class EndpointNotFoundResponse(BaseEndpointResponse): # 404 Not Found
def as_dict(self):
return JSONResponse(
status_code=status.HTTP_404_NOT_FOUND,
content=dict(completed=False, **self.response, lang=self.lang),
)
class EndpointMethodNotAllowedResponse(BaseEndpointResponse): # 405 Method Not Allowed
def as_dict(self):
return JSONResponse(
status_code=status.HTTP_405_METHOD_NOT_ALLOWED,
content=dict(completed=False, **self.response, lang=self.lang),
)
class EndpointNotAcceptableResponse(BaseEndpointResponse): # 406 Not Acceptable
def as_dict(self):
return JSONResponse(
status_code=status.HTTP_406_NOT_ACCEPTABLE,
content=dict(completed=False, **self.response, lang=self.lang),
)
class EndpointConflictResponse(BaseEndpointResponse): # 409 Conflict
def as_dict(self):
return JSONResponse(
@ -93,7 +120,16 @@ class EndpointConflictResponse(BaseEndpointResponse): # 409 Conflict
)
class EndpointTooManyRequestsResponse(BaseEndpointResponse): # 429 Too Many Requests
class EndpointUnprocessableEntityResponse(BaseEndpointResponse): # 422 Unprocessable Entity
def as_dict(self, data: Optional[dict] = None):
return JSONResponse(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
content=dict(completed=False, **self.response, lang=self.lang, data=data),
)
class EndpointTooManyRequestsResponse(BaseEndpointResponse): # 429 Too Many Requests
def __init__(self, retry_after: int, lang: str, code: str):
super().__init__(lang=lang, code=code)
@ -107,19 +143,10 @@ class EndpointTooManyRequestsResponse(BaseEndpointResponse): # 429 Too Many R
)
class EndpointInternalErrorResponse(BaseEndpointResponse): # 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, **self.response, lang=self.lang),
)
class EndpointErrorResponse(BaseEndpointResponse):
def as_dict(self):
return JSONResponse(
status_code=status.HTTP_304_NOT_MODIFIED,
content=dict(completed=False, **self.response, lang=self.lang),
)

View File

@ -1,20 +1,40 @@
import json
from typing import Any, Union, Awaitable
from fastapi import Request, WebSocket
from fastapi.responses import Response
from pydantic import ValidationError
from ApiLayers.LanguageModels.Errors.merge_all_error_languages import (
MergedErrorLanguageModels,
)
from fastapi import Request, WebSocket, status
from fastapi.responses import Response, JSONResponse
from ApiLayers.LanguageModels.Errors.merge_all_error_languages import MergedErrorLanguageModels
from ApiLayers.ErrorHandlers.Exceptions.api_exc import HTTPExceptionApi
from ApiLayers.ErrorHandlers.bases import BaseErrorModelClass
def validation_exception_handler(request, exc: ValidationError) -> JSONResponse:
"""
{"message": [{
"type": "missing", "location": ["company_uu_id"], "message": "Field required",
"input": {"invalid_key_input": "e9869a25"}
}], "request": "http://0.0.0.0:41575/authentication/select", "title": "EmployeeSelection"
}
Validation error on pydantic model of each event validation
"""
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)
return JSONResponse(
content=error_response_dict, status_code=status.HTTP_422_UNPROCESSABLE_ENTITY
)
class HTTPExceptionApiHandler:
def __init__(
self,
response_model: Any,
):
def __init__(self, response_model: Any):
self.RESPONSE_MODEL: Any = response_model
@staticmethod
@ -26,7 +46,6 @@ 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(

View File

@ -27,9 +27,7 @@ class MiddlewareModule:
"""
@staticmethod
def get_user_from_request(
request: Request,
) -> dict:
def get_user_from_request(request: Request) -> dict:
"""
Get authenticated token context from request.
@ -54,7 +52,6 @@ class MiddlewareModule:
loc=get_line_number_for_error(),
sys_msg="TokenService: Token Context couldnt retrieved from redis",
)
return token_context
@classmethod
@ -89,11 +86,8 @@ class MiddlewareModule:
async def wrapper(request: Request, *args, **kwargs):
# Get and validate token context from request
endpoint_url = str(request.url.path)
auth_context = AuthContext(
auth={"token": {"access_token": "", "refresher_token": "", "context": {}}},
url=endpoint_url,
request=request,
)
token_context = cls.get_user_from_request(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)

View File

@ -256,12 +256,11 @@ class Event2Employee(CrudCollection):
cls.employee_id == employee_id,
db=db,
).data
active_event_ids = Service2Events.filter_all(
active_event_ids = Service2Events.filter_all_system(
Service2Events.service_id.in_(
[event.event_service_id for event in employee_events]
),
db=db,
system=True,
).data
active_events = Events.filter_all(
Events.id.in_([event.event_id for event in active_event_ids]),
@ -278,41 +277,41 @@ class Event2Employee(CrudCollection):
active_events.extend(events_extra)
return [event.function_code for event in active_events]
@classmethod
def get_event_endpoints(cls, employee_id: int) -> list:
from Schemas import EndpointRestriction
db = cls.new_session()
employee_events = cls.filter_all(
cls.employee_id == employee_id,
db=db,
).data
active_event_ids = Service2Events.filter_all(
Service2Events.service_id.in_(
[event.event_service_id for event in employee_events]
),
db=db,
system=True,
).data
active_events = Events.filter_all(
Events.id.in_([event.event_id for event in active_event_ids]),
db=db,
).data
if extra_events := Event2EmployeeExtra.filter_all(
Event2EmployeeExtra.employee_id == employee_id,
db=db,
).data:
events_extra = Events.filter_all(
Events.id.in_([event.event_id for event in extra_events]),
db=db,
).data
active_events.extend(events_extra)
endpoint_restrictions = EndpointRestriction.filter_all(
EndpointRestriction.id.in_([event.endpoint_id for event in active_events]),
db=db,
).data
return [event.endpoint_name for event in endpoint_restrictions]
# @classmethod
# def get_event_endpoints(cls, employee_id: int) -> list:
# from Schemas import EndpointRestriction
#
# db = cls.new_session()
# employee_events = cls.filter_all(
# cls.employee_id == employee_id,
# db=db,
# ).data
# active_event_ids = Service2Events.filter_all(
# Service2Events.service_id.in_(
# [event.event_service_id for event in employee_events]
# ),
# db=db,
# system=True,
# ).data
# active_events = Events.filter_all(
# Events.id.in_([event.event_id for event in active_event_ids]),
# db=db,
# ).data
# if extra_events := Event2EmployeeExtra.filter_all(
# Event2EmployeeExtra.employee_id == employee_id,
# db=db,
# ).data:
# events_extra = Events.filter_all(
# Events.id.in_([event.event_id for event in extra_events]),
# db=db,
# ).data
# active_events.extend(events_extra)
# endpoint_restrictions = EndpointRestriction.filter_all(
# EndpointRestriction.id.in_([event.endpoint_id for event in active_events]),
# db=db,
# ).data
# return [event.endpoint_name for event in endpoint_restrictions]
#
class Event2Occupant(CrudCollection):
"""
@ -355,12 +354,11 @@ class Event2Occupant(CrudCollection):
cls.build_living_space_id == build_living_space_id,
db=db,
).data
active_event_ids = Service2Events.filter_all(
active_event_ids = Service2Events.filter_all_system(
Service2Events.service_id.in_(
[event.event_service_id for event in occupant_events]
),
db=db,
system=True,
).data
active_events = Events.filter_all(
Events.id.in_([event.event_id for event in active_event_ids]),
@ -377,40 +375,40 @@ class Event2Occupant(CrudCollection):
active_events.extend(events_extra)
return [event.function_code for event in active_events]
@classmethod
def get_event_endpoints(cls, build_living_space_id) -> list:
from Schemas import EndpointRestriction
db = cls.new_session()
occupant_events = cls.filter_all(
cls.build_living_space_id == build_living_space_id,
db=db,
).data
active_event_ids = Service2Events.filter_all(
Service2Events.service_id.in_(
[event.event_service_id for event in occupant_events]
),
db=db,
system=True,
).data
active_events = Events.filter_all(
Events.id.in_([event.event_id for event in active_event_ids]),
db=db,
).data
if extra_events := Event2OccupantExtra.filter_all(
Event2OccupantExtra.build_living_space_id == build_living_space_id,
db=db,
).data:
events_extra = Events.filter_all(
Events.id.in_([event.event_id for event in extra_events]),
db=db,
).data
active_events.extend(events_extra)
endpoint_restrictions = EndpointRestriction.filter_all(
EndpointRestriction.id.in_([event.endpoint_id for event in active_events]),
db=db,
).data
return [event.endpoint_name for event in endpoint_restrictions]
# @classmethod
# def get_event_endpoints(cls, build_living_space_id) -> list:
# from Schemas import EndpointRestriction
#
# db = cls.new_session()
# occupant_events = cls.filter_all(
# cls.build_living_space_id == build_living_space_id,
# db=db,
# ).data
# active_event_ids = Service2Events.filter_all(
# Service2Events.service_id.in_(
# [event.event_service_id for event in occupant_events]
# ),
# db=db,
# system=True,
# ).data
# active_events = Events.filter_all(
# Events.id.in_([event.event_id for event in active_event_ids]),
# db=db,
# ).data
# if extra_events := Event2OccupantExtra.filter_all(
# Event2OccupantExtra.build_living_space_id == build_living_space_id,
# db=db,
# ).data:
# events_extra = Events.filter_all(
# Events.id.in_([event.event_id for event in extra_events]),
# db=db,
# ).data
# active_events.extend(events_extra)
# endpoint_restrictions = EndpointRestriction.filter_all(
# EndpointRestriction.id.in_([event.endpoint_id for event in active_events]),
# db=db,
# ).data
# return [event.endpoint_name for event in endpoint_restrictions]
class ModulePrice(CrudCollection):

View File

@ -203,8 +203,6 @@ class Users(CrudCollection, UserLoginModule, SelectAction):
created_user.reset_password_token(found_user=created_user)
return created_user
def get_employee_and_duty_details(self):
from Schemas import Employees, Duties

View File

@ -9,8 +9,13 @@ This module contains all the handler functions for configuring and setting up th
from fastapi import FastAPI, Request, status
from fastapi.middleware.cors import CORSMiddleware
from pydantic import ValidationError
from fastapi.responses import JSONResponse
from ApiLayers.ErrorHandlers.ErrorHandlers.api_exc_handler import (
HTTPExceptionApiHandler,
validation_exception_handler,
)
from ApiLayers.ErrorHandlers.Exceptions.api_exc import HTTPExceptionApi
from ApiLayers.Middleware.auth_middleware import (
RequestTimingMiddleware,
@ -58,14 +63,9 @@ def setup_exception_handlers(app: FastAPI) -> None:
Args:
app: FastAPI application instance
"""
from ApiLayers.ErrorHandlers.ErrorHandlers.api_exc_handler import (
HTTPExceptionApiHandler,
)
custom_exception_handler = HTTPExceptionApiHandler(response_model=JSONResponse)
app.add_exception_handler(
HTTPExceptionApi, custom_exception_handler.handle_exception
)
app.add_exception_handler(ValidationError, validation_exception_handler)
app.add_exception_handler(HTTPExceptionApi, custom_exception_handler.handle_exception)
app.add_exception_handler(Exception, generic_exception_handler)

View File

@ -22,6 +22,7 @@ from .api_events import (
authentication_reset_password_event,
authentication_download_avatar_event,
)
from .function_handlers import AuthenticationFunctions
AuthenticationLoginEventMethods = MethodToEvent(
@ -39,7 +40,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}"
@ -68,7 +69,9 @@ AuthenticationSelectEventMethods = MethodToEvent(
)
def authentication_select_company_or_occupant_type(data: EndpointBaseRequestModel) -> Dict[str, Any]:
def authentication_select_company_or_occupant_type(
request: Request, data: EndpointBaseRequestModel
) -> Dict[str, Any]:
"""
Select company or occupant type.
"""
@ -76,8 +79,13 @@ def authentication_select_company_or_occupant_type(data: EndpointBaseRequestMode
function = AuthenticationSelectEventMethods.retrieve_event(
event_function_code=f"{authentication_select_super_user_event.key}"
)
setattr(function.endpoint_callable, context_retriever.key, context_retriever.context)
return function.endpoint_callable(data=data)
AuthenticationFunctions.context_retriever = context_retriever
data_model = None
if context_retriever.token.is_employee:
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)
return function.endpoint_callable(data=data_model)
AuthenticationSelectEventMethods.endpoint_callable = (
@ -103,7 +111,7 @@ def authentication_check_token_is_valid():
function = AuthenticationCheckTokenEventMethods.retrieve_event(
event_function_code=f"{authentication_check_token_event.key}"
)
setattr(function.endpoint_callable, context_retriever.key, context_retriever.context)
AuthenticationFunctions.context_retriever = context_retriever
return function.endpoint_callable()
@ -132,7 +140,7 @@ def authentication_refresh_user_info():
function = AuthenticationRefreshEventMethods.retrieve_event(
event_function_code=f"{authentication_refresh_user_info_event.key}"
)
setattr(function.endpoint_callable, context_retriever.key, context_retriever.context)
AuthenticationFunctions.context_retriever = context_retriever
return function.endpoint_callable()
@ -159,7 +167,7 @@ def authentication_change_password_event_callable(data: EndpointBaseRequestModel
function = AuthenticationChangePasswordEventMethods.retrieve_event(
event_function_code=f"{authentication_change_password_event.key}"
)
setattr(function.endpoint_callable, context_retriever.key, context_retriever.context)
AuthenticationFunctions.context_retriever = context_retriever
return function.endpoint_callable(data=data)
@ -184,7 +192,7 @@ def authentication_create_password(data: EndpointBaseRequestModel):
function = AuthenticationCreatePasswordEventMethods.retrieve_event(
event_function_code=f"{authentication_create_password_event.key}"
)
setattr(function.endpoint_callable, context_retriever.key, context_retriever.context)
AuthenticationFunctions.context_retriever = context_retriever
return function.endpoint_callable(data=data)
@ -213,7 +221,7 @@ def authentication_disconnect_user(data: EndpointBaseRequestModel):
function = AuthenticationDisconnectUserEventMethods.retrieve_event(
event_function_code=f"{authentication_disconnect_user_event.key}"
)
setattr(function.endpoint_callable, context_retriever.key, context_retriever.context)
AuthenticationFunctions.context_retriever = context_retriever
return function.endpoint_callable(data=data)
@ -235,7 +243,7 @@ def authentication_logout_user(data: EndpointBaseRequestModel):
function = AuthenticationLogoutEventMethods.retrieve_event(
event_function_code=f"{authentication_logout_user_event.key}"
)
setattr(function.endpoint_callable, context_retriever.key, context_retriever.context)
AuthenticationFunctions.context_retriever = context_retriever
return function.endpoint_callable(data=data)
@ -262,7 +270,7 @@ def authentication_refresher_token(data: EndpointBaseRequestModel):
function = AuthenticationRefreshTokenEventMethods.retrieve_event(
event_function_code=f"{authentication_refresher_token_event.key}"
)
setattr(function.endpoint_callable, context_retriever.key, context_retriever.context)
AuthenticationFunctions.context_retriever = context_retriever
return function.endpoint_callable(data=data)
@ -290,7 +298,7 @@ def authentication_forgot_password(data: EndpointBaseRequestModel):
function = AuthenticationForgotPasswordEventMethods.retrieve_event(
event_function_code=f"{authentication_forgot_password_event.key}"
)
setattr(function.endpoint_callable, context_retriever.key, context_retriever.context)
AuthenticationFunctions.context_retriever = context_retriever
return function.endpoint_callable(data=data)
@ -319,8 +327,8 @@ def authentication_reset_password(data: EndpointBaseRequestModel):
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)
AuthenticationFunctions.context_retriever = context_retriever
return function.endpoint_callable(data=data.data)
AuthenticationResetPasswordEventMethods.endpoint_callable = (
@ -348,7 +356,7 @@ def authentication_download_avatar():
function = AuthenticationDownloadAvatarEventMethods.retrieve_event(
event_function_code=f"{authentication_download_avatar_event.key}"
)
setattr(function.endpoint_callable, context_retriever.key, context_retriever.context)
AuthenticationFunctions.context_retriever = context_retriever
return function.endpoint_callable()

View File

@ -1,4 +1,4 @@
from typing import Any
from typing import Any, Union
from fastapi import Request
from ApiLayers.ApiLibrary.common.line_number import get_line_number_for_error
@ -30,7 +30,6 @@ class Handlers:
@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(
@ -40,8 +39,7 @@ class Handlers:
sys_msg="Company not found in token",
)
selected_company: Companies = Companies.filter_one(
Companies.uu_id == data.company_uu_id,
db=db,
Companies.uu_id == data.company_uu_id, db=db
).data
if not selected_company:
raise HTTPExceptionApi(
@ -51,15 +49,6 @@ class Handlers:
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,
).data
]
# Get duties IDs for the company
duties_ids = [
duty.id
@ -77,8 +66,7 @@ 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:
@ -91,9 +79,6 @@ class Handlers:
# 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
@ -107,7 +92,6 @@ class Handlers:
bulk_duty_id = Duties.filter_by_one(
company_id=selected_company.id,
duties_id=bulk_id.id,
**Duties.valid_record_dict,
db=db,
).data
@ -125,7 +109,6 @@ class Handlers:
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
@ -143,7 +126,6 @@ class Handlers:
@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(
@ -162,9 +144,6 @@ class Handlers:
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,
@ -208,7 +187,6 @@ class Handlers:
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
@ -227,25 +205,7 @@ class Handlers:
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}
context_retriever: Union[ContextRetrievers] = None
@classmethod # Requires no auth context
def authentication_login_with_domain_and_creds(cls, request: Request, data: Any):
@ -275,6 +235,32 @@ class AuthenticationFunctions:
code="LOGIN_SUCCESS", lang=user_login_module.language
).as_dict(data=user_login_module.as_dict)
@classmethod # Requires auth context
def authentication_select_company_or_occupant_type(cls, data: Any):
"""
Handle selection of company or occupant type
{"data": {"build_living_space_uu_id": ""}} | {"data": {"company_uu_id": ""}}
"""
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
):
return EndpointSuccessResponse(
code="LOGIN_SELECT", lang=cls.context_retriever.token.lang
).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
):
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}
@classmethod # Requires not auth context
def authentication_check_token_is_valid(cls, data: Any):
"""Check if token is valid for user"""

View File

@ -1,5 +1,9 @@
from pydantic import BaseModel
from ApiLayers.ApiValidations.Request import Login
from ApiLayers.ApiValidations.Request import (
Login,
EmployeeSelection,
OccupantSelection,
)
class LoginSuperUserRequestModel(Login):
@ -33,12 +37,15 @@ class OccupantSelectionSuperUserRequestModel(BaseModel):
class OccupantSelectionSuperUserResponseModel(BaseModel):
pass
"""
EmployeeSelection,
OccupantSelection,
"""
class AuthenticationRequestModels:
LoginSuperUserRequestModel = LoginSuperUserRequestModel
SelectCompanyOrOccupantTypeSuperUserRequestModel = (
SelectCompanyOrOccupantTypeSuperUserRequestModel
)
SelectCompanyOrOccupantTypeSuperUserRequestModel = {
"EmployeeSelection": EmployeeSelection, "OccupantSelection":OccupantSelection
}
EmployeeSelectionSuperUserRequestModel = EmployeeSelectionSuperUserRequestModel
OccupantSelectionSuperUserRequestModel = OccupantSelectionSuperUserRequestModel

View File

@ -181,7 +181,7 @@ class SetItems2Redis:
self.std_out += f"\n{RedisCategoryKeys.ENDPOINT2CLASS}: {dict_prep.get(RedisCategoryKeys.ENDPOINT2CLASS)}\n"
RedisActions.set_json(
list_keys=[f"{RedisCategoryKeys.REBUILD}:*"],
list_keys=[f"{RedisCategoryKeys.REBUILD}"],
value={
f"{RedisCategoryKeys.MENU_FIRST_LAYER}": True,
f"{RedisCategoryKeys.CLUSTER_INDEX}": True,

View File

@ -52,11 +52,7 @@ class ContextRetrievers:
@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
return getattr(self.func, self.key, None)
@property
def request(self) -> Union[Any, None]:

View File

@ -2,11 +2,13 @@ from typing import Optional
from uuid import UUID
from pydantic import field_validator
from ApiLayers.AllConfigs.Redis.configs import RedisAuthKeys
from Services.Redis.Models.row import BaseRedisModel
class AccessToken(BaseRedisModel):
auth_key: Optional[str] = RedisAuthKeys.AUTH
accessToken: Optional[str] = None
userUUID: Optional[str | UUID] = None
@ -19,7 +21,7 @@ class AccessToken(BaseRedisModel):
def to_list(self):
"""Convert to list for Redis storage."""
return [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):

View File

@ -29,9 +29,7 @@ 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):
@ -49,7 +47,6 @@ class RedisResponse:
@property
def count(self) -> int:
print()
row = self.all
if isinstance(row, list):
return len(row)
@ -57,13 +54,13 @@ class RedisResponse:
return 1
@property
def first(self) -> Union[RedisRow, None]:
def first(self) -> Union[RedisRow, dict, None]:
if self.data:
if isinstance(self.data, list):
if isinstance(self.data[0], RedisRow):
return self.data[0].row
return self.data[0]
elif isinstance(self.data, RedisRow):
return self.row
return self.data.row
self.status = False
return