middleware and respnse models updated

This commit is contained in:
2025-01-27 17:25:49 +03:00
parent e403993d24
commit b88f910a43
54 changed files with 1125 additions and 808 deletions

View File

@@ -1,56 +1,39 @@
from Events.Engine.abstract_class import Event
from .models import (
LoginSuperUserRequestModel,
LoginSuperUserResponseModel,
SelectCompanyOrOccupantTypeSuperUserRequestModel,
SelectCompanyOrOccupantTypeSuperUserResponseModel,
EmployeeSelectionSuperUserRequestModel,
EmployeeSelectionSuperUserResponseModel,
OccupantSelectionSuperUserRequestModel,
OccupantSelectionSuperUserResponseModel,
)
from .function_handlers import (
authentication_login_with_domain_and_creds,
authentication_select_company_or_occupant_type,
authentication_check_token_is_valid,
authentication_refresh_user_info,
authentication_change_password,
authentication_create_password,
authentication_disconnect_user,
authentication_logout_user,
authentication_refresher_token,
authentication_forgot_password,
authentication_reset_password,
authentication_download_avatar,
)
from .models import AuthenticationRequestModels, AuthenticationResponseModels
from .function_handlers import AuthenticationFunctions
# Auth Login
authentication_login_super_user_event = Event(
name="authentication_login_super_user_event",
key="a5d2d0d1-3e9b-4b0f-8c7d-6d4a4b4c4d4e",
request_validator=LoginSuperUserRequestModel,
request_validator=AuthenticationRequestModels.LoginSuperUserRequestModel,
# response_validator=LoginSuperUserResponseModel,
description="Login super user",
)
authentication_login_super_user_event.endpoint_callable = (
authentication_login_with_domain_and_creds
AuthenticationFunctions.authentication_login_with_domain_and_creds
)
# Auth Select Company or Occupant Type
authentication_select_company_or_occupant_type_super_user_event = Event(
name="authentication_select_company_or_occupant_type_super_user_event",
authentication_select_super_user_event = Event(
name="authentication_select_super_user_event",
key="a5d2d0d1-3e9b-4b0f-8c7d-6d4a4b4c4d4e",
request_validator=SelectCompanyOrOccupantTypeSuperUserRequestModel,
request_validator=AuthenticationRequestModels.SelectCompanyOrOccupantTypeSuperUserRequestModel,
# response_validator=SelectCompanyOrOccupantTypeSuperUserResponseModel,
description="Select company or occupant type super user",
)
authentication_select_company_or_occupant_type_super_user_event.endpoint_callable = (
authentication_select_company_or_occupant_type
authentication_select_super_user_event.endpoint_callable = (
AuthenticationFunctions.authentication_select_company_or_occupant_type
)
# Check Token Validity
authentication_check_token_event = Event(
name="authentication_check_token_event",
@@ -59,7 +42,12 @@ authentication_check_token_event = Event(
# response_validator=None, # TODO: Add response validator
description="Check if token is valid",
)
authentication_check_token_event.endpoint_callable = authentication_check_token_is_valid
authentication_check_token_event.endpoint_callable = (
AuthenticationFunctions.authentication_check_token_is_valid
)
# Refresh User Info
authentication_refresh_user_info_event = Event(
@@ -69,10 +57,13 @@ authentication_refresh_user_info_event = Event(
# response_validator=None, # TODO: Add response validator
description="Refresh user information",
)
authentication_refresh_user_info_event.endpoint_callable = (
authentication_refresh_user_info
AuthenticationFunctions.authentication_refresh_user_info
)
# Change Password
authentication_change_password_event = Event(
name="authentication_change_password_event",
@@ -81,7 +72,12 @@ authentication_change_password_event = Event(
# response_validator=None, # TODO: Add response validator
description="Change user password",
)
authentication_change_password_event.endpoint_callable = authentication_change_password
authentication_change_password_event.endpoint_callable = (
AuthenticationFunctions.authentication_change_password
)
# Create Password
authentication_create_password_event = Event(
@@ -91,7 +87,12 @@ authentication_create_password_event = Event(
# response_validator=None, # TODO: Add response validator
description="Create new password",
)
authentication_create_password_event.endpoint_callable = authentication_create_password
authentication_create_password_event.endpoint_callable = (
AuthenticationFunctions.authentication_create_password
)
# Disconnect User
authentication_disconnect_user_event = Event(
@@ -101,7 +102,12 @@ authentication_disconnect_user_event = Event(
# response_validator=None, # TODO: Add response validator
description="Disconnect all user sessions",
)
authentication_disconnect_user_event.endpoint_callable = authentication_disconnect_user
authentication_disconnect_user_event.endpoint_callable = (
AuthenticationFunctions.authentication_disconnect_user
)
# Logout User
authentication_logout_user_event = Event(
@@ -111,7 +117,12 @@ authentication_logout_user_event = Event(
# response_validator=None, # TODO: Add response validator
description="Logout user session",
)
authentication_logout_user_event.endpoint_callable = authentication_logout_user
authentication_logout_user_event.endpoint_callable = (
AuthenticationFunctions.authentication_logout_user
)
# Refresh Token
authentication_refresher_token_event = Event(
@@ -121,7 +132,12 @@ authentication_refresher_token_event = Event(
# response_validator=None, # TODO: Add response validator
description="Refresh authentication token",
)
authentication_refresher_token_event.endpoint_callable = authentication_refresher_token
authentication_refresher_token_event.endpoint_callable = (
AuthenticationFunctions.authentication_refresher_token
)
# Forgot Password
authentication_forgot_password_event = Event(
@@ -131,7 +147,12 @@ authentication_forgot_password_event = Event(
# response_validator=None, # TODO: Add response validator
description="Request password reset",
)
authentication_forgot_password_event.endpoint_callable = authentication_forgot_password
authentication_forgot_password_event.endpoint_callable = (
AuthenticationFunctions.authentication_forgot_password
)
# Reset Password
authentication_reset_password_event = Event(
@@ -141,7 +162,12 @@ authentication_reset_password_event = Event(
# response_validator=None, # TODO: Add response validator
description="Reset user password",
)
authentication_reset_password_event.endpoint_callable = authentication_reset_password
authentication_reset_password_event.endpoint_callable = (
AuthenticationFunctions.authentication_reset_password
)
# Download Avatar
authentication_download_avatar_event = Event(
@@ -151,4 +177,8 @@ authentication_download_avatar_event = Event(
# response_validator=None, # TODO: Add response validator
description="Download user avatar and profile info",
)
authentication_download_avatar_event.endpoint_callable = authentication_download_avatar
authentication_download_avatar_event.endpoint_callable = (
AuthenticationFunctions.authentication_download_avatar
)

View File

@@ -1,19 +1,16 @@
"""
Authentication related API endpoints.
"""
from typing import Any, Dict
from fastapi import Request
from typing import Union, Any, Dict
from ApiLayers.ApiValidations.Custom.wrapper_contexts import AuthContext, EventContext
from ApiLayers.Middleware import MiddlewareModule, TokenEventMiddleware
from ApiLayers.ApiValidations.Request import EmployeeSelection, OccupantSelection
from ApiLayers.Middleware import MiddlewareModule
from Events.Engine.abstract_class import MethodToEvent
from Events.base_request_model import EndpointBaseRequestModel
from Events.base_request_model import EndpointBaseRequestModel, ContextRetrievers
from .api_events import (
authentication_login_super_user_event,
authentication_select_company_or_occupant_type_super_user_event,
authentication_select_super_user_event,
authentication_check_token_event,
authentication_refresh_user_info_event,
authentication_change_password_event,
@@ -26,12 +23,6 @@ from .api_events import (
authentication_download_avatar_event,
)
from fastapi import Request
# Type aliases for common types
TokenDictType = Union["EmployeeTokenObject", "OccupantTokenObject"]
AuthenticationLoginEventMethods = MethodToEvent(
name="AuthenticationLoginEventMethods",
@@ -48,20 +39,24 @@ AuthenticationLoginEventMethods = MethodToEvent(
def authentication_login_with_domain_and_creds_endpoint(
request: Request,
data: EndpointBaseRequestModel,
request: Request, data: EndpointBaseRequestModel,
) -> Dict[str, Any]:
event_2_catch = AuthenticationLoginEventMethods.retrieve_event(event_function_code=f"{authentication_login_super_user_event.key}")
event_2_catch = AuthenticationLoginEventMethods.retrieve_event(
event_function_code=f"{authentication_login_super_user_event.key}"
)
data = event_2_catch.REQUEST_VALIDATOR(**data.data)
return event_2_catch.endpoint_callable(request=request, data=data)
AuthenticationLoginEventMethods.endpoint_callable = authentication_login_with_domain_and_creds_endpoint
AuthenticationLoginEventMethods.endpoint_callable = (
authentication_login_with_domain_and_creds_endpoint
)
AuthenticationSelectEventMethods = MethodToEvent(
name="AuthenticationSelectEventMethods",
events={
authentication_select_company_or_occupant_type_super_user_event.key: authentication_select_company_or_occupant_type_super_user_event,
authentication_select_super_user_event.key: authentication_select_super_user_event,
},
decorators_list=[MiddlewareModule.auth_required],
headers=[],
@@ -72,28 +67,27 @@ AuthenticationSelectEventMethods = MethodToEvent(
description="Select company or occupant type",
)
def authentication_select_company_or_occupant_type(
request: Request,
data: EndpointBaseRequestModel,
) -> Dict[str, Any]:
def authentication_select_company_or_occupant_type(data: EndpointBaseRequestModel) -> Dict[str, Any]:
"""
Select company or occupant type.
"""
auth_context = authentication_select_company_or_occupant_type.auth_context
context_retriever = ContextRetrievers(func=authentication_select_company_or_occupant_type)
function = AuthenticationSelectEventMethods.retrieve_event(
event_function_code=f"{authentication_select_company_or_occupant_type_super_user_event.key}"
event_function_code=f"{authentication_select_super_user_event.key}"
)
function.endpoint_callable.auth_context = auth_context
return function.endpoint_callable(request=request, data=data)
setattr(function.endpoint_callable, context_retriever.key, context_retriever.context)
return function.endpoint_callable(data=data)
AuthenticationSelectEventMethods.endpoint_callable = authentication_select_company_or_occupant_type
AuthenticationSelectEventMethods.endpoint_callable = (
authentication_select_company_or_occupant_type
)
AuthenticationCheckTokenEventMethods = MethodToEvent(
name="AuthenticationCheckTokenEventMethods",
events={
authentication_check_token_event.key: authentication_check_token_event
},
events={authentication_check_token_event.key: authentication_check_token_event},
headers=[],
errors=[],
decorators_list=[MiddlewareModule.auth_required],
@@ -103,14 +97,20 @@ AuthenticationCheckTokenEventMethods = MethodToEvent(
description="Check if access token is valid for user",
)
def authentication_check_token_is_valid(request: Request):
def authentication_check_token_is_valid():
context_retriever = ContextRetrievers(func=authentication_check_token_is_valid)
function = AuthenticationCheckTokenEventMethods.retrieve_event(
event_function_code=f"{authentication_check_token_event.key}"
)
return function.endpoint_callable(request=request)
setattr(function.endpoint_callable, context_retriever.key, context_retriever.context)
return function.endpoint_callable()
AuthenticationCheckTokenEventMethods.endpoint_callable = authentication_check_token_is_valid
AuthenticationCheckTokenEventMethods.endpoint_callable = (
authentication_check_token_is_valid
)
AuthenticationRefreshEventMethods = MethodToEvent(
name="AuthenticationRefreshEventMethods",
@@ -127,16 +127,18 @@ AuthenticationRefreshEventMethods = MethodToEvent(
)
def authentication_refresh_user_info(request: Request):
token_dict = authentication_refresh_user_info.auth
def authentication_refresh_user_info():
context_retriever = ContextRetrievers(func=authentication_refresh_user_info)
function = AuthenticationRefreshEventMethods.retrieve_event(
event_function_code=f"{authentication_refresh_user_info_event.key}"
)
return function.endpoint_callable(request=request, token_dict=token_dict)
setattr(function.endpoint_callable, context_retriever.key, context_retriever.context)
return function.endpoint_callable()
AuthenticationRefreshEventMethods.endpoint_callable = authentication_refresh_user_info
AuthenticationChangePasswordEventMethods = MethodToEvent(
name="AuthenticationChangePasswordEventMethods",
events={
@@ -151,21 +153,23 @@ AuthenticationChangePasswordEventMethods = MethodToEvent(
description="Change password with access token",
)
def authentication_change_password_event_callable(request: Request, data: EndpointBaseRequestModel):
token_dict = authentication_change_password_event_callable.auth
def authentication_change_password_event_callable(data: EndpointBaseRequestModel):
context_retriever = ContextRetrievers(func=authentication_change_password_event_callable)
function = AuthenticationChangePasswordEventMethods.retrieve_event(
event_function_code=f"{authentication_change_password_event.key}"
)
return function.endpoint_callable(data=data, token_dict=token_dict)
setattr(function.endpoint_callable, context_retriever.key, context_retriever.context)
return function.endpoint_callable(data=data)
AuthenticationChangePasswordEventMethods.endpoint_callable = authentication_change_password_event_callable
AuthenticationChangePasswordEventMethods.endpoint_callable = (
authentication_change_password_event_callable
)
AuthenticationCreatePasswordEventMethods = MethodToEvent(
name="AuthenticationCreatePasswordEventMethods",
events={
authentication_create_password_event: authentication_create_password_event
},
events={authentication_create_password_event: authentication_create_password_event},
headers=[],
errors=[],
url="/create-password",
@@ -174,14 +178,20 @@ AuthenticationCreatePasswordEventMethods = MethodToEvent(
description="Create password with password reset token requested via email",
)
def authentication_create_password(data: EndpointBaseRequestModel):
context_retriever = ContextRetrievers(func=authentication_create_password)
function = AuthenticationCreatePasswordEventMethods.retrieve_event(
event_function_code=f"{authentication_create_password_event.key}"
)
setattr(function.endpoint_callable, context_retriever.key, context_retriever.context)
return function.endpoint_callable(data=data)
AuthenticationCreatePasswordEventMethods.endpoint_callable = authentication_create_password
AuthenticationCreatePasswordEventMethods.endpoint_callable = (
authentication_create_password
)
AuthenticationDisconnectUserEventMethods = MethodToEvent(
name="AuthenticationDisconnectUserEventMethods",
@@ -197,22 +207,22 @@ AuthenticationDisconnectUserEventMethods = MethodToEvent(
description="Disconnect all sessions of user in access token",
)
def authentication_disconnect_user(request: Request, data: EndpointBaseRequestModel):
token_dict = authentication_disconnect_user.auth
def authentication_disconnect_user(data: EndpointBaseRequestModel):
context_retriever = ContextRetrievers(func=authentication_disconnect_user)
function = AuthenticationDisconnectUserEventMethods.retrieve_event(
event_function_code=f"{authentication_disconnect_user_event.key}"
)
return function.endpoint_callable(data=data, token_dict=token_dict)
setattr(function.endpoint_callable, context_retriever.key, context_retriever.context)
return function.endpoint_callable(data=data)
AuthenticationLogoutEventMethods = MethodToEvent(
name="AuthenticationLogoutEventMethods",
events={
authentication_logout_user_event.key: authentication_logout_user_event
},
events={authentication_logout_user_event.key: authentication_logout_user_event},
headers=[],
errors=[],
decorators_list=[TokenEventMiddleware.event_required],
decorators_list=[MiddlewareModule.auth_required],
url="/logout",
method="POST",
summary="Logout user",
@@ -220,12 +230,13 @@ AuthenticationLogoutEventMethods = MethodToEvent(
)
def authentication_logout_user(request: Request, data: EndpointBaseRequestModel):
event_context: EventContext = getattr(authentication_logout_user, "event_context", None)
print('event_context', event_context)
function = AuthenticationLogoutEventMethods.retrieve_event(event_function_code=f"{event_context.code}")
function.endpoint_callable.event_context = event_context
return function.endpoint_callable(request=request, data=data)
def authentication_logout_user(data: EndpointBaseRequestModel):
context_retriever = ContextRetrievers(func=authentication_logout_user)
function = AuthenticationLogoutEventMethods.retrieve_event(
event_function_code=f"{authentication_logout_user_event.key}"
)
setattr(function.endpoint_callable, context_retriever.key, context_retriever.context)
return function.endpoint_callable(data=data)
AuthenticationLogoutEventMethods.endpoint_callable = authentication_logout_user
@@ -246,16 +257,18 @@ AuthenticationRefreshTokenEventMethods = MethodToEvent(
)
def authentication_refresher_token(request: Request, data: EndpointBaseRequestModel):
auth_context: AuthContext = getattr(authentication_refresher_token, "auth_context", None)
def authentication_refresher_token(data: EndpointBaseRequestModel):
context_retriever = ContextRetrievers(func=authentication_refresher_token)
function = AuthenticationRefreshTokenEventMethods.retrieve_event(
event_function_code=f"{authentication_refresher_token_event.key}"
)
function.endpoint_callable.auth_context = auth_context
return function.endpoint_callable(data=data, request=request)
setattr(function.endpoint_callable, context_retriever.key, context_retriever.context)
return function.endpoint_callable(data=data)
AuthenticationRefreshTokenEventMethods.endpoint_callable = authentication_refresher_token
AuthenticationRefreshTokenEventMethods.endpoint_callable = (
authentication_refresher_token
)
AuthenticationForgotPasswordEventMethods = MethodToEvent(
@@ -272,15 +285,18 @@ AuthenticationForgotPasswordEventMethods = MethodToEvent(
)
def authentication_forgot_password(request: Request, data: EndpointBaseRequestModel):
token_dict = authentication_forgot_password.auth
def authentication_forgot_password(data: EndpointBaseRequestModel):
context_retriever = ContextRetrievers(func=authentication_forgot_password)
function = AuthenticationForgotPasswordEventMethods.retrieve_event(
event_function_code=f"{authentication_forgot_password_event.key}"
)
return function.endpoint_callable(data=data, token_dict=token_dict)
setattr(function.endpoint_callable, context_retriever.key, context_retriever.context)
return function.endpoint_callable(data=data)
AuthenticationForgotPasswordEventMethods.endpoint_callable = authentication_forgot_password
AuthenticationForgotPasswordEventMethods.endpoint_callable = (
authentication_forgot_password
)
AuthenticationResetPasswordEventMethods = MethodToEvent(
@@ -299,14 +315,18 @@ AuthenticationResetPasswordEventMethods = MethodToEvent(
def authentication_reset_password(data: EndpointBaseRequestModel):
# token_dict = authentication_reset_password.auth
context_retriever = ContextRetrievers(func=authentication_reset_password)
function = AuthenticationResetPasswordEventMethods.retrieve_event(
event_function_code=f"{authentication_reset_password_event.key}"
)
setattr(function.endpoint_callable, context_retriever.key, context_retriever.context)
return function.endpoint_callable(data=data)
AuthenticationResetPasswordEventMethods.endpoint_callable = authentication_reset_password
AuthenticationResetPasswordEventMethods.endpoint_callable = (
authentication_reset_password
)
AuthenticationDownloadAvatarEventMethods = MethodToEvent(
name="AuthenticationDownloadAvatarEventMethods",
@@ -315,7 +335,7 @@ AuthenticationDownloadAvatarEventMethods = MethodToEvent(
},
headers=[],
errors=[],
decorators_list=[],
decorators_list=[MiddlewareModule.auth_required],
url="/download-avatar",
method="POST",
summary="Download avatar",
@@ -323,13 +343,15 @@ AuthenticationDownloadAvatarEventMethods = MethodToEvent(
)
@MiddlewareModule.auth_required
def authentication_download_avatar(request: Request):
token_dict = authentication_download_avatar.auth
def authentication_download_avatar():
context_retriever = ContextRetrievers(func=authentication_download_avatar)
function = AuthenticationDownloadAvatarEventMethods.retrieve_event(
event_function_code=f"{authentication_download_avatar_event.key}"
)
return function.endpoint_callable(token_dict=token_dict)
setattr(function.endpoint_callable, context_retriever.key, context_retriever.context)
return function.endpoint_callable()
AuthenticationDownloadAvatarEventMethods.endpoint_callable = authentication_download_avatar
AuthenticationDownloadAvatarEventMethods.endpoint_callable = (
authentication_download_avatar
)

View File

@@ -1,11 +1,11 @@
from typing import Any, TYPE_CHECKING, Union, Dict
from typing import Any
from fastapi import Request
from ApiLayers.ApiLibrary.common.line_number import get_line_number_for_error
from ApiLayers.ApiServices.Login.user_login_handler import UserLoginModule
from ApiLayers.ApiServices.Token.token_handler import TokenService
from ApiLayers.ApiValidations.Custom.token_objects import CompanyToken, OccupantToken
from ApiLayers.ApiValidations.Custom.wrapper_contexts import AuthContext, EventContext
from ApiLayers.ApiValidations.Response.default_response import EndpointSuccessResponse
from ApiLayers.ErrorHandlers import HTTPExceptionApi
from ApiLayers.Schemas import (
BuildLivingSpace,
@@ -22,462 +22,452 @@ from ApiLayers.Schemas import (
OccupantTypes,
Users,
)
from ApiLayers.ApiValidations.Response.default_response import EndpointSuccessResponse
from fastapi import Request
from Events.base_request_model import ContextRetrievers, TokenDictType
# Type aliases for common types
TokenDictType = Union["EmployeeTokenObject", "OccupantTokenObject"]
class Handlers:
"""Class for handling authentication functions"""
def authentication_login_with_domain_and_creds(request: Request, data: Any):
"""
Authenticate user with domain and credentials.
Args:
request: FastAPI request object
data: Request body containing login credentials
{
"domain": "evyos.com.tr",
"access_key": "karatay.berkay.sup@evyos.com.tr",
"password": "string",
"remember_me": false
}
Returns:
SuccessResponse containing authentication token and user info
"""
# Get token from login module
user_login_module = UserLoginModule(request=request)
token = user_login_module.login_user_via_credentials(access_data=data)
# Return response with token and headers
user_login_module.language = "tr"
success_response = EndpointSuccessResponse(
code="LoginSuccess", lang=user_login_module.language
)
return success_response.as_dict(
data={
"access_token": token.get("access_token"),
"refresh_token": token.get("refresher_token"),
"access_object": {"user_type": token.get("user_type"), "companies_list": token.get("companies_list")},
"user": token.get("user"),
}
)
# return {
# "completed": True,
# "message": "User is logged in successfully",
# "access_token": token.get("access_token"),
# "refresh_token": token.get("refresher_token"),
# "access_object": {
# "user_type": token.get("user_type"), "companies_list": token.get("companies_list")
# },
# "user": token.get("user"),
# }
def handle_employee_selection(request: Request, data: Any, token_dict: TokenDictType):
Users.set_user_define_properties(token=token_dict)
db_session = Users.new_session()
if data.company_uu_id not in token_dict.companies_uu_id_list:
raise HTTPExceptionApi(
error_code="HTTP_400_BAD_REQUEST",
lang=token_dict.lang,
loc=get_line_number_for_error(),
sys_msg="Company not found in token",
)
selected_company = Companies.filter_one(
Companies.uu_id == data.company_uu_id,
db=db_session,
).first
if not selected_company:
raise HTTPExceptionApi(
error_code="HTTP_400_BAD_REQUEST",
lang=token_dict.lang,
loc=get_line_number_for_error(),
sys_msg="Company not found in token",
)
# Get department IDs for the company
department_ids = [
dept.id
for dept in Departments.filter_all(
Departments.company_id == selected_company.id,
db=db_session,
@classmethod # Requires no auth context
def handle_employee_selection(cls, request: Request, data: Any, token_dict: TokenDictType):
Users.set_user_define_properties(token=token_dict)
db = Users.new_session()
if data.company_uu_id not in token_dict.companies_uu_id_list:
raise HTTPExceptionApi(
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 = Companies.filter_one(
Companies.uu_id == data.company_uu_id,
db=db,
).data
]
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 duties IDs for the company
duties_ids = [
duty.id
for duty in Duties.filter_all(
Duties.company_id == selected_company.id, db=db_session
# Get department IDs for the company
department_ids = [
dept.id
for dept in Departments.filter_all(
Departments.company_id == selected_company.id,
db=db,
).data
]
# Get duties IDs for the company
duties_ids = [
duty.id
for duty in Duties.filter_all(
Duties.company_id == selected_company.id, db=db
).data
]
# Get staff IDs
staff_ids = [
staff.id
for staff in Staff.filter_all(Staff.duties_id.in_(duties_ids), db=db).data
]
# Get employee
employee: Employees = Employees.filter_one(
Employees.people_id == token_dict.person_id,
Employees.staff_id.in_(staff_ids),
db=db,
).data
]
# Get staff IDs
staff_ids = [
staff.id
for staff in Staff.filter_all(
Staff.duties_id.in_(duties_ids), db=db_session
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_codes = Event2Employee.get_event_codes(employee_id=employee.id)
reachable_event_endpoints = Event2Employee.get_event_endpoints(
employee_id=employee.id
)
# Get staff and duties
staff = Staff.filter_one(Staff.id == employee.staff_id, db=db).data
duties = Duties.filter_one(Duties.id == staff.duties_id, db=db).data
department = Departments.filter_one(
Departments.id == duties.department_id, db=db
).data
]
# Get employee
employee = Employees.filter_one(
Employees.people_id == token_dict.person_id,
Employees.staff_id.in_(staff_ids),
db=db_session,
).first
# Get bulk duty
bulk_id = Duty.filter_by_one(system=True, duty_code="BULK", db=db).data
bulk_duty_id = Duties.filter_by_one(
company_id=selected_company.id,
duties_id=bulk_id.id,
**Duties.valid_record_dict,
db=db,
).data
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",
# 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_codes=reachable_event_codes,
reachable_event_endpoints=reachable_event_endpoints,
)
# Get reachable events
reachable_event_codes = Event2Employee.get_event_codes(employee_id=employee.id)
reachable_event_endpoints = Event2Employee.get_event_endpoints(
employee_id=employee.id
)
try: # Update Redis
return TokenService.update_token_at_redis(
request=request, add_payload=company_token
)
except Exception as e:
raise HTTPExceptionApi(
error_code="",
lang="en",
loc=get_line_number_for_error(),
sys_msg=f"{e}",
)
# 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
@classmethod # Requires no auth context
def handle_occupant_selection(cls, request: Request, data: Any, token_dict: TokenDictType):
"""Handle occupant type selection"""
Users.set_user_define_properties(token=token_dict)
db = BuildLivingSpace.new_session()
# Get selected occupant type
selected_build_living_space: BuildLivingSpace = BuildLivingSpace.filter_one(
BuildLivingSpace.uu_id == data.build_living_space_uu_id,
db=db,
).data
if not selected_build_living_space:
raise HTTPExceptionApi(
error_code="HTTP_400_BAD_REQUEST",
lang=token_dict.lang,
loc=get_line_number_for_error(),
sys_msg="Selected occupant type not found",
)
# 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_codes=reachable_event_codes,
reachable_event_endpoints=reachable_event_endpoints,
)
try: # Update Redis
update_token = TokenService.update_token_at_redis(
request=request, add_payload=company_token
# Get reachable events
reachable_event_codes = Event2Occupant.get_event_codes(
build_living_space_id=selected_build_living_space.id
)
return update_token
except Exception as e:
raise HTTPExceptionApi(
error_code="",
lang="en",
loc=get_line_number_for_error(),
sys_msg=f"{e}",
reachable_event_endpoints = Event2Occupant.get_event_endpoints(
build_living_space_id=selected_build_living_space.id
)
occupant_type = OccupantTypes.filter_one(
OccupantTypes.id == selected_build_living_space.occupant_type_id,
db=db,
system=True,
).data
build_part = BuildParts.filter_one(
BuildParts.id == selected_build_living_space.build_parts_id,
db=db,
).data
build = BuildParts.filter_one(
BuildParts.id == build_part.build_id,
db=db,
).data
responsible_employee = Employees.filter_one(
Employees.id == build_part.responsible_employee_id,
db=db,
).data
related_company = RelationshipEmployee2Build.filter_one(
RelationshipEmployee2Build.member_id == build.id,
db=db,
).data
# Get company
company_related = Companies.filter_one(
Companies.id == related_company.company_id,
db=db,
).data
# Create occupant token
occupant_token = OccupantToken(
living_space_id=selected_build_living_space.id,
living_space_uu_id=selected_build_living_space.uu_id.__str__(),
occupant_type_id=occupant_type.id,
occupant_type_uu_id=occupant_type.uu_id.__str__(),
occupant_type=occupant_type.occupant_type,
build_id=build.id,
build_uuid=build.uu_id.__str__(),
build_part_id=build_part.id,
build_part_uuid=build_part.uu_id.__str__(),
responsible_employee_id=responsible_employee.id,
responsible_employee_uuid=responsible_employee.uu_id.__str__(),
responsible_company_id=company_related.id,
responsible_company_uuid=company_related.uu_id.__str__(),
reachable_event_codes=reachable_event_codes,
reachable_event_endpoints=reachable_event_endpoints,
)
def handle_occupant_selection(request: Request, data: Any, token_dict: TokenDictType):
"""Handle occupant type selection"""
db = BuildLivingSpace.new_session()
# Get selected occupant type
selected_build_living_space = BuildLivingSpace.filter_one(
BuildLivingSpace.uu_id == data.build_living_space_uu_id,
db=db,
).data
if not selected_build_living_space:
raise HTTPExceptionApi(
error_code="HTTP_400_BAD_REQUEST",
lang=token_dict.lang,
loc=get_line_number_for_error(),
sys_msg="Selected occupant type not found",
)
# Get reachable events
reachable_event_codes = Event2Occupant.get_event_codes(
build_living_space_id=selected_build_living_space.id
)
reachable_event_endpoints = Event2Occupant.get_event_endpoints(
build_living_space_id=selected_build_living_space.id
)
occupant_type = OccupantTypes.filter_one(
OccupantTypes.id == selected_build_living_space.occupant_type_id,
db=db,
system=True,
).data
build_part = BuildParts.filter_one(
BuildParts.id == selected_build_living_space.build_parts_id,
db=db,
).data
build = BuildParts.filter_one(
BuildParts.id == build_part.build_id,
db=db,
).data
responsible_employee = Employees.filter_one(
Employees.id == build_part.responsible_employee_id,
db=db,
).data
related_company = RelationshipEmployee2Build.filter_one(
RelationshipEmployee2Build.member_id == build.id,
db=db,
).data
# Get company
company_related = Companies.filter_one(
Companies.id == related_company.company_id,
db=db,
).data
# Create occupant token
occupant_token = OccupantToken(
living_space_id=selected_build_living_space.id,
living_space_uu_id=selected_build_living_space.uu_id.__str__(),
occupant_type_id=occupant_type.id,
occupant_type_uu_id=occupant_type.uu_id.__str__(),
occupant_type=occupant_type.occupant_type,
build_id=build.id,
build_uuid=build.uu_id.__str__(),
build_part_id=build_part.id,
build_part_uuid=build_part.uu_id.__str__(),
responsible_employee_id=responsible_employee.id,
responsible_employee_uuid=responsible_employee.uu_id.__str__(),
responsible_company_id=company_related.id,
responsible_company_uuid=company_related.uu_id.__str__(),
reachable_event_codes=reachable_event_codes,
reachable_event_endpoints=reachable_event_endpoints,
)
try: # Update Redis
update_token = TokenService.update_token_at_redis(
request=request, add_payload=occupant_token
)
return update_token
except Exception as e:
raise HTTPExceptionApi(
error_code="",
lang="en",
loc=get_line_number_for_error(),
sys_msg=f"{e}",
)
try: # Update Redis
return TokenService.update_token_at_redis(
request=request, add_payload=occupant_token
)
except Exception as e:
raise HTTPExceptionApi(
error_code="",
lang="en",
loc=get_line_number_for_error(),
sys_msg=f"{e}",
)
def authentication_select_company_or_occupant_type(request: Request, data: Any):
"""Handle selection of company or occupant type"""
token_dict: TokenDictType = authentication_select_company_or_occupant_type.auth_context
if token_dict.is_employee:
if handle_employee_selection(data, token_dict, request):
return {"selected_occupant": None, "selected_company": data.company_uu_id}
elif token_dict.is_occupant:
if handle_occupant_selection(data, token_dict, request):
return {"selected_company": None, "selected_occupant": data.build_living_space_uu_id}
return {"completed": False, "selected_company": None, "selected_occupant": None}
class AuthenticationFunctions:
"""Class for handling authentication functions"""
@classmethod # Requires auth context
def authentication_select_company_or_occupant_type(cls, data: Any):
"""Handle selection of company or occupant type"""
context_retriever = ContextRetrievers(func=cls.authentication_select_company_or_occupant_type)
if context_retriever.token.is_employee:
if Handlers.handle_employee_selection(
request=context_retriever.request, data=data, token_dict=context_retriever.token
):
return {
"completed": True, "selected": data.company_uu_id, **context_retriever.base,
}
elif context_retriever.token.is_occupant:
if Handlers.handle_occupant_selection(
request=context_retriever.request, data=data, token_dict=context_retriever.token
):
return {
"completed": True, "selected": data.build_living_space_uu_id, **context_retriever.base,
}
return {"completed": False, "selected": None, **context_retriever.base}
def authentication_check_token_is_valid(request: Request, data: Any):
"""Check if token is valid for user"""
# try:
# if RedisActions.get_object_via_access_key(request=request):
# return ResponseHandler.success("Access Token is valid")
# except HTTPException:
# return ResponseHandler.unauthorized("Access Token is NOT valid")
return
@classmethod # Requires no auth context
def authentication_login_with_domain_and_creds(cls, request: Request, data: Any):
"""
Authenticate user with domain and credentials.
Args:
request: FastAPI request object
data: Request body containing login credentials
{
"domain": "evyos.com.tr",
"access_key": "karatay.berkay.sup@evyos.com.tr",
"password": "string",
"remember_me": false
}
Returns:
SuccessResponse containing authentication token and user info
"""
def authentication_refresh_user_info(request: Request, token_dict: TokenDictType, data: Any):
"""Refresh user info using access token"""
# try:
# access_token = request.headers.get(Auth.ACCESS_TOKEN_TAG)
# if not access_token:
# return ResponseHandler.unauthorized()
# Get token from login module
user_login_module = UserLoginModule(request=request)
user_login_module.login_user_via_credentials(access_data=data)
user_login_module.language = "tr"
# found_user = Users.filter_one(Users.uu_id == token_dict.user_uu_id).data
# if not found_user:
# return ResponseHandler.not_found("User not found")
# user_token = UsersTokens.filter_one(
# UsersTokens.domain == found_user.domain_name,
# UsersTokens.user_id == found_user.id,
# UsersTokens.token_type == "RememberMe",
# ).data
# response_data = {
# "access_token": access_token,
# "refresh_token": getattr(user_token, "token", None),
# "user": found_user.get_dict(),
# }
# return ResponseHandler.success(
# "User info refreshed successfully",
# data=response_data,
# )
# except Exception as e:
# return ResponseHandler.error(str(e))
return
# Return response with token and headers
return EndpointSuccessResponse(
code="LOGIN_SUCCESS", lang=user_login_module.language
).as_dict(data=user_login_module.as_dict)
@classmethod # Requires not auth context
def authentication_check_token_is_valid(cls, data: Any):
"""Check if token is valid for user"""
# try:
# if RedisActions.get_object_via_access_key(request=request):
# return ResponseHandler.success("Access Token is valid")
# except HTTPException:
# return ResponseHandler.unauthorized("Access Token is NOT valid")
return
def authentication_change_password(request: Request, token_dict: TokenDictType, data: Any):
"""Change password with access token"""
# try:
# if not isinstance(token_dict, EmployeeTokenObject):
# return ResponseHandler.unauthorized("Only employees can change password")
@classmethod # Requires not auth context
def authentication_refresh_user_info(cls, data: Any):
"""Refresh user info using access token"""
# try:
# access_token = request.headers.get(Auth.ACCESS_TOKEN_TAG)
# if not access_token:
# return ResponseHandler.unauthorized()
# found_user = Users.filter_one(Users.uu_id == token_dict.user_uu_id).data
# if not found_user:
# return ResponseHandler.not_found("User not found")
# found_user = Users.filter_one(Users.uu_id == token_dict.user_uu_id).data
# if not found_user:
# return ResponseHandler.not_found("User not found")
# user_token = UsersTokens.filter_one(
# UsersTokens.domain == found_user.domain_name,
# UsersTokens.user_id == found_user.id,
# UsersTokens.token_type == "RememberMe",
# ).data
# response_data = {
# "access_token": access_token,
# "refresh_token": getattr(user_token, "token", None),
# "user": found_user.get_dict(),
# }
# return ResponseHandler.success(
# "User info refreshed successfully",
# data=response_data,
# )
# except Exception as e:
# return ResponseHandler.error(str(e))
return
# if not found_user.check_password(data.old_password):
# return ResponseHandler.unauthorized("Old password is incorrect")
@classmethod # Requires no auth context
def authentication_change_password(cls, data: Any):
"""Change password with access token"""
# try:
# if not isinstance(token_dict, EmployeeTokenObject):
# return ResponseHandler.unauthorized("Only employees can change password")
# found_user.set_password(data.new_password)
# return ResponseHandler.success("Password changed successfully")
# except Exception as e:
# return ResponseHandler.error(str(e))
return
# found_user = Users.filter_one(Users.uu_id == token_dict.user_uu_id).data
# if not found_user:
# return ResponseHandler.not_found("User not found")
# if not found_user.check_password(data.old_password):
# return ResponseHandler.unauthorized("Old password is incorrect")
def authentication_create_password(request: Request, data: Any):
"""Create password with password reset token requested via email"""
# if not data.re_password == data.password:
# raise HTTPException(status_code=status.HTTP_406_NOT_ACCEPTABLE, detail="Password must match")
# if found_user := Users.filter_one(Users.password_token == data.password_token).data:
# found_user.create_password(found_user=found_user, password=data.password)
# found_user.password_token = ""
# found_user.save()
# return ResponseHandler.success("Password is created successfully", data=found_user.get_dict())
# return ResponseHandler.not_found("Record not found")
return
# found_user.set_password(data.new_password)
# return ResponseHandler.success("Password changed successfully")
# except Exception as e:
# return ResponseHandler.error(str(e))
return
@classmethod # Requires not auth context
def authentication_create_password(cls, data: Any):
"""Create password with password reset token requested via email"""
# if not data.re_password == data.password:
# raise HTTPException(status_code=status.HTTP_406_NOT_ACCEPTABLE, detail="Password must match")
# if found_user := Users.filter_one(Users.password_token == data.password_token).data:
# found_user.create_password(found_user=found_user, password=data.password)
# found_user.password_token = ""
# found_user.save()
# return ResponseHandler.success("Password is created successfully", data=found_user.get_dict())
# return ResponseHandler.not_found("Record not found")
return
def authentication_disconnect_user(request: Request, token_dict: TokenDictType, data: Any):
"""Disconnect all sessions of user in access token"""
# found_user = Users.filter_one(Users.uu_id == token_dict.user_uu_id).data
# if not found_user:
# return ResponseHandler.not_found("User not found")
# if already_tokens := RedisActions.get_object_via_user_uu_id(user_id=str(found_user.uu_id)):
# for key, token_user in already_tokens.items():
# RedisActions.delete(key)
# selected_user = Users.filter_one(Users.uu_id == token_user.get("uu_id")).data
# selected_user.remove_refresher_token(domain=data.domain, disconnect=True)
# return ResponseHandler.success("All sessions are disconnected", data=selected_user.get_dict())
# return ResponseHandler.not_found("Invalid data")
return
@classmethod # Requires auth context
def authentication_disconnect_user(cls, data: Any):
"""Disconnect all sessions of user in access token"""
# found_user = Users.filter_one(Users.uu_id == token_dict.user_uu_id).data
# if not found_user:
# return ResponseHandler.not_found("User not found")
# if already_tokens := RedisActions.get_object_via_user_uu_id(user_id=str(found_user.uu_id)):
# for key, token_user in already_tokens.items():
# RedisActions.delete(key)
# selected_user = Users.filter_one(Users.uu_id == token_user.get("uu_id")).data
# selected_user.remove_refresher_token(domain=data.domain, disconnect=True)
# return ResponseHandler.success("All sessions are disconnected", data=selected_user.get_dict())
# return ResponseHandler.not_found("Invalid data")
return
@classmethod # Requires auth context
def authentication_logout_user(cls, data: Any):
"""Logout only single session of user which domain is provided"""
# token_user = None
# if already_tokens := RedisActions.get_object_via_access_key(request=request):
# for key in already_tokens:
# token_user = RedisActions.get_json(key)
# if token_user.get("domain") == data.domain:
# RedisActions.delete(key)
# selected_user = Users.filter_one(Users.uu_id == token_user.get("uu_id")).data
# selected_user.remove_refresher_token(domain=data.domain)
# return ResponseHandler.success("Session is logged out", data=token_user)
# return ResponseHandler.not_found("Logout is not successfully completed")
context_retriever = ContextRetrievers(func=cls.authentication_logout_user)
return context_retriever.base
def authentication_logout_user(request: Request, data: Any):
"""Logout only single session of user which domain is provided"""
# token_user = None
# if already_tokens := RedisActions.get_object_via_access_key(request=request):
# for key in already_tokens:
# token_user = RedisActions.get_json(key)
# if token_user.get("domain") == data.domain:
# RedisActions.delete(key)
# selected_user = Users.filter_one(Users.uu_id == token_user.get("uu_id")).data
# selected_user.remove_refresher_token(domain=data.domain)
# return ResponseHandler.success("Session is logged out", data=token_user)
# return ResponseHandler.not_found("Logout is not successfully completed")
@classmethod # Requires not auth context
def authentication_refresher_token(cls, data: Any):
"""Refresh access token with refresher token"""
# token_refresher = UsersTokens.filter_by_one(
# token=data.refresh_token,
# domain=data.domain,
# **UsersTokens.valid_record_dict,
# ).data
# if not token_refresher:
# return ResponseHandler.not_found("Invalid data")
# if found_user := Users.filter_one(Users.id == token_refresher.user_id).data:
# access_key = AuthActions.save_access_token_to_redis(
# request=request, found_user=found_user, domain=data.domain
# )
# found_user.last_agent = request.headers.get("User-Agent", None)
# found_user.last_platform = request.headers.get("Origin", None)
# found_user.last_remote_addr = getattr(request, "remote_addr", None) or request.headers.get("X-Forwarded-For", None)
# found_user.last_seen = str(system_arrow.now())
# response_data = {
# "access_token": access_key,
# "refresh_token": data.refresh_token,
# }
# return ResponseHandler.success("User is logged in successfully via refresher token", data=response_data)
# return ResponseHandler.not_found("Invalid data")
context_retriever = ContextRetrievers(func=cls.authentication_refresher_token)
return context_retriever.base
event_context: EventContext = getattr(authentication_logout_user, "event_context", None)
return event_context.model_dump()
@classmethod # Requires not auth context
def authentication_forgot_password(cls, data: Any):
"""Send an email to user for a valid password reset token"""
# found_user: Users = Users.check_user_exits(access_key=data.access_key, domain=data.domain)
# forgot_key = AuthActions.save_access_token_to_redis(request=request, found_user=found_user, domain=data.domain)
# forgot_link = ApiStatic.forgot_link(forgot_key=forgot_key)
# send_email_completed = send_email(
# subject=f"Dear {found_user.user_tag}, your forgot password link has been sent.",
# receivers=[str(found_user.email)],
# html=change_your_password_template(user_name=found_user.user_tag, forgot_link=forgot_link),
# )
# if not send_email_completed:
# raise HTTPException(status_code=400, detail="Email can not be sent. Try again later")
# found_user.password_token = forgot_key
# found_user.password_token_is_valid = str(system_arrow.shift(days=1))
# found_user.save()
# return ResponseHandler.success("Password is change link is sent to your email or phone", data={})
return
@classmethod # Requires not auth context
def authentication_reset_password(cls, data: Any):
"""Reset password with forgot password token"""
# from sqlalchemy import or_
# found_user = Users.query.filter(
# or_(
# Users.email == str(data.access_key).lower(),
# Users.phone_number == str(data.access_key).replace(" ", ""),
# ),
# ).first()
# if not found_user:
# raise HTTPException(
# status_code=status.HTTP_400_BAD_REQUEST,
# detail="Given access key or domain is not matching with the any user record.",
# )
# reset_password_token = found_user.reset_password_token(found_user=found_user)
# send_email_completed = send_email(
# subject=f"Dear {found_user.user_tag}, a password reset request has been received.",
# receivers=[str(found_user.email)],
# html=change_your_password_template(
# user_name=found_user.user_tag,
# forgot_link=ApiStatic.forgot_link(forgot_key=reset_password_token),
# ),
# )
# if not send_email_completed:
# raise found_user.raise_http_exception(status_code=400, message="Email can not be sent. Try again later")
# return ResponseHandler.success("Password change link is sent to your email or phone", data=found_user.get_dict())
return
def authentication_refresher_token(request: Request, data: Any):
"""Refresh access token with refresher token"""
# token_refresher = UsersTokens.filter_by_one(
# token=data.refresh_token,
# domain=data.domain,
# **UsersTokens.valid_record_dict,
# ).data
# if not token_refresher:
# return ResponseHandler.not_found("Invalid data")
# if found_user := Users.filter_one(Users.id == token_refresher.user_id).data:
# access_key = AuthActions.save_access_token_to_redis(
# request=request, found_user=found_user, domain=data.domain
# )
# found_user.last_agent = request.headers.get("User-Agent", None)
# found_user.last_platform = request.headers.get("Origin", None)
# found_user.last_remote_addr = getattr(request, "remote_addr", None) or request.headers.get("X-Forwarded-For", None)
# found_user.last_seen = str(system_arrow.now())
# response_data = {
# "access_token": access_key,
# "refresh_token": data.refresh_token,
# }
# return ResponseHandler.success("User is logged in successfully via refresher token", data=response_data)
# return ResponseHandler.not_found("Invalid data")
auth_context: AuthContext = getattr(authentication_refresher_token, "auth_context", None)
return auth_context.model_dump()
def authentication_forgot_password(request: Request, data: Any):
"""Send an email to user for a valid password reset token"""
# found_user: Users = Users.check_user_exits(access_key=data.access_key, domain=data.domain)
# forgot_key = AuthActions.save_access_token_to_redis(request=request, found_user=found_user, domain=data.domain)
# forgot_link = ApiStatic.forgot_link(forgot_key=forgot_key)
# send_email_completed = send_email(
# subject=f"Dear {found_user.user_tag}, your forgot password link has been sent.",
# receivers=[str(found_user.email)],
# html=change_your_password_template(user_name=found_user.user_tag, forgot_link=forgot_link),
# )
# if not send_email_completed:
# raise HTTPException(status_code=400, detail="Email can not be sent. Try again later")
# found_user.password_token = forgot_key
# found_user.password_token_is_valid = str(system_arrow.shift(days=1))
# found_user.save()
# return ResponseHandler.success("Password is change link is sent to your email or phone", data={})
return
def authentication_reset_password(request: Request, data: Any):
"""Reset password with forgot password token"""
# from sqlalchemy import or_
# found_user = Users.query.filter(
# or_(
# Users.email == str(data.access_key).lower(),
# Users.phone_number == str(data.access_key).replace(" ", ""),
# ),
# ).first()
# if not found_user:
# raise HTTPException(
# status_code=status.HTTP_400_BAD_REQUEST,
# detail="Given access key or domain is not matching with the any user record.",
# )
# reset_password_token = found_user.reset_password_token(found_user=found_user)
# send_email_completed = send_email(
# subject=f"Dear {found_user.user_tag}, a password reset request has been received.",
# receivers=[str(found_user.email)],
# html=change_your_password_template(
# user_name=found_user.user_tag,
# forgot_link=ApiStatic.forgot_link(forgot_key=reset_password_token),
# ),
# )
# if not send_email_completed:
# raise found_user.raise_http_exception(status_code=400, message="Email can not be sent. Try again later")
# return ResponseHandler.success("Password change link is sent to your email or phone", data=found_user.get_dict())
return
def authentication_download_avatar(request: Request, data: Any, token_dict: TokenDictType):
"""Download avatar icon and profile info of user"""
# if found_user := Users.filter_one(Users.id == token_dict.user_id).data:
# expired_starts = str(system_arrow.now() - system_arrow.get(str(found_user.expiry_ends)))
# expired_int = (system_arrow.now() - system_arrow.get(str(found_user.expiry_ends))).days
# user_info = {
# "lang": token_dict.lang,
# "full_name": found_user.person.full_name,
# "avatar": found_user.avatar,
# "remember_me": found_user.remember_me,
# "expiry_ends": str(found_user.expiry_ends),
# "expired_str": expired_starts,
# "expired_int": int(expired_int),
# }
# return ResponseHandler.success("Avatar and profile is shared via user credentials", data=user_info)
# return ResponseHandler.not_found("Invalid data")
return
@classmethod # Requires not auth context
def authentication_download_avatar(cls, data: Any):
"""Download avatar icon and profile info of user"""
# if found_user := Users.filter_one(Users.id == token_dict.user_id).data:
# expired_starts = str(system_arrow.now() - system_arrow.get(str(found_user.expiry_ends)))
# expired_int = (system_arrow.now() - system_arrow.get(str(found_user.expiry_ends))).days
# user_info = {
# "lang": token_dict.lang,
# "full_name": found_user.person.full_name,
# "avatar": found_user.avatar,
# "remember_me": found_user.remember_me,
# "expiry_ends": str(found_user.expiry_ends),
# "expired_str": expired_starts,
# "expired_int": int(expired_int),
# }
# return ResponseHandler.success("Avatar and profile is shared via user credentials", data=user_info)
# return ResponseHandler.not_found("Invalid data")
return

View File

@@ -1,7 +1,6 @@
from pydantic import BaseModel
from ApiLayers.ApiValidations.Request import (
Login,
)
from ApiLayers.ApiValidations.Request import Login
class LoginSuperUserRequestModel(Login):
pass
@@ -33,3 +32,21 @@ class OccupantSelectionSuperUserRequestModel(BaseModel):
class OccupantSelectionSuperUserResponseModel(BaseModel):
pass
class AuthenticationRequestModels:
LoginSuperUserRequestModel = LoginSuperUserRequestModel
SelectCompanyOrOccupantTypeSuperUserRequestModel = (
SelectCompanyOrOccupantTypeSuperUserRequestModel
)
EmployeeSelectionSuperUserRequestModel = EmployeeSelectionSuperUserRequestModel
OccupantSelectionSuperUserRequestModel = OccupantSelectionSuperUserRequestModel
class AuthenticationResponseModels:
LoginSuperUserResponseModel = LoginSuperUserResponseModel
SelectCompanyOrOccupantTypeSuperUserResponseModel = (
SelectCompanyOrOccupantTypeSuperUserResponseModel
)
EmployeeSelectionSuperUserResponseModel = EmployeeSelectionSuperUserResponseModel
OccupantSelectionSuperUserResponseModel = OccupantSelectionSuperUserResponseModel

View File

@@ -2,6 +2,4 @@
Events package initialization.
"""
__all__ = [
]
__all__ = []

View File

@@ -10,4 +10,3 @@ def retrieve_cluster_by_name(cluster_name: str):
for module in events_list:
if hasattr(module, cluster_name, None):
return getattr(module, cluster_name, None)

View File

@@ -62,7 +62,7 @@ class Event:
return self.NAME
@property
def key(self):
def key(self) -> str:
return str(self.KEY_)
@abstractmethod
@@ -156,8 +156,8 @@ class CategoryCluster:
PREFIX: str
PAGEINFO: PageInfo
DESCRIPTION: str
ENDPOINTS: dict[str, MethodToEvent] # {"MethodToEvent": MethodToEvent, ...}
SUBCATEGORY: Optional[List["CategoryCluster"]] # [CategoryCluster, ...]
ENDPOINTS: dict[str, MethodToEvent] # {"MethodToEvent": MethodToEvent, ...}
SUBCATEGORY: Optional[List["CategoryCluster"]] # [CategoryCluster, ...]
INCLUDE_IN_SCHEMA: Optional[bool] = True
def __init__(
@@ -189,7 +189,9 @@ class CategoryCluster:
RedisCategoryKeys.CLUSTER_2_METHOD_EVENT
Returns the class name and function codes for the class.
"""
dict_cluster_2_method, list_endpoints = {}, [i.name for i in self.ENDPOINTS.values()]
dict_cluster_2_method, list_endpoints = {}, [
i.name for i in self.ENDPOINTS.values()
]
for endpoint_name in list_endpoints:
dict_cluster_2_method[endpoint_name] = self.name
dict_cluster_2_method[self.name] = list_endpoints
@@ -201,7 +203,9 @@ class CategoryCluster:
"""
all_function_codes = []
for event_method in self.ENDPOINTS.values():
all_function_codes.extend([str(event_key) for event_key in event_method.EVENTS.keys()])
all_function_codes.extend(
[str(event_key) for event_key in event_method.EVENTS.keys()]
)
return all_function_codes
def retrieve_redis_value(self) -> Dict:

View File

@@ -23,14 +23,17 @@ class CategoryClusterController:
{ "category_cluster_name": "category_cluster_module" }
"""
if not hasattr(category_clusters, "__all__"):
raise ValueError(f"Given module {str(category_clusters)} does not have __all__ attribute")
raise ValueError(
f"Given module {str(category_clusters)} does not have __all__ attribute"
)
for iter_module in [str(item) for item in category_clusters.__all__]:
# CategoryCluster which represent api routers for each category
cls.imports_dict.append(
CategoryBulk(
category_cluster=getattr(category_clusters, iter_module, None),
name=iter_module
))
name=iter_module,
)
)
@classmethod
def as_dict(cls):
@@ -39,4 +42,5 @@ class CategoryClusterController:
to_dict[cluster.name] = cluster.category_cluster
return to_dict
cluster_controller = CategoryClusterController()
cluster_controller = CategoryClusterController()

View File

@@ -35,24 +35,32 @@ class DecoratorModule:
"""
decorators = []
current_func = func
original_qualname = getattr(func, '__qualname__', '')
original_qualname = getattr(func, "__qualname__", "")
while hasattr(current_func, '__wrapped__'):
if hasattr(current_func, '__closure__') and current_func.__closure__:
while hasattr(current_func, "__wrapped__"):
if hasattr(current_func, "__closure__") and current_func.__closure__:
for cell in current_func.__closure__:
decorator = cell.cell_contents
# Only add if it's a callable and not the original function
if callable(decorator) and getattr(decorator, '__qualname__', '') != original_qualname:
if (
callable(decorator)
and getattr(decorator, "__qualname__", "") != original_qualname
):
decorators.append(decorator)
current_func = current_func.__wrapped__
return list(dict.fromkeys(decorators)) # Remove duplicates while preserving order
return list(
dict.fromkeys(decorators)
) # Remove duplicates while preserving order
@staticmethod
def get_actual_decorators(method_endpoint):
original_qualname = getattr(method_endpoint.endpoint_callable, '__qualname__', '')
original_qualname = getattr(
method_endpoint.endpoint_callable, "__qualname__", ""
)
actual_decorators = [
d for d in method_endpoint.DECORATORS_LIST or []
if callable(d) and getattr(d, '__qualname__', '') != original_qualname
d
for d in method_endpoint.DECORATORS_LIST or []
if callable(d) and getattr(d, "__qualname__", "") != original_qualname
]
return actual_decorators
@@ -68,17 +76,27 @@ class DecoratorModule:
try:
function_callable = decorator(function_callable)
except Exception as e:
print(f"Warning: Failed to apply decorator {decorator.__qualname__}: {str(e)}")
print(
f"Warning: Failed to apply decorator {decorator.__qualname__}: {str(e)}"
)
method_endpoint.endpoint_callable = function_callable
# Get the final list of applied decorators (for debugging)
applied_decorators = cls.get_all_decorators(method_endpoint.endpoint_callable)
applied_decorators_qualname = [getattr(d, '__qualname__', str(d)) for d in applied_decorators]
applied_decorators_qualname = [
getattr(d, "__qualname__", str(d)) for d in applied_decorators
]
if applied_decorators:
print(f"Applied decorators for {method_endpoint.name}:", applied_decorators_qualname)
print(
f"Applied decorators for {method_endpoint.name}:",
applied_decorators_qualname,
)
return applied_decorators_qualname
@classmethod
def list_qualname(cls, method_endpoint_list):
return [getattr(method_endpoint, '__qualname__', '') for method_endpoint in method_endpoint_list]
return [
getattr(method_endpoint, "__qualname__", "")
for method_endpoint in method_endpoint_list
]

View File

@@ -9,8 +9,6 @@ def get_cluster_controller_group():
return cluster_controller
"""
prepare_routing = PrepareRouting(cluster_controller_group=cluster_controller)
prepare_events = PrepareEvents(cluster_controller_group=cluster_controller)

View File

@@ -2,7 +2,7 @@ from typing import Any
from ApiLayers.ApiServices.Cluster.create_router import (
CreateRouterFromCluster,
CreateEndpointFromCluster
CreateEndpointFromCluster,
)
from Events.Engine.abstract_class import CategoryCluster
from Services.Redis.Actions.actions import RedisActions
@@ -83,19 +83,27 @@ class PrepareEvents(DecoratorModule):
# [SAVE]REDIS => MENU_FIRST_LAYER = [ClusterToMethod, ...]
self.valid_redis_items.MENU_FIRST_LAYER_VALUE.add(cluster.name)
# [SAVE]REDIS => CLUSTER_INDEX = {ClusterToMethod: [MethodEvent, ...], "MethodEvent": "ClusterToMethod"}
self.valid_redis_items.CLUSTER_INDEX_VALUE.update(cluster.get_redis_cluster_index_value())
self.valid_redis_items.CLUSTER_INDEX_VALUE.update(
cluster.get_redis_cluster_index_value()
)
# [SAVE]REDIS => CLUSTER_FUNCTION_CODES = {"ClusterToMethod"} : [FUNCTION_CODE, ...]}
self.valid_redis_items.CLUSTER_FUNCTION_CODES_VALUE = {
f"{self.valid_redis_items.CLUSTER_FUNCTION_CODES_KEY}:{cluster.name}" : tuple(cluster.retrieve_all_function_codes())
f"{self.valid_redis_items.CLUSTER_FUNCTION_CODES_KEY}:{cluster.name}": tuple(
cluster.retrieve_all_function_codes()
)
}
for method_endpoint in list(cluster.ENDPOINTS.values()):
# [SAVE]REDIS => ENDPOINT2CLASS = {MethodEvent: Endpoint("/.../.../..."), ...}
self.valid_redis_items.ENDPOINT2CLASS_VALUE.update(
{f"{cluster.name}:{method_endpoint.name}": f"{cluster.PREFIX}{method_endpoint.URL}"}
{
f"{cluster.name}:{method_endpoint.name}": f"{cluster.PREFIX}{method_endpoint.URL}"
}
)
self.valid_redis_items.ENDPOINT2CLASS_VALUE.update(
{f"{cluster.PREFIX}{method_endpoint.URL}" :f"{cluster.name}:{method_endpoint.name}"}
{
f"{cluster.PREFIX}{method_endpoint.URL}": f"{cluster.name}:{method_endpoint.name}"
}
)
# [SAVE]REDIS => METHOD_FUNCTION_CODES:MethodEvent:Endpoint = [FUNCTION_CODE, ...]
self.valid_redis_items.METHOD_FUNCTION_CODES_VALUE.update(
@@ -116,8 +124,12 @@ class SetItems2Redis:
def set_items(self):
from ApiLayers.AllConfigs.Redis.configs import RedisCategoryKeys
dict_prep = self.prepare_events.valid_redis_items.as_dict
for redis_values_to_delete, redis_key_type in RedisCategoryKeys.__annotations__.items():
for (
redis_values_to_delete,
redis_key_type,
) in RedisCategoryKeys.__annotations__.items():
if isinstance(redis_key_type, str):
continue
RedisActions.delete(list_keys=[f"{redis_values_to_delete}*"])
@@ -125,19 +137,23 @@ class SetItems2Redis:
# Save MENU_FIRST_LAYER to Redis
redis_list = RedisList(redis_key=RedisCategoryKeys.MENU_FIRST_LAYER)
RedisActions.set_json(
list_keys=redis_list.to_list(), value=dict_prep.get(RedisCategoryKeys.MENU_FIRST_LAYER)
list_keys=redis_list.to_list(),
value=dict_prep.get(RedisCategoryKeys.MENU_FIRST_LAYER),
)
self.std_out += f"{RedisCategoryKeys.MENU_FIRST_LAYER}: {dict_prep.get(RedisCategoryKeys.MENU_FIRST_LAYER)}\n"
# Save CLUSTER_INDEX to Redis
redis_list = RedisList(redis_key=RedisCategoryKeys.CLUSTER_INDEX)
RedisActions.set_json(
list_keys=redis_list.to_list(), value=dict_prep.get(RedisCategoryKeys.CLUSTER_INDEX)
list_keys=redis_list.to_list(),
value=dict_prep.get(RedisCategoryKeys.CLUSTER_INDEX),
)
self.std_out += f"\n{RedisCategoryKeys.CLUSTER_INDEX}: {dict_prep.get(RedisCategoryKeys.CLUSTER_INDEX)}\n"
# Save CLUSTER_FUNCTION_CODES to Redis by iterating over the dict
for redis_key, redis_value in dict_prep.get(RedisCategoryKeys.CLUSTER_FUNCTION_CODES).items():
for redis_key, redis_value in dict_prep.get(
RedisCategoryKeys.CLUSTER_FUNCTION_CODES
).items():
redis_list = RedisList(redis_key=redis_key)
RedisActions.set_json(
list_keys=redis_list.to_list(), value=list(redis_value)
@@ -145,7 +161,9 @@ class SetItems2Redis:
self.std_out += f"\n{RedisCategoryKeys.CLUSTER_FUNCTION_CODES}: {dict_prep.get(RedisCategoryKeys.CLUSTER_FUNCTION_CODES)}\n"
# Save METHOD_FUNCTION_CODES to Redis by iterating over the dict
for redis_key, redis_value in dict_prep.get(RedisCategoryKeys.METHOD_FUNCTION_CODES).items():
for redis_key, redis_value in dict_prep.get(
RedisCategoryKeys.METHOD_FUNCTION_CODES
).items():
redis_list = RedisList(redis_key=redis_key)
RedisActions.set_json(
list_keys=redis_list.to_list(), value=list(redis_value)
@@ -153,19 +171,22 @@ class SetItems2Redis:
self.std_out += f"\n{RedisCategoryKeys.METHOD_FUNCTION_CODES}: {dict_prep.get(RedisCategoryKeys.METHOD_FUNCTION_CODES)}\n"
# Save ENDPOINT2CLASS to Redis by iterating over the dict
for redis_key, redis_value in dict_prep.get(RedisCategoryKeys.ENDPOINT2CLASS).items():
redis_list = RedisList(redis_key=f"{RedisCategoryKeys.ENDPOINT2CLASS}:{redis_key}\n")
RedisActions.set_json(
list_keys=redis_list.to_list(), value=redis_value
for redis_key, redis_value in dict_prep.get(
RedisCategoryKeys.ENDPOINT2CLASS
).items():
redis_list = RedisList(
redis_key=f"{RedisCategoryKeys.ENDPOINT2CLASS}:{redis_key}\n"
)
RedisActions.set_json(list_keys=redis_list.to_list(), value=redis_value)
self.std_out += f"\n{RedisCategoryKeys.ENDPOINT2CLASS}: {dict_prep.get(RedisCategoryKeys.ENDPOINT2CLASS)}\n"
RedisActions.set_json(
list_keys=[f"{RedisCategoryKeys.REBUILD}:*"], value={
list_keys=[f"{RedisCategoryKeys.REBUILD}:*"],
value={
f"{RedisCategoryKeys.MENU_FIRST_LAYER}": True,
f"{RedisCategoryKeys.CLUSTER_INDEX}": True,
f"{RedisCategoryKeys.CLUSTER_FUNCTION_CODES}": True,
f"{RedisCategoryKeys.METHOD_FUNCTION_CODES}": True,
f"{RedisCategoryKeys.ENDPOINT2CLASS}": True,
}
},
)

View File

@@ -5,11 +5,19 @@ This module provides base request models that can be used across different endpo
to ensure consistent request handling and validation.
"""
from typing import Dict, Any, TypeVar
from pydantic import BaseModel, Field, ConfigDict
from typing import Union, Optional, Any
from pydantic import BaseModel, Field
from ApiLayers.ApiValidations.Custom.token_objects import (
EmployeeTokenObject,
OccupantTokenObject,
)
from ApiLayers.ApiValidations.Custom.wrapper_contexts import AuthContext, EventContext
T = TypeVar("T")
TokenDictType = Union[
EmployeeTokenObject, OccupantTokenObject
] # Type aliases for common types
class EndpointBaseRequestModel(BaseModel):
@@ -17,35 +25,63 @@ class EndpointBaseRequestModel(BaseModel):
data: dict = Field(..., description="Data to be sent with the request")
class Config:
json_schema_extra = {
"data": {
"key": "value",
}
}
json_schema_extra = {"data": {"key": "value"}}
class SuccessResponse(BaseModel):
"""Standard success response model."""
class ContextRetrievers:
"""Utility class to retrieve context from functions."""
data: Dict[str, Any] = Field(
...,
example={
"id": "123",
"username": "john.doe",
"email": "john@example.com",
"role": "user",
},
)
is_auth: bool = False
is_event: bool = False
key_: str = ""
model_config = ConfigDict(
json_schema_extra={
"example": {
"data": {
"id": "123",
"username": "john.doe",
"email": "john@example.com",
"role": "user",
},
}
}
)
def __init__(self, func):
self.func = func
if hasattr(self.func, "auth_context"):
self.is_auth = True
self.key_ = "auth_context"
elif hasattr(self.func, "event_context"):
self.is_event = hasattr(self.func, "event_context")
self.key_ = "event_context"
@property
def key(self) -> Union[str, None]:
"""Retrieve key context from a function."""
return self.key_
@property
def context(self) -> Union[AuthContext, EventContext, None]:
"""Retrieve authentication or event context from a function."""
if self.is_auth:
return getattr(self.func, "auth_context", None)
elif self.is_event:
return getattr(self.func, "event_context", None)
return None
@property
def request(self) -> Union[Any, None]:
"""Retrieve request context from a function."""
return getattr(self.context, "request", None)
@property
def token(self) -> TokenDictType:
"""Retrieve token context from a function."""
if self.is_auth or self.is_event:
return getattr(self.context, "auth", None)
@property
def url(self) -> Union[str, None]:
"""Retrieve URL context from a function."""
return getattr(self.context, "url", None)
@property
def code(self) -> Union[str, None]:
"""Retrieve code context from a function."""
if self.is_event:
return getattr(self.context, "code", None)
return None
@property
def base(self) -> Optional[dict[str, Any]]:
"""Retrieve base request model from a function."""
return getattr(self.context, "base", None)