auth service up running
This commit is contained in:
parent
03accfed1b
commit
79aa3a1bc5
|
|
@ -22,7 +22,7 @@ def save_access_token_to_redis(
|
||||||
Employees,
|
Employees,
|
||||||
Staff,
|
Staff,
|
||||||
Addresses,
|
Addresses,
|
||||||
OccupantTypes
|
OccupantTypes,
|
||||||
)
|
)
|
||||||
|
|
||||||
if not found_user:
|
if not found_user:
|
||||||
|
|
@ -32,7 +32,9 @@ def save_access_token_to_redis(
|
||||||
)
|
)
|
||||||
|
|
||||||
# Check user is already logged in or has a previous session
|
# Check user is already logged in or has a previous session
|
||||||
already_tokens = AccessObjectActions.get_object_via_user_uu_id(user_id=found_user.uu_id)
|
already_tokens = AccessObjectActions.get_object_via_user_uu_id(
|
||||||
|
user_id=found_user.uu_id
|
||||||
|
)
|
||||||
for key, token_user in already_tokens.items():
|
for key, token_user in already_tokens.items():
|
||||||
if token_user.get("domain", "") == domain:
|
if token_user.get("domain", "") == domain:
|
||||||
redis_cli.delete(key)
|
redis_cli.delete(key)
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ class AccessObjectActions:
|
||||||
cls,
|
cls,
|
||||||
access_token,
|
access_token,
|
||||||
model_object: typing.Union[OccupantTokenObject, EmployeeTokenObject],
|
model_object: typing.Union[OccupantTokenObject, EmployeeTokenObject],
|
||||||
expiry_minutes: int = Auth.TOKEN_EXPIRE_MINUTES_30.total_seconds() // 60
|
expiry_minutes: int = Auth.TOKEN_EXPIRE_MINUTES_30.total_seconds() // 60,
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""Save access token object to Redis with expiry
|
"""Save access token object to Redis with expiry
|
||||||
Args:
|
Args:
|
||||||
|
|
@ -28,17 +28,14 @@ class AccessObjectActions:
|
||||||
RedisActions.save_object_to_redis(
|
RedisActions.save_object_to_redis(
|
||||||
access_token=access_token,
|
access_token=access_token,
|
||||||
model_object=model_object,
|
model_object=model_object,
|
||||||
expiry_minutes=expiry_minutes
|
expiry_minutes=expiry_minutes,
|
||||||
)
|
)
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("Save Object to Redis Error: ", e)
|
print("Save Object to Redis Error: ", e)
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
||||||
detail=dict(
|
detail=dict(message="Failed to save token to Redis", error=str(e)),
|
||||||
message="Failed to save token to Redis",
|
|
||||||
error=str(e)
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
@ -64,23 +61,21 @@ class AccessObjectActions:
|
||||||
if not hasattr(request, "headers"):
|
if not hasattr(request, "headers"):
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||||
detail=dict(
|
detail=dict(message="Headers not found in request"),
|
||||||
message="Headers not found in request"
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
access_token = request.headers.get(Auth.ACCESS_TOKEN_TAG)
|
access_token = request.headers.get(Auth.ACCESS_TOKEN_TAG)
|
||||||
if not access_token:
|
if not access_token:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||||
detail=dict(
|
detail=dict(message="Unauthorized user, please login"),
|
||||||
message="Unauthorized user, please login"
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
return access_token
|
return access_token
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_token_object(cls, request) -> typing.Union[OccupantTokenObject, EmployeeTokenObject]:
|
def get_token_object(
|
||||||
|
cls, request
|
||||||
|
) -> typing.Union[OccupantTokenObject, EmployeeTokenObject]:
|
||||||
"""Get and validate token object from request
|
"""Get and validate token object from request
|
||||||
Args:
|
Args:
|
||||||
request: The request object
|
request: The request object
|
||||||
|
|
@ -93,18 +88,16 @@ class AccessObjectActions:
|
||||||
return RedisActions.get_object_via_access_key(request)
|
return RedisActions.get_object_via_access_key(request)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
status_code=status.HTTP_401_UNAUTHORIZED, detail=dict(message=str(e))
|
||||||
detail=dict(
|
|
||||||
message=str(e)
|
|
||||||
)
|
)
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_object_via_access_key(
|
def get_object_via_access_key(
|
||||||
cls, request,
|
cls,
|
||||||
|
request,
|
||||||
) -> typing.Union[EmployeeTokenObject, OccupantTokenObject, None]:
|
) -> typing.Union[EmployeeTokenObject, OccupantTokenObject, None]:
|
||||||
from api_configs import Auth
|
from api_configs import Auth
|
||||||
|
|
||||||
access_object = RedisActions.get_with_regex(
|
access_object = RedisActions.get_with_regex(
|
||||||
value_regex=str(request.headers.get(Auth.ACCESS_TOKEN_TAG) + ":*")
|
value_regex=str(request.headers.get(Auth.ACCESS_TOKEN_TAG) + ":*")
|
||||||
).data
|
).data
|
||||||
|
|
@ -120,7 +113,7 @@ class AccessObjectActions:
|
||||||
status_code=401,
|
status_code=401,
|
||||||
detail=dict(
|
detail=dict(
|
||||||
message="User type is not found in the token object. Please reach to your administrator."
|
message="User type is not found in the token object. Please reach to your administrator."
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,15 @@ from typing import TypeVar, Union, Dict, Any, Optional, Type
|
||||||
|
|
||||||
from api_objects.auth.token_objects import EmployeeTokenObject, OccupantTokenObject
|
from api_objects.auth.token_objects import EmployeeTokenObject, OccupantTokenObject
|
||||||
|
|
||||||
TokenType = TypeVar('TokenType', bound=Union[EmployeeTokenObject, OccupantTokenObject])
|
TokenType = TypeVar("TokenType", bound=Union[EmployeeTokenObject, OccupantTokenObject])
|
||||||
|
|
||||||
|
|
||||||
class ActionsSchema(ABC):
|
class ActionsSchema(ABC):
|
||||||
"""Base class for defining API action schemas.
|
"""Base class for defining API action schemas.
|
||||||
|
|
||||||
This class handles endpoint registration and validation in the database.
|
This class handles endpoint registration and validation in the database.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, endpoint: str):
|
def __init__(self, endpoint: str):
|
||||||
"""Initialize with an API endpoint path.
|
"""Initialize with an API endpoint path.
|
||||||
|
|
||||||
|
|
@ -38,7 +40,7 @@ class ActionsSchema(ABC):
|
||||||
"endpoint_desc": "Temporary endpoint",
|
"endpoint_desc": "Temporary endpoint",
|
||||||
"endpoint_code": "dummy_code",
|
"endpoint_code": "dummy_code",
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"uu_id": "dummy_uuid"
|
"uu_id": "dummy_uuid",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -47,6 +49,7 @@ class ActionsSchemaFactory:
|
||||||
|
|
||||||
This class validates and initializes action schemas for API endpoints.
|
This class validates and initializes action schemas for API endpoints.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, action: ActionsSchema):
|
def __init__(self, action: ActionsSchema):
|
||||||
"""Initialize with an action schema.
|
"""Initialize with an action schema.
|
||||||
|
|
||||||
|
|
@ -67,7 +70,7 @@ class ActionsSchemaFactory:
|
||||||
print(f"ActionsSchemaFactory Error: {e}")
|
print(f"ActionsSchemaFactory Error: {e}")
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
detail="Failed to initialize action schema"
|
detail="Failed to initialize action schema",
|
||||||
) from e
|
) from e
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -76,6 +79,7 @@ class MethodToEvent(ABC, ActionsSchemaFactory):
|
||||||
|
|
||||||
This class handles method registration and validation for API events.
|
This class handles method registration and validation for API events.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
action_key: Optional[str] = None
|
action_key: Optional[str] = None
|
||||||
event_type: Optional[str] = None
|
event_type: Optional[str] = None
|
||||||
event_description: str = ""
|
event_description: str = ""
|
||||||
|
|
@ -106,11 +110,7 @@ class MethodToEvent(ABC, ActionsSchemaFactory):
|
||||||
return getattr(cls, function_name)(*args, **kwargs)
|
return getattr(cls, function_name)(*args, **kwargs)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def ban_token_objects(
|
def ban_token_objects(cls, token: TokenType, ban_list: Type[TokenType]) -> None:
|
||||||
cls,
|
|
||||||
token: TokenType,
|
|
||||||
ban_list: Type[TokenType]
|
|
||||||
) -> None:
|
|
||||||
"""Check if a token type is banned from accessing an event.
|
"""Check if a token type is banned from accessing an event.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
|
@ -121,8 +121,10 @@ class MethodToEvent(ABC, ActionsSchemaFactory):
|
||||||
HTTPException: If token type matches banned type
|
HTTPException: If token type matches banned type
|
||||||
"""
|
"""
|
||||||
if isinstance(token, ban_list):
|
if isinstance(token, ban_list):
|
||||||
user_type = "employee" if isinstance(token, EmployeeTokenObject) else "occupant"
|
user_type = (
|
||||||
|
"employee" if isinstance(token, EmployeeTokenObject) else "occupant"
|
||||||
|
)
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_406_NOT_ACCEPTABLE,
|
status_code=status.HTTP_406_NOT_ACCEPTABLE,
|
||||||
detail=f"No {user_type} can reach this event. A notification has been sent to admin."
|
detail=f"No {user_type} can reach this event. A notification has been sent to admin.",
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ class AccountRecordsListEventMethods(MethodToEvent):
|
||||||
result=records,
|
result=records,
|
||||||
cls_object=AccountRecords,
|
cls_object=AccountRecords,
|
||||||
filter_attributes=list_options,
|
filter_attributes=list_options,
|
||||||
response_model=AccountRecordResponse
|
response_model=AccountRecordResponse,
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
@ -224,7 +224,9 @@ class AccountRecordsCreateEventMethods(MethodToEvent):
|
||||||
)
|
)
|
||||||
account_record = AccountRecords.find_or_create(**data.excluded_dump())
|
account_record = AccountRecords.find_or_create(**data.excluded_dump())
|
||||||
return AlchemyJsonResponse(
|
return AlchemyJsonResponse(
|
||||||
completed=True, message="Account record created successfully", result=account_record
|
completed=True,
|
||||||
|
message="Account record created successfully",
|
||||||
|
result=account_record,
|
||||||
)
|
)
|
||||||
elif isinstance(token_dict, EmployeeTokenObject):
|
elif isinstance(token_dict, EmployeeTokenObject):
|
||||||
# Build.pre_query = Build.select_action(
|
# Build.pre_query = Build.select_action(
|
||||||
|
|
@ -266,7 +268,9 @@ class AccountRecordsCreateEventMethods(MethodToEvent):
|
||||||
|
|
||||||
account_record = AccountRecords.insert_one(data_dict).data
|
account_record = AccountRecords.insert_one(data_dict).data
|
||||||
return AlchemyJsonResponse(
|
return AlchemyJsonResponse(
|
||||||
completed=True, message="Account record created successfully", result=account_record
|
completed=True,
|
||||||
|
message="Account record created successfully",
|
||||||
|
result=account_record,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -297,7 +301,9 @@ class AccountRecordsUpdateEventMethods(MethodToEvent):
|
||||||
|
|
||||||
account_record = AccountRecords.update_one(build_uu_id, data).data
|
account_record = AccountRecords.update_one(build_uu_id, data).data
|
||||||
return AlchemyJsonResponse(
|
return AlchemyJsonResponse(
|
||||||
completed=True, message="Account record updated successfully", result=account_record
|
completed=True,
|
||||||
|
message="Account record updated successfully",
|
||||||
|
result=account_record,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -323,7 +329,9 @@ class AccountRecordsPatchEventMethods(MethodToEvent):
|
||||||
):
|
):
|
||||||
account_record = AccountRecords.patch_one(build_uu_id, data).data
|
account_record = AccountRecords.patch_one(build_uu_id, data).data
|
||||||
return AlchemyJsonResponse(
|
return AlchemyJsonResponse(
|
||||||
completed=True, message="Account record patched successfully", result=account_record
|
completed=True,
|
||||||
|
message="Account record patched successfully",
|
||||||
|
result=account_record,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -138,7 +138,9 @@ class AddressCreateEventMethods(MethodToEvent):
|
||||||
address.update(is_confirmed=True)
|
address.update(is_confirmed=True)
|
||||||
address.save()
|
address.save()
|
||||||
return AlchemyJsonResponse(
|
return AlchemyJsonResponse(
|
||||||
completed=True, message="Address created successfully", result=address.get_dict()
|
completed=True,
|
||||||
|
message="Address created successfully",
|
||||||
|
result=address.get_dict(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -148,6 +150,7 @@ class AddressSearchEventMethods(MethodToEvent):
|
||||||
This class handles address search functionality including text search
|
This class handles address search functionality including text search
|
||||||
and filtering.
|
and filtering.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
event_type = "SEARCH"
|
event_type = "SEARCH"
|
||||||
event_description = "Search for addresses using text and filters"
|
event_description = "Search for addresses using text and filters"
|
||||||
event_category = "Address"
|
event_category = "Address"
|
||||||
|
|
@ -161,10 +164,7 @@ class AddressSearchEventMethods(MethodToEvent):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _build_order_clause(
|
def _build_order_clause(
|
||||||
cls,
|
cls, filter_list: Dict[str, Any], schemas: List[str], filter_table: Any
|
||||||
filter_list: Dict[str, Any],
|
|
||||||
schemas: List[str],
|
|
||||||
filter_table: Any
|
|
||||||
) -> Any:
|
) -> Any:
|
||||||
"""Build the ORDER BY clause for the query.
|
"""Build the ORDER BY clause for the query.
|
||||||
|
|
||||||
|
|
@ -187,7 +187,11 @@ class AddressSearchEventMethods(MethodToEvent):
|
||||||
|
|
||||||
# Build order clause
|
# Build order clause
|
||||||
field = getattr(filter_table, filter_list.get("order_field"))
|
field = getattr(filter_table, filter_list.get("order_field"))
|
||||||
return field.desc() if str(filter_list.get("order_type"))[0] == "d" else field.asc()
|
return (
|
||||||
|
field.desc()
|
||||||
|
if str(filter_list.get("order_type"))[0] == "d"
|
||||||
|
else field.asc()
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _format_record(cls, record: Any, schemas: List[str]) -> Dict[str, str]:
|
def _format_record(cls, record: Any, schemas: List[str]) -> Dict[str, str]:
|
||||||
|
|
@ -236,7 +240,7 @@ class AddressSearchEventMethods(MethodToEvent):
|
||||||
if not search_result:
|
if not search_result:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_404_NOT_FOUND,
|
status_code=status.HTTP_404_NOT_FOUND,
|
||||||
detail="No addresses found matching search criteria"
|
detail="No addresses found matching search criteria",
|
||||||
)
|
)
|
||||||
|
|
||||||
query = search_result.get("query")
|
query = search_result.get("query")
|
||||||
|
|
@ -270,9 +274,7 @@ class AddressSearchEventMethods(MethodToEvent):
|
||||||
print(f"Address search completed in {duration:.3f}s")
|
print(f"Address search completed in {duration:.3f}s")
|
||||||
|
|
||||||
return AlchemyJsonResponse(
|
return AlchemyJsonResponse(
|
||||||
completed=True,
|
completed=True, message="Address search results", result=results
|
||||||
message="Address search results",
|
|
||||||
result=results
|
|
||||||
)
|
)
|
||||||
|
|
||||||
except HTTPException as e:
|
except HTTPException as e:
|
||||||
|
|
@ -283,7 +285,7 @@ class AddressSearchEventMethods(MethodToEvent):
|
||||||
print(f"Address search error: {str(e)}")
|
print(f"Address search error: {str(e)}")
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
detail="Failed to search addresses"
|
detail="Failed to search addresses",
|
||||||
) from e
|
) from e
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -321,7 +323,9 @@ class AddressUpdateEventMethods(MethodToEvent):
|
||||||
updated_address = address.update(**data_dict)
|
updated_address = address.update(**data_dict)
|
||||||
updated_address.save()
|
updated_address.save()
|
||||||
return AlchemyJsonResponse(
|
return AlchemyJsonResponse(
|
||||||
completed=True, message="Address updated successfully", result=updated_address.get_dict()
|
completed=True,
|
||||||
|
message="Address updated successfully",
|
||||||
|
result=updated_address.get_dict(),
|
||||||
)
|
)
|
||||||
elif isinstance(token_dict, OccupantTokenObject):
|
elif isinstance(token_dict, OccupantTokenObject):
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
|
|
@ -368,7 +372,9 @@ class AddressPatchEventMethods(MethodToEvent):
|
||||||
|
|
||||||
patched_address = address.patch(**data_dict)
|
patched_address = address.patch(**data_dict)
|
||||||
return AlchemyJsonResponse(
|
return AlchemyJsonResponse(
|
||||||
completed=True, message="Address patched successfully", result=patched_address.get_dict()
|
completed=True,
|
||||||
|
message="Address patched successfully",
|
||||||
|
result=patched_address.get_dict(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -416,7 +422,9 @@ class AddressPostCodeCreateEventMethods(MethodToEvent):
|
||||||
relation_table.update(is_confirmed=True)
|
relation_table.update(is_confirmed=True)
|
||||||
relation_table.save()
|
relation_table.save()
|
||||||
return AlchemyJsonResponse(
|
return AlchemyJsonResponse(
|
||||||
completed=True, message="Post code created successfully", result=post_code.get_dict()
|
completed=True,
|
||||||
|
message="Post code created successfully",
|
||||||
|
result=post_code.get_dict(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -457,7 +465,9 @@ class AddressPostCodeUpdateEventMethods(MethodToEvent):
|
||||||
updated_post_code = post_code.update(**data_dict)
|
updated_post_code = post_code.update(**data_dict)
|
||||||
updated_post_code.save()
|
updated_post_code.save()
|
||||||
return AlchemyJsonResponse(
|
return AlchemyJsonResponse(
|
||||||
completed=True, message="Post code updated successfully", result=updated_post_code.get_dict()
|
completed=True,
|
||||||
|
message="Post code updated successfully",
|
||||||
|
result=updated_post_code.get_dict(),
|
||||||
)
|
)
|
||||||
elif isinstance(token_dict, OccupantTokenObject):
|
elif isinstance(token_dict, OccupantTokenObject):
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,21 @@ from api_configs import Auth, ApiStatic
|
||||||
from api_events.events.abstract_class import MethodToEvent, ActionsSchema
|
from api_events.events.abstract_class import MethodToEvent, ActionsSchema
|
||||||
|
|
||||||
from databases import (
|
from databases import (
|
||||||
Companies, Staff, Duties, Departments, Employees,
|
Companies,
|
||||||
BuildLivingSpace, BuildParts, Build, Duty, Event2Occupant,
|
Staff,
|
||||||
Event2Employee, Users, UsersTokens, OccupantTypes,
|
Duties,
|
||||||
RelationshipEmployee2Build
|
Departments,
|
||||||
|
Employees,
|
||||||
|
BuildLivingSpace,
|
||||||
|
BuildParts,
|
||||||
|
Build,
|
||||||
|
Duty,
|
||||||
|
Event2Occupant,
|
||||||
|
Event2Employee,
|
||||||
|
Users,
|
||||||
|
UsersTokens,
|
||||||
|
OccupantTypes,
|
||||||
|
RelationshipEmployee2Build,
|
||||||
)
|
)
|
||||||
|
|
||||||
from api_services import (
|
from api_services import (
|
||||||
|
|
@ -28,17 +39,23 @@ from api_services import (
|
||||||
)
|
)
|
||||||
|
|
||||||
from api_validations.validations_request import (
|
from api_validations.validations_request import (
|
||||||
Login, Logout, ChangePassword, Remember,
|
Login,
|
||||||
Forgot, CreatePassword, OccupantSelection,
|
Logout,
|
||||||
|
ChangePassword,
|
||||||
|
Remember,
|
||||||
|
Forgot,
|
||||||
|
CreatePassword,
|
||||||
|
OccupantSelection,
|
||||||
EmployeeSelection,
|
EmployeeSelection,
|
||||||
)
|
)
|
||||||
|
|
||||||
from api_validations.validations_response import (
|
from api_validations.validations_response import (
|
||||||
AuthenticationLoginResponse,
|
AuthenticationLoginResponse,
|
||||||
AuthenticationRefreshResponse,
|
AuthenticationRefreshResponse,
|
||||||
AuthenticationUserInfoResponse
|
AuthenticationUserInfoResponse,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
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]"
|
||||||
|
|
@ -59,14 +76,17 @@ class AuthenticationLoginEventMethods(MethodToEvent):
|
||||||
|
|
||||||
if not found_user:
|
if not found_user:
|
||||||
user_logger.log_login_attempt(
|
user_logger.log_login_attempt(
|
||||||
request, None, data.domain, data.access_key,
|
request,
|
||||||
success=False, error="Invalid credentials"
|
None,
|
||||||
|
data.domain,
|
||||||
|
data.access_key,
|
||||||
|
success=False,
|
||||||
|
error="Invalid credentials",
|
||||||
)
|
)
|
||||||
return ResponseHandler.unauthorized("Invalid credentials")
|
return ResponseHandler.unauthorized("Invalid credentials")
|
||||||
|
|
||||||
user_logger.log_login_attempt(
|
user_logger.log_login_attempt(
|
||||||
request, found_user.id, data.domain, data.access_key,
|
request, found_user.id, data.domain, data.access_key, success=True
|
||||||
success=True
|
|
||||||
)
|
)
|
||||||
|
|
||||||
response_data = {
|
response_data = {
|
||||||
|
|
@ -78,17 +98,13 @@ class AuthenticationLoginEventMethods(MethodToEvent):
|
||||||
return ResponseHandler.success(
|
return ResponseHandler.success(
|
||||||
message="User logged in successfully",
|
message="User logged in successfully",
|
||||||
data=response_data,
|
data=response_data,
|
||||||
response_model=AuthenticationLoginResponse
|
response_model=AuthenticationLoginResponse,
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
user_logger.log_login_attempt(
|
user_logger.log_login_attempt(
|
||||||
request, None, data.domain, data.access_key,
|
request, None, data.domain, data.access_key, success=False, error=str(e)
|
||||||
success=False, error=str(e)
|
|
||||||
)
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
||||||
detail=str(e)
|
|
||||||
)
|
)
|
||||||
|
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=str(e))
|
||||||
|
|
||||||
|
|
||||||
class AuthenticationSelectEventMethods(MethodToEvent):
|
class AuthenticationSelectEventMethods(MethodToEvent):
|
||||||
|
|
@ -105,14 +121,13 @@ class AuthenticationSelectEventMethods(MethodToEvent):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _handle_employee_selection(
|
def _handle_employee_selection(
|
||||||
cls,
|
cls, data: EmployeeSelection, token_dict: EmployeeTokenObject, request: Request
|
||||||
data: EmployeeSelection,
|
|
||||||
token_dict: EmployeeTokenObject,
|
|
||||||
request: Request
|
|
||||||
):
|
):
|
||||||
"""Handle employee company selection"""
|
"""Handle employee company selection"""
|
||||||
if data.company_uu_id not in token_dict.companies_uu_id_list:
|
if data.company_uu_id not in token_dict.companies_uu_id_list:
|
||||||
return ResponseHandler.unauthorized("Company not found in user's company list")
|
return ResponseHandler.unauthorized(
|
||||||
|
"Company not found in user's company list"
|
||||||
|
)
|
||||||
|
|
||||||
selected_company = Companies.filter_one(
|
selected_company = Companies.filter_one(
|
||||||
Companies.uu_id == data.company_uu_id
|
Companies.uu_id == data.company_uu_id
|
||||||
|
|
@ -122,29 +137,27 @@ class AuthenticationSelectEventMethods(MethodToEvent):
|
||||||
|
|
||||||
# Get department IDs for the company
|
# Get department IDs for the company
|
||||||
department_ids = [
|
department_ids = [
|
||||||
dept.id for dept in Departments.filter_all(
|
dept.id
|
||||||
|
for dept in Departments.filter_all(
|
||||||
Departments.company_id == selected_company.id
|
Departments.company_id == selected_company.id
|
||||||
).data
|
).data
|
||||||
]
|
]
|
||||||
|
|
||||||
# Get duties IDs for the company
|
# Get duties IDs for the company
|
||||||
duties_ids = [
|
duties_ids = [
|
||||||
duty.id for duty in Duties.filter_all(
|
duty.id
|
||||||
Duties.company_id == selected_company.id
|
for duty in Duties.filter_all(Duties.company_id == selected_company.id).data
|
||||||
).data
|
|
||||||
]
|
]
|
||||||
|
|
||||||
# Get staff IDs
|
# Get staff IDs
|
||||||
staff_ids = [
|
staff_ids = [
|
||||||
staff.id for staff in Staff.filter_all(
|
staff.id for staff in Staff.filter_all(Staff.duties_id.in_(duties_ids)).data
|
||||||
Staff.duties_id.in_(duties_ids)
|
|
||||||
).data
|
|
||||||
]
|
]
|
||||||
|
|
||||||
# Get employee
|
# Get employee
|
||||||
employee = Employees.filter_one(
|
employee = Employees.filter_one(
|
||||||
Employees.people_id == token_dict.person_id,
|
Employees.people_id == token_dict.person_id,
|
||||||
Employees.staff_id.in_(staff_ids)
|
Employees.staff_id.in_(staff_ids),
|
||||||
).data
|
).data
|
||||||
|
|
||||||
if not employee:
|
if not employee:
|
||||||
|
|
@ -158,16 +171,14 @@ class AuthenticationSelectEventMethods(MethodToEvent):
|
||||||
# Get staff and duties
|
# Get staff and duties
|
||||||
staff = Staff.filter_one(Staff.id == employee.staff_id).data
|
staff = Staff.filter_one(Staff.id == employee.staff_id).data
|
||||||
duties = Duties.filter_one(Duties.id == staff.duties_id).data
|
duties = Duties.filter_one(Duties.id == staff.duties_id).data
|
||||||
department = Departments.filter_one(
|
department = Departments.filter_one(Departments.id == duties.department_id).data
|
||||||
Departments.id == duties.department_id
|
|
||||||
).data
|
|
||||||
|
|
||||||
# Get bulk duty
|
# Get bulk duty
|
||||||
bulk_id = Duty.filter_by_one(system=True, duty_code="BULK").data
|
bulk_id = Duty.filter_by_one(system=True, duty_code="BULK").data
|
||||||
bulk_duty_id = Duties.filter_by_one(
|
bulk_duty_id = Duties.filter_by_one(
|
||||||
company_id=selected_company.id,
|
company_id=selected_company.id,
|
||||||
duties_id=bulk_id.id,
|
duties_id=bulk_id.id,
|
||||||
**Duties.valid_record_dict
|
**Duties.valid_record_dict,
|
||||||
).data
|
).data
|
||||||
|
|
||||||
# Create company token
|
# Create company token
|
||||||
|
|
@ -183,7 +194,7 @@ class AuthenticationSelectEventMethods(MethodToEvent):
|
||||||
staff_uu_id=staff.uu_id.__str__(),
|
staff_uu_id=staff.uu_id.__str__(),
|
||||||
employee_id=employee.id,
|
employee_id=employee.id,
|
||||||
employee_uu_id=employee.uu_id.__str__(),
|
employee_uu_id=employee.uu_id.__str__(),
|
||||||
reachable_event_list_id=reachable_event_list_id
|
reachable_event_list_id=reachable_event_list_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Update Redis
|
# Update Redis
|
||||||
|
|
@ -192,24 +203,19 @@ class AuthenticationSelectEventMethods(MethodToEvent):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _handle_occupant_selection(
|
def _handle_occupant_selection(
|
||||||
cls,
|
cls, data: OccupantSelection, token_dict: OccupantTokenObject, request: Request
|
||||||
data: OccupantSelection,
|
|
||||||
token_dict: OccupantTokenObject,
|
|
||||||
request: Request
|
|
||||||
):
|
):
|
||||||
"""Handle occupant type selection"""
|
"""Handle occupant type selection"""
|
||||||
# Get occupant type
|
# Get occupant type
|
||||||
occupant_type = OccupantTypes.filter_by_one(
|
occupant_type = OccupantTypes.filter_by_one(
|
||||||
system=True,
|
system=True, uu_id=data.occupant_uu_id
|
||||||
uu_id=data.occupant_uu_id
|
|
||||||
).data
|
).data
|
||||||
if not occupant_type:
|
if not occupant_type:
|
||||||
return ResponseHandler.not_found("Occupant Type not found")
|
return ResponseHandler.not_found("Occupant Type not found")
|
||||||
|
|
||||||
# Get build part
|
# Get build part
|
||||||
build_part = BuildParts.filter_by_one(
|
build_part = BuildParts.filter_by_one(
|
||||||
system=True,
|
system=True, uu_id=data.build_part_uu_id
|
||||||
uu_id=data.build_part_uu_id
|
|
||||||
).data
|
).data
|
||||||
if not build_part:
|
if not build_part:
|
||||||
return ResponseHandler.not_found("Build Part not found")
|
return ResponseHandler.not_found("Build Part not found")
|
||||||
|
|
@ -230,7 +236,7 @@ class AuthenticationSelectEventMethods(MethodToEvent):
|
||||||
selected_occupant_type = BuildLivingSpace.filter_one(
|
selected_occupant_type = BuildLivingSpace.filter_one(
|
||||||
BuildLivingSpace.occupant_type == occupant_type.id,
|
BuildLivingSpace.occupant_type == occupant_type.id,
|
||||||
BuildLivingSpace.person_id == token_dict.person_id,
|
BuildLivingSpace.person_id == token_dict.person_id,
|
||||||
BuildLivingSpace.build_parts_id == build_part.id
|
BuildLivingSpace.build_parts_id == build_part.id,
|
||||||
).data
|
).data
|
||||||
if not selected_occupant_type:
|
if not selected_occupant_type:
|
||||||
return ResponseHandler.not_found("Selected occupant type not found")
|
return ResponseHandler.not_found("Selected occupant type not found")
|
||||||
|
|
@ -255,7 +261,7 @@ class AuthenticationSelectEventMethods(MethodToEvent):
|
||||||
responsible_employee_uuid=responsible_employee.uu_id.__str__(),
|
responsible_employee_uuid=responsible_employee.uu_id.__str__(),
|
||||||
responsible_company_id=company_related.id,
|
responsible_company_id=company_related.id,
|
||||||
responsible_company_uuid=company_related.uu_id.__str__(),
|
responsible_company_uuid=company_related.uu_id.__str__(),
|
||||||
reachable_event_list_id=reachable_event_list_id
|
reachable_event_list_id=reachable_event_list_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Update Redis
|
# Update Redis
|
||||||
|
|
@ -276,13 +282,11 @@ class AuthenticationSelectEventMethods(MethodToEvent):
|
||||||
elif isinstance(token_dict, OccupantTokenObject):
|
elif isinstance(token_dict, OccupantTokenObject):
|
||||||
return cls._handle_occupant_selection(data, token_dict, request)
|
return cls._handle_occupant_selection(data, token_dict, request)
|
||||||
return ResponseHandler.error(
|
return ResponseHandler.error(
|
||||||
"Invalid token type",
|
"Invalid token type", status_code=status.HTTP_400_BAD_REQUEST
|
||||||
status_code=status.HTTP_400_BAD_REQUEST
|
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return ResponseHandler.error(
|
return ResponseHandler.error(
|
||||||
str(e),
|
str(e), status_code=status.HTTP_500_INTERNAL_SERVER_ERROR
|
||||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -331,9 +335,7 @@ class AuthenticationRefreshEventMethods(MethodToEvent):
|
||||||
return ResponseHandler.unauthorized()
|
return ResponseHandler.unauthorized()
|
||||||
|
|
||||||
# Get user and token info
|
# Get user and token info
|
||||||
found_user = Users.filter_one(
|
found_user = Users.filter_one(Users.uu_id == token_dict.user_uu_id).data
|
||||||
Users.uu_id == token_dict.user_uu_id
|
|
||||||
).data
|
|
||||||
if not found_user:
|
if not found_user:
|
||||||
return ResponseHandler.not_found("User not found")
|
return ResponseHandler.not_found("User not found")
|
||||||
|
|
||||||
|
|
@ -349,12 +351,12 @@ class AuthenticationRefreshEventMethods(MethodToEvent):
|
||||||
response_data = {
|
response_data = {
|
||||||
"access_token": access_token,
|
"access_token": access_token,
|
||||||
"refresh_token": getattr(user_token, "token", None),
|
"refresh_token": getattr(user_token, "token", None),
|
||||||
"user": found_user.get_dict()
|
"user": found_user.get_dict(),
|
||||||
}
|
}
|
||||||
return ResponseHandler.success(
|
return ResponseHandler.success(
|
||||||
"User info refreshed successfully",
|
"User info refreshed successfully",
|
||||||
data=response_data,
|
data=response_data,
|
||||||
response_model=AuthenticationRefreshResponse
|
response_model=AuthenticationRefreshResponse,
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return ResponseHandler.error(str(e))
|
return ResponseHandler.error(str(e))
|
||||||
|
|
@ -381,7 +383,9 @@ class AuthenticationChangePasswordEventMethods(MethodToEvent):
|
||||||
):
|
):
|
||||||
try:
|
try:
|
||||||
if not isinstance(token_dict, EmployeeTokenObject):
|
if not isinstance(token_dict, EmployeeTokenObject):
|
||||||
return ResponseHandler.unauthorized("Only employees can change password")
|
return ResponseHandler.unauthorized(
|
||||||
|
"Only employees can change password"
|
||||||
|
)
|
||||||
|
|
||||||
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
|
||||||
if not found_user:
|
if not found_user:
|
||||||
|
|
@ -389,22 +393,27 @@ class AuthenticationChangePasswordEventMethods(MethodToEvent):
|
||||||
|
|
||||||
if not found_user.check_password(data.old_password):
|
if not found_user.check_password(data.old_password):
|
||||||
user_logger.log_password_change(
|
user_logger.log_password_change(
|
||||||
request, found_user.id, "change",
|
request,
|
||||||
success=False, error="Invalid old password"
|
found_user.id,
|
||||||
|
"change",
|
||||||
|
success=False,
|
||||||
|
error="Invalid old password",
|
||||||
)
|
)
|
||||||
return ResponseHandler.unauthorized("Old password is incorrect")
|
return ResponseHandler.unauthorized("Old password is incorrect")
|
||||||
|
|
||||||
found_user.set_password(data.new_password)
|
found_user.set_password(data.new_password)
|
||||||
user_logger.log_password_change(
|
user_logger.log_password_change(
|
||||||
request, found_user.id, "change",
|
request, found_user.id, "change", success=True
|
||||||
success=True
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return ResponseHandler.success("Password changed successfully")
|
return ResponseHandler.success("Password changed successfully")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
user_logger.log_password_change(
|
user_logger.log_password_change(
|
||||||
request, found_user.id if found_user else None,
|
request,
|
||||||
"change", success=False, error=str(e)
|
found_user.id if found_user else None,
|
||||||
|
"change",
|
||||||
|
success=False,
|
||||||
|
error=str(e),
|
||||||
)
|
)
|
||||||
return ResponseHandler.error(str(e))
|
return ResponseHandler.error(str(e))
|
||||||
|
|
||||||
|
|
@ -471,7 +480,9 @@ class AuthenticationDisconnectUserEventMethods(MethodToEvent):
|
||||||
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
|
||||||
if not found_user:
|
if not found_user:
|
||||||
return ResponseHandler.not_found("User not found")
|
return ResponseHandler.not_found("User not found")
|
||||||
if already_tokens := RedisActions.get_object_via_user_uu_id(user_id=str(found_user.uu_id)):
|
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():
|
for key, token_user in already_tokens.items():
|
||||||
RedisActions.delete_key(key)
|
RedisActions.delete_key(key)
|
||||||
selected_user = Users.filter_one(
|
selected_user = Users.filter_one(
|
||||||
|
|
@ -566,7 +577,7 @@ class AuthenticationRefreshTokenEventMethods(MethodToEvent):
|
||||||
return ResponseHandler.success(
|
return ResponseHandler.success(
|
||||||
"User is logged in successfully via refresher token",
|
"User is logged in successfully via refresher token",
|
||||||
data=response_data,
|
data=response_data,
|
||||||
response_model=AuthenticationRefreshResponse
|
response_model=AuthenticationRefreshResponse,
|
||||||
)
|
)
|
||||||
return ResponseHandler.not_found("Invalid data")
|
return ResponseHandler.not_found("Invalid data")
|
||||||
|
|
||||||
|
|
@ -697,7 +708,7 @@ class AuthenticationDownloadAvatarEventMethods(MethodToEvent):
|
||||||
return ResponseHandler.success(
|
return ResponseHandler.success(
|
||||||
"Avatar and profile is shared via user credentials",
|
"Avatar and profile is shared via user credentials",
|
||||||
data=user_info,
|
data=user_info,
|
||||||
response_model=AuthenticationUserInfoResponse
|
response_model=AuthenticationUserInfoResponse,
|
||||||
)
|
)
|
||||||
return ResponseHandler.not_found("Invalid data")
|
return ResponseHandler.not_found("Invalid data")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ class BuildListEventMethods(MethodToEvent):
|
||||||
result=records,
|
result=records,
|
||||||
cls_object=Build,
|
cls_object=Build,
|
||||||
filter_attributes=list_options,
|
filter_attributes=list_options,
|
||||||
response_model=BuildResponse
|
response_model=BuildResponse,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -213,7 +213,7 @@ class BuildUpdateEventMethods(MethodToEvent):
|
||||||
completed=False,
|
completed=False,
|
||||||
message="Building not found",
|
message="Building not found",
|
||||||
result={},
|
result={},
|
||||||
status_code="HTTP_404_NOT_FOUND"
|
status_code="HTTP_404_NOT_FOUND",
|
||||||
)
|
)
|
||||||
|
|
||||||
build.update(**data.excluded_dump())
|
build.update(**data.excluded_dump())
|
||||||
|
|
@ -256,7 +256,7 @@ class BuildPatchEventMethods(MethodToEvent):
|
||||||
completed=False,
|
completed=False,
|
||||||
message="Building not found",
|
message="Building not found",
|
||||||
result={},
|
result={},
|
||||||
status_code="HTTP_404_NOT_FOUND"
|
status_code="HTTP_404_NOT_FOUND",
|
||||||
)
|
)
|
||||||
|
|
||||||
build.update(**data.excluded_dump())
|
build.update(**data.excluded_dump())
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ class BuildAreaListEventMethods(MethodToEvent):
|
||||||
result=records,
|
result=records,
|
||||||
cls_object=BuildArea,
|
cls_object=BuildArea,
|
||||||
filter_attributes=list_options,
|
filter_attributes=list_options,
|
||||||
response_model=BuildResponse
|
response_model=BuildResponse,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -112,9 +112,7 @@ class BuildAreaCreateEventMethods(MethodToEvent):
|
||||||
data_dict["build_uu_id"] = str(selected_build.uu_id)
|
data_dict["build_uu_id"] = str(selected_build.uu_id)
|
||||||
area = BuildArea.insert_one(data_dict).data
|
area = BuildArea.insert_one(data_dict).data
|
||||||
return AlchemyJsonResponse(
|
return AlchemyJsonResponse(
|
||||||
completed=True,
|
completed=True, message="Building area created successfully", result=area
|
||||||
message="Building area created successfully",
|
|
||||||
result=area
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -137,9 +135,7 @@ class BuildAreaUpdateEventMethods(MethodToEvent):
|
||||||
):
|
):
|
||||||
area = BuildArea.update_one(build_uu_id, data).data
|
area = BuildArea.update_one(build_uu_id, data).data
|
||||||
return AlchemyJsonResponse(
|
return AlchemyJsonResponse(
|
||||||
completed=True,
|
completed=True, message="Building area updated successfully", result=area
|
||||||
message="Building area updated successfully",
|
|
||||||
result=area
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -162,9 +158,7 @@ class BuildAreaPatchEventMethods(MethodToEvent):
|
||||||
):
|
):
|
||||||
area = BuildArea.patch_one(build_uu_id, data).data
|
area = BuildArea.patch_one(build_uu_id, data).data
|
||||||
return AlchemyJsonResponse(
|
return AlchemyJsonResponse(
|
||||||
completed=True,
|
completed=True, message="Building area patched successfully", result=area
|
||||||
message="Building area patched successfully",
|
|
||||||
result=area
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ from databases import (
|
||||||
BuildParts,
|
BuildParts,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class BuildingBuildPartsListEventMethods(MethodToEvent):
|
class BuildingBuildPartsListEventMethods(MethodToEvent):
|
||||||
|
|
||||||
event_type = "SELECT"
|
event_type = "SELECT"
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ class BuildSitesListEventMethods(MethodToEvent):
|
||||||
result=records,
|
result=records,
|
||||||
cls_object=BuildSites,
|
cls_object=BuildSites,
|
||||||
filter_attributes=list_options,
|
filter_attributes=list_options,
|
||||||
response_model=BuildSitesResponse
|
response_model=BuildSitesResponse,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -110,9 +110,7 @@ class BuildSitesCreateEventMethods(MethodToEvent):
|
||||||
data_dict = data.excluded_dump()
|
data_dict = data.excluded_dump()
|
||||||
site = BuildSites.insert_one(data_dict).data
|
site = BuildSites.insert_one(data_dict).data
|
||||||
return AlchemyJsonResponse(
|
return AlchemyJsonResponse(
|
||||||
completed=True,
|
completed=True, message="Building site created successfully", result=site
|
||||||
message="Building site created successfully",
|
|
||||||
result=site
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -135,9 +133,7 @@ class BuildSitesUpdateEventMethods(MethodToEvent):
|
||||||
):
|
):
|
||||||
site = BuildSites.update_one(build_uu_id, data).data
|
site = BuildSites.update_one(build_uu_id, data).data
|
||||||
return AlchemyJsonResponse(
|
return AlchemyJsonResponse(
|
||||||
completed=True,
|
completed=True, message="Building site updated successfully", result=site
|
||||||
message="Building site updated successfully",
|
|
||||||
result=site
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -160,9 +156,7 @@ class BuildSitesPatchEventMethods(MethodToEvent):
|
||||||
):
|
):
|
||||||
site = BuildSites.patch_one(build_uu_id, data).data
|
site = BuildSites.patch_one(build_uu_id, data).data
|
||||||
return AlchemyJsonResponse(
|
return AlchemyJsonResponse(
|
||||||
completed=True,
|
completed=True, message="Building site patched successfully", result=site
|
||||||
message="Building site patched successfully",
|
|
||||||
result=site
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,7 @@ class BuildTypesListEventMethods(MethodToEvent):
|
||||||
__event_keys__ = {
|
__event_keys__ = {
|
||||||
"5344d03c-fc47-43ec-8c44-6c2acd7e5d9f": "build_types_list",
|
"5344d03c-fc47-43ec-8c44-6c2acd7e5d9f": "build_types_list",
|
||||||
}
|
}
|
||||||
__event_validation__ = {
|
__event_validation__ = {"5344d03c-fc47-43ec-8c44-6c2acd7e5d9f": BuildTypesResponse}
|
||||||
"5344d03c-fc47-43ec-8c44-6c2acd7e5d9f": BuildTypesResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def build_types_list(
|
def build_types_list(
|
||||||
|
|
@ -37,7 +35,7 @@ class BuildTypesListEventMethods(MethodToEvent):
|
||||||
result=results,
|
result=results,
|
||||||
cls_object=BuildTypes,
|
cls_object=BuildTypes,
|
||||||
filter_attributes=list_options,
|
filter_attributes=list_options,
|
||||||
response_model=BuildTypesListResponse
|
response_model=BuildTypesListResponse,
|
||||||
)
|
)
|
||||||
elif isinstance(token_dict, OccupantTokenObject):
|
elif isinstance(token_dict, OccupantTokenObject):
|
||||||
return AlchemyJsonResponse(
|
return AlchemyJsonResponse(
|
||||||
|
|
@ -46,7 +44,7 @@ class BuildTypesListEventMethods(MethodToEvent):
|
||||||
result=None,
|
result=None,
|
||||||
cls_object=BuildTypes,
|
cls_object=BuildTypes,
|
||||||
filter_attributes=list_options,
|
filter_attributes=list_options,
|
||||||
response_model=BuildTypesResponse
|
response_model=BuildTypesResponse,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ class BuildingLivingSpacesListEventMethods(MethodToEvent):
|
||||||
return AlchemyJsonResponse(
|
return AlchemyJsonResponse(
|
||||||
completed=True,
|
completed=True,
|
||||||
message="Living spaces listed successfully",
|
message="Living spaces listed successfully",
|
||||||
result=records
|
result=records,
|
||||||
)
|
)
|
||||||
elif isinstance(token_dict, EmployeeTokenObject):
|
elif isinstance(token_dict, EmployeeTokenObject):
|
||||||
build_id_list_query = Build.select_action(
|
build_id_list_query = Build.select_action(
|
||||||
|
|
@ -217,7 +217,7 @@ class BuildingLivingSpacesCreateEventMethods(MethodToEvent):
|
||||||
return AlchemyJsonResponse(
|
return AlchemyJsonResponse(
|
||||||
completed=True,
|
completed=True,
|
||||||
message="Living space created successfully",
|
message="Living space created successfully",
|
||||||
result=created_living_space
|
result=created_living_space,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -307,7 +307,7 @@ class BuildingLivingSpacesUpdateEventMethods(MethodToEvent):
|
||||||
return AlchemyJsonResponse(
|
return AlchemyJsonResponse(
|
||||||
completed=True,
|
completed=True,
|
||||||
message="Living space updated successfully",
|
message="Living space updated successfully",
|
||||||
result=living_space
|
result=living_space,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,7 @@ class CompanyUpdateEventMethods(MethodToEvent):
|
||||||
completed=False,
|
completed=False,
|
||||||
message="Company not found",
|
message="Company not found",
|
||||||
result={},
|
result={},
|
||||||
status_code="HTTP_404_NOT_FOUND"
|
status_code="HTTP_404_NOT_FOUND",
|
||||||
)
|
)
|
||||||
company.save()
|
company.save()
|
||||||
return AlchemyJsonResponse(
|
return AlchemyJsonResponse(
|
||||||
|
|
@ -142,7 +142,7 @@ class CompanyPatchEventMethods(MethodToEvent):
|
||||||
completed=False,
|
completed=False,
|
||||||
message="Company not found",
|
message="Company not found",
|
||||||
result={},
|
result={},
|
||||||
status_code="HTTP_404_NOT_FOUND"
|
status_code="HTTP_404_NOT_FOUND",
|
||||||
)
|
)
|
||||||
company.save()
|
company.save()
|
||||||
return AlchemyJsonResponse(
|
return AlchemyJsonResponse(
|
||||||
|
|
|
||||||
|
|
@ -4,17 +4,16 @@ from fastapi import status
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
|
|
||||||
from api_validations.validations_response import PeopleListResponse
|
from api_validations.validations_response import PeopleListResponse
|
||||||
|
from api_validations.validations_request import InsertPerson, UpdateUsers
|
||||||
|
from api_events.events.abstract_class import MethodToEvent, ActionsSchema
|
||||||
|
from api_objects.auth.token_objects import EmployeeTokenObject, OccupantTokenObject
|
||||||
|
from ApiServices.api_handlers import AlchemyJsonResponse
|
||||||
from databases import (
|
from databases import (
|
||||||
People,
|
People,
|
||||||
Users,
|
Users,
|
||||||
Companies,
|
Companies,
|
||||||
)
|
)
|
||||||
|
|
||||||
from api_validations.validations_request import InsertPerson, UpdateUsers
|
|
||||||
from api_events.events.abstract_class import MethodToEvent, ActionsSchema
|
|
||||||
from api_objects.auth.token_objects import EmployeeTokenObject, OccupantTokenObject
|
|
||||||
from ApiServices.api_handlers import AlchemyJsonResponse
|
|
||||||
|
|
||||||
|
|
||||||
class PeopleListEventMethods(MethodToEvent):
|
class PeopleListEventMethods(MethodToEvent):
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,9 @@ class DateTimeLocal:
|
||||||
|
|
||||||
def __init__(self, timezone: str = None, is_client: bool = True):
|
def __init__(self, timezone: str = None, is_client: bool = True):
|
||||||
if timezone and timezone not in Config.SUPPORTED_TIMEZONES:
|
if timezone and timezone not in Config.SUPPORTED_TIMEZONES:
|
||||||
raise ValueError(f"Unsupported timezone: {timezone}. Must be one of {Config.SUPPORTED_TIMEZONES}")
|
raise ValueError(
|
||||||
|
f"Unsupported timezone: {timezone}. Must be one of {Config.SUPPORTED_TIMEZONES}"
|
||||||
|
)
|
||||||
|
|
||||||
self.timezone = Config.SYSTEM_TIMEZONE
|
self.timezone = Config.SYSTEM_TIMEZONE
|
||||||
if is_client:
|
if is_client:
|
||||||
|
|
@ -84,11 +86,11 @@ class DateTimeLocal:
|
||||||
components = [str(base_key)]
|
components = [str(base_key)]
|
||||||
components.extend(str(arg) for arg in args)
|
components.extend(str(arg) for arg in args)
|
||||||
components.append(f"tz_{self.timezone}")
|
components.append(f"tz_{self.timezone}")
|
||||||
return ':'.join(components)
|
return ":".join(components)
|
||||||
|
|
||||||
def format_for_db(self, date):
|
def format_for_db(self, date):
|
||||||
"""Format date for database storage"""
|
"""Format date for database storage"""
|
||||||
return self.get(date).format('YYYY-MM-DD HH:mm:ss.SSSZZ')
|
return self.get(date).format("YYYY-MM-DD HH:mm:ss.SSSZZ")
|
||||||
|
|
||||||
def parse_from_db(self, date_str):
|
def parse_from_db(self, date_str):
|
||||||
"""Parse date from database format"""
|
"""Parse date from database format"""
|
||||||
|
|
@ -99,16 +101,17 @@ class DateTimeLocal:
|
||||||
def get_day_boundaries(self, date=None):
|
def get_day_boundaries(self, date=None):
|
||||||
"""Get start and end of day in current timezone"""
|
"""Get start and end of day in current timezone"""
|
||||||
dt = self.get(date) if date else self.now()
|
dt = self.get(date) if date else self.now()
|
||||||
start = dt.floor('day')
|
start = dt.floor("day")
|
||||||
end = dt.ceil('day')
|
end = dt.ceil("day")
|
||||||
return start, end
|
return start, end
|
||||||
|
|
||||||
def get_month_boundaries(self, date=None):
|
def get_month_boundaries(self, date=None):
|
||||||
"""Get start and end of month in current timezone"""
|
"""Get start and end of month in current timezone"""
|
||||||
dt = self.get(date) if date else self.now()
|
dt = self.get(date) if date else self.now()
|
||||||
start = dt.floor('month')
|
start = dt.floor("month")
|
||||||
end = dt.ceil('month')
|
end = dt.ceil("month")
|
||||||
return start, end
|
return start, end
|
||||||
|
|
||||||
|
|
||||||
client_arrow = DateTimeLocal(is_client=True)
|
client_arrow = DateTimeLocal(is_client=True)
|
||||||
system_arrow = DateTimeLocal(is_client=False)
|
system_arrow = DateTimeLocal(is_client=False)
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ from typing import Optional, Dict, Any
|
||||||
from fastapi.requests import Request
|
from fastapi.requests import Request
|
||||||
from api_library.date_time_actions.date_functions import system_arrow
|
from api_library.date_time_actions.date_functions import system_arrow
|
||||||
|
|
||||||
|
|
||||||
class UserActivityLogger:
|
class UserActivityLogger:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.logger = logging.getLogger("user_activity")
|
self.logger = logging.getLogger("user_activity")
|
||||||
|
|
@ -15,7 +16,7 @@ class UserActivityLogger:
|
||||||
os.makedirs(os.path.dirname(log_path), exist_ok=True)
|
os.makedirs(os.path.dirname(log_path), exist_ok=True)
|
||||||
handler = logging.FileHandler(log_path)
|
handler = logging.FileHandler(log_path)
|
||||||
formatter = logging.Formatter(
|
formatter = logging.Formatter(
|
||||||
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
||||||
)
|
)
|
||||||
handler.setFormatter(formatter)
|
handler.setFormatter(formatter)
|
||||||
self.logger.addHandler(handler)
|
self.logger.addHandler(handler)
|
||||||
|
|
@ -24,9 +25,10 @@ class UserActivityLogger:
|
||||||
"""Extract common metadata from request"""
|
"""Extract common metadata from request"""
|
||||||
return {
|
return {
|
||||||
"agent": request.headers.get("User-Agent"),
|
"agent": request.headers.get("User-Agent"),
|
||||||
"ip": getattr(request, "remote_addr", None) or request.headers.get("X-Forwarded-For"),
|
"ip": getattr(request, "remote_addr", None)
|
||||||
|
or request.headers.get("X-Forwarded-For"),
|
||||||
"platform": request.headers.get("Origin"),
|
"platform": request.headers.get("Origin"),
|
||||||
"timestamp": str(system_arrow.now())
|
"timestamp": str(system_arrow.now()),
|
||||||
}
|
}
|
||||||
|
|
||||||
def log_login_attempt(
|
def log_login_attempt(
|
||||||
|
|
@ -36,7 +38,7 @@ class UserActivityLogger:
|
||||||
domain: str,
|
domain: str,
|
||||||
access_key: str,
|
access_key: str,
|
||||||
success: bool,
|
success: bool,
|
||||||
error: Optional[str] = None
|
error: Optional[str] = None,
|
||||||
):
|
):
|
||||||
"""Log login attempts"""
|
"""Log login attempts"""
|
||||||
metadata = self._get_request_metadata(request)
|
metadata = self._get_request_metadata(request)
|
||||||
|
|
@ -47,7 +49,7 @@ class UserActivityLogger:
|
||||||
"access_key": access_key,
|
"access_key": access_key,
|
||||||
"success": success,
|
"success": success,
|
||||||
"error": error,
|
"error": error,
|
||||||
**metadata
|
**metadata,
|
||||||
}
|
}
|
||||||
|
|
||||||
if success:
|
if success:
|
||||||
|
|
@ -61,7 +63,7 @@ class UserActivityLogger:
|
||||||
user_id: int,
|
user_id: int,
|
||||||
change_type: str,
|
change_type: str,
|
||||||
success: bool,
|
success: bool,
|
||||||
error: Optional[str] = None
|
error: Optional[str] = None,
|
||||||
):
|
):
|
||||||
"""Log password changes"""
|
"""Log password changes"""
|
||||||
metadata = self._get_request_metadata(request)
|
metadata = self._get_request_metadata(request)
|
||||||
|
|
@ -71,7 +73,7 @@ class UserActivityLogger:
|
||||||
"change_type": change_type,
|
"change_type": change_type,
|
||||||
"success": success,
|
"success": success,
|
||||||
"error": error,
|
"error": error,
|
||||||
**metadata
|
**metadata,
|
||||||
}
|
}
|
||||||
|
|
||||||
if success:
|
if success:
|
||||||
|
|
@ -86,7 +88,7 @@ class UserActivityLogger:
|
||||||
activity_type: str,
|
activity_type: str,
|
||||||
domain: Optional[str] = None,
|
domain: Optional[str] = None,
|
||||||
success: bool = True,
|
success: bool = True,
|
||||||
error: Optional[str] = None
|
error: Optional[str] = None,
|
||||||
):
|
):
|
||||||
"""Log session activities (logout, disconnect, etc)"""
|
"""Log session activities (logout, disconnect, etc)"""
|
||||||
metadata = self._get_request_metadata(request)
|
metadata = self._get_request_metadata(request)
|
||||||
|
|
@ -97,7 +99,7 @@ class UserActivityLogger:
|
||||||
"domain": domain,
|
"domain": domain,
|
||||||
"success": success,
|
"success": success,
|
||||||
"error": error,
|
"error": error,
|
||||||
**metadata
|
**metadata,
|
||||||
}
|
}
|
||||||
|
|
||||||
if success:
|
if success:
|
||||||
|
|
@ -105,5 +107,6 @@ class UserActivityLogger:
|
||||||
else:
|
else:
|
||||||
self.logger.warning(f"{activity_type} failed", extra=log_data)
|
self.logger.warning(f"{activity_type} failed", extra=log_data)
|
||||||
|
|
||||||
|
|
||||||
# Global logger instance
|
# Global logger instance
|
||||||
user_logger = UserActivityLogger()
|
user_logger = UserActivityLogger()
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,12 @@ from typing import Any, Optional
|
||||||
from fastapi import status
|
from fastapi import status
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
|
|
||||||
|
|
||||||
class ResponseHandler:
|
class ResponseHandler:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def success(message: str, data: Optional[Any] = None, status_code: int = status.HTTP_200_OK) -> JSONResponse:
|
def success(
|
||||||
|
message: str, data: Optional[Any] = None, status_code: int = status.HTTP_200_OK
|
||||||
|
) -> JSONResponse:
|
||||||
"""Create a success response"""
|
"""Create a success response"""
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
content={
|
content={
|
||||||
|
|
@ -16,7 +19,11 @@ class ResponseHandler:
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def error(message: str, data: Optional[Any] = None, status_code: int = status.HTTP_400_BAD_REQUEST) -> JSONResponse:
|
def error(
|
||||||
|
message: str,
|
||||||
|
data: Optional[Any] = None,
|
||||||
|
status_code: int = status.HTTP_400_BAD_REQUEST,
|
||||||
|
) -> JSONResponse:
|
||||||
"""Create an error response"""
|
"""Create an error response"""
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
content={
|
content={
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,9 @@ class RedisActions:
|
||||||
already_tokens = redis_cli.scan_iter(match=str(value_regex))
|
already_tokens = redis_cli.scan_iter(match=str(value_regex))
|
||||||
already_tokens_list = {}
|
already_tokens_list = {}
|
||||||
for already_token in already_tokens:
|
for already_token in already_tokens:
|
||||||
already_tokens_list[already_token.decode()] = json.loads(redis_cli.get(already_token))
|
already_tokens_list[already_token.decode()] = json.loads(
|
||||||
|
redis_cli.get(already_token)
|
||||||
|
)
|
||||||
return RedisResponse(
|
return RedisResponse(
|
||||||
status=True,
|
status=True,
|
||||||
message="Values are listed successfully.",
|
message="Values are listed successfully.",
|
||||||
|
|
@ -187,21 +189,22 @@ class RedisActions:
|
||||||
try:
|
try:
|
||||||
search_name = str(name) if isinstance(name, str) else name.decode()
|
search_name = str(name) if isinstance(name, str) else name.decode()
|
||||||
expiry_time = system_arrow.get_expiry_time(**expiry_kwargs)
|
expiry_time = system_arrow.get_expiry_time(**expiry_kwargs)
|
||||||
seconds_until_expiry = int(expiry_time.timestamp() - system_arrow.now().timestamp())
|
seconds_until_expiry = int(
|
||||||
|
expiry_time.timestamp() - system_arrow.now().timestamp()
|
||||||
|
)
|
||||||
|
|
||||||
redis_cli.setex(
|
redis_cli.setex(
|
||||||
name=search_name,
|
name=search_name,
|
||||||
time=seconds_until_expiry,
|
time=seconds_until_expiry,
|
||||||
value=json.dumps({
|
value=json.dumps(
|
||||||
'value': value,
|
{"value": value, "expires_at": expiry_time.timestamp()}
|
||||||
'expires_at': expiry_time.timestamp()
|
),
|
||||||
})
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return RedisResponse(
|
return RedisResponse(
|
||||||
status=True,
|
status=True,
|
||||||
message="Value is set successfully with expiry.",
|
message="Value is set successfully with expiry.",
|
||||||
data={'value': value, 'expires_at': expiry_time.timestamp()},
|
data={"value": value, "expires_at": expiry_time.timestamp()},
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return RedisResponse(
|
return RedisResponse(
|
||||||
|
|
@ -224,7 +227,7 @@ class RedisActions:
|
||||||
)
|
)
|
||||||
|
|
||||||
data = json.loads(result)
|
data = json.loads(result)
|
||||||
if system_arrow.is_expired(data.get('expires_at')):
|
if system_arrow.is_expired(data.get("expires_at")):
|
||||||
redis_cli.delete(search_name)
|
redis_cli.delete(search_name)
|
||||||
return RedisResponse(
|
return RedisResponse(
|
||||||
status=False,
|
status=False,
|
||||||
|
|
@ -234,7 +237,7 @@ class RedisActions:
|
||||||
return RedisResponse(
|
return RedisResponse(
|
||||||
status=True,
|
status=True,
|
||||||
message="Value retrieved successfully.",
|
message="Value retrieved successfully.",
|
||||||
data=data['value'],
|
data=data["value"],
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return RedisResponse(
|
return RedisResponse(
|
||||||
|
|
@ -272,23 +275,21 @@ class RedisActions:
|
||||||
try:
|
try:
|
||||||
key = f"{access_token}:{model_object.user_uu_id}"
|
key = f"{access_token}:{model_object.user_uu_id}"
|
||||||
expiry_time = system_arrow.get_expiry_time(minutes=expiry_minutes)
|
expiry_time = system_arrow.get_expiry_time(minutes=expiry_minutes)
|
||||||
seconds_until_expiry = max(1, int(expiry_time.timestamp() - system_arrow.now().timestamp()))
|
seconds_until_expiry = max(
|
||||||
|
1, int(expiry_time.timestamp() - system_arrow.now().timestamp())
|
||||||
|
)
|
||||||
|
|
||||||
# Add expiry time to the model data
|
# Add expiry time to the model data
|
||||||
model_data = json.loads(model_object.model_dump_json())
|
model_data = json.loads(model_object.model_dump_json())
|
||||||
model_data['expires_at'] = expiry_time.timestamp()
|
model_data["expires_at"] = expiry_time.timestamp()
|
||||||
|
|
||||||
if redis_cli.setex(
|
if redis_cli.setex(
|
||||||
name=key,
|
name=key, time=seconds_until_expiry, value=json.dumps(model_data)
|
||||||
time=seconds_until_expiry,
|
|
||||||
value=json.dumps(model_data)
|
|
||||||
):
|
):
|
||||||
return access_token
|
return access_token
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise Exception(
|
raise Exception(f"Failed to save object to Redis. Error: {str(e)}")
|
||||||
f"Failed to save object to Redis. Error: {str(e)}"
|
|
||||||
)
|
|
||||||
|
|
||||||
raise Exception("Failed to save token to Redis")
|
raise Exception("Failed to save token to Redis")
|
||||||
|
|
||||||
|
|
@ -328,7 +329,7 @@ class RedisActions:
|
||||||
raise Exception("Token expired. Please login again")
|
raise Exception("Token expired. Please login again")
|
||||||
|
|
||||||
# Get the token data
|
# Get the token data
|
||||||
token_data = json.loads(redis_cli.get(token_key) or '{}')
|
token_data = json.loads(redis_cli.get(token_key) or "{}")
|
||||||
|
|
||||||
# Return appropriate token object based on user type
|
# Return appropriate token object based on user type
|
||||||
if token_data.get("user_type") == 1: # Employee
|
if token_data.get("user_type") == 1: # Employee
|
||||||
|
|
@ -359,10 +360,10 @@ class RedisActions:
|
||||||
|
|
||||||
tokens_dict = {}
|
tokens_dict = {}
|
||||||
for token_key in matching_tokens:
|
for token_key in matching_tokens:
|
||||||
token_data = json.loads(redis_cli.get(token_key) or '{}')
|
token_data = json.loads(redis_cli.get(token_key) or "{}")
|
||||||
|
|
||||||
# Skip expired tokens and clean them up
|
# Skip expired tokens and clean them up
|
||||||
if system_arrow.is_expired(token_data.get('expires_at')):
|
if system_arrow.is_expired(token_data.get("expires_at")):
|
||||||
redis_cli.delete(token_key)
|
redis_cli.delete(token_key)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
@ -373,7 +374,11 @@ class RedisActions:
|
||||||
|
|
||||||
class RedisResponse:
|
class RedisResponse:
|
||||||
def __init__(
|
def __init__(
|
||||||
self, status: bool, message: str, data: typing.Union[dict | list] = None, error: str = None
|
self,
|
||||||
|
status: bool,
|
||||||
|
message: str,
|
||||||
|
data: typing.Union[dict | list] = None,
|
||||||
|
error: str = None,
|
||||||
):
|
):
|
||||||
self.status = status
|
self.status = status
|
||||||
self.message = message
|
self.message = message
|
||||||
|
|
|
||||||
|
|
@ -8,16 +8,18 @@ from api_configs import Auth
|
||||||
from databases import Users, UsersTokens
|
from databases import Users, UsersTokens
|
||||||
from api_library.date_time_actions.date_functions import system_arrow
|
from api_library.date_time_actions.date_functions import system_arrow
|
||||||
|
|
||||||
|
|
||||||
class TokenService:
|
class TokenService:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def validate_token(request: Request) -> Union[OccupantTokenObject, EmployeeTokenObject]:
|
def validate_token(
|
||||||
|
request: Request,
|
||||||
|
) -> Union[OccupantTokenObject, EmployeeTokenObject]:
|
||||||
"""Validate and return token object from request"""
|
"""Validate and return token object from request"""
|
||||||
try:
|
try:
|
||||||
return RedisActions.get_object_via_access_key(request)
|
return RedisActions.get_object_via_access_key(request)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
status_code=status.HTTP_401_UNAUTHORIZED, detail={"message": str(e)}
|
||||||
detail={"message": str(e)}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
@ -26,12 +28,12 @@ class TokenService:
|
||||||
return RedisActions.get_object_via_user_uu_id(user_id)
|
return RedisActions.get_object_via_user_uu_id(user_id)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def validate_refresh_token(domain: str, refresh_token: str) -> Optional[UsersTokens]:
|
def validate_refresh_token(
|
||||||
|
domain: str, refresh_token: str
|
||||||
|
) -> Optional[UsersTokens]:
|
||||||
"""Validate refresh token and return token object"""
|
"""Validate refresh token and return token object"""
|
||||||
return UsersTokens.filter_by_one(
|
return UsersTokens.filter_by_one(
|
||||||
token=refresh_token,
|
token=refresh_token, domain=domain, **UsersTokens.valid_record_dict
|
||||||
domain=domain,
|
|
||||||
**UsersTokens.valid_record_dict
|
|
||||||
).data
|
).data
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
@ -39,10 +41,9 @@ class TokenService:
|
||||||
"""Update user metadata from request"""
|
"""Update user metadata from request"""
|
||||||
user.last_agent = request.headers.get("User-Agent")
|
user.last_agent = request.headers.get("User-Agent")
|
||||||
user.last_platform = request.headers.get("Origin")
|
user.last_platform = request.headers.get("Origin")
|
||||||
user.last_remote_addr = (
|
user.last_remote_addr = getattr(
|
||||||
getattr(request, "remote_addr", None) or
|
request, "remote_addr", None
|
||||||
request.headers.get("X-Forwarded-For")
|
) or request.headers.get("X-Forwarded-For")
|
||||||
)
|
|
||||||
user.last_seen = str(system_arrow.now())
|
user.last_seen = str(system_arrow.now())
|
||||||
user.save()
|
user.save()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,19 +19,19 @@ from .building_responses import (
|
||||||
BuildCompaniesProvidingResponse,
|
BuildCompaniesProvidingResponse,
|
||||||
BuildCompaniesProvidingCollection,
|
BuildCompaniesProvidingCollection,
|
||||||
BuildManagementResponse,
|
BuildManagementResponse,
|
||||||
BuildManagementCollection
|
BuildManagementCollection,
|
||||||
)
|
)
|
||||||
from .account_responses import (
|
from .account_responses import (
|
||||||
AccountRecordResponse,
|
AccountRecordResponse,
|
||||||
AccountRecordCollection,
|
AccountRecordCollection,
|
||||||
AccountRecordExchangeResponse,
|
AccountRecordExchangeResponse,
|
||||||
AccountRecordExchangeCollection
|
AccountRecordExchangeCollection,
|
||||||
)
|
)
|
||||||
from .address_responses import ListAddressResponse, AddressPostCodeResponse
|
from .address_responses import ListAddressResponse, AddressPostCodeResponse
|
||||||
from .auth_responses import (
|
from .auth_responses import (
|
||||||
AuthenticationLoginResponse,
|
AuthenticationLoginResponse,
|
||||||
AuthenticationRefreshResponse,
|
AuthenticationRefreshResponse,
|
||||||
AuthenticationUserInfoResponse
|
AuthenticationUserInfoResponse,
|
||||||
)
|
)
|
||||||
from .base_responses import BaseResponse, CrudCollection
|
from .base_responses import BaseResponse, CrudCollection
|
||||||
from .budget_responses import (
|
from .budget_responses import (
|
||||||
|
|
@ -42,13 +42,13 @@ from .budget_responses import (
|
||||||
DecisionBookBudgetMasterResponse,
|
DecisionBookBudgetMasterResponse,
|
||||||
DecisionBookBudgetMasterCollection,
|
DecisionBookBudgetMasterCollection,
|
||||||
DecisionBookBudgetsResponse,
|
DecisionBookBudgetsResponse,
|
||||||
DecisionBookBudgetsCollection
|
DecisionBookBudgetsCollection,
|
||||||
)
|
)
|
||||||
from .company_responses import (
|
from .company_responses import (
|
||||||
CompanyListResponse,
|
CompanyListResponse,
|
||||||
CompanyDepartmentListResponse,
|
CompanyDepartmentListResponse,
|
||||||
CompanyDutyListResponse,
|
CompanyDutyListResponse,
|
||||||
CompanyEmployeeListResponse
|
CompanyEmployeeListResponse,
|
||||||
)
|
)
|
||||||
from .decision_book_responses import (
|
from .decision_book_responses import (
|
||||||
BuildDecisionBookResponse,
|
BuildDecisionBookResponse,
|
||||||
|
|
@ -66,7 +66,7 @@ from .decision_book_responses import (
|
||||||
BuildDecisionBookPaymentsResponse,
|
BuildDecisionBookPaymentsResponse,
|
||||||
BuildDecisionBookPaymentsCollection,
|
BuildDecisionBookPaymentsCollection,
|
||||||
BuildDecisionBookLegalResponse,
|
BuildDecisionBookLegalResponse,
|
||||||
BuildDecisionBookLegalCollection
|
BuildDecisionBookLegalCollection,
|
||||||
)
|
)
|
||||||
from .living_space_responses import LivingSpaceListResponse
|
from .living_space_responses import LivingSpaceListResponse
|
||||||
from .parts_responses import BuildPartsListResponse
|
from .parts_responses import BuildPartsListResponse
|
||||||
|
|
@ -115,5 +115,5 @@ __all__ = [
|
||||||
"BuildDecisionBookLegalCollection",
|
"BuildDecisionBookLegalCollection",
|
||||||
"LivingSpaceListResponse",
|
"LivingSpaceListResponse",
|
||||||
"BuildPartsListResponse",
|
"BuildPartsListResponse",
|
||||||
"PeopleListResponse"
|
"PeopleListResponse",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ from .base_responses import BaseResponse, CrudCollection
|
||||||
|
|
||||||
class AccountBooksResponse(BaseResponse):
|
class AccountBooksResponse(BaseResponse):
|
||||||
"""Response model for account books"""
|
"""Response model for account books"""
|
||||||
|
|
||||||
country: str
|
country: str
|
||||||
branch_type: int
|
branch_type: int
|
||||||
company_id: int
|
company_id: int
|
||||||
|
|
@ -18,11 +19,13 @@ class AccountBooksResponse(BaseResponse):
|
||||||
|
|
||||||
class AccountBooksCollection(CrudCollection[AccountBooksResponse]):
|
class AccountBooksCollection(CrudCollection[AccountBooksResponse]):
|
||||||
"""Collection of account books"""
|
"""Collection of account books"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class AccountCodesResponse(BaseResponse):
|
class AccountCodesResponse(BaseResponse):
|
||||||
"""Response model for account codes"""
|
"""Response model for account codes"""
|
||||||
|
|
||||||
account_code: str
|
account_code: str
|
||||||
comment_line: str
|
comment_line: str
|
||||||
is_receive_or_debit: bool
|
is_receive_or_debit: bool
|
||||||
|
|
@ -42,11 +45,13 @@ class AccountCodesResponse(BaseResponse):
|
||||||
|
|
||||||
class AccountCodesCollection(CrudCollection[AccountCodesResponse]):
|
class AccountCodesCollection(CrudCollection[AccountCodesResponse]):
|
||||||
"""Collection of account codes"""
|
"""Collection of account codes"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class AccountCodeParserResponse(BaseResponse):
|
class AccountCodeParserResponse(BaseResponse):
|
||||||
"""Response model for account code parser"""
|
"""Response model for account code parser"""
|
||||||
|
|
||||||
account_code_1: str
|
account_code_1: str
|
||||||
account_code_2: str
|
account_code_2: str
|
||||||
account_code_3: str
|
account_code_3: str
|
||||||
|
|
@ -59,11 +64,13 @@ class AccountCodeParserResponse(BaseResponse):
|
||||||
|
|
||||||
class AccountCodeParserCollection(CrudCollection[AccountCodeParserResponse]):
|
class AccountCodeParserCollection(CrudCollection[AccountCodeParserResponse]):
|
||||||
"""Collection of account code parsers"""
|
"""Collection of account code parsers"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class AccountMasterResponse(BaseResponse):
|
class AccountMasterResponse(BaseResponse):
|
||||||
"""Response model for account master"""
|
"""Response model for account master"""
|
||||||
|
|
||||||
doc_date: datetime
|
doc_date: datetime
|
||||||
plug_type: str
|
plug_type: str
|
||||||
plug_number: int
|
plug_number: int
|
||||||
|
|
@ -106,11 +113,13 @@ class AccountMasterResponse(BaseResponse):
|
||||||
|
|
||||||
class AccountMasterCollection(CrudCollection[AccountMasterResponse]):
|
class AccountMasterCollection(CrudCollection[AccountMasterResponse]):
|
||||||
"""Collection of account masters"""
|
"""Collection of account masters"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class AccountDetailResponse(BaseResponse):
|
class AccountDetailResponse(BaseResponse):
|
||||||
"""Response model for account detail"""
|
"""Response model for account detail"""
|
||||||
|
|
||||||
doc_date: datetime
|
doc_date: datetime
|
||||||
line_no: int
|
line_no: int
|
||||||
receive_debit: str
|
receive_debit: str
|
||||||
|
|
@ -160,6 +169,7 @@ class AccountDetailResponse(BaseResponse):
|
||||||
|
|
||||||
class AccountDetailCollection(CrudCollection[AccountDetailResponse]):
|
class AccountDetailCollection(CrudCollection[AccountDetailResponse]):
|
||||||
"""Collection of account details"""
|
"""Collection of account details"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -206,6 +216,7 @@ class AccountRecordResponse(BaseResponse):
|
||||||
build_parts_uu_id (Optional[str]): Related building part ID
|
build_parts_uu_id (Optional[str]): Related building part ID
|
||||||
build_decision_book_uu_id (Optional[str]): Related decision book ID
|
build_decision_book_uu_id (Optional[str]): Related decision book ID
|
||||||
"""
|
"""
|
||||||
|
|
||||||
iban: str
|
iban: str
|
||||||
bank_date: datetime
|
bank_date: datetime
|
||||||
currency_value: Decimal
|
currency_value: Decimal
|
||||||
|
|
@ -249,6 +260,7 @@ class AccountRecordCollection(CrudCollection[AccountRecordResponse]):
|
||||||
This model represents a paginated list of account records with
|
This model represents a paginated list of account records with
|
||||||
sorting and pagination information.
|
sorting and pagination information.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -266,6 +278,7 @@ class AccountRecordExchangeResponse(BaseResponse):
|
||||||
exchange_value (Decimal): Converted amount
|
exchange_value (Decimal): Converted amount
|
||||||
exchange_date (datetime): When the exchange was calculated
|
exchange_date (datetime): When the exchange was calculated
|
||||||
"""
|
"""
|
||||||
|
|
||||||
account_record_id: int
|
account_record_id: int
|
||||||
account_record_uu_id: str
|
account_record_uu_id: str
|
||||||
exchange_rate: Decimal
|
exchange_rate: Decimal
|
||||||
|
|
@ -280,11 +293,13 @@ class AccountRecordExchangeCollection(CrudCollection[AccountRecordExchangeRespon
|
||||||
This model represents a paginated list of currency exchange records
|
This model represents a paginated list of currency exchange records
|
||||||
with sorting and pagination information.
|
with sorting and pagination information.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class AccountRecordsListResponse(BaseModel):
|
class AccountRecordsListResponse(BaseModel):
|
||||||
"""Response model for account records list endpoint"""
|
"""Response model for account records list endpoint"""
|
||||||
|
|
||||||
uu_id: UUID
|
uu_id: UUID
|
||||||
account_name: str
|
account_name: str
|
||||||
account_code: str
|
account_code: str
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ from uuid import UUID
|
||||||
|
|
||||||
class AuthenticationLoginResponse(BaseModel):
|
class AuthenticationLoginResponse(BaseModel):
|
||||||
"""Response model for authentication login endpoint"""
|
"""Response model for authentication login endpoint"""
|
||||||
|
|
||||||
token: str
|
token: str
|
||||||
refresh_token: str
|
refresh_token: str
|
||||||
token_type: str
|
token_type: str
|
||||||
|
|
@ -15,6 +16,7 @@ class AuthenticationLoginResponse(BaseModel):
|
||||||
|
|
||||||
class AuthenticationRefreshResponse(BaseModel):
|
class AuthenticationRefreshResponse(BaseModel):
|
||||||
"""Response model for authentication refresh endpoint"""
|
"""Response model for authentication refresh endpoint"""
|
||||||
|
|
||||||
token: str
|
token: str
|
||||||
refresh_token: str
|
refresh_token: str
|
||||||
token_type: str
|
token_type: str
|
||||||
|
|
@ -23,6 +25,7 @@ class AuthenticationRefreshResponse(BaseModel):
|
||||||
|
|
||||||
class AuthenticationUserInfoResponse(BaseModel):
|
class AuthenticationUserInfoResponse(BaseModel):
|
||||||
"""Response model for authentication user info endpoint"""
|
"""Response model for authentication user info endpoint"""
|
||||||
|
|
||||||
user_id: int
|
user_id: int
|
||||||
username: str
|
username: str
|
||||||
email: str
|
email: str
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,8 @@ from typing import Optional, TypeVar, Generic, List
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
T = TypeVar('T')
|
T = TypeVar("T")
|
||||||
|
|
||||||
|
|
||||||
class BaseResponse(BaseModel):
|
class BaseResponse(BaseModel):
|
||||||
"""Base response model that all response models inherit from.
|
"""Base response model that all response models inherit from.
|
||||||
|
|
@ -27,6 +28,7 @@ class BaseResponse(BaseModel):
|
||||||
is_notification_send (Optional[bool]): Whether notifications have been sent for this record
|
is_notification_send (Optional[bool]): Whether notifications have been sent for this record
|
||||||
is_email_send (Optional[bool]): Whether emails have been sent for this record
|
is_email_send (Optional[bool]): Whether emails have been sent for this record
|
||||||
"""
|
"""
|
||||||
|
|
||||||
uu_id: str
|
uu_id: str
|
||||||
created_at: datetime
|
created_at: datetime
|
||||||
updated_at: Optional[datetime]
|
updated_at: Optional[datetime]
|
||||||
|
|
@ -47,6 +49,7 @@ class BaseResponse(BaseModel):
|
||||||
Attributes:
|
Attributes:
|
||||||
from_attributes (bool): Enables ORM mode for SQLAlchemy integration
|
from_attributes (bool): Enables ORM mode for SQLAlchemy integration
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from_attributes = True
|
from_attributes = True
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -84,6 +87,7 @@ class CrudCollection(BaseModel, Generic[T]):
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
|
|
||||||
page: int = 1
|
page: int = 1
|
||||||
size: int = 10
|
size: int = 10
|
||||||
total: int = 0
|
total: int = 0
|
||||||
|
|
@ -97,4 +101,5 @@ class CrudCollection(BaseModel, Generic[T]):
|
||||||
Attributes:
|
Attributes:
|
||||||
from_attributes (bool): Enables ORM mode for SQLAlchemy integration
|
from_attributes (bool): Enables ORM mode for SQLAlchemy integration
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from_attributes = True
|
from_attributes = True
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ from .base_responses import BaseResponse, CrudCollection
|
||||||
|
|
||||||
class DecisionBookBudgetBooksResponse(BaseResponse):
|
class DecisionBookBudgetBooksResponse(BaseResponse):
|
||||||
"""Response model for decision book budget books"""
|
"""Response model for decision book budget books"""
|
||||||
|
|
||||||
country: str
|
country: str
|
||||||
branch_type: int = 0
|
branch_type: int = 0
|
||||||
company_id: int
|
company_id: int
|
||||||
|
|
@ -18,13 +19,17 @@ class DecisionBookBudgetBooksResponse(BaseResponse):
|
||||||
build_decision_book_uu_id: Optional[str]
|
build_decision_book_uu_id: Optional[str]
|
||||||
|
|
||||||
|
|
||||||
class DecisionBookBudgetBooksCollection(CrudCollection[DecisionBookBudgetBooksResponse]):
|
class DecisionBookBudgetBooksCollection(
|
||||||
|
CrudCollection[DecisionBookBudgetBooksResponse]
|
||||||
|
):
|
||||||
"""Collection of decision book budget books"""
|
"""Collection of decision book budget books"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class DecisionBookBudgetCodesResponse(BaseResponse):
|
class DecisionBookBudgetCodesResponse(BaseResponse):
|
||||||
"""Response model for decision book budget codes"""
|
"""Response model for decision book budget codes"""
|
||||||
|
|
||||||
budget_code: str
|
budget_code: str
|
||||||
comment_line: str
|
comment_line: str
|
||||||
budget_type: str
|
budget_type: str
|
||||||
|
|
@ -37,13 +42,17 @@ class DecisionBookBudgetCodesResponse(BaseResponse):
|
||||||
customer_uu_id: str
|
customer_uu_id: str
|
||||||
|
|
||||||
|
|
||||||
class DecisionBookBudgetCodesCollection(CrudCollection[DecisionBookBudgetCodesResponse]):
|
class DecisionBookBudgetCodesCollection(
|
||||||
|
CrudCollection[DecisionBookBudgetCodesResponse]
|
||||||
|
):
|
||||||
"""Collection of decision book budget codes"""
|
"""Collection of decision book budget codes"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class DecisionBookBudgetMasterResponse(BaseResponse):
|
class DecisionBookBudgetMasterResponse(BaseResponse):
|
||||||
"""Response model for decision book budget master"""
|
"""Response model for decision book budget master"""
|
||||||
|
|
||||||
budget_type: str
|
budget_type: str
|
||||||
currency: str = "TRY"
|
currency: str = "TRY"
|
||||||
total_budget: Decimal
|
total_budget: Decimal
|
||||||
|
|
@ -55,13 +64,17 @@ class DecisionBookBudgetMasterResponse(BaseResponse):
|
||||||
department_uu_id: Optional[str]
|
department_uu_id: Optional[str]
|
||||||
|
|
||||||
|
|
||||||
class DecisionBookBudgetMasterCollection(CrudCollection[DecisionBookBudgetMasterResponse]):
|
class DecisionBookBudgetMasterCollection(
|
||||||
|
CrudCollection[DecisionBookBudgetMasterResponse]
|
||||||
|
):
|
||||||
"""Collection of decision book budget masters"""
|
"""Collection of decision book budget masters"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class DecisionBookBudgetsResponse(BaseResponse):
|
class DecisionBookBudgetsResponse(BaseResponse):
|
||||||
"""Response model for decision book budgets"""
|
"""Response model for decision book budgets"""
|
||||||
|
|
||||||
process_date: datetime
|
process_date: datetime
|
||||||
budget_codes_id: int
|
budget_codes_id: int
|
||||||
total_budget: Decimal
|
total_budget: Decimal
|
||||||
|
|
@ -73,4 +86,5 @@ class DecisionBookBudgetsResponse(BaseResponse):
|
||||||
|
|
||||||
class DecisionBookBudgetsCollection(CrudCollection[DecisionBookBudgetsResponse]):
|
class DecisionBookBudgetsCollection(CrudCollection[DecisionBookBudgetsResponse]):
|
||||||
"""Collection of decision book budgets"""
|
"""Collection of decision book budgets"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ from .base_responses import BaseResponse, CrudCollection
|
||||||
|
|
||||||
class BuildAreaListResponse(BaseResponse):
|
class BuildAreaListResponse(BaseResponse):
|
||||||
"""Response model for building area list endpoint"""
|
"""Response model for building area list endpoint"""
|
||||||
|
|
||||||
uu_id: UUID
|
uu_id: UUID
|
||||||
build_id: int
|
build_id: int
|
||||||
build_uu_id: str
|
build_uu_id: str
|
||||||
|
|
@ -20,11 +21,13 @@ class BuildAreaListResponse(BaseResponse):
|
||||||
|
|
||||||
class BuildAreaListCollection(CrudCollection[BuildAreaListResponse]):
|
class BuildAreaListCollection(CrudCollection[BuildAreaListResponse]):
|
||||||
"""Collection of building area list"""
|
"""Collection of building area list"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BuildSitesListResponse(BaseResponse):
|
class BuildSitesListResponse(BaseResponse):
|
||||||
"""Response model for building sites list endpoint"""
|
"""Response model for building sites list endpoint"""
|
||||||
|
|
||||||
uu_id: UUID
|
uu_id: UUID
|
||||||
address_id: int
|
address_id: int
|
||||||
site_name: str
|
site_name: str
|
||||||
|
|
@ -36,11 +39,13 @@ class BuildSitesListResponse(BaseResponse):
|
||||||
|
|
||||||
class BuildSitesListCollection(CrudCollection[BuildSitesListResponse]):
|
class BuildSitesListCollection(CrudCollection[BuildSitesListResponse]):
|
||||||
"""Collection of building sites list"""
|
"""Collection of building sites list"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BuildTypesListResponse(BaseResponse):
|
class BuildTypesListResponse(BaseResponse):
|
||||||
"""Response model for building types list endpoint"""
|
"""Response model for building types list endpoint"""
|
||||||
|
|
||||||
uu_id: UUID
|
uu_id: UUID
|
||||||
type_name: str
|
type_name: str
|
||||||
type_value: str
|
type_value: str
|
||||||
|
|
@ -51,11 +56,13 @@ class BuildTypesListResponse(BaseResponse):
|
||||||
|
|
||||||
class BuildTypesListCollection(CrudCollection[BuildTypesListResponse]):
|
class BuildTypesListCollection(CrudCollection[BuildTypesListResponse]):
|
||||||
"""Collection of building types list"""
|
"""Collection of building types list"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BuildTypesResponse(BaseResponse):
|
class BuildTypesResponse(BaseResponse):
|
||||||
"""Response model for building types"""
|
"""Response model for building types"""
|
||||||
|
|
||||||
function_code: str
|
function_code: str
|
||||||
type_code: str
|
type_code: str
|
||||||
lang: str = "TR"
|
lang: str = "TR"
|
||||||
|
|
@ -63,11 +70,13 @@ class BuildTypesResponse(BaseResponse):
|
||||||
|
|
||||||
class BuildTypesCollection(CrudCollection[BuildTypesResponse]):
|
class BuildTypesCollection(CrudCollection[BuildTypesResponse]):
|
||||||
"""Collection of building types"""
|
"""Collection of building types"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Part2EmployeeResponse(BaseResponse):
|
class Part2EmployeeResponse(BaseResponse):
|
||||||
"""Response model for part to employee mapping"""
|
"""Response model for part to employee mapping"""
|
||||||
|
|
||||||
build_id: int
|
build_id: int
|
||||||
part_id: int
|
part_id: int
|
||||||
employee_id: int
|
employee_id: int
|
||||||
|
|
@ -75,11 +84,13 @@ class Part2EmployeeResponse(BaseResponse):
|
||||||
|
|
||||||
class Part2EmployeeCollection(CrudCollection[Part2EmployeeResponse]):
|
class Part2EmployeeCollection(CrudCollection[Part2EmployeeResponse]):
|
||||||
"""Collection of part to employee mappings"""
|
"""Collection of part to employee mappings"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class RelationshipEmployee2BuildResponse(BaseResponse):
|
class RelationshipEmployee2BuildResponse(BaseResponse):
|
||||||
"""Response model for employee to build relationship"""
|
"""Response model for employee to build relationship"""
|
||||||
|
|
||||||
company_id: int
|
company_id: int
|
||||||
employee_id: int
|
employee_id: int
|
||||||
member_id: int
|
member_id: int
|
||||||
|
|
@ -87,13 +98,17 @@ class RelationshipEmployee2BuildResponse(BaseResponse):
|
||||||
show_only: bool = False
|
show_only: bool = False
|
||||||
|
|
||||||
|
|
||||||
class RelationshipEmployee2BuildCollection(CrudCollection[RelationshipEmployee2BuildResponse]):
|
class RelationshipEmployee2BuildCollection(
|
||||||
|
CrudCollection[RelationshipEmployee2BuildResponse]
|
||||||
|
):
|
||||||
"""Collection of employee to build relationships"""
|
"""Collection of employee to build relationships"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BuildResponse(BaseResponse):
|
class BuildResponse(BaseResponse):
|
||||||
"""Response model for buildings"""
|
"""Response model for buildings"""
|
||||||
|
|
||||||
gov_address_code: str = ""
|
gov_address_code: str = ""
|
||||||
build_name: str
|
build_name: str
|
||||||
build_no: str
|
build_no: str
|
||||||
|
|
@ -120,11 +135,13 @@ class BuildResponse(BaseResponse):
|
||||||
|
|
||||||
class BuildCollection(CrudCollection[BuildResponse]):
|
class BuildCollection(CrudCollection[BuildResponse]):
|
||||||
"""Collection of buildings"""
|
"""Collection of buildings"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BuildPartsResponse(BaseResponse):
|
class BuildPartsResponse(BaseResponse):
|
||||||
"""Response model for building parts"""
|
"""Response model for building parts"""
|
||||||
|
|
||||||
address_gov_code: str
|
address_gov_code: str
|
||||||
part_no: int = 0
|
part_no: int = 0
|
||||||
part_level: int = 0
|
part_level: int = 0
|
||||||
|
|
@ -144,11 +161,13 @@ class BuildPartsResponse(BaseResponse):
|
||||||
|
|
||||||
class BuildPartsCollection(CrudCollection[BuildPartsResponse]):
|
class BuildPartsCollection(CrudCollection[BuildPartsResponse]):
|
||||||
"""Collection of building parts"""
|
"""Collection of building parts"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BuildLivingSpaceResponse(BaseResponse):
|
class BuildLivingSpaceResponse(BaseResponse):
|
||||||
"""Response model for building living space"""
|
"""Response model for building living space"""
|
||||||
|
|
||||||
fix_value: Decimal = Decimal("0")
|
fix_value: Decimal = Decimal("0")
|
||||||
fix_percent: Decimal = Decimal("0")
|
fix_percent: Decimal = Decimal("0")
|
||||||
agreement_no: str = ""
|
agreement_no: str = ""
|
||||||
|
|
@ -164,11 +183,13 @@ class BuildLivingSpaceResponse(BaseResponse):
|
||||||
|
|
||||||
class BuildLivingSpaceCollection(CrudCollection[BuildLivingSpaceResponse]):
|
class BuildLivingSpaceCollection(CrudCollection[BuildLivingSpaceResponse]):
|
||||||
"""Collection of building living spaces"""
|
"""Collection of building living spaces"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BuildManagementResponse(BaseResponse):
|
class BuildManagementResponse(BaseResponse):
|
||||||
"""Response model for building management"""
|
"""Response model for building management"""
|
||||||
|
|
||||||
discounted_percentage: Decimal = Decimal("0.00")
|
discounted_percentage: Decimal = Decimal("0.00")
|
||||||
discounted_price: Decimal = Decimal("0.00")
|
discounted_price: Decimal = Decimal("0.00")
|
||||||
calculated_price: Decimal = Decimal("0.00")
|
calculated_price: Decimal = Decimal("0.00")
|
||||||
|
|
@ -182,11 +203,13 @@ class BuildManagementResponse(BaseResponse):
|
||||||
|
|
||||||
class BuildManagementCollection(CrudCollection[BuildManagementResponse]):
|
class BuildManagementCollection(CrudCollection[BuildManagementResponse]):
|
||||||
"""Collection of building management records"""
|
"""Collection of building management records"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BuildAreaResponse(BaseResponse):
|
class BuildAreaResponse(BaseResponse):
|
||||||
"""Response model for building area"""
|
"""Response model for building area"""
|
||||||
|
|
||||||
area_name: str = ""
|
area_name: str = ""
|
||||||
area_code: str = ""
|
area_code: str = ""
|
||||||
area_type: str = "GREEN"
|
area_type: str = "GREEN"
|
||||||
|
|
@ -203,11 +226,13 @@ class BuildAreaResponse(BaseResponse):
|
||||||
|
|
||||||
class BuildAreaCollection(CrudCollection[BuildAreaResponse]):
|
class BuildAreaCollection(CrudCollection[BuildAreaResponse]):
|
||||||
"""Collection of building areas"""
|
"""Collection of building areas"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BuildSitesResponse(BaseResponse):
|
class BuildSitesResponse(BaseResponse):
|
||||||
"""Response model for building sites"""
|
"""Response model for building sites"""
|
||||||
|
|
||||||
site_name: str
|
site_name: str
|
||||||
site_no: str
|
site_no: str
|
||||||
address_id: int
|
address_id: int
|
||||||
|
|
@ -216,11 +241,13 @@ class BuildSitesResponse(BaseResponse):
|
||||||
|
|
||||||
class BuildSitesCollection(CrudCollection[BuildSitesResponse]):
|
class BuildSitesCollection(CrudCollection[BuildSitesResponse]):
|
||||||
"""Collection of building sites"""
|
"""Collection of building sites"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BuildCompaniesProvidingResponse(BaseResponse):
|
class BuildCompaniesProvidingResponse(BaseResponse):
|
||||||
"""Response model for building companies providing services"""
|
"""Response model for building companies providing services"""
|
||||||
|
|
||||||
build_id: int
|
build_id: int
|
||||||
build_uu_id: Optional[str]
|
build_uu_id: Optional[str]
|
||||||
company_id: int
|
company_id: int
|
||||||
|
|
@ -230,13 +257,17 @@ class BuildCompaniesProvidingResponse(BaseResponse):
|
||||||
contract_id: Optional[int]
|
contract_id: Optional[int]
|
||||||
|
|
||||||
|
|
||||||
class BuildCompaniesProvidingCollection(CrudCollection[BuildCompaniesProvidingResponse]):
|
class BuildCompaniesProvidingCollection(
|
||||||
|
CrudCollection[BuildCompaniesProvidingResponse]
|
||||||
|
):
|
||||||
"""Collection of building companies providing services"""
|
"""Collection of building companies providing services"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BuildPersonProvidingResponse(BaseResponse):
|
class BuildPersonProvidingResponse(BaseResponse):
|
||||||
"""Response model for building person providing services"""
|
"""Response model for building person providing services"""
|
||||||
|
|
||||||
build_id: int
|
build_id: int
|
||||||
build_uu_id: Optional[str]
|
build_uu_id: Optional[str]
|
||||||
people_id: int
|
people_id: int
|
||||||
|
|
@ -248,4 +279,5 @@ class BuildPersonProvidingResponse(BaseResponse):
|
||||||
|
|
||||||
class BuildPersonProvidingCollection(CrudCollection[BuildPersonProvidingResponse]):
|
class BuildPersonProvidingCollection(CrudCollection[BuildPersonProvidingResponse]):
|
||||||
"""Collection of building person providing services"""
|
"""Collection of building person providing services"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ from uuid import UUID
|
||||||
|
|
||||||
class CompanyListResponse(BaseModel):
|
class CompanyListResponse(BaseModel):
|
||||||
"""Response model for company list endpoint"""
|
"""Response model for company list endpoint"""
|
||||||
|
|
||||||
uu_id: UUID
|
uu_id: UUID
|
||||||
company_name: str
|
company_name: str
|
||||||
company_code: str
|
company_code: str
|
||||||
|
|
@ -19,6 +20,7 @@ class CompanyListResponse(BaseModel):
|
||||||
|
|
||||||
class CompanyDepartmentListResponse(BaseModel):
|
class CompanyDepartmentListResponse(BaseModel):
|
||||||
"""Response model for company department list endpoint"""
|
"""Response model for company department list endpoint"""
|
||||||
|
|
||||||
uu_id: UUID
|
uu_id: UUID
|
||||||
department_name: str
|
department_name: str
|
||||||
department_code: str
|
department_code: str
|
||||||
|
|
@ -31,6 +33,7 @@ class CompanyDepartmentListResponse(BaseModel):
|
||||||
|
|
||||||
class CompanyDutyListResponse(BaseModel):
|
class CompanyDutyListResponse(BaseModel):
|
||||||
"""Response model for company duty list endpoint"""
|
"""Response model for company duty list endpoint"""
|
||||||
|
|
||||||
uu_id: UUID
|
uu_id: UUID
|
||||||
duty_name: str
|
duty_name: str
|
||||||
duty_code: str
|
duty_code: str
|
||||||
|
|
@ -43,6 +46,7 @@ class CompanyDutyListResponse(BaseModel):
|
||||||
|
|
||||||
class CompanyEmployeeListResponse(BaseModel):
|
class CompanyEmployeeListResponse(BaseModel):
|
||||||
"""Response model for company employee list endpoint"""
|
"""Response model for company employee list endpoint"""
|
||||||
|
|
||||||
uu_id: UUID
|
uu_id: UUID
|
||||||
employee_id: int
|
employee_id: int
|
||||||
employee_uu_id: str
|
employee_uu_id: str
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ from .base_responses import BaseResponse, CrudCollection
|
||||||
|
|
||||||
class BuildDecisionBookResponse(BaseResponse):
|
class BuildDecisionBookResponse(BaseResponse):
|
||||||
"""Response model for building decision book"""
|
"""Response model for building decision book"""
|
||||||
|
|
||||||
decision_book_pdf_path: Optional[str] = ""
|
decision_book_pdf_path: Optional[str] = ""
|
||||||
resp_company_fix_wage: float = 0
|
resp_company_fix_wage: float = 0
|
||||||
contact_agreement_path: Optional[str] = ""
|
contact_agreement_path: Optional[str] = ""
|
||||||
|
|
@ -18,11 +19,13 @@ class BuildDecisionBookResponse(BaseResponse):
|
||||||
|
|
||||||
class BuildDecisionBookCollection(CrudCollection[BuildDecisionBookResponse]):
|
class BuildDecisionBookCollection(CrudCollection[BuildDecisionBookResponse]):
|
||||||
"""Collection of building decision books"""
|
"""Collection of building decision books"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BuildDecisionBookInvitationsResponse(BaseResponse):
|
class BuildDecisionBookInvitationsResponse(BaseResponse):
|
||||||
"""Response model for building decision book invitations"""
|
"""Response model for building decision book invitations"""
|
||||||
|
|
||||||
build_id: int
|
build_id: int
|
||||||
build_uu_id: Optional[str]
|
build_uu_id: Optional[str]
|
||||||
decision_book_id: int
|
decision_book_id: int
|
||||||
|
|
@ -36,13 +39,17 @@ class BuildDecisionBookInvitationsResponse(BaseResponse):
|
||||||
planned_date_expires: datetime
|
planned_date_expires: datetime
|
||||||
|
|
||||||
|
|
||||||
class BuildDecisionBookInvitationsCollection(CrudCollection[BuildDecisionBookInvitationsResponse]):
|
class BuildDecisionBookInvitationsCollection(
|
||||||
|
CrudCollection[BuildDecisionBookInvitationsResponse]
|
||||||
|
):
|
||||||
"""Collection of building decision book invitations"""
|
"""Collection of building decision book invitations"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BuildDecisionBookPersonResponse(BaseResponse):
|
class BuildDecisionBookPersonResponse(BaseResponse):
|
||||||
"""Response model for building decision book person"""
|
"""Response model for building decision book person"""
|
||||||
|
|
||||||
dues_percent_discount: int = 0
|
dues_percent_discount: int = 0
|
||||||
dues_fix_discount: Decimal = Decimal("0")
|
dues_fix_discount: Decimal = Decimal("0")
|
||||||
dues_discount_approval_date: datetime
|
dues_discount_approval_date: datetime
|
||||||
|
|
@ -61,13 +68,17 @@ class BuildDecisionBookPersonResponse(BaseResponse):
|
||||||
person_id: int
|
person_id: int
|
||||||
|
|
||||||
|
|
||||||
class BuildDecisionBookPersonCollection(CrudCollection[BuildDecisionBookPersonResponse]):
|
class BuildDecisionBookPersonCollection(
|
||||||
|
CrudCollection[BuildDecisionBookPersonResponse]
|
||||||
|
):
|
||||||
"""Collection of building decision book persons"""
|
"""Collection of building decision book persons"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BuildDecisionBookPersonOccupantsResponse(BaseResponse):
|
class BuildDecisionBookPersonOccupantsResponse(BaseResponse):
|
||||||
"""Response model for building decision book person occupants"""
|
"""Response model for building decision book person occupants"""
|
||||||
|
|
||||||
build_decision_book_person_id: int
|
build_decision_book_person_id: int
|
||||||
build_decision_book_person_uu_id: Optional[str]
|
build_decision_book_person_uu_id: Optional[str]
|
||||||
invite_id: Optional[int]
|
invite_id: Optional[int]
|
||||||
|
|
@ -76,13 +87,17 @@ class BuildDecisionBookPersonOccupantsResponse(BaseResponse):
|
||||||
occupant_type_uu_id: Optional[str]
|
occupant_type_uu_id: Optional[str]
|
||||||
|
|
||||||
|
|
||||||
class BuildDecisionBookPersonOccupantsCollection(CrudCollection[BuildDecisionBookPersonOccupantsResponse]):
|
class BuildDecisionBookPersonOccupantsCollection(
|
||||||
|
CrudCollection[BuildDecisionBookPersonOccupantsResponse]
|
||||||
|
):
|
||||||
"""Collection of building decision book person occupants"""
|
"""Collection of building decision book person occupants"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BuildDecisionBookItemsResponse(BaseResponse):
|
class BuildDecisionBookItemsResponse(BaseResponse):
|
||||||
"""Response model for building decision book items"""
|
"""Response model for building decision book items"""
|
||||||
|
|
||||||
item_order: int
|
item_order: int
|
||||||
item_comment: str
|
item_comment: str
|
||||||
item_objection: Optional[str]
|
item_objection: Optional[str]
|
||||||
|
|
@ -97,11 +112,13 @@ class BuildDecisionBookItemsResponse(BaseResponse):
|
||||||
|
|
||||||
class BuildDecisionBookItemsCollection(CrudCollection[BuildDecisionBookItemsResponse]):
|
class BuildDecisionBookItemsCollection(CrudCollection[BuildDecisionBookItemsResponse]):
|
||||||
"""Collection of building decision book items"""
|
"""Collection of building decision book items"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BuildDecisionBookItemsUnapprovedResponse(BaseResponse):
|
class BuildDecisionBookItemsUnapprovedResponse(BaseResponse):
|
||||||
"""Response model for building decision book items unapproved"""
|
"""Response model for building decision book items unapproved"""
|
||||||
|
|
||||||
item_objection: str
|
item_objection: str
|
||||||
item_order: int
|
item_order: int
|
||||||
decision_book_item_id: int
|
decision_book_item_id: int
|
||||||
|
|
@ -112,13 +129,17 @@ class BuildDecisionBookItemsUnapprovedResponse(BaseResponse):
|
||||||
build_decision_book_item_uu_id: Optional[str]
|
build_decision_book_item_uu_id: Optional[str]
|
||||||
|
|
||||||
|
|
||||||
class BuildDecisionBookItemsUnapprovedCollection(CrudCollection[BuildDecisionBookItemsUnapprovedResponse]):
|
class BuildDecisionBookItemsUnapprovedCollection(
|
||||||
|
CrudCollection[BuildDecisionBookItemsUnapprovedResponse]
|
||||||
|
):
|
||||||
"""Collection of building decision book items unapproved"""
|
"""Collection of building decision book items unapproved"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BuildDecisionBookPaymentsResponse(BaseResponse):
|
class BuildDecisionBookPaymentsResponse(BaseResponse):
|
||||||
"""Response model for building decision book payments"""
|
"""Response model for building decision book payments"""
|
||||||
|
|
||||||
payment_plan_time_periods: str
|
payment_plan_time_periods: str
|
||||||
process_date: datetime
|
process_date: datetime
|
||||||
payment_amount: Decimal
|
payment_amount: Decimal
|
||||||
|
|
@ -138,13 +159,17 @@ class BuildDecisionBookPaymentsResponse(BaseResponse):
|
||||||
account_records_uu_id: Optional[str]
|
account_records_uu_id: Optional[str]
|
||||||
|
|
||||||
|
|
||||||
class BuildDecisionBookPaymentsCollection(CrudCollection[BuildDecisionBookPaymentsResponse]):
|
class BuildDecisionBookPaymentsCollection(
|
||||||
|
CrudCollection[BuildDecisionBookPaymentsResponse]
|
||||||
|
):
|
||||||
"""Collection of building decision book payments"""
|
"""Collection of building decision book payments"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BuildDecisionBookLegalResponse(BaseResponse):
|
class BuildDecisionBookLegalResponse(BaseResponse):
|
||||||
"""Response model for building decision book legal"""
|
"""Response model for building decision book legal"""
|
||||||
|
|
||||||
period_start_date: datetime
|
period_start_date: datetime
|
||||||
lawsuits_decision_number: str
|
lawsuits_decision_number: str
|
||||||
lawsuits_decision_date: datetime
|
lawsuits_decision_date: datetime
|
||||||
|
|
@ -175,4 +200,5 @@ class BuildDecisionBookLegalResponse(BaseResponse):
|
||||||
|
|
||||||
class BuildDecisionBookLegalCollection(CrudCollection[BuildDecisionBookLegalResponse]):
|
class BuildDecisionBookLegalCollection(CrudCollection[BuildDecisionBookLegalResponse]):
|
||||||
"""Collection of building decision book legal records"""
|
"""Collection of building decision book legal records"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ RelationshipDutyPeopleLanguageModel = dict(
|
||||||
"member_id": "Member ID",
|
"member_id": "Member ID",
|
||||||
"relationship_type": "Relationship Type",
|
"relationship_type": "Relationship Type",
|
||||||
"show_only": "Show Only",
|
"show_only": "Show Only",
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
PeopleLanguageModel = dict(
|
PeopleLanguageModel = dict(
|
||||||
|
|
@ -105,7 +105,7 @@ PeopleLanguageModel = dict(
|
||||||
"birth_place": "Birth Place",
|
"birth_place": "Birth Place",
|
||||||
"birth_date": "Birth Date",
|
"birth_date": "Birth Date",
|
||||||
"tax_no": "Tax No",
|
"tax_no": "Tax No",
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
RelationshipEmployee2PostCodeLanguageModel = dict(
|
RelationshipEmployee2PostCodeLanguageModel = dict(
|
||||||
|
|
@ -124,7 +124,7 @@ RelationshipEmployee2PostCodeLanguageModel = dict(
|
||||||
"member_id": "Member ID",
|
"member_id": "Member ID",
|
||||||
"relationship_type": "Relationship Type",
|
"relationship_type": "Relationship Type",
|
||||||
"show_only": "Show Only",
|
"show_only": "Show Only",
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
AddressPostcodeLanguageModel = dict(
|
AddressPostcodeLanguageModel = dict(
|
||||||
|
|
@ -168,7 +168,7 @@ AddressesLanguageModel = dict(
|
||||||
"longitude": "Longitude",
|
"longitude": "Longitude",
|
||||||
"street_id": "Street ID",
|
"street_id": "Street ID",
|
||||||
"street_uu_id": "Street UUID",
|
"street_uu_id": "Street UUID",
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
AddressGeographicLocationsLanguageModel = dict(
|
AddressGeographicLocationsLanguageModel = dict(
|
||||||
|
|
@ -195,7 +195,7 @@ AddressGeographicLocationsLanguageModel = dict(
|
||||||
"geo_description": "Description",
|
"geo_description": "Description",
|
||||||
"geo_area_size": "Area",
|
"geo_area_size": "Area",
|
||||||
"geo_population": "Population",
|
"geo_population": "Population",
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
AddressCountryLanguageModel = dict(
|
AddressCountryLanguageModel = dict(
|
||||||
|
|
|
||||||
|
|
@ -16,5 +16,5 @@ EndpointRestrictionLanguageModel = dict(
|
||||||
"endpoint_method": "API Method",
|
"endpoint_method": "API Method",
|
||||||
"endpoint_desc": "API Description",
|
"endpoint_desc": "API Description",
|
||||||
"endpoint_code": "API Code",
|
"endpoint_code": "API Code",
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ def validate_timestamp(doc):
|
||||||
if not doc:
|
if not doc:
|
||||||
return doc
|
return doc
|
||||||
|
|
||||||
timestamp_fields = ['modified_at', 'created_at', 'accessed_at', 'timestamp']
|
timestamp_fields = ["modified_at", "created_at", "accessed_at", "timestamp"]
|
||||||
for field in timestamp_fields:
|
for field in timestamp_fields:
|
||||||
if field in doc and not isinstance(doc[field], (int, float)):
|
if field in doc and not isinstance(doc[field], (int, float)):
|
||||||
# Convert to proper timestamp if it's not already
|
# Convert to proper timestamp if it's not already
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ from databases.language_models.building.build import (
|
||||||
BuildPersonProvidingLanguageModel,
|
BuildPersonProvidingLanguageModel,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class BuildTypes(CrudCollection):
|
class BuildTypes(CrudCollection):
|
||||||
"""
|
"""
|
||||||
BuildTypes class based on declarative_base and BaseMixin via session
|
BuildTypes class based on declarative_base and BaseMixin via session
|
||||||
|
|
@ -177,12 +178,8 @@ class Build(CrudCollection, SelectActionWithEmployee):
|
||||||
heating_system: Mapped[bool] = mapped_column(Boolean, server_default="True")
|
heating_system: Mapped[bool] = mapped_column(Boolean, server_default="True")
|
||||||
cooling_system: Mapped[bool] = mapped_column(Boolean, server_default="False")
|
cooling_system: Mapped[bool] = mapped_column(Boolean, server_default="False")
|
||||||
hot_water_system: Mapped[bool] = mapped_column(Boolean, server_default="False")
|
hot_water_system: Mapped[bool] = mapped_column(Boolean, server_default="False")
|
||||||
block_service_man_count: Mapped[int] = mapped_column(
|
block_service_man_count: Mapped[int] = mapped_column(Integer, server_default="0")
|
||||||
Integer, server_default="0"
|
security_service_man_count: Mapped[int] = mapped_column(Integer, server_default="0")
|
||||||
)
|
|
||||||
security_service_man_count: Mapped[int] = mapped_column(
|
|
||||||
Integer, server_default="0"
|
|
||||||
)
|
|
||||||
garage_count: Mapped[int] = mapped_column(
|
garage_count: Mapped[int] = mapped_column(
|
||||||
Integer, server_default="0", comment="Garage Count"
|
Integer, server_default="0", comment="Garage Count"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,16 @@ from fastapi.exceptions import HTTPException
|
||||||
|
|
||||||
from databases.sql_models.core_mixin import CrudCollection
|
from databases.sql_models.core_mixin import CrudCollection
|
||||||
|
|
||||||
from sqlalchemy import String, Integer, Boolean, ForeignKey, Index, Identity, TIMESTAMP, func
|
from sqlalchemy import (
|
||||||
|
String,
|
||||||
|
Integer,
|
||||||
|
Boolean,
|
||||||
|
ForeignKey,
|
||||||
|
Index,
|
||||||
|
Identity,
|
||||||
|
TIMESTAMP,
|
||||||
|
func,
|
||||||
|
)
|
||||||
from sqlalchemy.orm import mapped_column, relationship, Mapped
|
from sqlalchemy.orm import mapped_column, relationship, Mapped
|
||||||
|
|
||||||
from api_configs import RelationAccess
|
from api_configs import RelationAccess
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,9 @@ engine_config = {
|
||||||
"pool_pre_ping": True,
|
"pool_pre_ping": True,
|
||||||
}
|
}
|
||||||
|
|
||||||
engine = create_engine(**engine_config, )
|
engine = create_engine(
|
||||||
|
**engine_config,
|
||||||
|
)
|
||||||
SessionLocal = sessionmaker(bind=engine, autoflush=False, autocommit=False)
|
SessionLocal = sessionmaker(bind=engine, autoflush=False, autocommit=False)
|
||||||
session = scoped_session(sessionmaker(bind=engine))
|
session = scoped_session(sessionmaker(bind=engine))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,9 +52,9 @@ class FilterAttributes:
|
||||||
meta_data = getattr(cls, "meta_data", {})
|
meta_data = getattr(cls, "meta_data", {})
|
||||||
meta_data_created = meta_data.get("created", False)
|
meta_data_created = meta_data.get("created", False)
|
||||||
if meta_data_created:
|
if meta_data_created:
|
||||||
print('meta_data_created commit', meta_data_created)
|
print("meta_data_created commit", meta_data_created)
|
||||||
cls.__session__.commit()
|
cls.__session__.commit()
|
||||||
print('meta_data_created rollback', meta_data_created)
|
print("meta_data_created rollback", meta_data_created)
|
||||||
cls.__session__.rollback()
|
cls.__session__.rollback()
|
||||||
# cls.raise_http_exception(
|
# cls.raise_http_exception(
|
||||||
# status_code="HTTP_304_NOT_MODIFIED",
|
# status_code="HTTP_304_NOT_MODIFIED",
|
||||||
|
|
@ -82,6 +82,7 @@ class FilterAttributes:
|
||||||
data={},
|
data={},
|
||||||
message=str(e.__context__).split("\n")[0],
|
message=str(e.__context__).split("\n")[0],
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def rollback(cls):
|
def rollback(cls):
|
||||||
"""Rollback the current session."""
|
"""Rollback the current session."""
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ def do_alembic():
|
||||||
|
|
||||||
generate_alembic_with_session(text=text)
|
generate_alembic_with_session(text=text)
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# def create_one_address():
|
# def create_one_address():
|
||||||
# from databases import (
|
# from databases import (
|
||||||
|
|
|
||||||
|
|
@ -36,10 +36,9 @@ CrudCollection.http_exception = HTTPException
|
||||||
new_person_find_or_create = People.find_or_create(**person_dict)
|
new_person_find_or_create = People.find_or_create(**person_dict)
|
||||||
new_person_find_or_create.save_via_metadata()
|
new_person_find_or_create.save_via_metadata()
|
||||||
|
|
||||||
print('meta_data', new_person_find_or_create.meta_data)
|
print("meta_data", new_person_find_or_create.meta_data)
|
||||||
print('new_person_find_or_create', new_person_find_or_create)
|
print("new_person_find_or_create", new_person_find_or_create)
|
||||||
|
|
||||||
quit()
|
quit()
|
||||||
new_user_find_or_create = Users.find_or_create(**user_dict)
|
new_user_find_or_create = Users.find_or_create(**user_dict)
|
||||||
new_user_find_or_abort = Users.find_or_abort(**user_dict)
|
new_user_find_or_abort = Users.find_or_abort(**user_dict)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ def create_test_occupant_token(
|
||||||
person_id: int = 1,
|
person_id: int = 1,
|
||||||
person_uu_id: str = "test-person",
|
person_uu_id: str = "test-person",
|
||||||
credentials: Optional[Dict[str, Any]] = None,
|
credentials: Optional[Dict[str, Any]] = None,
|
||||||
available_occupants: Optional[Dict[str, Any]] = None
|
available_occupants: Optional[Dict[str, Any]] = None,
|
||||||
) -> OccupantTokenObject:
|
) -> OccupantTokenObject:
|
||||||
"""Create a test occupant token object"""
|
"""Create a test occupant token object"""
|
||||||
return OccupantTokenObject(
|
return OccupantTokenObject(
|
||||||
|
|
@ -32,7 +32,7 @@ def create_test_employee_token(
|
||||||
person_id: int = 1,
|
person_id: int = 1,
|
||||||
person_uu_id: str = "test-person",
|
person_uu_id: str = "test-person",
|
||||||
credentials: Optional[Dict[str, Any]] = None,
|
credentials: Optional[Dict[str, Any]] = None,
|
||||||
selected_company: Optional[Dict[str, Any]] = None
|
selected_company: Optional[Dict[str, Any]] = None,
|
||||||
) -> EmployeeTokenObject:
|
) -> EmployeeTokenObject:
|
||||||
"""Create a test employee token object"""
|
"""Create a test employee token object"""
|
||||||
return EmployeeTokenObject(
|
return EmployeeTokenObject(
|
||||||
|
|
@ -50,5 +50,6 @@ def create_test_employee_token(
|
||||||
|
|
||||||
class MockRequest:
|
class MockRequest:
|
||||||
"""Mock request object for testing"""
|
"""Mock request object for testing"""
|
||||||
|
|
||||||
def __init__(self, headers: Optional[Dict[str, str]] = None):
|
def __init__(self, headers: Optional[Dict[str, str]] = None):
|
||||||
self.headers = headers or {}
|
self.headers = headers or {}
|
||||||
|
|
|
||||||
|
|
@ -35,9 +35,7 @@ def test_save_object_to_redis_success():
|
||||||
|
|
||||||
# Test save
|
# Test save
|
||||||
result = AccessObjectActions.save_object_to_redis(
|
result = AccessObjectActions.save_object_to_redis(
|
||||||
access_token=access_token,
|
access_token=access_token, model_object=model_object, expiry_minutes=1
|
||||||
model_object=model_object,
|
|
||||||
expiry_minutes=1
|
|
||||||
)
|
)
|
||||||
assert result is True
|
assert result is True
|
||||||
|
|
||||||
|
|
@ -69,7 +67,7 @@ def test_save_object_to_redis_expiry():
|
||||||
AccessObjectActions.save_object_to_redis(
|
AccessObjectActions.save_object_to_redis(
|
||||||
access_token=access_token,
|
access_token=access_token,
|
||||||
model_object=model_object,
|
model_object=model_object,
|
||||||
expiry_minutes=2/60 # 2 seconds
|
expiry_minutes=2 / 60, # 2 seconds
|
||||||
)
|
)
|
||||||
|
|
||||||
# Verify token exists
|
# Verify token exists
|
||||||
|
|
@ -86,7 +84,9 @@ def test_save_object_to_redis_expiry():
|
||||||
RedisActions.get_object_via_access_key(
|
RedisActions.get_object_via_access_key(
|
||||||
MockRequest(headers={Auth.ACCESS_TOKEN_TAG: access_token})
|
MockRequest(headers={Auth.ACCESS_TOKEN_TAG: access_token})
|
||||||
)
|
)
|
||||||
assert any(msg in str(exc_info.value) for msg in ["Token expired", "Invalid credentials"])
|
assert any(
|
||||||
|
msg in str(exc_info.value) for msg in ["Token expired", "Invalid credentials"]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_get_object_via_user_uu_id():
|
def test_get_object_via_user_uu_id():
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue