events auth repair
This commit is contained in:
parent
426b69b33c
commit
61229cb761
|
|
@ -0,0 +1,9 @@
|
||||||
|
"""
|
||||||
|
Authentication package initialization.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from .endpoints import AUTH_CONFIG
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"AUTH_CONFIG",
|
||||||
|
]
|
||||||
|
|
@ -2,103 +2,37 @@
|
||||||
Authentication related API endpoints.
|
Authentication related API endpoints.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import TYPE_CHECKING, Union, Optional, Dict, Any
|
from typing import TYPE_CHECKING, Union, Dict, Any
|
||||||
|
|
||||||
# Regular imports (non-TYPE_CHECKING)
|
# Regular imports (non-TYPE_CHECKING)
|
||||||
from ApiEvents.abstract_class import (
|
from ApiEvents.abstract_class import MethodToEvent
|
||||||
MethodToEvent,
|
from ApiEvents.base_request_model import DictRequestModel, SuccessResponse
|
||||||
RouteFactoryConfig,
|
from ApiLibrary.common.line_number import get_line_number_for_error
|
||||||
EndpointFactoryConfig,
|
from ApiServices.Login.user_login_handler import UserLoginModule
|
||||||
)
|
from ApiServices.Token.token_handler import AccessToken, TokenService
|
||||||
from ApiEvents.base_request_model import (
|
from ApiValidations.Request.authentication import EmployeeSelectionValidation, Login, OccupantSelectionValidation
|
||||||
BaseRequestModel,
|
from ErrorHandlers import HTTPExceptionApi
|
||||||
DictRequestModel,
|
from .models import (
|
||||||
SuccessResponse,
|
LoginData,
|
||||||
|
LoginRequestModel,
|
||||||
|
LogoutRequestModel,
|
||||||
|
RememberRequestModel,
|
||||||
|
ForgotRequestModel,
|
||||||
|
ChangePasswordRequestModel,
|
||||||
|
CreatePasswordRequestModel,
|
||||||
|
SelectionDataEmployee,
|
||||||
|
SelectionDataOccupant,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
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
|
||||||
from Schemas import (
|
|
||||||
Login,
|
|
||||||
ChangePassword,
|
|
||||||
CreatePassword,
|
|
||||||
Forgot,
|
|
||||||
Logout,
|
|
||||||
Remember,
|
|
||||||
EmployeeSelection,
|
|
||||||
OccupantSelection,
|
|
||||||
)
|
|
||||||
|
|
||||||
from ApiLibrary.common.line_number import get_line_number_for_error
|
|
||||||
from ApiServices.Login.user_login_handler import UserLoginModule
|
|
||||||
from ApiValidations.Request import (
|
|
||||||
Login,
|
|
||||||
Logout,
|
|
||||||
Remember,
|
|
||||||
Forgot,
|
|
||||||
ChangePassword,
|
|
||||||
CreatePassword,
|
|
||||||
EmployeeSelection,
|
|
||||||
OccupantSelection,
|
|
||||||
)
|
|
||||||
from Services.PostgresDb.Models.alchemy_response import AlchemyJsonResponse
|
|
||||||
from ApiValidations.Response import AccountRecordResponse
|
|
||||||
from ApiServices.Token.token_handler import AccessToken, TokenService
|
|
||||||
from ErrorHandlers import HTTPExceptionApi
|
|
||||||
|
|
||||||
# Type aliases for common types
|
# Type aliases for common types
|
||||||
TokenDictType = Union["EmployeeTokenObject", "OccupantTokenObject"]
|
TokenDictType = Union["EmployeeTokenObject", "OccupantTokenObject"]
|
||||||
|
|
||||||
|
|
||||||
class LoginRequestModel(BaseRequestModel[Login]):
|
|
||||||
"""Request model for login endpoint."""
|
|
||||||
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class LogoutRequestModel(BaseRequestModel[Logout]):
|
|
||||||
"""Request model for logout endpoint."""
|
|
||||||
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class RememberRequestModel(BaseRequestModel[Remember]):
|
|
||||||
"""Request model for remember token endpoint."""
|
|
||||||
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class ForgotRequestModel(BaseRequestModel[Forgot]):
|
|
||||||
"""Request model for forgot password endpoint."""
|
|
||||||
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class ChangePasswordRequestModel(BaseRequestModel[ChangePassword]):
|
|
||||||
"""Request model for change password endpoint."""
|
|
||||||
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class CreatePasswordRequestModel(BaseRequestModel[CreatePassword]):
|
|
||||||
"""Request model for create password endpoint."""
|
|
||||||
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class EmployeeSelectionRequestModel(BaseRequestModel[EmployeeSelection]):
|
|
||||||
"""Request model for employee selection endpoint."""
|
|
||||||
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class OccupantSelectionRequestModel(BaseRequestModel[OccupantSelection]):
|
|
||||||
"""Request model for occupant selection endpoint."""
|
|
||||||
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class AuthenticationLoginEventMethods(MethodToEvent):
|
class AuthenticationLoginEventMethods(MethodToEvent):
|
||||||
event_type = "LOGIN"
|
event_type = "LOGIN"
|
||||||
event_description = "Login via domain and access key : [email] | [phone]"
|
event_description = "Login via domain and access key : [email] | [phone]"
|
||||||
|
|
@ -112,7 +46,7 @@ class AuthenticationLoginEventMethods(MethodToEvent):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def authentication_login_with_domain_and_creds(
|
async def authentication_login_with_domain_and_creds(
|
||||||
cls, request: "Request", data: LoginRequestModel
|
cls, request: "Request", data: Login
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Authenticate user with domain and credentials.
|
Authenticate user with domain and credentials.
|
||||||
|
|
@ -129,11 +63,9 @@ class AuthenticationLoginEventMethods(MethodToEvent):
|
||||||
Returns:
|
Returns:
|
||||||
SuccessResponse containing authentication token and user info
|
SuccessResponse containing authentication token and user info
|
||||||
"""
|
"""
|
||||||
# Create login module instance
|
|
||||||
login_module = UserLoginModule(request=request)
|
|
||||||
|
|
||||||
# Get token from login module
|
# Get token from login module
|
||||||
token = await login_module.login_user_via_credentials(access_data=data)
|
user_login_module = UserLoginModule(request=request)
|
||||||
|
token = await user_login_module.login_user_via_credentials(access_data=data)
|
||||||
|
|
||||||
# Return response with token and headers
|
# Return response with token and headers
|
||||||
return {
|
return {
|
||||||
|
|
@ -157,134 +89,52 @@ class AuthenticationSelectEventMethods(MethodToEvent):
|
||||||
@classmethod
|
@classmethod
|
||||||
def _handle_employee_selection(
|
def _handle_employee_selection(
|
||||||
cls,
|
cls,
|
||||||
data: EmployeeSelectionRequestModel,
|
data: SelectionDataEmployee,
|
||||||
token_dict: TokenDictType,
|
token_dict: TokenDictType,
|
||||||
request: "Request",
|
request: "Request",
|
||||||
):
|
):
|
||||||
return
|
raise HTTPExceptionApi(
|
||||||
# """Handle employee company selection"""
|
error_code="", lang="en", loc=get_line_number_for_error()
|
||||||
# Users.client_arrow = DateTimeLocal(is_client=True, timezone=token_dict.timezone)
|
)
|
||||||
# if data.company_uu_id not in token_dict.companies_uu_id_list:
|
|
||||||
# return ResponseHandler.unauthorized(
|
|
||||||
# "Company not found in user's company list"
|
|
||||||
# )
|
|
||||||
|
|
||||||
# selected_company = Companies.filter_one(
|
|
||||||
# Companies.uu_id == data.company_uu_id
|
|
||||||
# ).data
|
|
||||||
# if not selected_company:
|
|
||||||
# return ResponseHandler.not_found("Company not found")
|
|
||||||
|
|
||||||
# # Get department IDs for the company
|
|
||||||
# department_ids = [
|
|
||||||
# dept.id
|
|
||||||
# for dept in Departments.filter_all(
|
|
||||||
# Departments.company_id == selected_company.id
|
|
||||||
# ).data
|
|
||||||
# ]
|
|
||||||
|
|
||||||
# # Get duties IDs for the company
|
|
||||||
# duties_ids = [
|
|
||||||
# duty.id
|
|
||||||
# for duty in Duties.filter_all(Duties.company_id == selected_company.id).data
|
|
||||||
# ]
|
|
||||||
|
|
||||||
# # Get staff IDs
|
|
||||||
# staff_ids = [
|
|
||||||
# staff.id for staff in Staff.filter_all(Staff.duties_id.in_(duties_ids)).data
|
|
||||||
# ]
|
|
||||||
|
|
||||||
# # Get employee
|
|
||||||
# employee = Employees.filter_one(
|
|
||||||
# Employees.people_id == token_dict.person_id,
|
|
||||||
# Employees.staff_id.in_(staff_ids),
|
|
||||||
# ).data
|
|
||||||
|
|
||||||
# if not employee:
|
|
||||||
# return ResponseHandler.not_found("Employee not found")
|
|
||||||
|
|
||||||
# # 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).data
|
|
||||||
# duties = Duties.filter_one(Duties.id == staff.duties_id).data
|
|
||||||
# department = Departments.filter_one(Departments.id == duties.department_id).data
|
|
||||||
|
|
||||||
# # Get bulk duty
|
|
||||||
# bulk_id = Duty.filter_by_one(system=True, duty_code="BULK").data
|
|
||||||
# bulk_duty_id = Duties.filter_by_one(
|
|
||||||
# company_id=selected_company.id,
|
|
||||||
# duties_id=bulk_id.id,
|
|
||||||
# **Duties.valid_record_dict,
|
|
||||||
# ).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,
|
|
||||||
# )
|
|
||||||
|
|
||||||
# # Update Redis
|
|
||||||
# AuthActions.update_selected_to_redis(request=request, add_payload=company_token)
|
|
||||||
# return ResponseHandler.success("Company selected successfully")
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _handle_occupant_selection(
|
def _handle_occupant_selection(
|
||||||
cls,
|
cls,
|
||||||
data: OccupantSelectionRequestModel,
|
data: SelectionDataOccupant,
|
||||||
token_dict: TokenDictType,
|
token_dict: TokenDictType,
|
||||||
request: "Request",
|
request: "Request",
|
||||||
):
|
):
|
||||||
"""Handle selection of company or occupant type"""
|
"""Handle occupant type selection"""
|
||||||
try:
|
|
||||||
if isinstance(token_dict, EmployeeTokenObject):
|
|
||||||
return cls._handle_employee_selection(data, token_dict, request)
|
|
||||||
elif isinstance(token_dict, OccupantTokenObject):
|
|
||||||
return cls._handle_occupant_selection(data, token_dict, request)
|
|
||||||
raise HTTPExceptionApi(
|
raise HTTPExceptionApi(
|
||||||
error_code="HTTP_400_BAD_REQUEST",
|
error_code="HTTP_400_BAD_REQUEST",
|
||||||
lang=token_dict.lang,
|
lang=token_dict.lang,
|
||||||
loc=get_line_number_for_error(),
|
loc=get_line_number_for_error(),
|
||||||
)
|
sys_msg="Occupant selection not implemented",
|
||||||
except Exception as e:
|
|
||||||
return ResponseHandler.error(
|
|
||||||
str(e), status_code=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def authentication_select_company_or_occupant_type(
|
async def authentication_select_company_or_occupant_type(
|
||||||
cls,
|
cls,
|
||||||
request: "Request",
|
request: "Request",
|
||||||
data: Union[EmployeeSelectionRequestModel, OccupantSelectionRequestModel],
|
data: Union[EmployeeSelectionValidation, OccupantSelectionValidation],
|
||||||
token_dict: TokenDictType,
|
token_dict: TokenDictType,
|
||||||
):
|
):
|
||||||
"""Handle selection of company or occupant type"""
|
"""Handle selection of company or occupant type"""
|
||||||
# try:
|
try:
|
||||||
# if isinstance(token_dict, EmployeeTokenObject):
|
print(
|
||||||
# return cls._handle_employee_selection(data, token_dict, request)
|
dict(
|
||||||
# elif isinstance(token_dict, OccupantTokenObject):
|
data=data,
|
||||||
# return cls._handle_occupant_selection(data, token_dict, request)
|
token_dict=token_dict.model_dump(),
|
||||||
# return ResponseHandler.error(
|
request=dict(request.headers)
|
||||||
# "Invalid token type", status_code=status.HTTP_400_BAD_REQUEST
|
)
|
||||||
# )
|
)
|
||||||
# except Exception as e:
|
except Exception as e:
|
||||||
# return ResponseHandler.error(
|
raise HTTPExceptionApi(
|
||||||
# str(e), status_code=status.HTTP_500_INTERNAL_SERVER_ERROR
|
error_code="HTTP_500_INTERNAL_SERVER_ERROR",
|
||||||
# )
|
lang="en",
|
||||||
return
|
loc=get_line_number_for_error(),
|
||||||
|
sys_msg=str(e),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class AuthenticationCheckTokenEventMethods(MethodToEvent):
|
class AuthenticationCheckTokenEventMethods(MethodToEvent):
|
||||||
|
|
@ -300,7 +150,7 @@ class AuthenticationCheckTokenEventMethods(MethodToEvent):
|
||||||
# }
|
# }
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def authentication_check_token_is_valid(
|
async def authentication_check_token_is_valid(
|
||||||
cls, request: "Request", data: DictRequestModel
|
cls, request: "Request", data: DictRequestModel
|
||||||
):
|
):
|
||||||
# try:
|
# try:
|
||||||
|
|
@ -324,7 +174,7 @@ class AuthenticationRefreshEventMethods(MethodToEvent):
|
||||||
# }
|
# }
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def authentication_refresh_user_info(
|
async def authentication_refresh_user_info(
|
||||||
cls,
|
cls,
|
||||||
request: "Request",
|
request: "Request",
|
||||||
token_dict: TokenDictType,
|
token_dict: TokenDictType,
|
||||||
|
|
@ -371,7 +221,7 @@ class AuthenticationChangePasswordEventMethods(MethodToEvent):
|
||||||
# }
|
# }
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def authentication_change_password(
|
async def authentication_change_password(
|
||||||
cls,
|
cls,
|
||||||
request: "Request",
|
request: "Request",
|
||||||
data: ChangePasswordRequestModel,
|
data: ChangePasswordRequestModel,
|
||||||
|
|
@ -429,7 +279,7 @@ class AuthenticationCreatePasswordEventMethods(MethodToEvent):
|
||||||
# }
|
# }
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def authentication_create_password(
|
async def authentication_create_password(
|
||||||
cls, request: "Request", data: CreatePasswordRequestModel
|
cls, request: "Request", data: CreatePasswordRequestModel
|
||||||
):
|
):
|
||||||
|
|
||||||
|
|
@ -475,7 +325,7 @@ class AuthenticationDisconnectUserEventMethods(MethodToEvent):
|
||||||
# }
|
# }
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def authentication_disconnect_user(
|
async def authentication_disconnect_user(
|
||||||
cls, request: "Request", data: LogoutRequestModel, token_dict: TokenDictType
|
cls, request: "Request", data: LogoutRequestModel, token_dict: TokenDictType
|
||||||
):
|
):
|
||||||
# found_user = Users.filter_one(Users.uu_id == token_dict.user_uu_id).data
|
# found_user = Users.filter_one(Users.uu_id == token_dict.user_uu_id).data
|
||||||
|
|
@ -514,11 +364,11 @@ class AuthenticationLogoutEventMethods(MethodToEvent):
|
||||||
# }
|
# }
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def authentication_logout_user(
|
async def authentication_logout_user(
|
||||||
cls,
|
cls,
|
||||||
request: "Request",
|
request: "Request",
|
||||||
data: LogoutRequestModel,
|
data: LogoutRequestModel,
|
||||||
token_dict: TokenDictType = None,
|
token_dict: TokenDictType,
|
||||||
):
|
):
|
||||||
# token_user = None
|
# token_user = None
|
||||||
# if already_tokens := RedisActions.get_object_via_access_key(request=request):
|
# if already_tokens := RedisActions.get_object_via_access_key(request=request):
|
||||||
|
|
@ -553,7 +403,7 @@ class AuthenticationRefreshTokenEventMethods(MethodToEvent):
|
||||||
# }
|
# }
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def authentication_refresher_token(
|
async def authentication_refresher_token(
|
||||||
cls, request: "Request", data: RememberRequestModel, token_dict: TokenDictType
|
cls, request: "Request", data: RememberRequestModel, token_dict: TokenDictType
|
||||||
):
|
):
|
||||||
# token_refresher = UsersTokens.filter_by_one(
|
# token_refresher = UsersTokens.filter_by_one(
|
||||||
|
|
@ -602,7 +452,7 @@ class AuthenticationForgotPasswordEventMethods(MethodToEvent):
|
||||||
# }
|
# }
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def authentication_forgot_password(
|
async def authentication_forgot_password(
|
||||||
cls,
|
cls,
|
||||||
request: "Request",
|
request: "Request",
|
||||||
data: ForgotRequestModel,
|
data: ForgotRequestModel,
|
||||||
|
|
@ -644,7 +494,7 @@ class AuthenticationResetPasswordEventMethods(MethodToEvent):
|
||||||
}
|
}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def authentication_reset_password(
|
async def authentication_reset_password(
|
||||||
cls, request: "Request", data: ForgotRequestModel
|
cls, request: "Request", data: ForgotRequestModel
|
||||||
):
|
):
|
||||||
# from sqlalchemy import or_
|
# from sqlalchemy import or_
|
||||||
|
|
@ -695,11 +545,11 @@ class AuthenticationDownloadAvatarEventMethods(MethodToEvent):
|
||||||
# }
|
# }
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def authentication_download_avatar(
|
async def authentication_download_avatar(
|
||||||
cls,
|
cls,
|
||||||
token_dict: TokenDictType,
|
|
||||||
request: "Request",
|
request: "Request",
|
||||||
data: DictRequestModel,
|
data: DictRequestModel,
|
||||||
|
token_dict: TokenDictType,
|
||||||
):
|
):
|
||||||
# if found_user := Users.filter_one(Users.id == token_dict.user_id).data:
|
# if found_user := Users.filter_one(Users.id == token_dict.user_id).data:
|
||||||
# expired_starts = str(
|
# expired_starts = str(
|
||||||
|
|
@ -725,253 +575,3 @@ class AuthenticationDownloadAvatarEventMethods(MethodToEvent):
|
||||||
# return ResponseHandler.not_found("Invalid data")
|
# return ResponseHandler.not_found("Invalid data")
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
async def authentication_select_company_or_occupant_type(
|
|
||||||
request: "Request",
|
|
||||||
data: Union[EmployeeSelectionRequestModel, OccupantSelectionRequestModel],
|
|
||||||
) -> Dict[str, Any]:
|
|
||||||
return await AuthenticationSelectEventMethods.authentication_select_company_or_occupant_type(
|
|
||||||
request=request, data=data
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def authentication_login_with_domain_and_creds(
|
|
||||||
request: "Request", data: LoginRequestModel
|
|
||||||
) -> SuccessResponse:
|
|
||||||
"""
|
|
||||||
Authenticate user with domain and credentials.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request: FastAPI request object
|
|
||||||
data: Request body containing login credentials
|
|
||||||
{
|
|
||||||
"domain": str,
|
|
||||||
"username": str,
|
|
||||||
"password": str
|
|
||||||
}
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
SuccessResponse containing authentication token and user info
|
|
||||||
"""
|
|
||||||
return await AuthenticationLoginEventMethods.authentication_login_with_domain_and_creds(
|
|
||||||
request=request, data=data
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def authentication_check_token_is_valid(
|
|
||||||
request: "Request", data: DictRequestModel
|
|
||||||
) -> Dict[str, Any]:
|
|
||||||
return (
|
|
||||||
await AuthenticationCheckTokenEventMethods.authentication_check_token_is_valid(
|
|
||||||
request=request, data=data
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def authentication_refresh_user_info(
|
|
||||||
request: "Request", data: DictRequestModel
|
|
||||||
) -> Dict[str, Any]:
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
def authentication_change_password(
|
|
||||||
request: "Request", data: ChangePasswordRequestModel
|
|
||||||
) -> Dict[str, Any]:
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
def authentication_create_password(
|
|
||||||
request: "Request", data: CreatePasswordRequestModel
|
|
||||||
) -> Dict[str, Any]:
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
def authentication_forgot_password(
|
|
||||||
request: "Request", data: ForgotRequestModel
|
|
||||||
) -> Dict[str, Any]:
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
def authentication_reset_password(
|
|
||||||
request: "Request", data: ForgotRequestModel
|
|
||||||
) -> Dict[str, Any]:
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
def authentication_disconnect_user(
|
|
||||||
request: "Request", data: LogoutRequestModel
|
|
||||||
) -> Dict[str, Any]:
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
def authentication_logout_user(
|
|
||||||
request: "Request", data: LogoutRequestModel
|
|
||||||
) -> Dict[str, Any]:
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
def authentication_refresher_token(
|
|
||||||
request: "Request", data: RememberRequestModel
|
|
||||||
) -> Dict[str, Any]:
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
def authentication_download_avatar(
|
|
||||||
request: "Request", data: DictRequestModel
|
|
||||||
) -> Dict[str, Any]:
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
AUTH_CONFIG = RouteFactoryConfig(
|
|
||||||
name="authentication",
|
|
||||||
prefix="/authentication",
|
|
||||||
tags=["Authentication"],
|
|
||||||
include_in_schema=True,
|
|
||||||
endpoints=[
|
|
||||||
EndpointFactoryConfig(
|
|
||||||
url_prefix="/authentication",
|
|
||||||
url_endpoint="/select",
|
|
||||||
url_of_endpoint="/authentication/select",
|
|
||||||
endpoint="/select",
|
|
||||||
method="POST",
|
|
||||||
summary="Select company or occupant type",
|
|
||||||
description="Select company or occupant type",
|
|
||||||
is_auth_required=True, # Needs token_dict
|
|
||||||
is_event_required=False,
|
|
||||||
endpoint_function=authentication_select_company_or_occupant_type,
|
|
||||||
),
|
|
||||||
EndpointFactoryConfig(
|
|
||||||
url_prefix="/authentication",
|
|
||||||
url_endpoint="/login",
|
|
||||||
url_of_endpoint="/authentication/login",
|
|
||||||
endpoint="/login",
|
|
||||||
method="POST",
|
|
||||||
summary="Login user with domain and password",
|
|
||||||
description="Login user with domain and password",
|
|
||||||
is_auth_required=False, # Public endpoint
|
|
||||||
is_event_required=False,
|
|
||||||
endpoint_function=authentication_login_with_domain_and_creds,
|
|
||||||
),
|
|
||||||
EndpointFactoryConfig(
|
|
||||||
url_prefix="/authentication",
|
|
||||||
url_endpoint="/valid",
|
|
||||||
url_of_endpoint="/authentication/valid",
|
|
||||||
endpoint="/valid",
|
|
||||||
method="GET",
|
|
||||||
summary="Check access token is valid",
|
|
||||||
description="Check access token is valid",
|
|
||||||
is_auth_required=True, # Needs token validation
|
|
||||||
is_event_required=False,
|
|
||||||
endpoint_function=authentication_check_token_is_valid,
|
|
||||||
),
|
|
||||||
EndpointFactoryConfig(
|
|
||||||
url_prefix="/authentication",
|
|
||||||
url_endpoint="/refresh",
|
|
||||||
url_of_endpoint="/authentication/refresh",
|
|
||||||
endpoint="/refresh",
|
|
||||||
method="GET",
|
|
||||||
summary="Refresh credentials with access token",
|
|
||||||
description="Refresh credentials with access token",
|
|
||||||
is_auth_required=True, # Needs token_dict
|
|
||||||
is_event_required=False,
|
|
||||||
endpoint_function=authentication_refresh_user_info,
|
|
||||||
),
|
|
||||||
EndpointFactoryConfig(
|
|
||||||
url_prefix="/authentication",
|
|
||||||
url_endpoint="/change_password",
|
|
||||||
url_of_endpoint="/authentication/change_password",
|
|
||||||
endpoint="/change_password",
|
|
||||||
method="POST",
|
|
||||||
summary="Change password with access token",
|
|
||||||
description="Change password with access token",
|
|
||||||
is_auth_required=True, # Needs token_dict
|
|
||||||
is_event_required=False,
|
|
||||||
endpoint_function=authentication_change_password,
|
|
||||||
),
|
|
||||||
EndpointFactoryConfig(
|
|
||||||
url_prefix="/authentication",
|
|
||||||
url_endpoint="/create_password",
|
|
||||||
url_of_endpoint="/authentication/create_password",
|
|
||||||
endpoint="/create_password",
|
|
||||||
method="POST",
|
|
||||||
summary="Create password with password token",
|
|
||||||
description="Create password with password token",
|
|
||||||
is_auth_required=False, # Public endpoint
|
|
||||||
is_event_required=False,
|
|
||||||
endpoint_function=authentication_create_password,
|
|
||||||
),
|
|
||||||
EndpointFactoryConfig(
|
|
||||||
url_prefix="/authentication",
|
|
||||||
url_endpoint="/reset_password",
|
|
||||||
url_of_endpoint="/authentication/reset_password",
|
|
||||||
endpoint="/reset_password",
|
|
||||||
method="POST",
|
|
||||||
summary="Create password with password token",
|
|
||||||
description="Create password with password token",
|
|
||||||
is_auth_required=False, # Public endpoint
|
|
||||||
is_event_required=False,
|
|
||||||
endpoint_function=authentication_reset_password,
|
|
||||||
),
|
|
||||||
EndpointFactoryConfig(
|
|
||||||
url_prefix="/authentication",
|
|
||||||
url_endpoint="/disconnect",
|
|
||||||
url_of_endpoint="/authentication/disconnect",
|
|
||||||
endpoint="/disconnect",
|
|
||||||
method="POST",
|
|
||||||
summary="Disconnect user with access token",
|
|
||||||
description="Disconnect user with access token",
|
|
||||||
is_auth_required=True, # Needs token_dict
|
|
||||||
is_event_required=False,
|
|
||||||
endpoint_function=authentication_disconnect_user,
|
|
||||||
),
|
|
||||||
EndpointFactoryConfig(
|
|
||||||
url_prefix="/authentication",
|
|
||||||
url_endpoint="/logout",
|
|
||||||
url_of_endpoint="/authentication/logout",
|
|
||||||
endpoint="/logout",
|
|
||||||
method="POST",
|
|
||||||
summary="Logout user with access token",
|
|
||||||
description="Logout user with access token",
|
|
||||||
is_auth_required=True, # Needs token_dict
|
|
||||||
is_event_required=False,
|
|
||||||
endpoint_function=authentication_logout_user,
|
|
||||||
),
|
|
||||||
EndpointFactoryConfig(
|
|
||||||
url_prefix="/authentication",
|
|
||||||
url_endpoint="/refresher",
|
|
||||||
url_of_endpoint="/authentication/refresher",
|
|
||||||
endpoint="/refresher",
|
|
||||||
method="POST",
|
|
||||||
summary="Refresh token with refresh token",
|
|
||||||
description="Refresh token with refresh token",
|
|
||||||
is_auth_required=True, # Needs token_dict
|
|
||||||
is_event_required=False,
|
|
||||||
endpoint_function=authentication_refresher_token,
|
|
||||||
),
|
|
||||||
EndpointFactoryConfig(
|
|
||||||
url_prefix="/authentication",
|
|
||||||
url_endpoint="/forgot",
|
|
||||||
url_of_endpoint="/authentication/forgot",
|
|
||||||
endpoint="/forgot",
|
|
||||||
method="POST",
|
|
||||||
summary="Forgot password with email or phone number",
|
|
||||||
description="Forgot password with email or phone number",
|
|
||||||
is_auth_required=False, # Public endpoint
|
|
||||||
is_event_required=False,
|
|
||||||
endpoint_function=authentication_forgot_password,
|
|
||||||
),
|
|
||||||
EndpointFactoryConfig(
|
|
||||||
url_prefix="/authentication",
|
|
||||||
url_endpoint="/avatar",
|
|
||||||
url_of_endpoint="/authentication/avatar",
|
|
||||||
endpoint="/avatar",
|
|
||||||
method="POST",
|
|
||||||
summary="Get link of avatar with credentials",
|
|
||||||
description="Get link of avatar with credentials",
|
|
||||||
is_auth_required=True, # Needs token_dict
|
|
||||||
is_event_required=False,
|
|
||||||
endpoint_function=authentication_download_avatar,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
).as_dict()
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,371 @@
|
||||||
|
"""
|
||||||
|
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 .auth import (
|
||||||
|
AuthenticationChangePasswordEventMethods,
|
||||||
|
AuthenticationCheckTokenEventMethods,
|
||||||
|
AuthenticationCreatePasswordEventMethods,
|
||||||
|
AuthenticationDisconnectUserEventMethods,
|
||||||
|
AuthenticationDownloadAvatarEventMethods,
|
||||||
|
AuthenticationForgotPasswordEventMethods,
|
||||||
|
AuthenticationLoginEventMethods,
|
||||||
|
AuthenticationLogoutEventMethods,
|
||||||
|
AuthenticationRefreshEventMethods,
|
||||||
|
AuthenticationRefreshTokenEventMethods,
|
||||||
|
AuthenticationResetPasswordEventMethods,
|
||||||
|
AuthenticationSelectEventMethods,
|
||||||
|
)
|
||||||
|
from .models import (
|
||||||
|
ChangePasswordRequestModel,
|
||||||
|
CreatePasswordRequestModel,
|
||||||
|
ForgotRequestModel,
|
||||||
|
LoginData,
|
||||||
|
LoginRequestModel,
|
||||||
|
LogoutRequestModel,
|
||||||
|
SelectionDataEmployee,
|
||||||
|
SelectionDataOccupant,
|
||||||
|
RememberRequestModel,
|
||||||
|
)
|
||||||
|
from ApiEvents.base_request_model import DictRequestModel
|
||||||
|
from ApiEvents.abstract_class import RouteFactoryConfig, EndpointFactoryConfig, endpoint_wrapper
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from fastapi import Request
|
||||||
|
from ApiValidations.Custom.token_objects import EmployeeTokenObject, OccupantTokenObject
|
||||||
|
|
||||||
|
|
||||||
|
# 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
|
||||||
|
) -> 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
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
"headers": dict(request.headers),
|
||||||
|
"data": data,
|
||||||
|
"token": token_dict
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@endpoint_wrapper("/authentication/login")
|
||||||
|
async def authentication_login_with_domain_and_creds(
|
||||||
|
request: "Request",
|
||||||
|
data: Login,
|
||||||
|
) -> Dict[str, Any]:
|
||||||
|
"""
|
||||||
|
Authenticate user with domain and credentials.
|
||||||
|
"""
|
||||||
|
return AuthenticationLoginEventMethods.authentication_login_with_domain_and_creds(
|
||||||
|
request=request, data=data
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@endpoint_wrapper("/authentication/check")
|
||||||
|
async def authentication_check_token_is_valid(
|
||||||
|
request: "Request",
|
||||||
|
data: DictRequestModel,
|
||||||
|
) -> Dict[str, Any]:
|
||||||
|
"""
|
||||||
|
Check if a token is valid.
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
"status": "OK",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@endpoint_wrapper("/authentication/refresh")
|
||||||
|
async def authentication_refresh_user_info(
|
||||||
|
request: "Request",
|
||||||
|
data: DictRequestModel,
|
||||||
|
token_dict: TokenDictType = None,
|
||||||
|
) -> Dict[str, Any]:
|
||||||
|
"""
|
||||||
|
Refresh user information.
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
"status": "OK",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@endpoint_wrapper("/authentication/change-password")
|
||||||
|
async def authentication_change_password(
|
||||||
|
request: "Request",
|
||||||
|
data: ChangePasswordRequestModel,
|
||||||
|
token_dict: TokenDictType = None,
|
||||||
|
) -> Dict[str, Any]:
|
||||||
|
"""
|
||||||
|
Change user password.
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
"status": "OK",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@endpoint_wrapper("/authentication/create-password")
|
||||||
|
async def authentication_create_password(
|
||||||
|
request: "Request",
|
||||||
|
data: CreatePasswordRequestModel,
|
||||||
|
) -> Dict[str, Any]:
|
||||||
|
"""
|
||||||
|
Create new password.
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
"status": "OK",
|
||||||
|
}
|
||||||
|
|
||||||
|
@endpoint_wrapper("/authentication/forgot-password")
|
||||||
|
async def authentication_forgot_password(
|
||||||
|
request: "Request",
|
||||||
|
data: ForgotRequestModel,
|
||||||
|
) -> Dict[str, Any]:
|
||||||
|
"""
|
||||||
|
Handle forgot password request.
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
"status": "OK",
|
||||||
|
}
|
||||||
|
|
||||||
|
@endpoint_wrapper("/authentication/reset-password")
|
||||||
|
async def authentication_reset_password(
|
||||||
|
request: "Request",
|
||||||
|
data: ForgotRequestModel,
|
||||||
|
) -> Dict[str, Any]:
|
||||||
|
"""
|
||||||
|
Reset password.
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
"status": "OK",
|
||||||
|
}
|
||||||
|
|
||||||
|
@endpoint_wrapper("/authentication/disconnect")
|
||||||
|
async def authentication_disconnect_user(
|
||||||
|
request: "Request",
|
||||||
|
data: LogoutRequestModel,
|
||||||
|
token_dict: TokenDictType = None,
|
||||||
|
) -> Dict[str, Any]:
|
||||||
|
"""
|
||||||
|
Disconnect user.
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
"status": "OK",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@endpoint_wrapper("/authentication/logout")
|
||||||
|
async def authentication_logout_user(
|
||||||
|
request: "Request",
|
||||||
|
data: LogoutRequestModel,
|
||||||
|
token_dict: TokenDictType = None,
|
||||||
|
) -> Dict[str, Any]:
|
||||||
|
"""
|
||||||
|
Logout user.
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
"status": "OK",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@endpoint_wrapper("/authentication/remember")
|
||||||
|
async def authentication_refresher_token(
|
||||||
|
request: "Request",
|
||||||
|
data: RememberRequestModel,
|
||||||
|
token_dict: TokenDictType = None,
|
||||||
|
) -> Dict[str, Any]:
|
||||||
|
"""
|
||||||
|
Refresh remember token.
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
"status": "OK",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@endpoint_wrapper("/authentication/avatar")
|
||||||
|
async def authentication_download_avatar(
|
||||||
|
request: "Request",
|
||||||
|
data: DictRequestModel,
|
||||||
|
token_dict: TokenDictType = None,
|
||||||
|
) -> Dict[str, Any]:
|
||||||
|
"""
|
||||||
|
Download user avatar.
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
"status": "OK",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
prefix = "/authentication"
|
||||||
|
|
||||||
|
|
||||||
|
AUTH_CONFIG = RouteFactoryConfig(
|
||||||
|
name="authentication",
|
||||||
|
prefix=prefix,
|
||||||
|
tags=["Authentication"],
|
||||||
|
include_in_schema=True,
|
||||||
|
endpoints=[
|
||||||
|
EndpointFactoryConfig(
|
||||||
|
url_prefix=prefix,
|
||||||
|
url_endpoint="/select",
|
||||||
|
url_of_endpoint="/authentication/select",
|
||||||
|
endpoint="/select",
|
||||||
|
method="POST",
|
||||||
|
summary="Select company or occupant type",
|
||||||
|
description="Select company or occupant type",
|
||||||
|
is_auth_required=True, # Needs token_dict
|
||||||
|
is_event_required=False,
|
||||||
|
endpoint_function=authentication_select_company_or_occupant_type,
|
||||||
|
),
|
||||||
|
EndpointFactoryConfig(
|
||||||
|
url_prefix=prefix,
|
||||||
|
url_endpoint="/login",
|
||||||
|
url_of_endpoint="/authentication/login",
|
||||||
|
endpoint="/login",
|
||||||
|
method="POST",
|
||||||
|
summary="Login user with domain and password",
|
||||||
|
description="Login user with domain and password",
|
||||||
|
is_auth_required=False, # Public endpoint
|
||||||
|
is_event_required=False,
|
||||||
|
endpoint_function=authentication_login_with_domain_and_creds,
|
||||||
|
),
|
||||||
|
EndpointFactoryConfig(
|
||||||
|
url_prefix=prefix,
|
||||||
|
url_endpoint="/check",
|
||||||
|
url_of_endpoint="/authentication/check",
|
||||||
|
endpoint="/check",
|
||||||
|
method="GET",
|
||||||
|
summary="Check access token is valid",
|
||||||
|
description="Check access token is valid",
|
||||||
|
is_auth_required=True, # Needs token validation
|
||||||
|
is_event_required=False,
|
||||||
|
endpoint_function=authentication_check_token_is_valid,
|
||||||
|
),
|
||||||
|
EndpointFactoryConfig(
|
||||||
|
url_prefix=prefix,
|
||||||
|
url_endpoint="/refresh",
|
||||||
|
url_of_endpoint="/authentication/refresh",
|
||||||
|
endpoint="/refresh",
|
||||||
|
method="GET",
|
||||||
|
summary="Refresh credentials with access token",
|
||||||
|
description="Refresh credentials with access token",
|
||||||
|
is_auth_required=True, # Needs token_dict
|
||||||
|
is_event_required=False,
|
||||||
|
endpoint_function=authentication_refresh_user_info,
|
||||||
|
),
|
||||||
|
EndpointFactoryConfig(
|
||||||
|
url_prefix=prefix,
|
||||||
|
url_endpoint="/change-password",
|
||||||
|
url_of_endpoint="/authentication/change-password",
|
||||||
|
endpoint="/change-password",
|
||||||
|
method="POST",
|
||||||
|
summary="Change password with access token",
|
||||||
|
description="Change password with access token",
|
||||||
|
is_auth_required=True, # Needs token_dict
|
||||||
|
is_event_required=False,
|
||||||
|
endpoint_function=authentication_change_password,
|
||||||
|
),
|
||||||
|
EndpointFactoryConfig(
|
||||||
|
url_prefix=prefix,
|
||||||
|
url_endpoint="/create-password",
|
||||||
|
url_of_endpoint="/authentication/create-password",
|
||||||
|
endpoint="/create-password",
|
||||||
|
method="POST",
|
||||||
|
summary="Create password with password token",
|
||||||
|
description="Create password with password token",
|
||||||
|
is_auth_required=False, # Public endpoint
|
||||||
|
is_event_required=False,
|
||||||
|
endpoint_function=authentication_create_password,
|
||||||
|
),
|
||||||
|
EndpointFactoryConfig(
|
||||||
|
url_prefix=prefix,
|
||||||
|
url_endpoint="/reset-password",
|
||||||
|
url_of_endpoint="/authentication/reset-password",
|
||||||
|
endpoint="/reset-password",
|
||||||
|
method="POST",
|
||||||
|
summary="Reset password with token",
|
||||||
|
description="Reset password with token",
|
||||||
|
is_auth_required=False, # Public endpoint
|
||||||
|
is_event_required=False,
|
||||||
|
endpoint_function=authentication_reset_password,
|
||||||
|
),
|
||||||
|
EndpointFactoryConfig(
|
||||||
|
url_prefix=prefix,
|
||||||
|
url_endpoint="/disconnect",
|
||||||
|
url_of_endpoint="/authentication/disconnect",
|
||||||
|
endpoint="/disconnect",
|
||||||
|
method="POST",
|
||||||
|
summary="Disconnect user with access token",
|
||||||
|
description="Disconnect user with access token",
|
||||||
|
is_auth_required=True, # Needs token_dict
|
||||||
|
is_event_required=False,
|
||||||
|
endpoint_function=authentication_disconnect_user,
|
||||||
|
),
|
||||||
|
EndpointFactoryConfig(
|
||||||
|
url_prefix=prefix,
|
||||||
|
url_endpoint="/logout",
|
||||||
|
url_of_endpoint="/authentication/logout",
|
||||||
|
endpoint="/logout",
|
||||||
|
method="POST",
|
||||||
|
summary="Logout user with access token",
|
||||||
|
description="Logout user with access token",
|
||||||
|
is_auth_required=True, # Needs token_dict
|
||||||
|
is_event_required=False,
|
||||||
|
endpoint_function=authentication_logout_user,
|
||||||
|
),
|
||||||
|
EndpointFactoryConfig(
|
||||||
|
url_prefix=prefix,
|
||||||
|
url_endpoint="/remember",
|
||||||
|
url_of_endpoint="/authentication/remember",
|
||||||
|
endpoint="/remember",
|
||||||
|
method="POST",
|
||||||
|
summary="Refresh token with refresh token",
|
||||||
|
description="Refresh token with refresh token",
|
||||||
|
is_auth_required=True, # Needs token_dict
|
||||||
|
is_event_required=False,
|
||||||
|
endpoint_function=authentication_refresher_token,
|
||||||
|
),
|
||||||
|
EndpointFactoryConfig(
|
||||||
|
url_prefix=prefix,
|
||||||
|
url_endpoint="/forgot-password",
|
||||||
|
url_of_endpoint="/authentication/forgot-password",
|
||||||
|
endpoint="/forgot-password",
|
||||||
|
method="POST",
|
||||||
|
summary="Request password reset via email",
|
||||||
|
description="Request password reset via email",
|
||||||
|
is_auth_required=False, # Public endpoint
|
||||||
|
is_event_required=False,
|
||||||
|
endpoint_function=authentication_forgot_password,
|
||||||
|
),
|
||||||
|
EndpointFactoryConfig(
|
||||||
|
url_prefix=prefix,
|
||||||
|
url_endpoint="/avatar",
|
||||||
|
url_of_endpoint="/authentication/avatar",
|
||||||
|
endpoint="/avatar",
|
||||||
|
method="POST",
|
||||||
|
summary="Get user avatar with credentials",
|
||||||
|
description="Get user avatar with credentials",
|
||||||
|
is_auth_required=True, # Needs token_dict
|
||||||
|
is_event_required=False,
|
||||||
|
endpoint_function=authentication_download_avatar,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).as_dict()
|
||||||
|
|
@ -0,0 +1,138 @@
|
||||||
|
"""
|
||||||
|
Authentication request models.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING, Dict, Any, Literal, Optional, TypedDict
|
||||||
|
from pydantic import BaseModel, Field, model_validator, RootModel, ConfigDict
|
||||||
|
from ApiEvents.base_request_model import BaseRequestModel, DictRequestModel
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from fastapi import Request
|
||||||
|
|
||||||
|
|
||||||
|
class TokenObjectBase(BaseModel):
|
||||||
|
"""Base model for token objects."""
|
||||||
|
user_type: str = Field(..., description="Type of user")
|
||||||
|
user_id: str = Field(..., description="User ID")
|
||||||
|
token: str = Field(..., description="Authentication token")
|
||||||
|
permissions: Dict[str, Any] = Field(default_factory=dict, description="User permissions")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class LoginData(TypedDict):
|
||||||
|
"""Type for login data."""
|
||||||
|
domain: str
|
||||||
|
access_key: str
|
||||||
|
password: str
|
||||||
|
remember_me: bool
|
||||||
|
|
||||||
|
|
||||||
|
class LoginRequestModel(BaseRequestModel[LoginData]):
|
||||||
|
"""Request model for login endpoint."""
|
||||||
|
model_config = ConfigDict(
|
||||||
|
json_schema_extra={
|
||||||
|
"example": {
|
||||||
|
"domain": "example.com",
|
||||||
|
"access_key": "user@example",
|
||||||
|
"password": "password",
|
||||||
|
"remember_me": False
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class LogoutData(TypedDict):
|
||||||
|
"""Type for logout data."""
|
||||||
|
token: str
|
||||||
|
|
||||||
|
|
||||||
|
class LogoutRequestModel(BaseRequestModel[LogoutData]):
|
||||||
|
"""Request model for logout endpoint."""
|
||||||
|
model_config = ConfigDict(
|
||||||
|
json_schema_extra={
|
||||||
|
"example": {
|
||||||
|
"token": "your-token-here"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class RememberData(TypedDict):
|
||||||
|
"""Type for remember token data."""
|
||||||
|
remember_token: str
|
||||||
|
|
||||||
|
|
||||||
|
class RememberRequestModel(BaseRequestModel[RememberData]):
|
||||||
|
"""Request model for remember token endpoint."""
|
||||||
|
model_config = ConfigDict(
|
||||||
|
json_schema_extra={
|
||||||
|
"example": {
|
||||||
|
"remember_token": "your-remember-token-here"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ForgotData(TypedDict):
|
||||||
|
"""Type for forgot password data."""
|
||||||
|
email: str
|
||||||
|
domain: str
|
||||||
|
|
||||||
|
|
||||||
|
class ForgotRequestModel(BaseRequestModel[ForgotData]):
|
||||||
|
"""Request model for forgot password endpoint."""
|
||||||
|
model_config = ConfigDict(
|
||||||
|
json_schema_extra={
|
||||||
|
"example": {
|
||||||
|
"email": "user@example.com",
|
||||||
|
"domain": "example.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ChangePasswordData(TypedDict):
|
||||||
|
"""Type for change password data."""
|
||||||
|
old_password: str
|
||||||
|
new_password: str
|
||||||
|
|
||||||
|
|
||||||
|
class ChangePasswordRequestModel(BaseRequestModel[ChangePasswordData]):
|
||||||
|
"""Request model for change password endpoint."""
|
||||||
|
model_config = ConfigDict(
|
||||||
|
json_schema_extra={
|
||||||
|
"example": {
|
||||||
|
"old_password": "old-pass",
|
||||||
|
"new_password": "new-pass"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class CreatePasswordData(TypedDict):
|
||||||
|
"""Type for create password data."""
|
||||||
|
token: str
|
||||||
|
password: str
|
||||||
|
|
||||||
|
|
||||||
|
class CreatePasswordRequestModel(BaseRequestModel[CreatePasswordData]):
|
||||||
|
"""Request model for create password endpoint."""
|
||||||
|
model_config = ConfigDict(
|
||||||
|
json_schema_extra={
|
||||||
|
"example": {
|
||||||
|
"token": "password-creation-token",
|
||||||
|
"password": "new-password"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class SelectionDataOccupant(TypedDict):
|
||||||
|
"""Type for selection data."""
|
||||||
|
build_living_space_uu_id: Optional[str]
|
||||||
|
|
||||||
|
|
||||||
|
class SelectionDataEmployee(TypedDict):
|
||||||
|
"""Type for selection data."""
|
||||||
|
company_uu_id: Optional[str]
|
||||||
|
|
||||||
|
|
@ -6,7 +6,7 @@ to be used by the dynamic route creation system.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import Dict, List, Any
|
from typing import Dict, List, Any
|
||||||
from .auth.auth import AUTH_CONFIG
|
from .auth.endpoints import AUTH_CONFIG
|
||||||
|
|
||||||
|
|
||||||
# Registry of all route configurations
|
# Registry of all route configurations
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
"""
|
||||||
|
Account records package initialization.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from .endpoints import ACCOUNT_RECORDS_CONFIG
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"ACCOUNT_RECORDS_CONFIG",
|
||||||
|
]
|
||||||
|
|
@ -1,24 +1,22 @@
|
||||||
import typing
|
"""
|
||||||
|
Account records service implementation.
|
||||||
|
"""
|
||||||
|
|
||||||
from ApiEvents.abstract_class import (
|
from typing import Dict, Any, Union
|
||||||
MethodToEvent,
|
from pydantic import Field
|
||||||
RouteFactoryConfig,
|
|
||||||
EndpointFactoryConfig,
|
|
||||||
endpoint_wrapper,
|
|
||||||
)
|
|
||||||
from ApiEvents.base_request_model import BaseRequestModel, DictRequestModel
|
|
||||||
|
|
||||||
from typing import TYPE_CHECKING, Dict, Any
|
|
||||||
from fastapi import Request, Path, Body, Depends, APIRouter
|
|
||||||
from pydantic import BaseModel, Field
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from fastapi import Request
|
|
||||||
|
|
||||||
|
from ApiEvents.abstract_class import MethodToEvent, endpoint_wrapper
|
||||||
|
from ApiEvents.base_request_model import DictRequestModel
|
||||||
from ApiValidations.Custom.token_objects import (
|
from ApiValidations.Custom.token_objects import (
|
||||||
OccupantTokenObject,
|
OccupantTokenObject,
|
||||||
EmployeeTokenObject,
|
EmployeeTokenObject,
|
||||||
)
|
)
|
||||||
|
from ApiLibrary import system_arrow
|
||||||
|
from ApiValidations.Request.account_records import (
|
||||||
|
InsertAccountRecord,
|
||||||
|
UpdateAccountRecord,
|
||||||
|
)
|
||||||
|
from ApiValidations.Request.base_validations import ListOptions
|
||||||
from Schemas import (
|
from Schemas import (
|
||||||
BuildLivingSpace,
|
BuildLivingSpace,
|
||||||
AccountRecords,
|
AccountRecords,
|
||||||
|
|
@ -26,49 +24,16 @@ from Schemas import (
|
||||||
BuildDecisionBookPayments,
|
BuildDecisionBookPayments,
|
||||||
ApiEnumDropdown,
|
ApiEnumDropdown,
|
||||||
)
|
)
|
||||||
from ApiLibrary import system_arrow
|
|
||||||
from ApiValidations.Request import (
|
|
||||||
InsertAccountRecord,
|
|
||||||
UpdateAccountRecord,
|
|
||||||
ListOptions,
|
|
||||||
)
|
|
||||||
from Services.PostgresDb.Models.alchemy_response import (
|
from Services.PostgresDb.Models.alchemy_response import (
|
||||||
AlchemyJsonResponse,
|
AlchemyJsonResponse,
|
||||||
DictJsonResponse,
|
DictJsonResponse,
|
||||||
)
|
)
|
||||||
from ApiValidations.Response import AccountRecordResponse
|
from ApiValidations.Response import AccountRecordResponse
|
||||||
|
from .models import (
|
||||||
|
InsertAccountRecordRequestModel,
|
||||||
class AddressUpdateRequest(BaseModel):
|
UpdateAccountRecordRequestModel,
|
||||||
"""Request model for address update."""
|
ListOptionsRequestModel,
|
||||||
|
)
|
||||||
data: Dict[str, Any] = Field(..., description="Updated address data")
|
|
||||||
|
|
||||||
|
|
||||||
class AddressUpdateResponse(BaseModel):
|
|
||||||
"""Response model for address update."""
|
|
||||||
|
|
||||||
address_uu_id: str = Field(..., description="UUID of the updated address")
|
|
||||||
data: Dict[str, Any] = Field(..., description="Updated address data")
|
|
||||||
function_code: str = Field(..., description="Function code for the endpoint")
|
|
||||||
|
|
||||||
|
|
||||||
class InsertAccountRecordRequestModel(BaseRequestModel[InsertAccountRecord]):
|
|
||||||
"""Request model for inserting account records."""
|
|
||||||
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class UpdateAccountRecordRequestModel(BaseRequestModel[UpdateAccountRecord]):
|
|
||||||
"""Request model for updating account records."""
|
|
||||||
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class ListOptionsRequestModel(BaseRequestModel[ListOptions]):
|
|
||||||
"""Request model for list options."""
|
|
||||||
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class AccountRecordsListEventMethods(MethodToEvent):
|
class AccountRecordsListEventMethods(MethodToEvent):
|
||||||
|
|
@ -90,7 +55,7 @@ class AccountRecordsListEventMethods(MethodToEvent):
|
||||||
def account_records_list(
|
def account_records_list(
|
||||||
cls,
|
cls,
|
||||||
list_options: ListOptionsRequestModel,
|
list_options: ListOptionsRequestModel,
|
||||||
token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject],
|
token_dict: Union[EmployeeTokenObject, OccupantTokenObject],
|
||||||
):
|
):
|
||||||
db_session = AccountRecords.new_session()
|
db_session = AccountRecords.new_session()
|
||||||
if isinstance(token_dict, OccupantTokenObject):
|
if isinstance(token_dict, OccupantTokenObject):
|
||||||
|
|
@ -119,7 +84,7 @@ class AccountRecordsListEventMethods(MethodToEvent):
|
||||||
def account_records_list_flt_res(
|
def account_records_list_flt_res(
|
||||||
cls,
|
cls,
|
||||||
list_options: ListOptionsRequestModel,
|
list_options: ListOptionsRequestModel,
|
||||||
token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject],
|
token_dict: Union[EmployeeTokenObject, OccupantTokenObject],
|
||||||
):
|
):
|
||||||
db_session = AccountRecords.new_session()
|
db_session = AccountRecords.new_session()
|
||||||
if not isinstance(token_dict, OccupantTokenObject):
|
if not isinstance(token_dict, OccupantTokenObject):
|
||||||
|
|
@ -269,7 +234,7 @@ class AccountRecordsCreateEventMethods(MethodToEvent):
|
||||||
def account_records_create(
|
def account_records_create(
|
||||||
cls,
|
cls,
|
||||||
data: InsertAccountRecordRequestModel,
|
data: InsertAccountRecordRequestModel,
|
||||||
token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject],
|
token_dict: Union[EmployeeTokenObject, OccupantTokenObject],
|
||||||
):
|
):
|
||||||
data_dict = data.excluded_dump()
|
data_dict = data.excluded_dump()
|
||||||
if isinstance(token_dict, OccupantTokenObject):
|
if isinstance(token_dict, OccupantTokenObject):
|
||||||
|
|
@ -358,7 +323,7 @@ class AccountRecordsUpdateEventMethods(MethodToEvent):
|
||||||
cls,
|
cls,
|
||||||
build_uu_id: str,
|
build_uu_id: str,
|
||||||
data: UpdateAccountRecordRequestModel,
|
data: UpdateAccountRecordRequestModel,
|
||||||
token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject],
|
token_dict: Union[EmployeeTokenObject, OccupantTokenObject],
|
||||||
):
|
):
|
||||||
if isinstance(token_dict, OccupantTokenObject):
|
if isinstance(token_dict, OccupantTokenObject):
|
||||||
pass
|
pass
|
||||||
|
|
@ -373,123 +338,3 @@ class AccountRecordsUpdateEventMethods(MethodToEvent):
|
||||||
cls_object=AccountRecords,
|
cls_object=AccountRecords,
|
||||||
response_model=UpdateAccountRecord,
|
response_model=UpdateAccountRecord,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@endpoint_wrapper("/account/records/address/list")
|
|
||||||
async def address_list(request: "Request", data: ListOptionsRequestModel):
|
|
||||||
"""Handle address list endpoint."""
|
|
||||||
return {
|
|
||||||
"data": data,
|
|
||||||
"request": str(request.headers),
|
|
||||||
"request_url": str(request.url),
|
|
||||||
"request_base_url": str(request.base_url),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@endpoint_wrapper("/account/records/address/create")
|
|
||||||
async def address_create(request: "Request", data: DictRequestModel):
|
|
||||||
"""Handle address creation endpoint."""
|
|
||||||
return {
|
|
||||||
"data": data,
|
|
||||||
"request": str(request.headers),
|
|
||||||
"request_url": str(request.url),
|
|
||||||
"request_base_url": str(request.base_url),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@endpoint_wrapper("/account/records/address/search")
|
|
||||||
async def address_search(request: "Request", data: DictRequestModel):
|
|
||||||
"""Handle address search endpoint."""
|
|
||||||
return {"data": data}
|
|
||||||
|
|
||||||
|
|
||||||
router = APIRouter()
|
|
||||||
|
|
||||||
|
|
||||||
@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"),
|
|
||||||
):
|
|
||||||
"""
|
|
||||||
Handle address update endpoint.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request: FastAPI request object
|
|
||||||
address_uu_id: UUID of the address to update
|
|
||||||
request_data: Request body containing updated address data
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
DictJsonResponse: Response containing updated address info
|
|
||||||
"""
|
|
||||||
return DictJsonResponse(
|
|
||||||
data={
|
|
||||||
"address_uu_id": address_uu_id,
|
|
||||||
"data": request_data.root,
|
|
||||||
"request": str(request.headers),
|
|
||||||
"request_url": str(request.url),
|
|
||||||
"request_base_url": str(request.base_url),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
prefix = "/account/records"
|
|
||||||
|
|
||||||
# Account Records Router Configuration
|
|
||||||
ACCOUNT_RECORDS_CONFIG = RouteFactoryConfig(
|
|
||||||
name="account_records",
|
|
||||||
prefix=prefix,
|
|
||||||
tags=["Account Records"],
|
|
||||||
include_in_schema=True,
|
|
||||||
endpoints=[
|
|
||||||
EndpointFactoryConfig(
|
|
||||||
url_prefix=prefix,
|
|
||||||
url_endpoint="/address/list",
|
|
||||||
url_of_endpoint="/account/records/address/list",
|
|
||||||
endpoint="/address/list",
|
|
||||||
method="POST",
|
|
||||||
summary="List Active/Delete/Confirm Address",
|
|
||||||
description="List Active/Delete/Confirm Address",
|
|
||||||
is_auth_required=True,
|
|
||||||
is_event_required=True,
|
|
||||||
endpoint_function=address_list,
|
|
||||||
),
|
|
||||||
EndpointFactoryConfig(
|
|
||||||
url_prefix=prefix,
|
|
||||||
url_endpoint="/address/create",
|
|
||||||
url_of_endpoint="/account/records/address/create",
|
|
||||||
endpoint="/address/create",
|
|
||||||
method="POST",
|
|
||||||
summary="Create Address with given auth levels",
|
|
||||||
description="Create Address with given auth levels",
|
|
||||||
is_auth_required=False,
|
|
||||||
is_event_required=False,
|
|
||||||
endpoint_function=address_create,
|
|
||||||
),
|
|
||||||
EndpointFactoryConfig(
|
|
||||||
url_prefix=prefix,
|
|
||||||
url_endpoint="/address/search",
|
|
||||||
url_of_endpoint="/account/records/address/search",
|
|
||||||
endpoint="/address/search",
|
|
||||||
method="POST",
|
|
||||||
summary="Search Address with given auth levels",
|
|
||||||
description="Search Address with given auth levels",
|
|
||||||
is_auth_required=True,
|
|
||||||
is_event_required=True,
|
|
||||||
endpoint_function=address_search,
|
|
||||||
),
|
|
||||||
EndpointFactoryConfig(
|
|
||||||
url_prefix=prefix,
|
|
||||||
url_endpoint="/address/{address_uu_id}",
|
|
||||||
url_of_endpoint="/account/records/address/{address_uu_id}",
|
|
||||||
endpoint="/address/{address_uu_id}",
|
|
||||||
method="PUT",
|
|
||||||
summary="Update Address with given auth levels",
|
|
||||||
description="Update Address with given auth levels",
|
|
||||||
is_auth_required=True,
|
|
||||||
is_event_required=True,
|
|
||||||
endpoint_function=address_update,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
).as_dict()
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,129 @@
|
||||||
|
"""
|
||||||
|
Account records endpoint configurations.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from ApiEvents.abstract_class import RouteFactoryConfig, EndpointFactoryConfig, endpoint_wrapper
|
||||||
|
from ApiEvents.base_request_model import DictRequestModel
|
||||||
|
|
||||||
|
|
||||||
|
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):
|
||||||
|
"""Handle address list endpoint."""
|
||||||
|
return {
|
||||||
|
"data": data,
|
||||||
|
"request": str(request.headers),
|
||||||
|
"request_url": str(request.url),
|
||||||
|
"request_base_url": str(request.base_url),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@endpoint_wrapper("/account/records/address/create")
|
||||||
|
async def address_create(request: "Request", data: DictRequestModel):
|
||||||
|
"""Handle address creation endpoint."""
|
||||||
|
return {
|
||||||
|
"data": data,
|
||||||
|
"request": str(request.headers),
|
||||||
|
"request_url": str(request.url),
|
||||||
|
"request_base_url": str(request.base_url),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@endpoint_wrapper("/account/records/address/search")
|
||||||
|
async def address_search(request: "Request", data: DictRequestModel):
|
||||||
|
"""Handle address search endpoint."""
|
||||||
|
return {"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"),
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Handle address update endpoint.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request: FastAPI request object
|
||||||
|
address_uu_id: UUID of the address to update
|
||||||
|
request_data: Request body containing updated address data
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
DictJsonResponse: Response containing updated address info
|
||||||
|
"""
|
||||||
|
return DictJsonResponse(
|
||||||
|
data={
|
||||||
|
"address_uu_id": address_uu_id,
|
||||||
|
"data": request_data.root,
|
||||||
|
"request": str(request.headers),
|
||||||
|
"request_url": str(request.url),
|
||||||
|
"request_base_url": str(request.base_url),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
prefix = "/account/records"
|
||||||
|
|
||||||
|
# Account Records Router Configuration
|
||||||
|
ACCOUNT_RECORDS_CONFIG = RouteFactoryConfig(
|
||||||
|
name="account_records",
|
||||||
|
prefix=prefix,
|
||||||
|
tags=["Account Records"],
|
||||||
|
include_in_schema=True,
|
||||||
|
endpoints=[
|
||||||
|
EndpointFactoryConfig(
|
||||||
|
url_prefix=prefix,
|
||||||
|
url_endpoint="/address/list",
|
||||||
|
url_of_endpoint="/account/records/address/list",
|
||||||
|
endpoint="/address/list",
|
||||||
|
method="POST",
|
||||||
|
summary="List Active/Delete/Confirm Address",
|
||||||
|
description="List Active/Delete/Confirm Address",
|
||||||
|
is_auth_required=True,
|
||||||
|
is_event_required=True,
|
||||||
|
endpoint_function=address_list,
|
||||||
|
),
|
||||||
|
EndpointFactoryConfig(
|
||||||
|
url_prefix=prefix,
|
||||||
|
url_endpoint="/address/create",
|
||||||
|
url_of_endpoint="/account/records/address/create",
|
||||||
|
endpoint="/address/create",
|
||||||
|
method="POST",
|
||||||
|
summary="Create Address with given auth levels",
|
||||||
|
description="Create Address with given auth levels",
|
||||||
|
is_auth_required=False,
|
||||||
|
is_event_required=False,
|
||||||
|
endpoint_function=address_create,
|
||||||
|
),
|
||||||
|
EndpointFactoryConfig(
|
||||||
|
url_prefix=prefix,
|
||||||
|
url_endpoint="/address/search",
|
||||||
|
url_of_endpoint="/account/records/address/search",
|
||||||
|
endpoint="/address/search",
|
||||||
|
method="POST",
|
||||||
|
summary="Search Address with given auth levels",
|
||||||
|
description="Search Address with given auth levels",
|
||||||
|
is_auth_required=True,
|
||||||
|
is_event_required=True,
|
||||||
|
endpoint_function=address_search,
|
||||||
|
),
|
||||||
|
EndpointFactoryConfig(
|
||||||
|
url_prefix=prefix,
|
||||||
|
url_endpoint="/address/{address_uu_id}",
|
||||||
|
url_of_endpoint="/account/records/address/{address_uu_id}",
|
||||||
|
endpoint="/address/{address_uu_id}",
|
||||||
|
method="PUT",
|
||||||
|
summary="Update Address with given auth levels",
|
||||||
|
description="Update Address with given auth levels",
|
||||||
|
is_auth_required=True,
|
||||||
|
is_event_required=True,
|
||||||
|
endpoint_function=address_update,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).as_dict()
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
"""
|
||||||
|
Account records request and response models.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING, Dict, Any
|
||||||
|
from pydantic import BaseModel, Field, RootModel
|
||||||
|
from ApiEvents.base_request_model import BaseRequestModel
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from ApiValidations.Request import (
|
||||||
|
InsertAccountRecord,
|
||||||
|
UpdateAccountRecord,
|
||||||
|
ListOptions,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class AddressUpdateRequest(RootModel[Dict[str, Any]]):
|
||||||
|
"""Request model for address update."""
|
||||||
|
model_config = {
|
||||||
|
"json_schema_extra": {
|
||||||
|
"example": {
|
||||||
|
"street": "123 Main St",
|
||||||
|
"city": "Example City",
|
||||||
|
"country": "Example Country"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class AddressUpdateResponse(BaseModel):
|
||||||
|
"""Response model for address update."""
|
||||||
|
address_uu_id: str = Field(..., description="UUID of the updated address")
|
||||||
|
data: Dict[str, Any] = Field(..., description="Updated address data")
|
||||||
|
function_code: str = Field(..., description="Function code for the endpoint")
|
||||||
|
|
||||||
|
|
||||||
|
class InsertAccountRecordRequestModel(BaseRequestModel["InsertAccountRecord"]):
|
||||||
|
"""Request model for inserting account records."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateAccountRecordRequestModel(BaseRequestModel["UpdateAccountRecord"]):
|
||||||
|
"""Request model for updating account records."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ListOptionsRequestModel(BaseRequestModel["ListOptions"]):
|
||||||
|
"""Request model for list options."""
|
||||||
|
pass
|
||||||
|
|
@ -6,7 +6,7 @@ to be used by the dynamic route creation system.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import Dict, List, Any
|
from typing import Dict, List, Any
|
||||||
from .account.account_records import ACCOUNT_RECORDS_CONFIG
|
from .account.endpoints import ACCOUNT_RECORDS_CONFIG
|
||||||
|
|
||||||
|
|
||||||
# Registry of all route configurations
|
# Registry of all route configurations
|
||||||
|
|
|
||||||
|
|
@ -5,54 +5,22 @@ This module provides base request models that can be used across different endpo
|
||||||
to ensure consistent request handling and validation.
|
to ensure consistent request handling and validation.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import Dict, Any, Generic, TypeVar, Optional, get_args, get_origin
|
from typing import Dict, Any, Generic, TypeVar, Optional, Union, get_args
|
||||||
from pydantic import RootModel, BaseModel, Field, ConfigDict
|
from pydantic import BaseModel, Field, ConfigDict, RootModel
|
||||||
|
|
||||||
|
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
|
|
||||||
|
|
||||||
class BaseRequestModel(RootModel[T]):
|
class BaseRequestModel(RootModel[T], Generic[T]):
|
||||||
"""Base model for all API requests.
|
"""Base model for all API requests."""
|
||||||
|
|
||||||
This model can be extended to create specific request models for different endpoints.
|
|
||||||
"""
|
|
||||||
|
|
||||||
model_config = ConfigDict(
|
model_config = ConfigDict(
|
||||||
json_schema_extra={"example": {}} # Will be populated by subclasses
|
json_schema_extra={"example": {}} # Will be populated by subclasses
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def model_json_schema(cls, *args, **kwargs):
|
|
||||||
schema = super().model_json_schema(*args, **kwargs)
|
|
||||||
if hasattr(cls, "__orig_bases__"):
|
|
||||||
generic_type = get_args(cls.__orig_bases__[0])[0]
|
|
||||||
if generic_type and hasattr(generic_type, "model_json_schema"):
|
|
||||||
type_schema = generic_type.model_json_schema()
|
|
||||||
if "properties" in type_schema:
|
|
||||||
schema["properties"] = type_schema["properties"]
|
|
||||||
if "required" in type_schema:
|
|
||||||
schema["required"] = type_schema["required"]
|
|
||||||
if "title" in type_schema:
|
|
||||||
schema["title"] = type_schema["title"]
|
|
||||||
if "example" in type_schema:
|
|
||||||
schema["example"] = type_schema["example"]
|
|
||||||
elif "properties" in type_schema:
|
|
||||||
schema["example"] = {
|
|
||||||
key: prop.get("example", "string")
|
|
||||||
for key, prop in type_schema["properties"].items()
|
|
||||||
}
|
|
||||||
schema["type"] = "object"
|
|
||||||
return schema
|
|
||||||
|
|
||||||
@property
|
|
||||||
def data(self) -> T:
|
|
||||||
return self.root
|
|
||||||
|
|
||||||
|
|
||||||
class DictRequestModel(RootModel[Dict[str, Any]]):
|
class DictRequestModel(RootModel[Dict[str, Any]]):
|
||||||
"""Request model for endpoints that accept dictionary data."""
|
"""Request model for endpoints that accept dictionary data."""
|
||||||
|
|
||||||
model_config = ConfigDict(
|
model_config = ConfigDict(
|
||||||
json_schema_extra={
|
json_schema_extra={
|
||||||
"example": {
|
"example": {
|
||||||
|
|
@ -63,40 +31,9 @@ class DictRequestModel(RootModel[Dict[str, Any]]):
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def model_json_schema(cls, *args, **kwargs):
|
|
||||||
schema = super().model_json_schema(*args, **kwargs)
|
|
||||||
schema.update(
|
|
||||||
{
|
|
||||||
"title": "Dictionary Request Model",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"key1": {"type": "string", "example": "value1"},
|
|
||||||
"key2": {"type": "string", "example": "value2"},
|
|
||||||
"nested": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"inner_key": {"type": "string", "example": "inner_value"}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"example": {
|
|
||||||
"key1": "value1",
|
|
||||||
"key2": "value2",
|
|
||||||
"nested": {"inner_key": "inner_value"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
return schema
|
|
||||||
|
|
||||||
@property
|
|
||||||
def data(self) -> Dict[str, Any]:
|
|
||||||
return self.root
|
|
||||||
|
|
||||||
|
|
||||||
class SuccessResponse(BaseModel):
|
class SuccessResponse(BaseModel):
|
||||||
"""Standard success response model."""
|
"""Standard success response model."""
|
||||||
|
|
||||||
token: str = Field(..., example="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...")
|
token: str = Field(..., example="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...")
|
||||||
user_info: Dict[str, Any] = Field(
|
user_info: Dict[str, Any] = Field(
|
||||||
...,
|
...,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,14 @@
|
||||||
def get_line_number_for_error():
|
"""Utility functions for getting line numbers and file locations."""
|
||||||
from inspect import currentframe, getframeinfo
|
|
||||||
|
|
||||||
frameinfo = getframeinfo(currentframe())
|
from inspect import currentframe, getframeinfo, stack
|
||||||
|
|
||||||
|
|
||||||
|
def get_line_number_for_error() -> str:
|
||||||
|
"""Get the file name and line number of where an error occurred.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: A string in the format 'filename | line_number' showing where the error occurred
|
||||||
|
"""
|
||||||
|
caller = stack()[1] # Get the caller's frame
|
||||||
|
frameinfo = getframeinfo(caller[0])
|
||||||
return f"{frameinfo.filename} | {frameinfo.lineno}"
|
return f"{frameinfo.filename} | {frameinfo.lineno}"
|
||||||
|
|
|
||||||
|
|
@ -30,12 +30,14 @@ class UserLoginModule:
|
||||||
error_code="HTTP_400_BAD_REQUEST",
|
error_code="HTTP_400_BAD_REQUEST",
|
||||||
lang="en",
|
lang="en",
|
||||||
loc=get_line_number_for_error(),
|
loc=get_line_number_for_error(),
|
||||||
|
sys_msg="User not found",
|
||||||
)
|
)
|
||||||
return found_user
|
return found_user
|
||||||
|
|
||||||
async def login_user_via_credentials(self, access_data: "Login") -> Dict[str, Any]:
|
async def login_user_via_credentials(self, access_data: "Login") -> Dict[str, Any]:
|
||||||
"""Login user via credentials."""
|
"""Login user via credentials."""
|
||||||
# Get the actual data from the BaseRequestModel if needed
|
# Get the actual data from the BaseRequestModel if needed
|
||||||
|
print("access_data", access_data)
|
||||||
if hasattr(access_data, "data"):
|
if hasattr(access_data, "data"):
|
||||||
access_data = access_data.data
|
access_data = access_data.data
|
||||||
|
|
||||||
|
|
@ -47,6 +49,7 @@ class UserLoginModule:
|
||||||
error_code="HTTP_400_BAD_REQUEST",
|
error_code="HTTP_400_BAD_REQUEST",
|
||||||
lang=found_user.lang,
|
lang=found_user.lang,
|
||||||
loc=get_line_number_for_error(),
|
loc=get_line_number_for_error(),
|
||||||
|
sys_msg="Invalid password create a password to user first",
|
||||||
)
|
)
|
||||||
|
|
||||||
if PasswordModule.check_password(
|
if PasswordModule.check_password(
|
||||||
|
|
@ -65,4 +68,5 @@ class UserLoginModule:
|
||||||
error_code="HTTP_400_BAD_REQUEST",
|
error_code="HTTP_400_BAD_REQUEST",
|
||||||
lang=found_user.lang,
|
lang=found_user.lang,
|
||||||
loc=get_line_number_for_error(),
|
loc=get_line_number_for_error(),
|
||||||
|
sys_msg="login_user_via_credentials raised error",
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,10 @@ class TokenService:
|
||||||
).data
|
).data
|
||||||
if not living_spaces:
|
if not living_spaces:
|
||||||
raise HTTPExceptionApi(
|
raise HTTPExceptionApi(
|
||||||
error_code="", lang="en", loc=get_line_number_for_error()
|
error_code="",
|
||||||
|
lang="en",
|
||||||
|
loc=get_line_number_for_error(),
|
||||||
|
sys_msg="User does not have any living space",
|
||||||
)
|
)
|
||||||
|
|
||||||
occupants_selection_dict: Dict[str, Any] = {}
|
occupants_selection_dict: Dict[str, Any] = {}
|
||||||
|
|
@ -79,7 +82,10 @@ class TokenService:
|
||||||
).data
|
).data
|
||||||
if not build_parts_selection:
|
if not build_parts_selection:
|
||||||
raise HTTPExceptionApi(
|
raise HTTPExceptionApi(
|
||||||
error_code="", lang="en", loc=get_line_number_for_error()
|
error_code="",
|
||||||
|
lang="en",
|
||||||
|
loc=get_line_number_for_error(),
|
||||||
|
sys_msg="User does not have any living space",
|
||||||
)
|
)
|
||||||
|
|
||||||
build_part = build_parts_selection.get(1)
|
build_part = build_parts_selection.get(1)
|
||||||
|
|
@ -211,7 +217,10 @@ class TokenService:
|
||||||
"companies_list": companies_list,
|
"companies_list": companies_list,
|
||||||
}
|
}
|
||||||
raise HTTPExceptionApi(
|
raise HTTPExceptionApi(
|
||||||
error_code="", lang="en", loc=get_line_number_for_error()
|
error_code="",
|
||||||
|
lang="en",
|
||||||
|
loc=get_line_number_for_error(),
|
||||||
|
sys_msg="Creating Token failed...",
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
@ -287,11 +296,17 @@ class TokenService:
|
||||||
"""Validate request has required token headers."""
|
"""Validate request has required token headers."""
|
||||||
if not hasattr(request, "headers"):
|
if not hasattr(request, "headers"):
|
||||||
raise HTTPExceptionApi(
|
raise HTTPExceptionApi(
|
||||||
error_code="", lang="en", loc=get_line_number_for_error()
|
error_code="",
|
||||||
|
lang="en",
|
||||||
|
loc=get_line_number_for_error(),
|
||||||
|
sys_msg="Request has no headers",
|
||||||
)
|
)
|
||||||
if not request.headers.get(Auth.ACCESS_TOKEN_TAG):
|
if not request.headers.get(Auth.ACCESS_TOKEN_TAG):
|
||||||
raise HTTPExceptionApi(
|
raise HTTPExceptionApi(
|
||||||
error_code="", lang="en", loc=get_line_number_for_error()
|
error_code="",
|
||||||
|
lang="en",
|
||||||
|
loc=get_line_number_for_error(),
|
||||||
|
sys_msg="Request has no access token presented",
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
@ -322,7 +337,10 @@ class TokenService:
|
||||||
return OccupantTokenObject(**redis_object)
|
return OccupantTokenObject(**redis_object)
|
||||||
|
|
||||||
raise HTTPExceptionApi(
|
raise HTTPExceptionApi(
|
||||||
error_code="", lang="en", loc=get_line_number_for_error()
|
error_code="",
|
||||||
|
lang="en",
|
||||||
|
loc=get_line_number_for_error(),
|
||||||
|
sys_msg="Unknown user type",
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
@ -336,7 +354,10 @@ class TokenService:
|
||||||
return cls._process_redis_object(redis_object)
|
return cls._process_redis_object(redis_object)
|
||||||
|
|
||||||
raise HTTPExceptionApi(
|
raise HTTPExceptionApi(
|
||||||
error_code="", lang="en", loc=get_line_number_for_error()
|
error_code="",
|
||||||
|
lang="en",
|
||||||
|
loc=get_line_number_for_error(),
|
||||||
|
sys_msg="Invalid access token",
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
@ -350,5 +371,8 @@ class TokenService:
|
||||||
return cls._process_redis_object(redis_object)
|
return cls._process_redis_object(redis_object)
|
||||||
|
|
||||||
raise HTTPExceptionApi(
|
raise HTTPExceptionApi(
|
||||||
error_code="", lang="en", loc=get_line_number_for_error()
|
error_code="",
|
||||||
|
lang="en",
|
||||||
|
loc=get_line_number_for_error(),
|
||||||
|
sys_msg="Invalid access token",
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ 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 setup_security_schema, configure_route_security
|
||||||
from fastapi.openapi.utils import get_openapi
|
from open_api_creator import OpenAPISchemaCreator, create_openapi_schema
|
||||||
|
|
||||||
|
|
||||||
def create_app() -> FastAPI:
|
def create_app() -> FastAPI:
|
||||||
|
|
@ -63,12 +63,8 @@ def create_app() -> FastAPI:
|
||||||
if app.openapi_schema:
|
if app.openapi_schema:
|
||||||
return app.openapi_schema
|
return app.openapi_schema
|
||||||
|
|
||||||
openapi_schema = get_openapi(
|
# Create OpenAPI schema using our custom creator
|
||||||
title="WAG Management API",
|
openapi_schema = create_openapi_schema(app)
|
||||||
version="4.0.0",
|
|
||||||
description="WAG Management API Service",
|
|
||||||
routes=app.routes,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Add security scheme
|
# Add security scheme
|
||||||
openapi_schema.update(setup_security_schema())
|
openapi_schema.update(setup_security_schema())
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,10 @@ class MiddlewareModule:
|
||||||
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:
|
||||||
raise HTTPExceptionApi(
|
raise HTTPExceptionApi(
|
||||||
error_code="USER_NOT_FOUND", lang="tr", loc=get_line_number_for_error()
|
error_code="USER_NOT_FOUND",
|
||||||
|
lang="tr",
|
||||||
|
loc=get_line_number_for_error(),
|
||||||
|
sys_msg="TokenService: Token Context couldnt retrieved from redis",
|
||||||
)
|
)
|
||||||
|
|
||||||
return AuthContext(token_context=token_context)
|
return AuthContext(token_context=token_context)
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,10 @@ This module provides functionality to create and customize OpenAPI documentation
|
||||||
|
|
||||||
from typing import Any, Dict, List, Optional, Set
|
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.openapi.utils import get_openapi
|
from fastapi.openapi.utils import get_openapi
|
||||||
from AllConfigs.main import MainConfig as Config
|
from AllConfigs.main import MainConfig as Config
|
||||||
|
from create_routes import get_all_routers
|
||||||
|
|
||||||
|
|
||||||
class OpenAPISchemaCreator:
|
class OpenAPISchemaCreator:
|
||||||
|
|
@ -28,7 +30,7 @@ class OpenAPISchemaCreator:
|
||||||
app: FastAPI application instance
|
app: FastAPI application instance
|
||||||
"""
|
"""
|
||||||
self.app = app
|
self.app = app
|
||||||
self.protected_paths: Set[str] = set()
|
_, self.protected_routes = get_all_routers()
|
||||||
self.tags_metadata = self._create_tags_metadata()
|
self.tags_metadata = self._create_tags_metadata()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
@ -60,16 +62,16 @@ class OpenAPISchemaCreator:
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
"Bearer Auth": {
|
"Bearer Auth": {
|
||||||
"type": "apiKey",
|
"type": "http",
|
||||||
"in": "header",
|
"scheme": "bearer",
|
||||||
"name": "evyos-session-key",
|
"bearerFormat": "JWT",
|
||||||
"description": "Enter: **'Bearer <JWT>'**, where JWT is the access token",
|
"description": "Enter the token with the `Bearer: ` prefix",
|
||||||
},
|
},
|
||||||
"API Key": {
|
"API Key": {
|
||||||
"type": "apiKey",
|
"type": "apiKey",
|
||||||
"in": "header",
|
"in": "header",
|
||||||
"name": "X-API-Key",
|
"name": "X-API-Key",
|
||||||
"description": "API key for service authentication",
|
"description": "Optional API key for service authentication",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -82,20 +84,10 @@ class OpenAPISchemaCreator:
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
"401": {
|
"401": {
|
||||||
"description": "Unauthorized - Authentication failed or not provided",
|
"description": "Unauthorized - Invalid or missing credentials",
|
||||||
"content": {
|
"content": {
|
||||||
"application/json": {
|
"application/json": {
|
||||||
"schema": {
|
"schema": {"$ref": "#/components/schemas/HTTPValidationError"}
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"detail": {"type": "string"},
|
|
||||||
"error_code": {"type": "string"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"example": {
|
|
||||||
"detail": "Invalid authentication credentials",
|
|
||||||
"error_code": "INVALID_CREDENTIALS",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -135,6 +127,62 @@ class OpenAPISchemaCreator:
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def _process_request_body(self, path: str, method: str, schema: Dict[str, Any]) -> None:
|
||||||
|
"""
|
||||||
|
Process request body to include examples from model config.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path: Route path
|
||||||
|
method: HTTP method
|
||||||
|
schema: OpenAPI schema to modify
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
route_schema = schema["paths"][path][method]
|
||||||
|
if "requestBody" in route_schema:
|
||||||
|
request_body = route_schema["requestBody"]
|
||||||
|
if "content" in request_body:
|
||||||
|
content = request_body["content"]
|
||||||
|
if "application/json" in content:
|
||||||
|
json_content = content["application/json"]
|
||||||
|
if "schema" in json_content and "$ref" in json_content["schema"]:
|
||||||
|
ref = json_content["schema"]["$ref"]
|
||||||
|
model_name = ref.split("/")[-1]
|
||||||
|
if model_name in schema["components"]["schemas"]:
|
||||||
|
model_schema = schema["components"]["schemas"][model_name]
|
||||||
|
if "example" in model_schema:
|
||||||
|
json_content["example"] = model_schema["example"]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _process_response_examples(self, path: str, method: str, schema: Dict[str, Any]) -> None:
|
||||||
|
"""
|
||||||
|
Process response body to include examples from model config.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path: Route path
|
||||||
|
method: HTTP method
|
||||||
|
schema: OpenAPI schema to modify
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
route_schema = schema["paths"][path][method]
|
||||||
|
if "responses" in route_schema:
|
||||||
|
responses = route_schema["responses"]
|
||||||
|
if "200" in responses:
|
||||||
|
response = responses["200"]
|
||||||
|
if "content" in response:
|
||||||
|
content = response["content"]
|
||||||
|
if "application/json" in content:
|
||||||
|
json_content = content["application/json"]
|
||||||
|
if "schema" in json_content and "$ref" in json_content["schema"]:
|
||||||
|
ref = json_content["schema"]["$ref"]
|
||||||
|
model_name = ref.split("/")[-1]
|
||||||
|
if model_name in schema["components"]["schemas"]:
|
||||||
|
model_schema = schema["components"]["schemas"][model_name]
|
||||||
|
if "example" in model_schema:
|
||||||
|
json_content["example"] = model_schema["example"]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
def configure_route_security(
|
def configure_route_security(
|
||||||
self, path: str, method: str, schema: Dict[str, Any]
|
self, path: str, method: str, schema: Dict[str, Any]
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|
@ -146,7 +194,8 @@ class OpenAPISchemaCreator:
|
||||||
method: HTTP method
|
method: HTTP method
|
||||||
schema: OpenAPI schema to modify
|
schema: OpenAPI schema to modify
|
||||||
"""
|
"""
|
||||||
if path not in Config.INSECURE_PATHS:
|
# Check if route is protected based on dynamic routing info
|
||||||
|
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": []},
|
{"API Key": []},
|
||||||
|
|
@ -155,6 +204,11 @@ class OpenAPISchemaCreator:
|
||||||
self._create_common_responses()
|
self._create_common_responses()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Process request body examples
|
||||||
|
self._process_request_body(path, method, schema)
|
||||||
|
# Process response examples
|
||||||
|
self._process_response_examples(path, method, schema)
|
||||||
|
|
||||||
def create_schema(self) -> Dict[str, Any]:
|
def create_schema(self) -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
Create the complete OpenAPI schema.
|
Create the complete OpenAPI schema.
|
||||||
|
|
@ -174,9 +228,7 @@ class OpenAPISchemaCreator:
|
||||||
if "components" not in openapi_schema:
|
if "components" not in openapi_schema:
|
||||||
openapi_schema["components"] = {}
|
openapi_schema["components"] = {}
|
||||||
|
|
||||||
openapi_schema["components"][
|
openapi_schema["components"]["securitySchemes"] = self._create_security_schemes()
|
||||||
"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:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
class HTTPExceptionApi(Exception):
|
class HTTPExceptionApi(Exception):
|
||||||
|
|
||||||
def __init__(self, error_code: str, lang: str, loc: str = ""):
|
def __init__(self, error_code: str, lang: str, loc: str = "", sys_msg: str = ""):
|
||||||
self.error_code = error_code
|
self.error_code = error_code
|
||||||
self.lang = lang
|
self.lang = lang
|
||||||
self.loc = loc
|
self.loc = loc
|
||||||
|
self.sys_msg = sys_msg
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ def handle_mongo_errors(func: Callable) -> Callable:
|
||||||
lang="en",
|
lang="en",
|
||||||
error_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
error_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
loc=get_line_number_for_error(),
|
loc=get_line_number_for_error(),
|
||||||
|
sys_msg=str(e),
|
||||||
)
|
)
|
||||||
|
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ operations and password-related functionality.
|
||||||
|
|
||||||
from typing import Any, Dict, Optional
|
from typing import Any, Dict, Optional
|
||||||
from fastapi import HTTPException, status
|
from fastapi import HTTPException, status
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -26,9 +27,11 @@ class MongoBaseException(Exception):
|
||||||
|
|
||||||
def to_http_exception(self) -> HTTPException:
|
def to_http_exception(self) -> HTTPException:
|
||||||
"""Convert to FastAPI HTTPException."""
|
"""Convert to FastAPI HTTPException."""
|
||||||
return HTTPExceptionApi(
|
raise HTTPExceptionApi(
|
||||||
lang="en",
|
lang="en",
|
||||||
error_code=self.status_code,
|
error_code=self.status_code,
|
||||||
|
loc=get_line_number_for_error(),
|
||||||
|
sys_msg=self.message,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,24 +39,28 @@ def handle_mongo_errors(func):
|
||||||
error_code="HTTP_503_SERVICE_UNAVAILABLE",
|
error_code="HTTP_503_SERVICE_UNAVAILABLE",
|
||||||
lang="en",
|
lang="en",
|
||||||
loc=get_line_number_for_error(),
|
loc=get_line_number_for_error(),
|
||||||
|
sys_msg="MongoDB connection failed",
|
||||||
)
|
)
|
||||||
except ServerSelectionTimeoutError:
|
except ServerSelectionTimeoutError:
|
||||||
raise HTTPExceptionApi(
|
raise HTTPExceptionApi(
|
||||||
error_code="HTTP_504_GATEWAY_TIMEOUT",
|
error_code="HTTP_504_GATEWAY_TIMEOUT",
|
||||||
lang="en",
|
lang="en",
|
||||||
loc=get_line_number_for_error(),
|
loc=get_line_number_for_error(),
|
||||||
|
sys_msg="MongoDB connection timed out",
|
||||||
)
|
)
|
||||||
except OperationFailure as e:
|
except OperationFailure as e:
|
||||||
raise HTTPExceptionApi(
|
raise HTTPExceptionApi(
|
||||||
error_code="HTTP_400_BAD_REQUEST",
|
error_code="HTTP_400_BAD_REQUEST",
|
||||||
lang="en",
|
lang="en",
|
||||||
loc=get_line_number_for_error(),
|
loc=get_line_number_for_error(),
|
||||||
|
sys_msg=str(e),
|
||||||
)
|
)
|
||||||
except PyMongoError as e:
|
except PyMongoError as e:
|
||||||
raise HTTPExceptionApi(
|
raise HTTPExceptionApi(
|
||||||
error_code="HTTP_500_INTERNAL_SERVER_ERROR",
|
error_code="HTTP_500_INTERNAL_SERVER_ERROR",
|
||||||
lang="en",
|
lang="en",
|
||||||
loc=get_line_number_for_error(),
|
loc=get_line_number_for_error(),
|
||||||
|
sys_msg=str(e),
|
||||||
)
|
)
|
||||||
|
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
|
||||||
|
|
@ -161,6 +161,7 @@ class BaseJsonResponse(Generic[T]):
|
||||||
lang=cls_object.lang,
|
lang=cls_object.lang,
|
||||||
error_code="HTTP_400_BAD_REQUEST",
|
error_code="HTTP_400_BAD_REQUEST",
|
||||||
loc=get_line_number_for_error(),
|
loc=get_line_number_for_error(),
|
||||||
|
sys_msg=f"Invalid data type: {type(data)}",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -201,6 +202,7 @@ class SinglePostgresResponse(BaseJsonResponse[T]):
|
||||||
lang=cls_object.lang,
|
lang=cls_object.lang,
|
||||||
error_code="HTTP_400_BAD_REQUEST",
|
error_code="HTTP_400_BAD_REQUEST",
|
||||||
loc=get_line_number_for_error(),
|
loc=get_line_number_for_error(),
|
||||||
|
sys_msg="No data found",
|
||||||
)
|
)
|
||||||
|
|
||||||
instance = super().__new__(cls)
|
instance = super().__new__(cls)
|
||||||
|
|
@ -257,6 +259,7 @@ class AlchemyJsonResponse(BaseJsonResponse[T]):
|
||||||
lang=cls_object.lang,
|
lang=cls_object.lang,
|
||||||
error_code="HTTP_400_BAD_REQUEST",
|
error_code="HTTP_400_BAD_REQUEST",
|
||||||
loc=get_line_number_for_error(),
|
loc=get_line_number_for_error(),
|
||||||
|
sys_msg="No data found",
|
||||||
)
|
)
|
||||||
|
|
||||||
instance = super().__new__(cls)
|
instance = super().__new__(cls)
|
||||||
|
|
|
||||||
|
|
@ -139,6 +139,7 @@ class FilterAttributes:
|
||||||
error_code="HTTP_304_NOT_MODIFIED",
|
error_code="HTTP_304_NOT_MODIFIED",
|
||||||
lang=cls.lang or "tr",
|
lang=cls.lang or "tr",
|
||||||
loc=get_line_number_for_error(),
|
loc=get_line_number_for_error(),
|
||||||
|
sys_msg=str(e),
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
@ -173,6 +174,7 @@ class FilterAttributes:
|
||||||
error_code="HTTP_304_NOT_MODIFIED",
|
error_code="HTTP_304_NOT_MODIFIED",
|
||||||
lang=cls.lang or "tr",
|
lang=cls.lang or "tr",
|
||||||
loc=get_line_number_for_error(),
|
loc=get_line_number_for_error(),
|
||||||
|
sys_msg=str(e),
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
@ -193,6 +195,7 @@ class FilterAttributes:
|
||||||
error_code="HTTP_304_NOT_MODIFIED",
|
error_code="HTTP_304_NOT_MODIFIED",
|
||||||
lang=cls.lang or "tr",
|
lang=cls.lang or "tr",
|
||||||
loc=get_line_number_for_error(),
|
loc=get_line_number_for_error(),
|
||||||
|
sys_msg=str(e),
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
@ -225,6 +228,7 @@ class FilterAttributes:
|
||||||
error_code="HTTP_304_NOT_MODIFIED",
|
error_code="HTTP_304_NOT_MODIFIED",
|
||||||
lang=cls.lang or "tr",
|
lang=cls.lang or "tr",
|
||||||
loc=get_line_number_for_error(),
|
loc=get_line_number_for_error(),
|
||||||
|
sys_msg=str(e),
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue