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