base context for wrappers updated
This commit is contained in:
parent
61229cb761
commit
628f6bd483
|
|
@ -19,7 +19,7 @@ class ApiStatic:
|
|||
class Auth:
|
||||
ACCESS_EMAIL_EXT = "evyos.com.tr"
|
||||
ACCESS_TOKEN_TAG = "evyos-session-key"
|
||||
REFRESHER_TOKEN_TAG = "eys_token_refresher"
|
||||
REFRESHER_TOKEN_TAG = "eys-session-refresher"
|
||||
SECRET_KEY_72 = (
|
||||
"t3sUAmjTGeTgDc6dAUrB41u2SNg0ZHzj4HTjem95y3fRH1nZXOHIBj163kib6iLybT0gLaxq"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -8,10 +8,22 @@ from typing import TYPE_CHECKING, Union, Dict, Any
|
|||
from ApiEvents.abstract_class import MethodToEvent
|
||||
from ApiEvents.base_request_model import DictRequestModel, SuccessResponse
|
||||
from ApiLibrary.common.line_number import get_line_number_for_error
|
||||
from ApiLibrary.date_time_actions.date_functions import DateTimeLocal
|
||||
from ApiServices.Login.user_login_handler import UserLoginModule
|
||||
from ApiServices.Token.token_handler import AccessToken, TokenService
|
||||
from ApiValidations.Request.authentication import EmployeeSelectionValidation, Login, OccupantSelectionValidation
|
||||
from ApiServices.Token.token_handler import TokenService
|
||||
from ApiValidations.Custom.token_objects import CompanyToken
|
||||
from ApiValidations.Request.authentication import (
|
||||
Login,
|
||||
EmployeeSelectionValidation,
|
||||
OccupantSelectionValidation, OccupantSelection, EmployeeSelection,
|
||||
)
|
||||
from ErrorHandlers import HTTPExceptionApi
|
||||
from Schemas.company.company import Companies
|
||||
from Schemas.company.department import Departments, Duties, Duty
|
||||
from Schemas.company.employee import Staff, Employees
|
||||
from Schemas.event.event import Event2Employee
|
||||
from Schemas.identity.identity import Users
|
||||
from Services.Redis.Actions.actions import RedisActions
|
||||
from .models import (
|
||||
LoginData,
|
||||
LoginRequestModel,
|
||||
|
|
@ -27,7 +39,10 @@ from .models import (
|
|||
|
||||
if TYPE_CHECKING:
|
||||
from fastapi import Request
|
||||
from ApiServices.Token.token_handler import OccupantTokenObject, EmployeeTokenObject
|
||||
from ApiServices.Token.token_handler import (
|
||||
OccupantTokenObject,
|
||||
EmployeeTokenObject
|
||||
)
|
||||
|
||||
# Type aliases for common types
|
||||
TokenDictType = Union["EmployeeTokenObject", "OccupantTokenObject"]
|
||||
|
|
@ -69,7 +84,7 @@ class AuthenticationLoginEventMethods(MethodToEvent):
|
|||
|
||||
# Return response with token and headers
|
||||
return {
|
||||
"token": token,
|
||||
**token,
|
||||
"headers": dict(request.headers),
|
||||
}
|
||||
|
||||
|
|
@ -89,18 +104,113 @@ class AuthenticationSelectEventMethods(MethodToEvent):
|
|||
@classmethod
|
||||
def _handle_employee_selection(
|
||||
cls,
|
||||
data: SelectionDataEmployee,
|
||||
data: EmployeeSelection,
|
||||
token_dict: TokenDictType,
|
||||
request: "Request",
|
||||
):
|
||||
raise HTTPExceptionApi(
|
||||
error_code="", lang="en", loc=get_line_number_for_error()
|
||||
Users.set_user_define_properties(token=token_dict)
|
||||
db_session = Users.new_session()
|
||||
|
||||
if data.company_uu_id not in token_dict.companies_uu_id_list:
|
||||
raise HTTPExceptionApi(
|
||||
error_code="HTTP_400_BAD_REQUEST",
|
||||
lang=token_dict.lang,
|
||||
loc=get_line_number_for_error(),
|
||||
sys_msg="Company not found in token"
|
||||
)
|
||||
selected_company = Companies.filter_one(
|
||||
Companies.uu_id == data.company_uu_id,
|
||||
db=db_session,
|
||||
).first
|
||||
if not selected_company:
|
||||
raise HTTPExceptionApi(
|
||||
error_code="HTTP_400_BAD_REQUEST",
|
||||
lang=token_dict.lang,
|
||||
loc=get_line_number_for_error(),
|
||||
sys_msg="Company not found in token"
|
||||
)
|
||||
|
||||
# Get department IDs for the company
|
||||
department_ids = [
|
||||
dept.id
|
||||
for dept in Departments.filter_all(
|
||||
Departments.company_id == selected_company.id,
|
||||
db=db_session,
|
||||
).data
|
||||
]
|
||||
|
||||
# Get duties IDs for the company
|
||||
duties_ids = [
|
||||
duty.id
|
||||
for duty in Duties.filter_all(Duties.company_id == selected_company.id, db=db_session).data
|
||||
]
|
||||
|
||||
# Get staff IDs
|
||||
staff_ids = [
|
||||
staff.id for staff in Staff.filter_all(Staff.duties_id.in_(duties_ids), db=db_session).data
|
||||
]
|
||||
|
||||
# Get employee
|
||||
employee = Employees.filter_one(
|
||||
Employees.people_id == token_dict.person_id,
|
||||
Employees.staff_id.in_(staff_ids),
|
||||
db=db_session,
|
||||
).first
|
||||
|
||||
if not employee:
|
||||
raise HTTPExceptionApi(
|
||||
error_code="HTTP_400_BAD_REQUEST",
|
||||
lang=token_dict.lang,
|
||||
loc=get_line_number_for_error(),
|
||||
sys_msg="Employee not found in token"
|
||||
)
|
||||
|
||||
# Get reachable events
|
||||
reachable_event_list_id = Event2Employee.get_event_id_by_employee_id(
|
||||
employee_id=employee.id
|
||||
)
|
||||
|
||||
# Get staff and duties
|
||||
staff = Staff.filter_one(Staff.id == employee.staff_id, db=db_session).data
|
||||
duties = Duties.filter_one(Duties.id == staff.duties_id, db=db_session).data
|
||||
department = Departments.filter_one(Departments.id == duties.department_id, db=db_session).data
|
||||
|
||||
# Get bulk duty
|
||||
bulk_id = Duty.filter_by_one(system=True, duty_code="BULK", db=db_session).data
|
||||
bulk_duty_id = Duties.filter_by_one(
|
||||
company_id=selected_company.id,
|
||||
duties_id=bulk_id.id,
|
||||
**Duties.valid_record_dict,
|
||||
db=db_session,
|
||||
).data
|
||||
|
||||
# Create company token
|
||||
company_token = CompanyToken(
|
||||
company_uu_id=selected_company.uu_id.__str__(),
|
||||
company_id=selected_company.id,
|
||||
department_id=department.id,
|
||||
department_uu_id=department.uu_id.__str__(),
|
||||
duty_id=duties.id,
|
||||
duty_uu_id=duties.uu_id.__str__(),
|
||||
bulk_duties_id=bulk_duty_id.id,
|
||||
staff_id=staff.id,
|
||||
staff_uu_id=staff.uu_id.__str__(),
|
||||
employee_id=employee.id,
|
||||
employee_uu_id=employee.uu_id.__str__(),
|
||||
reachable_event_list_id=reachable_event_list_id,
|
||||
)
|
||||
try: # Update Redis
|
||||
update_token = TokenService.update_token_at_redis(request=request, add_payload=company_token)
|
||||
return update_token
|
||||
except Exception as e:
|
||||
raise HTTPExceptionApi(
|
||||
error_code="", lang="en", loc=get_line_number_for_error(), sys_msg=f"{e}"
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def _handle_occupant_selection(
|
||||
cls,
|
||||
data: SelectionDataOccupant,
|
||||
data: OccupantSelection,
|
||||
token_dict: TokenDictType,
|
||||
request: "Request",
|
||||
):
|
||||
|
|
@ -116,25 +226,22 @@ class AuthenticationSelectEventMethods(MethodToEvent):
|
|||
async def authentication_select_company_or_occupant_type(
|
||||
cls,
|
||||
request: "Request",
|
||||
data: Union[EmployeeSelectionValidation, OccupantSelectionValidation],
|
||||
data: Union[EmployeeSelection, OccupantSelection],
|
||||
token_dict: TokenDictType,
|
||||
):
|
||||
"""Handle selection of company or occupant type"""
|
||||
try:
|
||||
print(
|
||||
dict(
|
||||
data=data,
|
||||
token_dict=token_dict.model_dump(),
|
||||
request=dict(request.headers)
|
||||
)
|
||||
)
|
||||
except Exception as e:
|
||||
raise HTTPExceptionApi(
|
||||
error_code="HTTP_500_INTERNAL_SERVER_ERROR",
|
||||
lang="en",
|
||||
loc=get_line_number_for_error(),
|
||||
sys_msg=str(e),
|
||||
)
|
||||
if token_dict.is_employee:
|
||||
return cls._handle_employee_selection(data, token_dict, request)
|
||||
elif token_dict.is_occupant:
|
||||
return cls._handle_occupant_selection(data, token_dict, request)
|
||||
|
||||
# except Exception as e:
|
||||
# raise HTTPExceptionApi(
|
||||
# error_code="HTTP_500_INTERNAL_SERVER_ERROR",
|
||||
# lang="en",
|
||||
# loc=get_line_number_for_error(),
|
||||
# sys_msg=str(e),
|
||||
# )
|
||||
|
||||
|
||||
class AuthenticationCheckTokenEventMethods(MethodToEvent):
|
||||
|
|
|
|||
|
|
@ -5,7 +5,16 @@ Authentication endpoint configurations.
|
|||
from typing import TYPE_CHECKING, Dict, Any, Union, Annotated
|
||||
from fastapi import HTTPException, status, Body
|
||||
|
||||
from ApiValidations.Request.authentication import Login
|
||||
from ApiValidations.Request import (
|
||||
Logout,
|
||||
Login,
|
||||
Remember,
|
||||
Forgot,
|
||||
CreatePassword,
|
||||
ChangePassword,
|
||||
OccupantSelection,
|
||||
EmployeeSelection,
|
||||
)
|
||||
|
||||
from .auth import (
|
||||
AuthenticationChangePasswordEventMethods,
|
||||
|
|
@ -32,7 +41,7 @@ from .models import (
|
|||
SelectionDataOccupant,
|
||||
RememberRequestModel,
|
||||
)
|
||||
from ApiEvents.base_request_model import DictRequestModel
|
||||
from ApiEvents.base_request_model import DictRequestModel, EndpointBaseRequestModel
|
||||
from ApiEvents.abstract_class import RouteFactoryConfig, EndpointFactoryConfig, endpoint_wrapper
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
|
@ -41,30 +50,27 @@ from ApiValidations.Custom.token_objects import EmployeeTokenObject, OccupantTok
|
|||
|
||||
|
||||
# Type aliases for common types
|
||||
TokenDictType = Union[EmployeeTokenObject, OccupantTokenObject]
|
||||
|
||||
|
||||
@endpoint_wrapper("/authentication/select")
|
||||
async def authentication_select_company_or_occupant_type(
|
||||
request: "Request",
|
||||
data: Union[SelectionDataEmployee, SelectionDataOccupant],
|
||||
token_dict: TokenDictType = None
|
||||
data: EndpointBaseRequestModel,
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Handle selection of company or occupant type.
|
||||
|
||||
Args:
|
||||
request: The FastAPI request object
|
||||
data: Selection request data
|
||||
|
||||
Returns:
|
||||
Dict containing the response data
|
||||
Select company or occupant type.
|
||||
"""
|
||||
return {
|
||||
"headers": dict(request.headers),
|
||||
"data": data,
|
||||
"token": token_dict
|
||||
}
|
||||
auth_dict = authentication_select_company_or_occupant_type.auth
|
||||
if data.data.get("company_uu_id"):
|
||||
data = EmployeeSelection(**data.data)
|
||||
elif data.data.get("build_living_space_uu_id"):
|
||||
data = OccupantSelection(**data.data)
|
||||
if r := await AuthenticationSelectEventMethods.authentication_select_company_or_occupant_type(
|
||||
request=request, data=data, token_dict=auth_dict
|
||||
):
|
||||
if isinstance(data, EmployeeSelection):
|
||||
return {"selected_company": data.company_uu_id}
|
||||
elif isinstance(data, OccupantSelection):
|
||||
return {"selected_occupant": data.build_living_space_uu_id}
|
||||
|
||||
|
||||
@endpoint_wrapper("/authentication/login")
|
||||
|
|
@ -75,7 +81,7 @@ async def authentication_login_with_domain_and_creds(
|
|||
"""
|
||||
Authenticate user with domain and credentials.
|
||||
"""
|
||||
return AuthenticationLoginEventMethods.authentication_login_with_domain_and_creds(
|
||||
return await AuthenticationLoginEventMethods.authentication_login_with_domain_and_creds(
|
||||
request=request, data=data
|
||||
)
|
||||
|
||||
|
|
@ -83,13 +89,14 @@ async def authentication_login_with_domain_and_creds(
|
|||
@endpoint_wrapper("/authentication/check")
|
||||
async def authentication_check_token_is_valid(
|
||||
request: "Request",
|
||||
data: DictRequestModel,
|
||||
data: EndpointBaseRequestModel,
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Check if a token is valid.
|
||||
"""
|
||||
return {
|
||||
"status": "OK",
|
||||
"headers": dict(request.headers),
|
||||
"data": data.model_dump(),
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -97,8 +104,7 @@ async def authentication_check_token_is_valid(
|
|||
@endpoint_wrapper("/authentication/refresh")
|
||||
async def authentication_refresh_user_info(
|
||||
request: "Request",
|
||||
data: DictRequestModel,
|
||||
token_dict: TokenDictType = None,
|
||||
data: EndpointBaseRequestModel,
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Refresh user information.
|
||||
|
|
@ -111,8 +117,7 @@ async def authentication_refresh_user_info(
|
|||
@endpoint_wrapper("/authentication/change-password")
|
||||
async def authentication_change_password(
|
||||
request: "Request",
|
||||
data: ChangePasswordRequestModel,
|
||||
token_dict: TokenDictType = None,
|
||||
data: EndpointBaseRequestModel,
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Change user password.
|
||||
|
|
@ -125,7 +130,7 @@ async def authentication_change_password(
|
|||
@endpoint_wrapper("/authentication/create-password")
|
||||
async def authentication_create_password(
|
||||
request: "Request",
|
||||
data: CreatePasswordRequestModel,
|
||||
data: EndpointBaseRequestModel,
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Create new password.
|
||||
|
|
@ -137,7 +142,7 @@ async def authentication_create_password(
|
|||
@endpoint_wrapper("/authentication/forgot-password")
|
||||
async def authentication_forgot_password(
|
||||
request: "Request",
|
||||
data: ForgotRequestModel,
|
||||
data: EndpointBaseRequestModel,
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Handle forgot password request.
|
||||
|
|
@ -149,7 +154,7 @@ async def authentication_forgot_password(
|
|||
@endpoint_wrapper("/authentication/reset-password")
|
||||
async def authentication_reset_password(
|
||||
request: "Request",
|
||||
data: ForgotRequestModel,
|
||||
data: EndpointBaseRequestModel,
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Reset password.
|
||||
|
|
@ -161,8 +166,7 @@ async def authentication_reset_password(
|
|||
@endpoint_wrapper("/authentication/disconnect")
|
||||
async def authentication_disconnect_user(
|
||||
request: "Request",
|
||||
data: LogoutRequestModel,
|
||||
token_dict: TokenDictType = None,
|
||||
data: EndpointBaseRequestModel,
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Disconnect user.
|
||||
|
|
@ -175,8 +179,7 @@ async def authentication_disconnect_user(
|
|||
@endpoint_wrapper("/authentication/logout")
|
||||
async def authentication_logout_user(
|
||||
request: "Request",
|
||||
data: LogoutRequestModel,
|
||||
token_dict: TokenDictType = None,
|
||||
data: EndpointBaseRequestModel,
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Logout user.
|
||||
|
|
@ -189,8 +192,7 @@ async def authentication_logout_user(
|
|||
@endpoint_wrapper("/authentication/remember")
|
||||
async def authentication_refresher_token(
|
||||
request: "Request",
|
||||
data: RememberRequestModel,
|
||||
token_dict: TokenDictType = None,
|
||||
data: EndpointBaseRequestModel,
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Refresh remember token.
|
||||
|
|
@ -203,8 +205,7 @@ async def authentication_refresher_token(
|
|||
@endpoint_wrapper("/authentication/avatar")
|
||||
async def authentication_download_avatar(
|
||||
request: "Request",
|
||||
data: DictRequestModel,
|
||||
token_dict: TokenDictType = None,
|
||||
data: EndpointBaseRequestModel,
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Download user avatar.
|
||||
|
|
|
|||
|
|
@ -127,12 +127,12 @@ class CreatePasswordRequestModel(BaseRequestModel[CreatePasswordData]):
|
|||
)
|
||||
|
||||
|
||||
class SelectionDataOccupant(TypedDict):
|
||||
class SelectionDataOccupant(BaseModel):
|
||||
"""Type for selection data."""
|
||||
build_living_space_uu_id: Optional[str]
|
||||
|
||||
|
||||
class SelectionDataEmployee(TypedDict):
|
||||
class SelectionDataEmployee(BaseModel):
|
||||
"""Type for selection data."""
|
||||
company_uu_id: Optional[str]
|
||||
|
||||
|
|
|
|||
|
|
@ -4,18 +4,16 @@ Account records endpoint configurations.
|
|||
"""
|
||||
|
||||
from ApiEvents.abstract_class import RouteFactoryConfig, EndpointFactoryConfig, endpoint_wrapper
|
||||
from ApiEvents.base_request_model import DictRequestModel
|
||||
|
||||
from ApiEvents.base_request_model import EndpointBaseRequestModel
|
||||
|
||||
from Services.PostgresDb.Models.alchemy_response import DictJsonResponse
|
||||
from fastapi import Request, Path, Body
|
||||
|
||||
from .models import ListOptionsRequestModel
|
||||
|
||||
|
||||
@endpoint_wrapper("/account/records/address/list")
|
||||
async def address_list(request: "Request", data: ListOptionsRequestModel):
|
||||
async def address_list(request: "Request", data: EndpointBaseRequestModel):
|
||||
"""Handle address list endpoint."""
|
||||
auth_dict = address_list.auth
|
||||
return {
|
||||
"data": data,
|
||||
"request": str(request.headers),
|
||||
|
|
@ -25,7 +23,7 @@ async def address_list(request: "Request", data: ListOptionsRequestModel):
|
|||
|
||||
|
||||
@endpoint_wrapper("/account/records/address/create")
|
||||
async def address_create(request: "Request", data: DictRequestModel):
|
||||
async def address_create(request: "Request", data: EndpointBaseRequestModel):
|
||||
"""Handle address creation endpoint."""
|
||||
return {
|
||||
"data": data,
|
||||
|
|
@ -36,16 +34,18 @@ async def address_create(request: "Request", data: DictRequestModel):
|
|||
|
||||
|
||||
@endpoint_wrapper("/account/records/address/search")
|
||||
async def address_search(request: "Request", data: DictRequestModel):
|
||||
async def address_search(request: "Request", data: EndpointBaseRequestModel):
|
||||
"""Handle address search endpoint."""
|
||||
return {"data": data}
|
||||
auth_dict = address_search.auth
|
||||
code_dict = getattr(address_search, 'func_code', {"function_code": None})
|
||||
return {"auth_dict": auth_dict, "code_dict": code_dict, "data": data}
|
||||
|
||||
|
||||
@endpoint_wrapper("/account/records/address/{address_uu_id}")
|
||||
async def address_update(
|
||||
request: Request,
|
||||
address_uu_id: str = Path(..., description="UUID of the address to update"),
|
||||
request_data: DictRequestModel = Body(..., description="Request body"),
|
||||
request_data: EndpointBaseRequestModel = Body(..., description="Request body"),
|
||||
):
|
||||
"""
|
||||
Handle address update endpoint.
|
||||
|
|
@ -58,6 +58,7 @@ async def address_update(
|
|||
Returns:
|
||||
DictJsonResponse: Response containing updated address info
|
||||
"""
|
||||
auth_dict = address_update.auth
|
||||
return DictJsonResponse(
|
||||
data={
|
||||
"address_uu_id": address_uu_id,
|
||||
|
|
|
|||
|
|
@ -49,15 +49,15 @@ def endpoint_wrapper(url_of_endpoint: Optional[str] = None):
|
|||
# If result is a coroutine, await it
|
||||
if inspect.iscoroutine(result):
|
||||
result = await result
|
||||
|
||||
# Add function_code to the result
|
||||
print('result', result)
|
||||
# Add endpoint to the result
|
||||
if isinstance(result, dict):
|
||||
result["function_code"] = url_of_endpoint
|
||||
result["endpoint"] = url_of_endpoint
|
||||
return result
|
||||
elif isinstance(result, BaseModel):
|
||||
# Convert Pydantic model to dict and add function_code
|
||||
# Convert Pydantic model to dict and add endpoint
|
||||
result_dict = result.model_dump()
|
||||
result_dict["function_code"] = url_of_endpoint
|
||||
result_dict["endpoint"] = url_of_endpoint
|
||||
return result_dict
|
||||
return result
|
||||
|
||||
|
|
@ -107,24 +107,23 @@ class EndpointFactoryConfig:
|
|||
- If only event required -> wrap with EventMiddleware
|
||||
- If only auth required -> wrap with MiddlewareModule.auth_required
|
||||
"""
|
||||
# Wrap the endpoint function to store url_of_endpoint
|
||||
self.endpoint_function = endpoint_wrapper(self.url_of_endpoint)(
|
||||
self.endpoint_function
|
||||
)
|
||||
|
||||
if self.is_auth_required and self.is_event_required:
|
||||
# First apply auth/event middleware
|
||||
if self.is_event_required:
|
||||
from middleware import TokenEventMiddleware
|
||||
|
||||
self.endpoint_function = TokenEventMiddleware.event_required(
|
||||
self.endpoint_function
|
||||
)
|
||||
elif self.is_auth_required:
|
||||
from middleware import MiddlewareModule
|
||||
|
||||
self.endpoint_function = MiddlewareModule.auth_required(
|
||||
self.endpoint_function
|
||||
)
|
||||
|
||||
# Then wrap with endpoint_wrapper to store url_of_endpoint
|
||||
self.endpoint_function = endpoint_wrapper(self.url_of_endpoint)(
|
||||
self.endpoint_function
|
||||
)
|
||||
|
||||
|
||||
class RouteFactoryConfig:
|
||||
"""Configuration class for API route factories.
|
||||
|
|
|
|||
|
|
@ -12,10 +12,21 @@ from pydantic import BaseModel, Field, ConfigDict, RootModel
|
|||
T = TypeVar("T")
|
||||
|
||||
|
||||
class EndpointBaseRequestModel(BaseModel):
|
||||
|
||||
data: dict = Field(..., description="Data to be sent with the request")
|
||||
class Config:
|
||||
json_schema_extra = {
|
||||
"data": {
|
||||
"key": "value",
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class BaseRequestModel(RootModel[T], Generic[T]):
|
||||
"""Base model for all API requests."""
|
||||
model_config = ConfigDict(
|
||||
json_schema_extra={"example": {}} # Will be populated by subclasses
|
||||
json_schema_extra={"example": {"base": "example"}} # Will be populated by subclasses
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -8,12 +8,14 @@ from ApiLibrary.common.line_number import get_line_number_for_error
|
|||
from ApiLibrary.date_time_actions.date_functions import DateTimeLocal
|
||||
from ApiLibrary.token.password_module import PasswordModule
|
||||
from ErrorHandlers import HTTPExceptionApi
|
||||
from Schemas.identity.identity import UsersTokens
|
||||
from Schemas.identity.identity import UsersTokens, People
|
||||
from Services.Redis import RedisActions, AccessToken
|
||||
from ApiValidations.Custom.token_objects import (
|
||||
EmployeeTokenObject,
|
||||
OccupantTokenObject,
|
||||
UserType,
|
||||
CompanyToken,
|
||||
OccupantToken,
|
||||
)
|
||||
from Schemas import (
|
||||
Users,
|
||||
|
|
@ -37,6 +39,7 @@ if TYPE_CHECKING:
|
|||
T = TypeVar("T", EmployeeTokenObject, OccupantTokenObject)
|
||||
|
||||
|
||||
|
||||
class TokenService:
|
||||
"""Service class for handling authentication tokens and user sessions."""
|
||||
|
||||
|
|
@ -128,22 +131,57 @@ class TokenService:
|
|||
timezone=user.local_timezone or "GMT+0",
|
||||
lang=user.lang or "tr",
|
||||
).model_dump()
|
||||
cls.set_object_to_redis(user, model_value)
|
||||
return {
|
||||
"user_type": UserType.occupant.name,
|
||||
"available_occupants": occupants_selection_dict,
|
||||
}
|
||||
if access_token := cls.set_object_to_redis(user, model_value):
|
||||
return {
|
||||
"access_token": access_token,
|
||||
"user_type": UserType.occupant.name,
|
||||
"available_occupants": occupants_selection_dict,
|
||||
}
|
||||
raise HTTPExceptionApi(
|
||||
error_code="",
|
||||
lang="en",
|
||||
loc=get_line_number_for_error(),
|
||||
sys_msg="Creating Token failed...",
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def set_object_to_redis(cls, user, model: Dict):
|
||||
accessObject = AccessToken(
|
||||
access_object = AccessToken(
|
||||
userUUID=user.uu_id,
|
||||
accessToken=cls._create_access_token(),
|
||||
)
|
||||
return RedisActions.set_json(
|
||||
list_keys=accessObject.to_list(),
|
||||
value=json.dumps(model),
|
||||
expires=Auth.TOKEN_EXPIRE_MINUTES_30.seconds,
|
||||
redis_action = RedisActions.set_json(
|
||||
list_keys=access_object.to_list(),
|
||||
value=model,
|
||||
expires={"seconds": int(Auth.TOKEN_EXPIRE_MINUTES_30.seconds)},
|
||||
)
|
||||
if redis_action.status:
|
||||
return access_object.accessToken
|
||||
raise HTTPExceptionApi(
|
||||
error_code="",
|
||||
lang="en",
|
||||
loc=get_line_number_for_error(),
|
||||
sys_msg="Saving Token failed...",
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def update_object_to_redis(cls, access_token: str, user_uu_id: str, model: Dict):
|
||||
access_object = AccessToken(
|
||||
userUUID=user_uu_id,
|
||||
accessToken=access_token,
|
||||
)
|
||||
redis_action = RedisActions.set_json(
|
||||
list_keys=access_object.to_list(),
|
||||
value=model,
|
||||
expires={"seconds": int(Auth.TOKEN_EXPIRE_MINUTES_30.seconds)},
|
||||
)
|
||||
if redis_action.status:
|
||||
return access_object.accessToken
|
||||
raise HTTPExceptionApi(
|
||||
error_code="",
|
||||
lang="en",
|
||||
loc=get_line_number_for_error(),
|
||||
sys_msg="Saving Token failed...",
|
||||
)
|
||||
|
||||
@classmethod
|
||||
|
|
@ -194,15 +232,17 @@ class TokenService:
|
|||
"company_address": company_address,
|
||||
}
|
||||
)
|
||||
|
||||
person = People.filter_one(
|
||||
People.id == user.person_id, db=db_session
|
||||
).data
|
||||
model_value = EmployeeTokenObject(
|
||||
domain=domain,
|
||||
user_type=UserType.employee.value,
|
||||
user_uu_id=str(user.uu_id),
|
||||
credentials=user.credentials(),
|
||||
user_id=user.id,
|
||||
person_id=user.person_id,
|
||||
person_uu_id=str(user.person.uu_id),
|
||||
person_id=person.id,
|
||||
person_uu_id=str(person.uu_id),
|
||||
request=dict(request.headers),
|
||||
companies_uu_id_list=companies_uu_id_list,
|
||||
companies_id_list=companies_id_list,
|
||||
|
|
@ -211,8 +251,9 @@ class TokenService:
|
|||
timezone=user.local_timezone or "GMT+0",
|
||||
lang=user.lang or "tr",
|
||||
).model_dump()
|
||||
if cls.set_object_to_redis(user, model_value):
|
||||
if access_token := cls.set_object_to_redis(user, model_value):
|
||||
return {
|
||||
"access_token": access_token,
|
||||
"user_type": UserType.employee.name,
|
||||
"companies_list": companies_list,
|
||||
}
|
||||
|
|
@ -228,7 +269,8 @@ class TokenService:
|
|||
"""Remove all tokens for a user with specific domain."""
|
||||
redis_rows = cls._get_user_tokens(user)
|
||||
for redis_row in redis_rows.all:
|
||||
if redis_row.get("domain") == domain:
|
||||
print('redis_row', redis_row.data)
|
||||
if redis_row.data.get("domain") == domain:
|
||||
RedisActions.delete_key(redis_row.key)
|
||||
|
||||
@classmethod
|
||||
|
|
@ -291,6 +333,36 @@ class TokenService:
|
|||
"user": user.get_dict(),
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def update_token_at_redis(
|
||||
cls, request: "Request", add_payload: Union[CompanyToken, OccupantToken]
|
||||
) -> Dict[str, Any]:
|
||||
"""Update token at Redis."""
|
||||
access_token = cls.get_access_token_from_request(request=request)
|
||||
token_object = cls.get_object_via_access_key(access_token=access_token)
|
||||
if isinstance(token_object, EmployeeTokenObject) and isinstance(add_payload, CompanyToken):
|
||||
token_object.selected_company = add_payload
|
||||
cls.update_object_to_redis(
|
||||
access_token=access_token,
|
||||
user_uu_id=token_object.user_uu_id,
|
||||
model=token_object.model_dump()
|
||||
)
|
||||
return token_object.selected_company.model_dump()
|
||||
elif isinstance(token_object, OccupantTokenObject) and isinstance(add_payload, OccupantToken):
|
||||
token_object.selected_occupant = add_payload
|
||||
cls.update_object_to_redis(
|
||||
access_token=access_token,
|
||||
user_uu_id=token_object.user_uu_id,
|
||||
model=token_object.model_dump()
|
||||
)
|
||||
return token_object.selected_occupant.model_dump()
|
||||
raise HTTPExceptionApi(
|
||||
error_code="",
|
||||
lang="en",
|
||||
loc=get_line_number_for_error(),
|
||||
sys_msg="Token not found",
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def raise_error_if_request_has_no_token(cls, request: "Request") -> None:
|
||||
"""Validate request has required token headers."""
|
||||
|
|
@ -330,7 +402,6 @@ class TokenService:
|
|||
redis_object["selected_company"] = None
|
||||
if not redis_object.get("selected_occupant"):
|
||||
redis_object["selected_occupant"] = None
|
||||
|
||||
if redis_object.get("user_type") == UserType.employee.value:
|
||||
return EmployeeTokenObject(**redis_object)
|
||||
elif redis_object.get("user_type") == UserType.occupant.value:
|
||||
|
|
@ -348,17 +419,17 @@ class TokenService:
|
|||
"""Get token object using access key."""
|
||||
access_token_obj = AccessToken(accessToken=access_token)
|
||||
redis_response = RedisActions.get_json(list_keys=access_token_obj.to_list())
|
||||
|
||||
if redis_object := redis_response.first.data:
|
||||
access_token_obj.userUUID = redis_object.get("user_uu_id")
|
||||
return cls._process_redis_object(redis_object)
|
||||
|
||||
raise HTTPExceptionApi(
|
||||
error_code="",
|
||||
lang="en",
|
||||
loc=get_line_number_for_error(),
|
||||
sys_msg="Invalid access token",
|
||||
)
|
||||
if not redis_response.status:
|
||||
raise HTTPExceptionApi(
|
||||
error_code="",
|
||||
lang="en",
|
||||
loc=get_line_number_for_error(),
|
||||
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)
|
||||
|
||||
@classmethod
|
||||
def get_object_via_user_uu_id(cls, user_id: str) -> T:
|
||||
|
|
|
|||
|
|
@ -91,7 +91,15 @@ class OccupantTokenObject(ApplicationToken):
|
|||
available_occupants: dict = None
|
||||
|
||||
selected_occupant: Optional[OccupantToken] = None # Selected Occupant Type
|
||||
available_event: Optional[Any] = None
|
||||
|
||||
|
||||
@property
|
||||
def is_employee(self) -> bool:
|
||||
return False
|
||||
|
||||
@property
|
||||
def is_occupant(self) -> bool:
|
||||
return True
|
||||
|
||||
|
||||
class EmployeeTokenObject(ApplicationToken):
|
||||
|
|
@ -104,4 +112,12 @@ class EmployeeTokenObject(ApplicationToken):
|
|||
duty_uu_id_list: List[str] # List of duty objects
|
||||
|
||||
selected_company: Optional[CompanyToken] = None # Selected Company Object
|
||||
available_event: Optional[Any] = None
|
||||
|
||||
|
||||
@property
|
||||
def is_employee(self) -> bool:
|
||||
return True
|
||||
|
||||
@property
|
||||
def is_occupant(self) -> bool:
|
||||
return False
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
|
||||
|
||||
from ApiValidations.Request import BaseModelRegular
|
||||
|
||||
from typing import Optional
|
||||
|
|
@ -55,15 +57,11 @@ class OccupantSelectionValidation:
|
|||
|
||||
|
||||
class OccupantSelection(BaseModel, OccupantSelectionValidation):
|
||||
occupant_uu_id: str = Field(..., example="123e4567-e89b-12d3-a456-426614174000")
|
||||
build_part_uu_id: str = Field(..., example="987fcdeb-51a2-43e7-9876-543210987654")
|
||||
build_living_space_uu_id: str = Field(..., example="987fcdeb-51a2-43e7-9876-543210987654")
|
||||
|
||||
model_config = ConfigDict(
|
||||
json_schema_extra={
|
||||
"example": {
|
||||
"occupant_uu_id": "123e4567-e89b-12d3-a456-426614174000",
|
||||
"build_part_uu_id": "987fcdeb-51a2-43e7-9876-543210987654",
|
||||
}
|
||||
"example": {"build_living_space_uu_id": "987fcdeb-51a2-43e7-9876-543210987654"}
|
||||
}
|
||||
)
|
||||
|
||||
|
|
@ -107,10 +105,10 @@ class Login(BaseModelRegular, LoginValidation):
|
|||
model_config = ConfigDict(
|
||||
json_schema_extra={
|
||||
"example": {
|
||||
"domain": "example.com",
|
||||
"access_key": "user@example.com",
|
||||
"password": "password123",
|
||||
"remember_me": True,
|
||||
"domain": "evyos.com.tr",
|
||||
"access_key": "karatay.berkay.sup@evyos.com.tr",
|
||||
"password": "string",
|
||||
"remember_me": False
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -10,77 +10,9 @@ This module initializes and configures the FastAPI application with:
|
|||
"""
|
||||
|
||||
import uvicorn
|
||||
from fastapi import FastAPI
|
||||
from create_routes import get_all_routers
|
||||
from prometheus_fastapi_instrumentator import Instrumentator
|
||||
from app_handler import setup_middleware, get_uvicorn_config
|
||||
from create_file import setup_security_schema, configure_route_security
|
||||
from open_api_creator import OpenAPISchemaCreator, create_openapi_schema
|
||||
|
||||
|
||||
def create_app() -> FastAPI:
|
||||
"""Create and configure the FastAPI application."""
|
||||
app = FastAPI(
|
||||
responses={
|
||||
422: {
|
||||
"description": "Validation Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"detail": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"loc": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
},
|
||||
"msg": {"type": "string"},
|
||||
"type": {"type": "string"},
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
# Get all routers and protected routes from the new configuration
|
||||
routers, protected_routes = get_all_routers()
|
||||
|
||||
# Include all routers
|
||||
for router in routers:
|
||||
app.include_router(router)
|
||||
|
||||
# Configure OpenAPI schema with security
|
||||
def custom_openapi():
|
||||
if app.openapi_schema:
|
||||
return app.openapi_schema
|
||||
|
||||
# Create OpenAPI schema using our custom creator
|
||||
openapi_schema = create_openapi_schema(app)
|
||||
|
||||
# Add security scheme
|
||||
openapi_schema.update(setup_security_schema())
|
||||
|
||||
# Configure security for protected routes
|
||||
for path, methods in protected_routes.items():
|
||||
for method in methods:
|
||||
configure_route_security(
|
||||
path, method, openapi_schema, list(protected_routes.keys())
|
||||
)
|
||||
|
||||
app.openapi_schema = openapi_schema
|
||||
return app.openapi_schema
|
||||
|
||||
app.openapi = custom_openapi
|
||||
return app
|
||||
from create_file import create_app
|
||||
|
||||
|
||||
app = create_app() # Initialize FastAPI application
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ from fastapi import FastAPI, APIRouter
|
|||
from fastapi.responses import JSONResponse, RedirectResponse
|
||||
from fastapi.openapi.utils import get_openapi
|
||||
|
||||
from AllConfigs.Token.config import Auth
|
||||
from AllConfigs.main import MainConfig as Config
|
||||
|
||||
from create_routes import get_all_routers
|
||||
|
|
@ -29,11 +30,11 @@ def setup_security_schema() -> Dict[str, Any]:
|
|||
return {
|
||||
"components": {
|
||||
"securitySchemes": {
|
||||
"Bearer": {
|
||||
"type": "http",
|
||||
"scheme": "bearer",
|
||||
"bearerFormat": "JWT",
|
||||
"description": "Enter the token",
|
||||
"Bearer Auth": {
|
||||
"type": "apiKey",
|
||||
"in": "header",
|
||||
"name": Auth.ACCESS_TOKEN_TAG,
|
||||
"description": "Enter: **'Bearer <JWT>'**, where JWT is the access token",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -65,12 +66,15 @@ def create_app() -> FastAPI:
|
|||
Returns:
|
||||
FastAPI: Configured FastAPI application instance
|
||||
"""
|
||||
# Initialize FastAPI app
|
||||
|
||||
from open_api_creator import create_openapi_schema
|
||||
# Get all routers and protected routes using the dynamic route creation
|
||||
|
||||
app = FastAPI(
|
||||
title=Config.TITLE,
|
||||
description=Config.DESCRIPTION,
|
||||
default_response_class=JSONResponse,
|
||||
)
|
||||
) # Initialize FastAPI app
|
||||
|
||||
@app.get("/", include_in_schema=False, summary=str(Config.DESCRIPTION))
|
||||
async def home() -> RedirectResponse:
|
||||
|
|
@ -84,31 +88,5 @@ def create_app() -> FastAPI:
|
|||
for router in routers:
|
||||
app.include_router(router)
|
||||
|
||||
# Configure OpenAPI schema with security
|
||||
def custom_openapi():
|
||||
if app.openapi_schema:
|
||||
return app.openapi_schema
|
||||
|
||||
openapi_schema = get_openapi(
|
||||
title="WAG Management API",
|
||||
version="4.0.0",
|
||||
description="WAG Management API Service",
|
||||
routes=app.routes,
|
||||
)
|
||||
|
||||
# Add security scheme
|
||||
security_schema = setup_security_schema()
|
||||
openapi_schema.update(security_schema)
|
||||
|
||||
# Configure security for protected routes
|
||||
for path, methods in protected_routes.items():
|
||||
for method in methods:
|
||||
configure_route_security(
|
||||
path, method, openapi_schema, list(protected_routes.keys())
|
||||
)
|
||||
|
||||
app.openapi_schema = openapi_schema
|
||||
return app.openapi_schema
|
||||
|
||||
app.openapi = custom_openapi
|
||||
app.openapi = lambda app=app: create_openapi_schema(app)
|
||||
return app
|
||||
|
|
|
|||
|
|
@ -24,8 +24,6 @@ class EndpointFactoryConfig:
|
|||
summary: str
|
||||
description: str
|
||||
endpoint_function: Callable[P, R] # Now accepts any parameters and return type
|
||||
response_model: Optional[type] = None
|
||||
request_model: Optional[type] = None
|
||||
is_auth_required: bool = True
|
||||
is_event_required: bool = False
|
||||
extra_options: Dict[str, Any] = None
|
||||
|
|
@ -56,7 +54,7 @@ class EnhancedEndpointFactory:
|
|||
endpoint_function = config.endpoint_function
|
||||
|
||||
if config.is_auth_required:
|
||||
endpoint_function = MiddlewareModule.auth_required(endpoint_function)
|
||||
# endpoint_function = MiddlewareModule.auth_required(endpoint_function)
|
||||
# Track protected routes
|
||||
full_path = f"{self.router.prefix}{endpoint_path}"
|
||||
if full_path not in self.protected_routes:
|
||||
|
|
@ -66,7 +64,6 @@ class EnhancedEndpointFactory:
|
|||
# Register the endpoint with FastAPI router
|
||||
getattr(self.router, config.method.lower())(
|
||||
endpoint_path,
|
||||
response_model=config.response_model,
|
||||
summary=config.summary,
|
||||
description=config.description,
|
||||
**config.extra_options,
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ from ApiLibrary.common.line_number import get_line_number_for_error
|
|||
from ErrorHandlers.ErrorHandlers.api_exc_handler import HTTPExceptionApi
|
||||
from .base_context import BaseContext
|
||||
from ApiServices.Token.token_handler import OccupantTokenObject, EmployeeTokenObject
|
||||
import inspect
|
||||
|
||||
|
||||
class AuthContext(BaseContext):
|
||||
|
|
@ -42,7 +43,12 @@ class AuthContext(BaseContext):
|
|||
@property
|
||||
def user_id(self) -> str:
|
||||
"""Get the user's UUID from token context."""
|
||||
return self.token_context.user_uu_id if self.token_context else ""
|
||||
return self.token_context.user_uu_id if self.token_context else None
|
||||
|
||||
def as_dict(self):
|
||||
if not isinstance(self.token_context, dict):
|
||||
return self.token_context.model_dump()
|
||||
return self.token_context
|
||||
|
||||
def __repr__(self) -> str:
|
||||
user_type = "Employee" if self.is_employee else "Occupant"
|
||||
|
|
@ -57,7 +63,7 @@ class MiddlewareModule:
|
|||
@staticmethod
|
||||
def get_user_from_request(
|
||||
request: Request,
|
||||
) -> AuthContext:
|
||||
) -> dict:
|
||||
"""
|
||||
Get authenticated token context from request.
|
||||
|
||||
|
|
@ -74,7 +80,6 @@ class MiddlewareModule:
|
|||
|
||||
# Get token and validate - will raise HTTPExceptionApi if invalid
|
||||
redis_token = TokenService.get_access_token_from_request(request=request)
|
||||
|
||||
# Get token context - will validate token and raise appropriate errors
|
||||
token_context = TokenService.get_object_via_access_key(access_token=redis_token)
|
||||
if not token_context:
|
||||
|
|
@ -85,7 +90,7 @@ class MiddlewareModule:
|
|||
sys_msg="TokenService: Token Context couldnt retrieved from redis",
|
||||
)
|
||||
|
||||
return AuthContext(token_context=token_context)
|
||||
return token_context
|
||||
|
||||
@classmethod
|
||||
def auth_required(cls, func: Callable) -> Callable:
|
||||
|
|
@ -116,14 +121,13 @@ class MiddlewareModule:
|
|||
"""
|
||||
|
||||
@wraps(func)
|
||||
def wrapper(request: Request, *args, **kwargs):
|
||||
async def wrapper(request: Request, *args, **kwargs):
|
||||
# Get and validate token context from request
|
||||
auth_context = cls.get_user_from_request(request)
|
||||
|
||||
# Attach auth context to function
|
||||
func.auth = auth_context
|
||||
|
||||
# Create auth context and Attach auth context to both wrapper and original function
|
||||
func.auth = cls.get_user_from_request(request) # This ensures the context is available in both places
|
||||
# Call the original endpoint function
|
||||
if inspect.iscoroutinefunction(func):
|
||||
return await func(request, *args, **kwargs)
|
||||
return func(request, *args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
|
@ -147,7 +151,6 @@ class RequestTimingMiddleware(BaseHTTPMiddleware):
|
|||
Response: Processed response with timing headers
|
||||
"""
|
||||
start_time = perf_counter()
|
||||
|
||||
# Process the request
|
||||
response = await call_next(request)
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ from functools import wraps
|
|||
from typing import Callable, Dict, Any
|
||||
from .auth_middleware import MiddlewareModule
|
||||
from .base_context import BaseContext
|
||||
import inspect
|
||||
|
||||
|
||||
class TokenEventHandler(BaseContext):
|
||||
|
|
@ -51,26 +52,14 @@ class TokenEventMiddleware:
|
|||
authenticated_func = MiddlewareModule.auth_required(func)
|
||||
|
||||
@wraps(authenticated_func)
|
||||
def wrapper(*args, **kwargs) -> Dict[str, Any]:
|
||||
async def wrapper(*args, **kwargs) -> Dict[str, Any]:
|
||||
# Create handler with context
|
||||
handler = TokenEventHandler(
|
||||
func=authenticated_func,
|
||||
url_of_endpoint=authenticated_func.url_of_endpoint,
|
||||
)
|
||||
|
||||
# Update event-specific context
|
||||
handler.update_context(
|
||||
function_code="7192c2aa-5352-4e36-98b3-dafb7d036a3d" # Keep function_code as URL
|
||||
)
|
||||
|
||||
# Copy auth context from authenticated function
|
||||
if hasattr(authenticated_func, "auth"):
|
||||
handler.token_context = authenticated_func.auth.token_context
|
||||
|
||||
# Make handler available to the function
|
||||
authenticated_func.handler = handler
|
||||
function_code = "7192c2aa-5352-4e36-98b3-dafb7d036a3d" # Keep function_code as URL
|
||||
|
||||
# Make handler available to all functions in the chain
|
||||
func.func_code = {"function_code": function_code}
|
||||
# Call the authenticated function
|
||||
if inspect.iscoroutinefunction(authenticated_func):
|
||||
return await authenticated_func(*args, **kwargs)
|
||||
return authenticated_func(*args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ from typing import Any, Dict, List, Optional, Set
|
|||
from fastapi import FastAPI, APIRouter
|
||||
from fastapi.routing import APIRoute
|
||||
from fastapi.openapi.utils import get_openapi
|
||||
|
||||
from AllConfigs.Token.config import Auth
|
||||
from AllConfigs.main import MainConfig as Config
|
||||
from create_routes import get_all_routers
|
||||
|
||||
|
|
@ -62,17 +64,11 @@ class OpenAPISchemaCreator:
|
|||
"""
|
||||
return {
|
||||
"Bearer Auth": {
|
||||
"type": "http",
|
||||
"scheme": "bearer",
|
||||
"bearerFormat": "JWT",
|
||||
"description": "Enter the token with the `Bearer: ` prefix",
|
||||
},
|
||||
"API Key": {
|
||||
"type": "apiKey",
|
||||
"in": "header",
|
||||
"name": "X-API-Key",
|
||||
"description": "Optional API key for service authentication",
|
||||
},
|
||||
"name": Auth.ACCESS_TOKEN_TAG,
|
||||
"description": "Enter: **'Bearer <JWT>'**, where JWT is the access token",
|
||||
}
|
||||
}
|
||||
|
||||
def _create_common_responses(self) -> Dict[str, Any]:
|
||||
|
|
@ -198,7 +194,6 @@ class OpenAPISchemaCreator:
|
|||
if path in self.protected_routes and method in self.protected_routes[path]:
|
||||
schema["paths"][path][method]["security"] = [
|
||||
{"Bearer Auth": []},
|
||||
{"API Key": []},
|
||||
]
|
||||
schema["paths"][path][method]["responses"].update(
|
||||
self._create_common_responses()
|
||||
|
|
@ -219,7 +214,7 @@ class OpenAPISchemaCreator:
|
|||
openapi_schema = get_openapi(
|
||||
title=Config.TITLE,
|
||||
description=Config.DESCRIPTION,
|
||||
version="1.0.0",
|
||||
version="1.1.1",
|
||||
routes=self.app.routes,
|
||||
tags=self.tags_metadata,
|
||||
)
|
||||
|
|
@ -229,17 +224,15 @@ class OpenAPISchemaCreator:
|
|||
openapi_schema["components"] = {}
|
||||
|
||||
openapi_schema["components"]["securitySchemes"] = self._create_security_schemes()
|
||||
|
||||
# Configure route security and responses
|
||||
for route in self.app.routes:
|
||||
if isinstance(route, APIRoute) and route.include_in_schema:
|
||||
path = str(route.path)
|
||||
methods = [method.lower() for method in route.methods]
|
||||
|
||||
for method in methods:
|
||||
self.configure_route_security(path, method, openapi_schema)
|
||||
|
||||
# Add custom documentation extensions
|
||||
# # Add custom documentation extensions
|
||||
openapi_schema["x-documentation"] = {
|
||||
"postman_collection": "/docs/postman",
|
||||
"swagger_ui": "/docs",
|
||||
|
|
|
|||
|
|
@ -251,18 +251,22 @@ class Event2Employee(CrudCollection):
|
|||
|
||||
@classmethod
|
||||
def get_event_id_by_employee_id(cls, employee_id) -> list:
|
||||
db = cls.new_session()
|
||||
occupant_events = cls.filter_all(
|
||||
cls.employee_id == employee_id,
|
||||
db=db,
|
||||
).data
|
||||
active_events = Service2Events.filter_all(
|
||||
Service2Events.service_id.in_(
|
||||
[event.event_service_id for event in occupant_events]
|
||||
),
|
||||
db=db,
|
||||
system=True,
|
||||
).data
|
||||
active_events_id = [event.event_id for event in active_events]
|
||||
if extra_events := Event2EmployeeExtra.filter_all(
|
||||
Event2EmployeeExtra.employee_id == employee_id
|
||||
Event2EmployeeExtra.employee_id == employee_id,
|
||||
db=db,
|
||||
).data:
|
||||
active_events_id.extend([event.event_id for event in extra_events])
|
||||
return active_events_id
|
||||
|
|
|
|||
|
|
@ -77,12 +77,7 @@ class RedisActions:
|
|||
time=expiry_time,
|
||||
value=redis_row.value,
|
||||
)
|
||||
redis_row.expires_at = (
|
||||
arrow.now()
|
||||
.shift(seconds=expiry_time)
|
||||
.format(MainConfig.DATETIME_FORMAT)
|
||||
)
|
||||
|
||||
redis_row.expires_at = str(arrow.now().shift(seconds=expiry_time).format(MainConfig.DATETIME_FORMAT))
|
||||
else:
|
||||
redis_cli.set(name=redis_row.redis_key, value=redis_row.value)
|
||||
|
||||
|
|
@ -115,7 +110,6 @@ class RedisActions:
|
|||
list_of_rows = []
|
||||
regex = RedisRow.regex(list_keys=list_keys)
|
||||
json_get = redis_cli.scan_iter(match=regex)
|
||||
|
||||
for row in list(json_get):
|
||||
redis_row = RedisRow()
|
||||
redis_row.set_key(key=row)
|
||||
|
|
@ -123,11 +117,16 @@ class RedisActions:
|
|||
redis_value = redis_cli.get(redis_row.redis_key)
|
||||
redis_row.feed(redis_value)
|
||||
list_of_rows.append(redis_row)
|
||||
|
||||
if list_of_rows:
|
||||
return RedisResponse(
|
||||
status=True,
|
||||
message="Value is get successfully.",
|
||||
data=list_of_rows,
|
||||
)
|
||||
return RedisResponse(
|
||||
status=True,
|
||||
message="Value is get successfully.",
|
||||
data=list_of_rows,
|
||||
status=False,
|
||||
message="Value is not get successfully.",
|
||||
data=list_of_rows
|
||||
)
|
||||
except Exception as e:
|
||||
return RedisResponse(
|
||||
|
|
@ -135,3 +134,4 @@ class RedisActions:
|
|||
message="Value is not get successfully.",
|
||||
error=str(e),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ class RedisRow:
|
|||
# Filter and convert valid keys
|
||||
valid_keys = []
|
||||
for key in list_keys:
|
||||
if key is None:
|
||||
if key is None or str(key) == "None":
|
||||
continue
|
||||
if isinstance(key, bytes):
|
||||
key = key.decode()
|
||||
|
|
@ -108,7 +108,8 @@ class RedisRow:
|
|||
# Add wildcard if first key was None
|
||||
if list_keys[0] is None:
|
||||
pattern = f"*{cls.delimiter}{pattern}"
|
||||
|
||||
if '*' not in pattern:
|
||||
pattern = f"{pattern}:*"
|
||||
return pattern
|
||||
|
||||
@classmethod
|
||||
|
|
|
|||
|
|
@ -47,4 +47,7 @@ class RedisResponse:
|
|||
|
||||
@property
|
||||
def first(self) -> Union[RedisRow, None]:
|
||||
return self.data[0] if self.data else None
|
||||
if self.data:
|
||||
return self.data[0]
|
||||
self.status = False
|
||||
return
|
||||
|
|
|
|||
|
|
@ -1,23 +1,23 @@
|
|||
from typing import Optional
|
||||
from typing import Optional, Literal
|
||||
from uuid import UUID
|
||||
from pydantic import BaseModel, validator
|
||||
from pydantic import BaseModel, field_validator
|
||||
|
||||
|
||||
class AccessToken(BaseModel):
|
||||
|
||||
accessToken: Optional[str] = None
|
||||
userUUID: Optional[str] = None
|
||||
userUUID: Optional[str | UUID] = None
|
||||
|
||||
@validator("userUUID", pre=True)
|
||||
@field_validator("userUUID", mode="after")
|
||||
def validate_uuid(cls, v):
|
||||
"""Convert UUID to string during validation."""
|
||||
if isinstance(v, UUID):
|
||||
return str(v)
|
||||
return v
|
||||
if v is None:
|
||||
return None
|
||||
return str(v)
|
||||
|
||||
def to_list(self):
|
||||
"""Convert to list for Redis storage."""
|
||||
return [self.accessToken, self.userUUID]
|
||||
return [self.accessToken, str(self.userUUID) if self.userUUID else None]
|
||||
|
||||
@property
|
||||
def count(self):
|
||||
|
|
|
|||
Loading…
Reference in New Issue