updated handler exceptions
This commit is contained in:
parent
cecf1e69a2
commit
56b693989d
|
|
@ -5,9 +5,11 @@ from fastapi.middleware.cors import CORSMiddleware
|
|||
from fastapi import Request, HTTPException, status
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
from api_objects.errors.errorMessages import EXCEPTION_DICTS, ERRORS_DICT, ERRORS_LANG
|
||||
from api_objects.errors.errorHandlers import HTTPExceptionEvyos, HTTPExceptionAnyHandler, HTTPExceptionEvyosHandler
|
||||
|
||||
from middlewares.token_middleware import AuthHeaderMiddleware
|
||||
from application.create_file import create_app
|
||||
from api_objects.errors.errors_dictionary import ErrorHandlers
|
||||
from prometheus_fastapi_instrumentator import Instrumentator
|
||||
|
||||
app = create_app(routers=routers)
|
||||
|
|
@ -24,17 +26,20 @@ app.add_middleware(
|
|||
)
|
||||
app.add_middleware(AuthHeaderMiddleware)
|
||||
|
||||
# Initialize error handlers
|
||||
error_handlers = ErrorHandlers.create(
|
||||
requests=Request,
|
||||
# Initialize Exception and ExceptionInstance handlers
|
||||
CustomExceptionHandler = HTTPExceptionEvyosHandler(**dict(
|
||||
statuses=status,
|
||||
exceptions=HTTPException,
|
||||
response_model=JSONResponse,
|
||||
status=status,
|
||||
)
|
||||
exceptions_dict=EXCEPTION_DICTS,
|
||||
errors_dict=ERRORS_DICT,
|
||||
error_language_dict=ERRORS_LANG
|
||||
))
|
||||
CustomExceptionAnyHandler = HTTPExceptionAnyHandler(response_model=JSONResponse)
|
||||
|
||||
# Register error handlers with bound methods
|
||||
app.add_exception_handler(HTTPException, error_handlers.exception_handler_http)
|
||||
app.add_exception_handler(Exception, error_handlers.exception_handler_exception)
|
||||
app.add_exception_handler(HTTPExceptionEvyos, CustomExceptionHandler.handle_exception)
|
||||
app.add_exception_handler(Exception, CustomExceptionAnyHandler.any_exception_handler)
|
||||
|
||||
if __name__ == "__main__":
|
||||
uvicorn_config = {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ from api_services.templates.password_templates import (
|
|||
from api_services.token_service import TokenService
|
||||
from api_services.redis.functions import RedisActions
|
||||
from api_library.response_handlers import ResponseHandler
|
||||
from api_library.date_time_actions.date_functions import system_arrow
|
||||
from api_library.date_time_actions.date_functions import system_arrow, DateTimeLocal
|
||||
|
||||
# from api_library.user_logger import UserLogger
|
||||
|
||||
|
|
@ -74,9 +74,17 @@ class AuthenticationLoginEventMethods(MethodToEvent):
|
|||
|
||||
@classmethod
|
||||
def authentication_login_with_domain_and_creds(cls, data: Login, request: Request):
|
||||
try:
|
||||
from api_objects import HTTPExceptionEvyos
|
||||
|
||||
raise HTTPExceptionEvyos(
|
||||
error_code="UNKNOWN_ERROR",
|
||||
lang="en",
|
||||
)
|
||||
access_dict = Users.login_user_with_credentials(data=data, request=request)
|
||||
found_user = access_dict.get("user")
|
||||
Users.client_arrow = DateTimeLocal(
|
||||
is_client=True, timezone=found_user.local_timezone
|
||||
)
|
||||
if not found_user:
|
||||
# UserLogger.log_login_attempt(
|
||||
# request,
|
||||
|
|
@ -87,25 +95,20 @@ class AuthenticationLoginEventMethods(MethodToEvent):
|
|||
# error="Invalid credentials",
|
||||
# )
|
||||
return ResponseHandler.unauthorized("Invalid credentials")
|
||||
|
||||
# UserLogger.log_login_attempt(
|
||||
# request, found_user.id, data.domain, data.access_key, success=True
|
||||
# )
|
||||
response_data = {
|
||||
return ResponseHandler.success(
|
||||
message="User logged in successfully",
|
||||
data={
|
||||
"access_token": access_dict.get("access_token"),
|
||||
"refresh_token": access_dict.get("refresher_token"),
|
||||
"access_object": access_dict.get("access_object"),
|
||||
"user": found_user.get_dict(),
|
||||
}
|
||||
return ResponseHandler.success(
|
||||
message="User logged in successfully",
|
||||
data=response_data,
|
||||
},
|
||||
)
|
||||
except Exception as e:
|
||||
# UserLogger.log_login_attempt(
|
||||
# request, None, data.domain, data.access_key, success=False, error=str(e)
|
||||
# )
|
||||
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=str(e))
|
||||
# except Exception as e:
|
||||
# # UserLogger.log_login_attempt(
|
||||
# # request, None, data.domain, data.access_key, success=False, error=str(e)
|
||||
# # )
|
||||
# raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=str(e))
|
||||
|
||||
|
||||
class AuthenticationSelectEventMethods(MethodToEvent):
|
||||
|
|
@ -125,6 +128,9 @@ class AuthenticationSelectEventMethods(MethodToEvent):
|
|||
cls, data: EmployeeSelection, token_dict: EmployeeTokenObject, request: Request
|
||||
):
|
||||
"""Handle employee company selection"""
|
||||
Users.client_arrow = DateTimeLocal(
|
||||
is_client=True, timezone=token_dict.local_timezone
|
||||
)
|
||||
if data.company_uu_id not in token_dict.companies_uu_id_list:
|
||||
return ResponseHandler.unauthorized(
|
||||
"Company not found in user's company list"
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ def endpoint_restriction_available(request: Request, data: CheckEndpointAccess):
|
|||
system=True,
|
||||
).data
|
||||
if not endpoint:
|
||||
EndpointRestriction.raise_http_exception(
|
||||
raise EndpointRestriction.raise_http_exception(
|
||||
status_code="HTTP_404_NOT_FOUND",
|
||||
error_case="UNAUTHORIZED",
|
||||
message="Only Occupant can see this data",
|
||||
|
|
@ -94,7 +94,7 @@ def endpoint_restriction_available(request: Request, data: CheckEndpointAccess):
|
|||
== token_dict.selected_occupant.living_space_id,
|
||||
).data
|
||||
if not event_occupant:
|
||||
EndpointRestriction.raise_http_exception(
|
||||
raise EndpointRestriction.raise_http_exception(
|
||||
status_code="HTTP_404_NOT_FOUND",
|
||||
error_case="UNAUTHORIZED",
|
||||
message="This endpoint is not available for this occupant",
|
||||
|
|
@ -110,7 +110,7 @@ def endpoint_restriction_available(request: Request, data: CheckEndpointAccess):
|
|||
Event2Employee.employee_id == token_dict.selected_company.employee_id,
|
||||
).data
|
||||
if not event_employee:
|
||||
EndpointRestriction.raise_http_exception(
|
||||
raise EndpointRestriction.raise_http_exception(
|
||||
status_code="HTTP_404_NOT_FOUND",
|
||||
error_case="UNAUTHORIZED",
|
||||
message="This endpoint is not available for this employee",
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ from application.create_file import create_app
|
|||
from api_objects.errors.errors_dictionary import ErrorHandlers
|
||||
from prometheus_fastapi_instrumentator import Instrumentator
|
||||
|
||||
|
||||
app = create_app(routers=routers)
|
||||
Instrumentator().instrument(app=app).expose(app=app)
|
||||
|
||||
|
|
|
|||
|
|
@ -84,6 +84,10 @@ class AuthActions:
|
|||
person_uu_id=str(found_user.person.uu_id),
|
||||
request=dict(request.headers),
|
||||
available_occupants=occupants_selection_dict,
|
||||
timezone=(
|
||||
found_user.local_timezone if found_user.local_timezone else "GMT+0"
|
||||
),
|
||||
lang=found_user.lang if found_user.lang else "tr",
|
||||
),
|
||||
)
|
||||
return dict(
|
||||
|
|
@ -136,6 +140,7 @@ class AuthActions:
|
|||
company_address=company_address,
|
||||
)
|
||||
)
|
||||
|
||||
AccessObjectActions.save_object_to_redis(
|
||||
access_token=access_token,
|
||||
model_object=EmployeeTokenObject(
|
||||
|
|
@ -151,6 +156,10 @@ class AuthActions:
|
|||
companies_id_list=companies_id_list,
|
||||
duty_uu_id_list=duty_uu_id_list,
|
||||
duty_id_list=duty_id_list,
|
||||
timezone=(
|
||||
found_user.local_timezone if found_user.local_timezone else "GMT+0"
|
||||
),
|
||||
lang=found_user.lang if found_user.lang else "tr",
|
||||
),
|
||||
)
|
||||
return dict(
|
||||
|
|
@ -185,11 +194,30 @@ class AuthActions:
|
|||
found_user.generate_access_token() if not access_token else access_token
|
||||
)
|
||||
# Prepare the user's details to save in Redis Session
|
||||
if found_user.is_occupant: # Check if user is NOT an occupant
|
||||
return cls.do_occupant_login_token(
|
||||
if found_user.is_occupant: # Check if user is an occupant
|
||||
cls.do_occupant_login_token(request, found_user, domain, access_token)
|
||||
|
||||
return {
|
||||
"access_object": cls.do_occupant_login_token(
|
||||
request, found_user, domain, access_token
|
||||
)
|
||||
return cls.do_employee_login_token(request, found_user, domain, access_token)
|
||||
),
|
||||
"access_token": access_token,
|
||||
"refresher_token": (
|
||||
found_user.generate_refresh_token()
|
||||
if found_user.remember_me
|
||||
else None
|
||||
),
|
||||
}
|
||||
cls.do_employee_login_token(request, found_user, domain, access_token)
|
||||
return {
|
||||
"access_object": cls.do_employee_login_token(
|
||||
request, found_user, domain, access_token
|
||||
),
|
||||
"access_token": access_token,
|
||||
"refresher_token": (
|
||||
found_user.generate_refresh_token() if found_user.remember_me else None
|
||||
),
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def update_selected_to_redis(cls, request, add_payload):
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ class AccessObjectActions:
|
|||
Raises:
|
||||
HTTPException: If save fails
|
||||
"""
|
||||
|
||||
try:
|
||||
RedisActions.save_object_to_redis(
|
||||
access_token=access_token,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,100 @@
|
|||
from typing import Any, Union
|
||||
from typing import Any, Union, Callable, Any
|
||||
from fastapi import status
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
from pydantic import BaseModel
|
||||
from api_validations.validations_request import PydanticBaseModel, BaseModelRegular
|
||||
from databases.sql_models.response_model import AlchemyResponse
|
||||
from sqlalchemy.orm import Query
|
||||
|
||||
MODEL_TYPE = Callable[[Any], Any]
|
||||
|
||||
class Pagination:
|
||||
size: int = 10
|
||||
page: int = 1
|
||||
orderField: str = "id"
|
||||
orderType: str = "asc"
|
||||
pageCount: int = 1
|
||||
totalCount: int = 1
|
||||
totalPage: int = 1
|
||||
|
||||
def change(self, page=None, size=None, order_field=None, order_type=None):
|
||||
self.page = page or self.page
|
||||
self.size = size or self.size
|
||||
self.orderField = order_field or self.orderField
|
||||
self.orderType = order_type or self.orderType
|
||||
self.setter_page()
|
||||
|
||||
def feed(self, data):
|
||||
if isinstance(data, list):
|
||||
self.totalCount = len(data)
|
||||
elif isinstance(data, AlchemyResponse):
|
||||
self.totalCount = data.count
|
||||
elif isinstance(data, Query):
|
||||
self.totalCount = data.count()
|
||||
|
||||
def setter_page(self):
|
||||
self.pageCount = self.size
|
||||
self.totalPage = int(round(self.totalCount / self.size, 0))
|
||||
if self.totalCount % self.size > 0:
|
||||
if self.page == self.totalPage:
|
||||
self.pageCount = self.totalCount % self.size
|
||||
self.totalPage = int(round(self.totalCount / self.size, 0)) + 1
|
||||
|
||||
def as_dict(self):
|
||||
return {
|
||||
"size": self.size,
|
||||
"page": self.page,
|
||||
"totalCount": self.totalCount,
|
||||
"totalPage": self.totalPage,
|
||||
"pageCount": self.pageCount,
|
||||
"orderField": self.orderField,
|
||||
"orderType": self.orderType,
|
||||
}
|
||||
|
||||
|
||||
class SingleAlchemyResponse:
|
||||
status_code = "HTTP_200_OK"
|
||||
result: AlchemyResponse
|
||||
response_model: MODEL_TYPE
|
||||
message: str
|
||||
completed: bool
|
||||
|
||||
def __new__(
|
||||
cls,
|
||||
message: str,
|
||||
response_model: MODEL_TYPE,
|
||||
status_code: str = "HTTP_200_OK",
|
||||
result: AlchemyResponse = None,
|
||||
completed: bool = True,
|
||||
):
|
||||
cls.status_code = getattr(status, status_code, "HTTP_200_OK")
|
||||
cls.message = message
|
||||
cls.result = result
|
||||
cls.completed = completed
|
||||
cls.response_model = response_model
|
||||
|
||||
if not isinstance(cls.result, AlchemyResponse):
|
||||
raise Exception("Invalid response type 4 single alchemy response")
|
||||
|
||||
if not cls.result.first:
|
||||
raise Exception("Invalid data type 4 single alchemy response")
|
||||
|
||||
pagination = Pagination()
|
||||
pagination.change(page=1)
|
||||
BaseModelRegular(**cls.result.data.get_dict())
|
||||
data = cls.result.data.get_dict()
|
||||
if cls.response_model:
|
||||
data = cls.response_model(**cls.result.data.get_dict()).dump()
|
||||
return JSONResponse(
|
||||
status_code=cls.status_code,
|
||||
content=dict(
|
||||
pagination=pagination.as_dict(),
|
||||
completed=cls.completed,
|
||||
message=cls.message,
|
||||
data=data,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
class AlchemyJsonResponse:
|
||||
|
|
@ -11,27 +103,16 @@ class AlchemyJsonResponse:
|
|||
result: AlchemyResponse
|
||||
completed: bool
|
||||
filter_attributes: Any = None
|
||||
response_model: Any = None
|
||||
response_model: MODEL_TYPE = None
|
||||
cls_object: Any = None
|
||||
|
||||
@staticmethod
|
||||
def get_total_count(cls_object, filter_attributes):
|
||||
total_page_number = 1
|
||||
count_to_use = cls_object.total_count / int(filter_attributes.size)
|
||||
if cls_object.total_count > int(filter_attributes.size):
|
||||
if isinstance(count_to_use, int):
|
||||
total_page_number = round(count_to_use, 0)
|
||||
elif isinstance(count_to_use, float):
|
||||
total_page_number = round(count_to_use, 0) + 1
|
||||
return total_page_number
|
||||
|
||||
def __new__(
|
||||
cls,
|
||||
message: str,
|
||||
status_code: str = "HTTP_200_OK",
|
||||
result: Union[Any, list] = None,
|
||||
result: Union[BaseModelRegular, BaseModel, PydanticBaseModel] = None,
|
||||
completed: bool = True,
|
||||
response_model: Any = None,
|
||||
response_model: MODEL_TYPE = None,
|
||||
cls_object: Any = None,
|
||||
filter_attributes: Any = None,
|
||||
):
|
||||
|
|
@ -40,108 +121,121 @@ class AlchemyJsonResponse:
|
|||
cls.result = result
|
||||
cls.completed = completed
|
||||
cls.response_model = response_model
|
||||
cls.filter_attributes = filter_attributes
|
||||
cls.cls_object = cls_object
|
||||
pagination = Pagination()
|
||||
|
||||
if cls.result.first:
|
||||
raise Exception("Invalid data type 4 alchemy response")
|
||||
|
||||
pagination_dict = {
|
||||
"size/total_count": [10, 10],
|
||||
"page/total_page": [1, 1],
|
||||
"order_field": "id",
|
||||
"order_type": "asc",
|
||||
}
|
||||
if filter_attributes:
|
||||
total_page_number = cls.get_total_count(cls_object, filter_attributes)
|
||||
pagination_dict = {
|
||||
"size/total_count": [filter_attributes.size, cls_object.total_count],
|
||||
"page/total_page": [filter_attributes.page, total_page_number],
|
||||
"order_field": filter_attributes.order_field,
|
||||
"order_type": filter_attributes.order_type,
|
||||
}
|
||||
|
||||
if isinstance(cls.result, dict) or isinstance(cls.result, list):
|
||||
pagination.change(
|
||||
page=filter_attributes.page, size=filter_attributes.size,
|
||||
order_field=filter_attributes.order_field,
|
||||
order_type=filter_attributes.order_type,
|
||||
)
|
||||
data = []
|
||||
for data_object in cls.result.data:
|
||||
data_dict = data_object.get_dict()
|
||||
if cls.response_model:
|
||||
data_dict = cls.response_model(**data_object.get_dict()).dump()
|
||||
data.append(data_dict)
|
||||
pagination.feed(data)
|
||||
return JSONResponse(
|
||||
status_code=cls.status_code,
|
||||
content=dict(
|
||||
total_count=len(cls.result),
|
||||
count=len(cls.result),
|
||||
pagination=pagination_dict,
|
||||
pagination=pagination.as_dict(),
|
||||
message=cls.message,
|
||||
completed=cls.completed,
|
||||
data=data,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
class ListJsonResponse:
|
||||
status_code = "HTTP_200_OK"
|
||||
result: list
|
||||
message: str
|
||||
completed: bool
|
||||
filter_attributes: Any
|
||||
response_model: MODEL_TYPE = None,
|
||||
cls_object: Any = None,
|
||||
|
||||
def __new__(
|
||||
cls,
|
||||
message: str,
|
||||
status_code: str = "HTTP_200_OK",
|
||||
result: Union[BaseModelRegular, BaseModel, PydanticBaseModel] = None,
|
||||
completed: bool = True,
|
||||
response_model: MODEL_TYPE = None,
|
||||
cls_object: Any = None,
|
||||
filter_attributes: Any = None,
|
||||
):
|
||||
cls.status_code = getattr(status, status_code, "HTTP_200_OK")
|
||||
cls.message = message
|
||||
cls.result = result
|
||||
cls.completed = completed
|
||||
cls.filter_attributes = filter_attributes
|
||||
cls.response_model: MODEL_TYPE = response_model
|
||||
|
||||
if not isinstance(cls.result, list):
|
||||
raise Exception("Invalid data type 4 list json response")
|
||||
pagination = Pagination()
|
||||
pagination.change(page=1)
|
||||
data = list(cls.result)
|
||||
if cls.response_model:
|
||||
data = [cls.response_model(**data_object).dump() for data_object in cls.result]
|
||||
pagination.feed(data)
|
||||
return JSONResponse(
|
||||
status_code=cls.status_code,
|
||||
content=dict(
|
||||
pagination=pagination.as_dict(),
|
||||
completed=cls.completed,
|
||||
message=cls.message,
|
||||
data=cls.result,
|
||||
),
|
||||
)
|
||||
|
||||
first_item = getattr(cls.result, "data", None)
|
||||
if not first_item:
|
||||
return JSONResponse(
|
||||
status_code=cls.status_code,
|
||||
content=dict(
|
||||
total_count=0,
|
||||
count=0,
|
||||
pagination=pagination_dict,
|
||||
completed=cls.completed,
|
||||
message=cls.message,
|
||||
data=[],
|
||||
),
|
||||
)
|
||||
class DictJsonResponse:
|
||||
status_code = "HTTP_200_OK"
|
||||
result: dict
|
||||
message: str
|
||||
completed: bool
|
||||
filter_attributes: Any
|
||||
response_model: MODEL_TYPE = None,
|
||||
cls_object: Any = None,
|
||||
|
||||
if cls.result.first:
|
||||
return JSONResponse(
|
||||
status_code=cls.status_code,
|
||||
content=dict(
|
||||
total_count=1,
|
||||
count=1,
|
||||
pagination=pagination_dict,
|
||||
completed=cls.completed,
|
||||
message=cls.message,
|
||||
data=cls.result.data.get_dict(),
|
||||
),
|
||||
)
|
||||
def __new__(
|
||||
cls,
|
||||
message: str,
|
||||
status_code: str = "HTTP_200_OK",
|
||||
result: Union[BaseModelRegular, BaseModel, PydanticBaseModel] = None,
|
||||
completed: bool = True,
|
||||
response_model: MODEL_TYPE = None,
|
||||
cls_object: Any = None,
|
||||
filter_attributes: Any = None,
|
||||
):
|
||||
cls.status_code = getattr(status, status_code, "HTTP_200_OK")
|
||||
cls.message = message
|
||||
cls.result = result
|
||||
cls.completed = completed
|
||||
cls.filter_attributes = filter_attributes
|
||||
cls.response_model: MODEL_TYPE = response_model
|
||||
|
||||
if not cls.result.get(1).filter_attr and isinstance(cls.result.data, list):
|
||||
counts = cls.result.count
|
||||
return JSONResponse(
|
||||
status_code=cls.status_code,
|
||||
content=dict(
|
||||
total_count=counts,
|
||||
count=counts,
|
||||
pagination=pagination_dict,
|
||||
completed=cls.completed,
|
||||
message=cls.message,
|
||||
data=[result_data.get_dict() for result_data in cls.result.data],
|
||||
),
|
||||
)
|
||||
if not isinstance(cls.result, dict):
|
||||
raise Exception("Invalid data type 4 dict json response")
|
||||
|
||||
# filter_model = cls.result.get(1).filter_attr
|
||||
total_count = cls.result.get(1).query.limit(None).offset(None).count()
|
||||
total_page_number = cls.get_total_count(cls_object, filter_attributes)
|
||||
pagination_dict = {
|
||||
"size/total_count": [filter_attributes.size, cls_object.total_count],
|
||||
"page/total_page": [filter_attributes.page, total_page_number],
|
||||
"order_field": filter_attributes.order_field,
|
||||
"order_type": filter_attributes.order_type,
|
||||
}
|
||||
include_joins = dict(
|
||||
include_joins=(
|
||||
filter_attributes.include_joins
|
||||
if filter_attributes.include_joins
|
||||
else []
|
||||
)
|
||||
)
|
||||
data = []
|
||||
for data_object in cls.result.data:
|
||||
data_dict = data_object.get_dict(include_joins=include_joins)
|
||||
pagination = Pagination()
|
||||
pagination.change(page=1)
|
||||
data = cls.result
|
||||
if cls.response_model:
|
||||
data_dict = cls.response_model(
|
||||
**data_object.get_dict(include_joins=include_joins)
|
||||
).dump()
|
||||
data.append(data_dict)
|
||||
data = cls.response_model(**cls.result).dump()
|
||||
return JSONResponse(
|
||||
status_code=cls.status_code,
|
||||
content=dict(
|
||||
total_count=total_count or 1,
|
||||
count=cls.result.count,
|
||||
pagination=pagination_dict,
|
||||
message=cls.message,
|
||||
pagination=pagination.as_dict(),
|
||||
completed=cls.completed,
|
||||
message=cls.message,
|
||||
data=data,
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -13,6 +13,12 @@ services:
|
|||
- auth_venv:/service_app/.venv
|
||||
- auth_logs:/service_app/logs
|
||||
|
||||
# wag_management_init_service:
|
||||
# container_name: wag_management_init_service
|
||||
# build:
|
||||
# context: .
|
||||
# dockerfile: service_app_init/Dockerfile
|
||||
|
||||
# wag_management_event_service:
|
||||
# container_name: wag_management_event_service
|
||||
# # restart: on-failure
|
||||
|
|
@ -41,11 +47,7 @@ services:
|
|||
# - validation_venv:/service_app/.venv
|
||||
# - validation_logs:/service_app/logs
|
||||
|
||||
# wag_management_init_service:
|
||||
# container_name: wag_management_init_service
|
||||
# build:
|
||||
# context: .
|
||||
# dockerfile: service_app_init/Dockerfile
|
||||
|
||||
|
||||
volumes:
|
||||
auth_venv:
|
||||
|
|
|
|||
|
|
@ -14,20 +14,6 @@ from api_events.events.address.address import (
|
|||
AddressPostCodeUpdateEventMethod,
|
||||
AddressPostCodeListEventMethod,
|
||||
)
|
||||
from api_events.events.application.authentication import (
|
||||
AuthenticationLoginEventMethod,
|
||||
AuthenticationSelectEventMethod,
|
||||
AuthenticationCheckTokenEventMethod,
|
||||
AuthenticationRefreshEventMethod,
|
||||
AuthenticationChangePasswordEventMethod,
|
||||
AuthenticationCreatePasswordEventMethod,
|
||||
AuthenticationResetPasswordEventMethod,
|
||||
AuthenticationDisconnectUserEventMethod,
|
||||
AuthenticationLogoutEventMethod,
|
||||
AuthenticationRefreshTokenEventMethod,
|
||||
AuthenticationForgotPasswordEventMethod,
|
||||
AuthenticationDownloadAvatarEventMethod,
|
||||
)
|
||||
from api_events.events.account.account_records import (
|
||||
AccountRecordsListEventMethod,
|
||||
AccountRecordsCreateEventMethod,
|
||||
|
|
@ -184,18 +170,6 @@ __all__ = [
|
|||
"PeopleUpdateEventMethod",
|
||||
"PeoplePatchEventMethod",
|
||||
"PeopleCreateEventMethod",
|
||||
"AuthenticationLoginEventMethod",
|
||||
"AuthenticationSelectEventMethod",
|
||||
"AuthenticationCheckTokenEventMethod",
|
||||
"AuthenticationRefreshEventMethod",
|
||||
"AuthenticationChangePasswordEventMethod",
|
||||
"AuthenticationCreatePasswordEventMethod",
|
||||
"AuthenticationResetPasswordEventMethod",
|
||||
"AuthenticationDisconnectUserEventMethod",
|
||||
"AuthenticationLogoutEventMethod",
|
||||
"AuthenticationRefreshTokenEventMethod",
|
||||
"AuthenticationForgotPasswordEventMethod",
|
||||
"AuthenticationDownloadAvatarEventMethod",
|
||||
"AccountRecordsListEventMethod",
|
||||
"AccountRecordsCreateEventMethod",
|
||||
"AccountRecordsUpdateEventMethod",
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ class AccountRecordsListEventMethods(MethodToEvent):
|
|||
token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject],
|
||||
):
|
||||
if not isinstance(token_dict, OccupantTokenObject):
|
||||
raise AccountRecords().raise_http_exception(
|
||||
raise AccountRecords.raise_http_exception(
|
||||
status_code="HTTP_404_NOT_FOUND",
|
||||
error_case="UNAUTHORIZED",
|
||||
message="Only Occupant can see this data",
|
||||
|
|
@ -76,7 +76,7 @@ class AccountRecordsListEventMethods(MethodToEvent):
|
|||
id=token_dict.selected_occupant.living_space_id
|
||||
).data
|
||||
if not living_space:
|
||||
raise AccountRecords().raise_http_exception(
|
||||
raise AccountRecords.raise_http_exception(
|
||||
status_code="HTTP_404_NOT_FOUND",
|
||||
error_case="UNAUTHORIZED",
|
||||
message="Living space not found",
|
||||
|
|
@ -214,7 +214,7 @@ class AccountRecordsCreateEventMethods(MethodToEvent):
|
|||
BuildIbans.build_id == token_dict.selected_occupant.build_id,
|
||||
).data
|
||||
if not build_iban:
|
||||
BuildIbans.raise_http_exception(
|
||||
raise BuildIbans.raise_http_exception(
|
||||
status_code="HTTP_404_NOT_FOUND",
|
||||
error_case="UNAUTHORIZED",
|
||||
message=f"{data.iban} is not found in company related to your organization",
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
from api_events.events.abstract_class import MethodToEvent, ActionsSchema
|
||||
from api_objects.auth.token_objects import EmployeeTokenObject, OccupantTokenObject
|
||||
|
||||
|
||||
class DecisionBookEvents(MethodToEvent): ...
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
from api_events.events.abstract_class import MethodToEvent, ActionsSchema
|
||||
from api_objects.auth.token_objects import EmployeeTokenObject, OccupantTokenObject
|
||||
|
||||
|
||||
class ApplicationEvents(MethodToEvent): ...
|
||||
|
|
@ -1,750 +0,0 @@
|
|||
import json
|
||||
from typing import Union
|
||||
from fastapi import status
|
||||
from fastapi.requests import Request
|
||||
from fastapi.exceptions import HTTPException
|
||||
|
||||
from api_objects import OccupantTokenObject, EmployeeTokenObject
|
||||
from api_objects.auth.token_objects import CompanyToken, OccupantToken
|
||||
from api_services.templates.password_templates import (
|
||||
password_is_changed_template,
|
||||
change_your_password_template,
|
||||
)
|
||||
from api_services.token_service import TokenService
|
||||
from api_services.redis.functions import RedisActions
|
||||
from api_library.response_handlers import ResponseHandler
|
||||
from api_library.date_time_actions.date_functions import system_arrow
|
||||
|
||||
# from api_library.user_logger import UserLogger
|
||||
|
||||
from api_validations.validations_request import (
|
||||
Login,
|
||||
Logout,
|
||||
ChangePassword,
|
||||
EmployeeSelection,
|
||||
OccupantSelection,
|
||||
CreatePassword,
|
||||
Forgot,
|
||||
# ResetPassword,
|
||||
# RefreshToken,
|
||||
)
|
||||
from api_validations.validations_response import (
|
||||
AuthenticationLoginResponse,
|
||||
AuthenticationRefreshResponse,
|
||||
AuthenticationUserInfoResponse,
|
||||
)
|
||||
from ApiServices.api_handlers.auth_actions.auth import AuthActions
|
||||
from api_configs import Auth, ApiStatic
|
||||
from api_events.events.abstract_class import MethodToEvent, ActionsSchema
|
||||
|
||||
from databases import (
|
||||
Companies,
|
||||
Staff,
|
||||
Duties,
|
||||
Departments,
|
||||
Employees,
|
||||
BuildLivingSpace,
|
||||
BuildParts,
|
||||
Build,
|
||||
Duty,
|
||||
Event2Occupant,
|
||||
Event2Employee,
|
||||
Users,
|
||||
UsersTokens,
|
||||
OccupantTypes,
|
||||
RelationshipEmployee2Build,
|
||||
)
|
||||
|
||||
from api_services import (
|
||||
send_email,
|
||||
)
|
||||
|
||||
|
||||
class AuthenticationLoginEventMethods(MethodToEvent):
|
||||
event_type = "LOGIN"
|
||||
event_description = "Login via domain and access key : [email] | [phone]"
|
||||
event_category = "AUTHENTICATION"
|
||||
|
||||
__event_keys__ = {
|
||||
"e672846d-cc45-4d97-85d5-6f96747fac67": "authentication_login_with_domain_and_creds",
|
||||
}
|
||||
__event_validation__ = {
|
||||
"e672846d-cc45-4d97-85d5-6f96747fac67": AuthenticationLoginResponse,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def authentication_login_with_domain_and_creds(cls, data: Login, request: Request):
|
||||
try:
|
||||
access_dict = Users.login_user_with_credentials(data=data, request=request)
|
||||
found_user = access_dict.get("user")
|
||||
if not found_user:
|
||||
# UserLogger.log_login_attempt(
|
||||
# request,
|
||||
# None,
|
||||
# data.domain,
|
||||
# data.access_key,
|
||||
# success=False,
|
||||
# error="Invalid credentials",
|
||||
# )
|
||||
return ResponseHandler.unauthorized("Invalid credentials")
|
||||
|
||||
# UserLogger.log_login_attempt(
|
||||
# request, found_user.id, data.domain, data.access_key, success=True
|
||||
# )
|
||||
response_data = {
|
||||
"access_token": access_dict.get("access_token"),
|
||||
"refresh_token": access_dict.get("refresher_token"),
|
||||
"access_object": access_dict.get("access_object"),
|
||||
"user": found_user.get_dict(),
|
||||
}
|
||||
return ResponseHandler.success(
|
||||
message="User logged in successfully",
|
||||
data=response_data,
|
||||
)
|
||||
except Exception as e:
|
||||
# UserLogger.log_login_attempt(
|
||||
# request, None, data.domain, data.access_key, success=False, error=str(e)
|
||||
# )
|
||||
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=str(e))
|
||||
|
||||
|
||||
class AuthenticationSelectEventMethods(MethodToEvent):
|
||||
event_type = "LOGIN"
|
||||
event_description = "Select Employee Duty or Occupant Type"
|
||||
event_category = "AUTHENTICATION"
|
||||
|
||||
__event_keys__ = {
|
||||
"cee96b9b-8487-4e9f-aaed-2e8c79687bf9": "authentication_select_company_or_occupant_type",
|
||||
}
|
||||
__event_validation__ = {
|
||||
"cee96b9b-8487-4e9f-aaed-2e8c79687bf9": "authentication_select_company_or_occupant_type",
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def _handle_employee_selection(
|
||||
cls, data: EmployeeSelection, token_dict: EmployeeTokenObject, request: Request
|
||||
):
|
||||
"""Handle employee company selection"""
|
||||
if data.company_uu_id not in token_dict.companies_uu_id_list:
|
||||
return ResponseHandler.unauthorized(
|
||||
"Company not found in user's company list"
|
||||
)
|
||||
|
||||
selected_company = Companies.filter_one(
|
||||
Companies.uu_id == data.company_uu_id
|
||||
).data
|
||||
if not selected_company:
|
||||
return ResponseHandler.not_found("Company not found")
|
||||
|
||||
# Get department IDs for the company
|
||||
department_ids = [
|
||||
dept.id
|
||||
for dept in Departments.filter_all(
|
||||
Departments.company_id == selected_company.id
|
||||
).data
|
||||
]
|
||||
|
||||
# Get duties IDs for the company
|
||||
duties_ids = [
|
||||
duty.id
|
||||
for duty in Duties.filter_all(Duties.company_id == selected_company.id).data
|
||||
]
|
||||
|
||||
# Get staff IDs
|
||||
staff_ids = [
|
||||
staff.id for staff in Staff.filter_all(Staff.duties_id.in_(duties_ids)).data
|
||||
]
|
||||
|
||||
# Get employee
|
||||
employee = Employees.filter_one(
|
||||
Employees.people_id == token_dict.person_id,
|
||||
Employees.staff_id.in_(staff_ids),
|
||||
).data
|
||||
|
||||
if not employee:
|
||||
return ResponseHandler.not_found("Employee not found")
|
||||
|
||||
# Get reachable events
|
||||
reachable_event_list_id = Event2Employee.get_event_id_by_employee_id(
|
||||
employee_id=employee.id
|
||||
)
|
||||
|
||||
# Get staff and duties
|
||||
staff = Staff.filter_one(Staff.id == employee.staff_id).data
|
||||
duties = Duties.filter_one(Duties.id == staff.duties_id).data
|
||||
department = Departments.filter_one(Departments.id == duties.department_id).data
|
||||
|
||||
# Get bulk duty
|
||||
bulk_id = Duty.filter_by_one(system=True, duty_code="BULK").data
|
||||
bulk_duty_id = Duties.filter_by_one(
|
||||
company_id=selected_company.id,
|
||||
duties_id=bulk_id.id,
|
||||
**Duties.valid_record_dict,
|
||||
).data
|
||||
|
||||
# Create company token
|
||||
company_token = CompanyToken(
|
||||
company_uu_id=selected_company.uu_id.__str__(),
|
||||
company_id=selected_company.id,
|
||||
department_id=department.id,
|
||||
department_uu_id=department.uu_id.__str__(),
|
||||
duty_id=duties.id,
|
||||
duty_uu_id=duties.uu_id.__str__(),
|
||||
bulk_duties_id=bulk_duty_id.id,
|
||||
staff_id=staff.id,
|
||||
staff_uu_id=staff.uu_id.__str__(),
|
||||
employee_id=employee.id,
|
||||
employee_uu_id=employee.uu_id.__str__(),
|
||||
reachable_event_list_id=reachable_event_list_id,
|
||||
)
|
||||
|
||||
# Update Redis
|
||||
AuthActions.update_selected_to_redis(request=request, add_payload=company_token)
|
||||
return ResponseHandler.success("Company selected successfully")
|
||||
|
||||
@classmethod
|
||||
def _handle_occupant_selection(
|
||||
cls, data: OccupantSelection, token_dict: OccupantTokenObject, request: Request
|
||||
):
|
||||
"""Handle occupant type selection"""
|
||||
# Get occupant type
|
||||
occupant_type = OccupantTypes.filter_by_one(
|
||||
system=True, uu_id=data.occupant_uu_id
|
||||
).data
|
||||
if not occupant_type:
|
||||
return ResponseHandler.not_found("Occupant Type not found")
|
||||
|
||||
# Get build part
|
||||
build_part = BuildParts.filter_by_one(
|
||||
system=True, uu_id=data.build_part_uu_id
|
||||
).data
|
||||
if not build_part:
|
||||
return ResponseHandler.not_found("Build Part not found")
|
||||
|
||||
# Get build and company info
|
||||
build = Build.filter_one(Build.id == build_part.build_id).data
|
||||
related_company = RelationshipEmployee2Build.filter_one(
|
||||
RelationshipEmployee2Build.member_id == build.id
|
||||
).data
|
||||
company_related = Companies.filter_one(
|
||||
Companies.id == related_company.company_id
|
||||
).data
|
||||
responsible_employee = Employees.filter_one(
|
||||
Employees.id == related_company.employee_id
|
||||
).data
|
||||
|
||||
# Get selected occupant type
|
||||
selected_occupant_type = BuildLivingSpace.filter_one(
|
||||
BuildLivingSpace.occupant_type == occupant_type.id,
|
||||
BuildLivingSpace.person_id == token_dict.person_id,
|
||||
BuildLivingSpace.build_parts_id == build_part.id,
|
||||
).data
|
||||
if not selected_occupant_type:
|
||||
return ResponseHandler.not_found("Selected occupant type not found")
|
||||
|
||||
# Get reachable events
|
||||
reachable_event_list_id = Event2Occupant.get_event_id_by_build_living_space_id(
|
||||
build_living_space_id=selected_occupant_type.id
|
||||
)
|
||||
|
||||
# Create occupant token
|
||||
occupant_token = OccupantToken(
|
||||
living_space_id=selected_occupant_type.id,
|
||||
living_space_uu_id=selected_occupant_type.uu_id.__str__(),
|
||||
occupant_type_id=occupant_type.id,
|
||||
occupant_type_uu_id=occupant_type.uu_id.__str__(),
|
||||
occupant_type=occupant_type.occupant_type,
|
||||
build_id=build.id,
|
||||
build_uuid=build.uu_id.__str__(),
|
||||
build_part_id=build_part.id,
|
||||
build_part_uuid=build_part.uu_id.__str__(),
|
||||
responsible_employee_id=responsible_employee.id,
|
||||
responsible_employee_uuid=responsible_employee.uu_id.__str__(),
|
||||
responsible_company_id=company_related.id,
|
||||
responsible_company_uuid=company_related.uu_id.__str__(),
|
||||
reachable_event_list_id=reachable_event_list_id,
|
||||
)
|
||||
|
||||
# Update Redis
|
||||
AuthActions.update_selected_to_redis(
|
||||
request=request, add_payload=occupant_token
|
||||
)
|
||||
return ResponseHandler.success("Occupant selected successfully")
|
||||
|
||||
@classmethod
|
||||
def authentication_select_company_or_occupant_type(
|
||||
cls,
|
||||
request: Request,
|
||||
data: Union[EmployeeSelection, OccupantSelection],
|
||||
token_dict: Union[EmployeeTokenObject, OccupantTokenObject],
|
||||
):
|
||||
"""Handle selection of company or occupant type"""
|
||||
try:
|
||||
if isinstance(token_dict, EmployeeTokenObject):
|
||||
return cls._handle_employee_selection(data, token_dict, request)
|
||||
elif isinstance(token_dict, OccupantTokenObject):
|
||||
return cls._handle_occupant_selection(data, token_dict, request)
|
||||
return ResponseHandler.error(
|
||||
"Invalid token type", status_code=status.HTTP_400_BAD_REQUEST
|
||||
)
|
||||
except Exception as e:
|
||||
return ResponseHandler.error(
|
||||
str(e), status_code=status.HTTP_500_INTERNAL_SERVER_ERROR
|
||||
)
|
||||
|
||||
|
||||
class AuthenticationCheckTokenEventMethods(MethodToEvent):
|
||||
event_type = "LOGIN"
|
||||
event_description = "Check Token is valid for user"
|
||||
event_category = "AUTHENTICATION"
|
||||
|
||||
__event_keys__ = {
|
||||
"73d77e45-a33f-4f12-909e-3b56f00d8a12": "authentication_check_token_is_valid",
|
||||
}
|
||||
__event_validation__ = {
|
||||
"73d77e45-a33f-4f12-909e-3b56f00d8a12": "authentication_check_token_is_valid",
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def authentication_check_token_is_valid(cls, request: Request):
|
||||
try:
|
||||
if RedisActions.get_object_via_access_key(request=request):
|
||||
return ResponseHandler.success("Access Token is valid")
|
||||
except HTTPException:
|
||||
return ResponseHandler.unauthorized("Access Token is NOT valid")
|
||||
|
||||
|
||||
class AuthenticationRefreshEventMethods(MethodToEvent):
|
||||
event_type = "LOGIN"
|
||||
event_description = "Refresh user info using access token"
|
||||
event_category = "AUTHENTICATION"
|
||||
|
||||
__event_keys__ = {
|
||||
"48379bb2-ba81-4d8e-a9dd-58837cfcbf67": "authentication_refresh_user_info",
|
||||
}
|
||||
__event_validation__ = {
|
||||
"48379bb2-ba81-4d8e-a9dd-58837cfcbf67": AuthenticationRefreshResponse,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def authentication_refresh_user_info(
|
||||
cls,
|
||||
request: Request,
|
||||
token_dict: Union[EmployeeTokenObject, OccupantTokenObject],
|
||||
):
|
||||
try:
|
||||
access_token = request.headers.get(Auth.ACCESS_TOKEN_TAG)
|
||||
if not access_token:
|
||||
return ResponseHandler.unauthorized()
|
||||
|
||||
# Get user and token info
|
||||
found_user = Users.filter_one(Users.uu_id == token_dict.user_uu_id).data
|
||||
if not found_user:
|
||||
return ResponseHandler.not_found("User not found")
|
||||
user_token = UsersTokens.filter_one(
|
||||
UsersTokens.domain == found_user.domain_name,
|
||||
UsersTokens.user_id == found_user.id,
|
||||
UsersTokens.token_type == "RememberMe",
|
||||
).data
|
||||
response_data = {
|
||||
"access_token": access_token,
|
||||
"refresh_token": getattr(user_token, "token", None),
|
||||
"user": found_user.get_dict(),
|
||||
}
|
||||
return ResponseHandler.success(
|
||||
"User info refreshed successfully",
|
||||
data=response_data,
|
||||
)
|
||||
except Exception as e:
|
||||
return ResponseHandler.error(str(e))
|
||||
|
||||
|
||||
class AuthenticationChangePasswordEventMethods(MethodToEvent):
|
||||
event_type = "LOGIN"
|
||||
event_description = "Change password with access token"
|
||||
event_category = "AUTHENTICATION"
|
||||
|
||||
__event_keys__ = {
|
||||
"f09f7c1a-bee6-4e32-8444-962ec8f39091": "authentication_change_password",
|
||||
}
|
||||
__event_validation__ = {
|
||||
"f09f7c1a-bee6-4e32-8444-962ec8f39091": "authentication_change_password",
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def authentication_change_password(
|
||||
cls,
|
||||
request: Request,
|
||||
data: ChangePassword,
|
||||
token_dict: Union[EmployeeTokenObject, OccupantTokenObject],
|
||||
):
|
||||
try:
|
||||
if not isinstance(token_dict, EmployeeTokenObject):
|
||||
return ResponseHandler.unauthorized(
|
||||
"Only employees can change password"
|
||||
)
|
||||
|
||||
found_user = Users.filter_one(Users.uu_id == token_dict.user_uu_id).data
|
||||
if not found_user:
|
||||
return ResponseHandler.not_found("User not found")
|
||||
|
||||
if not found_user.check_password(data.old_password):
|
||||
# UserLogger.log_password_change(
|
||||
# request,
|
||||
# found_user.id,
|
||||
# "change",
|
||||
# success=False,
|
||||
# error="Invalid old password",
|
||||
# )
|
||||
return ResponseHandler.unauthorized("Old password is incorrect")
|
||||
|
||||
found_user.set_password(data.new_password)
|
||||
# UserLogger.log_password_change(
|
||||
# request, found_user.id, "change", success=True
|
||||
# )
|
||||
|
||||
return ResponseHandler.success("Password changed successfully")
|
||||
except Exception as e:
|
||||
# UserLogger.log_password_change(
|
||||
# request,
|
||||
# found_user.id if found_user else None,
|
||||
# "change",
|
||||
# success=False,
|
||||
# error=str(e),
|
||||
# )
|
||||
return ResponseHandler.error(str(e))
|
||||
|
||||
|
||||
class AuthenticationCreatePasswordEventMethods(MethodToEvent):
|
||||
|
||||
event_type = "LOGIN"
|
||||
event_description = "Create password with password reset token requested via email"
|
||||
event_category = "AUTHENTICATION"
|
||||
|
||||
__event_keys__ = {
|
||||
"c519f9af-92e1-47b2-abf7-5a3316d075f7": "authentication_create_password",
|
||||
}
|
||||
__event_validation__ = {
|
||||
"c519f9af-92e1-47b2-abf7-5a3316d075f7": "authentication_create_password",
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def authentication_create_password(cls, data: CreatePassword):
|
||||
|
||||
if not data.re_password == data.password:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_406_NOT_ACCEPTABLE, detail="Password must match"
|
||||
)
|
||||
if found_user := Users.filter_one(
|
||||
Users.password_token == data.password_token
|
||||
).data:
|
||||
found_user.create_password(found_user=found_user, password=data.password)
|
||||
found_user.password_token = ""
|
||||
found_user.save()
|
||||
send_email_completed = send_email(
|
||||
subject=f"Dear {found_user.user_tag}, your password has been changed.",
|
||||
receivers=[str(found_user.email)],
|
||||
html=password_is_changed_template(user_name=found_user.user_tag),
|
||||
)
|
||||
if not send_email_completed:
|
||||
raise HTTPException(
|
||||
status_code=400, detail="Email can not be sent. Try again later"
|
||||
)
|
||||
return ResponseHandler.success(
|
||||
"Password is created successfully",
|
||||
data=found_user.get_dict(),
|
||||
)
|
||||
return ResponseHandler.not_found("Record not found")
|
||||
|
||||
|
||||
class AuthenticationDisconnectUserEventMethods(MethodToEvent):
|
||||
|
||||
event_type = "LOGIN"
|
||||
event_description = "Disconnect all sessions of user in access token"
|
||||
event_category = "AUTHENTICATION"
|
||||
|
||||
__event_keys__ = {
|
||||
"8b586848-2fb3-4161-abbe-642157eec7ce": "authentication_disconnect_user",
|
||||
}
|
||||
__event_validation__ = {
|
||||
"8b586848-2fb3-4161-abbe-642157eec7ce": "authentication_disconnect_user",
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def authentication_disconnect_user(
|
||||
cls, data: Logout, token_dict: Union[EmployeeTokenObject, OccupantTokenObject]
|
||||
):
|
||||
found_user = Users.filter_one(Users.uu_id == token_dict.user_uu_id).data
|
||||
if not found_user:
|
||||
return ResponseHandler.not_found("User not found")
|
||||
if already_tokens := RedisActions.get_object_via_user_uu_id(
|
||||
user_id=str(found_user.uu_id)
|
||||
):
|
||||
for key, token_user in already_tokens.items():
|
||||
RedisActions.delete(key)
|
||||
selected_user = Users.filter_one(
|
||||
Users.uu_id == token_user.get("uu_id"),
|
||||
).data
|
||||
selected_user.remove_refresher_token(
|
||||
domain=data.domain, disconnect=True
|
||||
)
|
||||
return ResponseHandler.success(
|
||||
"All sessions are disconnected",
|
||||
data=selected_user.get_dict(),
|
||||
)
|
||||
return ResponseHandler.not_found("Invalid data")
|
||||
|
||||
|
||||
class AuthenticationLogoutEventMethods(MethodToEvent):
|
||||
|
||||
event_type = "LOGIN"
|
||||
event_description = "Logout only single session of user which domain is provided"
|
||||
event_category = "AUTHENTICATION"
|
||||
|
||||
__event_keys__ = {
|
||||
"5cc22e4e-a0f7-4077-be41-1871feb3dfd1": "authentication_logout_user",
|
||||
}
|
||||
__event_validation__ = {
|
||||
"5cc22e4e-a0f7-4077-be41-1871feb3dfd1": "authentication_logout_user",
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def authentication_logout_user(
|
||||
cls, request: Request, data: Logout, token_dict: dict = None
|
||||
):
|
||||
token_user = None
|
||||
if already_tokens := RedisActions.get_object_via_access_key(request=request):
|
||||
for key in already_tokens:
|
||||
token_user = RedisActions.get_json(key)
|
||||
if token_user.get("domain") == data.domain:
|
||||
RedisActions.delete(key)
|
||||
selected_user = Users.filter_one(
|
||||
Users.uu_id == token_user.get("uu_id"),
|
||||
).data
|
||||
selected_user.remove_refresher_token(domain=data.domain)
|
||||
|
||||
return ResponseHandler.success(
|
||||
"Session is logged out",
|
||||
data=token_user,
|
||||
)
|
||||
return ResponseHandler.not_found("Logout is not successfully completed")
|
||||
|
||||
|
||||
class AuthenticationRefreshTokenEventMethods(MethodToEvent):
|
||||
|
||||
event_type = "LOGIN"
|
||||
event_description = "Refresh access token with refresher token"
|
||||
event_category = "AUTHENTICATION"
|
||||
|
||||
__event_keys__ = {
|
||||
"c90f3334-10c9-4181-b5ff-90d98a0287b2": "authentication_refresher_token",
|
||||
}
|
||||
__event_validation__ = {
|
||||
"c90f3334-10c9-4181-b5ff-90d98a0287b2": AuthenticationRefreshResponse,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def authentication_refresher_token(
|
||||
# cls, request: Request, data: RefreshToken, token_dict: dict = None
|
||||
cls,
|
||||
request: Request,
|
||||
data,
|
||||
token_dict: dict = None,
|
||||
):
|
||||
token_refresher = UsersTokens.filter_by_one(
|
||||
token=data.refresh_token,
|
||||
domain=data.domain,
|
||||
**UsersTokens.valid_record_dict,
|
||||
).data
|
||||
if not token_refresher:
|
||||
return ResponseHandler.not_found("Invalid data")
|
||||
if found_user := Users.filter_one(
|
||||
Users.id == token_refresher.user_id,
|
||||
).data:
|
||||
found_user: Users = found_user
|
||||
access_key = AuthActions.save_access_token_to_redis(
|
||||
request=request, found_user=found_user, domain=data.domain
|
||||
)
|
||||
found_user.last_agent = request.headers.get("User-Agent", None)
|
||||
found_user.last_platform = request.headers.get("Origin", None)
|
||||
found_user.last_remote_addr = getattr(
|
||||
request, "remote_addr", None
|
||||
) or request.headers.get("X-Forwarded-For", None)
|
||||
found_user.last_seen = str(system_arrow.now())
|
||||
response_data = {
|
||||
"access_token": access_key,
|
||||
"refresh_token": data.refresh_token,
|
||||
}
|
||||
return ResponseHandler.success(
|
||||
"User is logged in successfully via refresher token",
|
||||
data=response_data,
|
||||
)
|
||||
return ResponseHandler.not_found("Invalid data")
|
||||
|
||||
|
||||
class AuthenticationForgotPasswordEventMethods(MethodToEvent):
|
||||
|
||||
event_type = "LOGIN"
|
||||
event_description = "Send an email to user for a valid password reset token"
|
||||
event_category = "AUTHENTICATION"
|
||||
|
||||
__event_keys__ = {
|
||||
"e3ca6e24-b9f8-4127-949c-3bfa364e3513": "authentication_forgot_password",
|
||||
}
|
||||
__event_validation__ = {
|
||||
"e3ca6e24-b9f8-4127-949c-3bfa364e3513": "authentication_forgot_password",
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def authentication_forgot_password(
|
||||
cls,
|
||||
request: Request,
|
||||
data: Forgot,
|
||||
):
|
||||
found_user: Users = Users.check_user_exits(
|
||||
access_key=data.access_key, domain=data.domain
|
||||
)
|
||||
forgot_key = AuthActions.save_access_token_to_redis(
|
||||
request=request, found_user=found_user, domain=data.domain
|
||||
)
|
||||
forgot_link = ApiStatic.forgot_link(forgot_key=forgot_key)
|
||||
send_email_completed = send_email(
|
||||
subject=f"Dear {found_user.user_tag}, your forgot password link has been sent.",
|
||||
receivers=[str(found_user.email)],
|
||||
html=change_your_password_template(
|
||||
user_name=found_user.user_tag, forgot_link=forgot_link
|
||||
),
|
||||
)
|
||||
if not send_email_completed:
|
||||
raise HTTPException(
|
||||
status_code=400, detail="Email can not be sent. Try again later"
|
||||
)
|
||||
found_user.password_token = forgot_key
|
||||
found_user.password_token_is_valid = str(system_arrow.shift(days=1))
|
||||
found_user.save()
|
||||
|
||||
return ResponseHandler.success(
|
||||
"Password is change link is sent to your email or phone",
|
||||
data={},
|
||||
)
|
||||
|
||||
|
||||
class AuthenticationResetPasswordEventMethods(MethodToEvent):
|
||||
|
||||
event_type = "UPDATE"
|
||||
__event_keys__ = {
|
||||
"af9e121e-24bb-44ac-a616-471d5754360e": "authentication_reset_password",
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def authentication_reset_password(cls, data: Forgot):
|
||||
from sqlalchemy import or_
|
||||
|
||||
found_user = Users.query.filter(
|
||||
or_(
|
||||
Users.email == str(data.access_key).lower(),
|
||||
Users.phone_number == str(data.access_key).replace(" ", ""),
|
||||
),
|
||||
).first()
|
||||
if not found_user:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="Given access key or domain is not matching with the any user record.",
|
||||
)
|
||||
|
||||
reset_password_token = found_user.reset_password_token(found_user=found_user)
|
||||
send_email_completed = send_email(
|
||||
subject=f"Dear {found_user.user_tag}, a password reset request has been received.",
|
||||
receivers=[str(found_user.email)],
|
||||
html=change_your_password_template(
|
||||
user_name=found_user.user_tag,
|
||||
forgot_link=ApiStatic.forgot_link(forgot_key=reset_password_token),
|
||||
),
|
||||
)
|
||||
if not send_email_completed:
|
||||
raise found_user.raise_http_exception(
|
||||
status_code=400, message="Email can not be sent. Try again later"
|
||||
)
|
||||
return ResponseHandler.success(
|
||||
"Password change link is sent to your email or phone",
|
||||
data=found_user.get_dict(),
|
||||
)
|
||||
|
||||
|
||||
class AuthenticationDownloadAvatarEventMethods(MethodToEvent):
|
||||
|
||||
event_type = "LOGIN"
|
||||
event_description = "Download avatar icon and profile info of user"
|
||||
event_category = "AUTHENTICATION"
|
||||
|
||||
__event_keys__ = {
|
||||
"c140cd5f-307f-4046-a93e-3ade032a57a7": "authentication_download_avatar",
|
||||
}
|
||||
__event_validation__ = {
|
||||
"c140cd5f-307f-4046-a93e-3ade032a57a7": AuthenticationUserInfoResponse,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def authentication_download_avatar(
|
||||
cls, token_dict: Union[EmployeeTokenObject, OccupantTokenObject]
|
||||
):
|
||||
if found_user := Users.filter_one(Users.id == token_dict.user_id).data:
|
||||
expired_starts = str(
|
||||
system_arrow.now() - system_arrow.get(str(found_user.expiry_ends))
|
||||
)
|
||||
expired_int = (
|
||||
system_arrow.now() - system_arrow.get(str(found_user.expiry_ends))
|
||||
).days
|
||||
|
||||
user_info = {
|
||||
"lang": token_dict.lang,
|
||||
"full_name": found_user.person.full_name,
|
||||
"avatar": found_user.avatar,
|
||||
"remember_me": found_user.remember_me,
|
||||
"expiry_ends": str(found_user.expiry_ends),
|
||||
"expired_str": expired_starts,
|
||||
"expired_int": int(expired_int),
|
||||
}
|
||||
return ResponseHandler.success(
|
||||
"Avatar and profile is shared via user credentials",
|
||||
data=user_info,
|
||||
)
|
||||
return ResponseHandler.not_found("Invalid data")
|
||||
|
||||
|
||||
AuthenticationLoginEventMethod = AuthenticationLoginEventMethods(
|
||||
action=ActionsSchema(endpoint="/authentication/login")
|
||||
)
|
||||
AuthenticationSelectEventMethod = AuthenticationSelectEventMethods(
|
||||
action=ActionsSchema(endpoint="/authentication/select")
|
||||
)
|
||||
AuthenticationCheckTokenEventMethod = AuthenticationCheckTokenEventMethods(
|
||||
action=ActionsSchema(endpoint="/authentication/valid")
|
||||
)
|
||||
AuthenticationRefreshEventMethod = AuthenticationRefreshEventMethods(
|
||||
action=ActionsSchema(endpoint="/authentication/refresh")
|
||||
)
|
||||
AuthenticationChangePasswordEventMethod = AuthenticationChangePasswordEventMethods(
|
||||
action=ActionsSchema(endpoint="/authentication/change_password")
|
||||
)
|
||||
AuthenticationCreatePasswordEventMethod = AuthenticationCreatePasswordEventMethods(
|
||||
action=ActionsSchema(endpoint="/authentication/create_password")
|
||||
)
|
||||
AuthenticationDisconnectUserEventMethod = AuthenticationDisconnectUserEventMethods(
|
||||
action=ActionsSchema(endpoint="/authentication/disconnect")
|
||||
)
|
||||
AuthenticationLogoutEventMethod = AuthenticationLogoutEventMethods(
|
||||
action=ActionsSchema(endpoint="/authentication/logout")
|
||||
)
|
||||
AuthenticationRefreshTokenEventMethod = AuthenticationRefreshTokenEventMethods(
|
||||
action=ActionsSchema(endpoint="/authentication/refresher")
|
||||
)
|
||||
AuthenticationForgotPasswordEventMethod = AuthenticationForgotPasswordEventMethods(
|
||||
action=ActionsSchema(endpoint="/authentication/forgot")
|
||||
)
|
||||
AuthenticationDownloadAvatarEventMethod = AuthenticationDownloadAvatarEventMethods(
|
||||
action=ActionsSchema(endpoint="/authentication/avatar")
|
||||
)
|
||||
AuthenticationResetPasswordEventMethod = AuthenticationResetPasswordEventMethods(
|
||||
action=ActionsSchema(endpoint="/authentication/reset_password")
|
||||
)
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
from api_events.events.abstract_class import MethodToEvent, ActionsSchema
|
||||
from api_objects.auth.token_objects import EmployeeTokenObject, OccupantTokenObject
|
||||
|
||||
|
||||
class RulesEvents(MethodToEvent): ...
|
||||
|
|
@ -80,7 +80,7 @@ class BuildAreaCreateEventMethods(MethodToEvent):
|
|||
selected_build = None
|
||||
if isinstance(token_dict, OccupantTokenObject):
|
||||
if not token_dict.selected_occupant.build_uuid == data.build_uu_id:
|
||||
BuildArea.raise_http_exception(
|
||||
raise BuildArea.raise_http_exception(
|
||||
status_code="HTTP_403_FORBIDDEN",
|
||||
error_case="UNAUTHORIZED",
|
||||
message=f"Occupant can not create build area for {data.build_uu_id}",
|
||||
|
|
@ -96,7 +96,7 @@ class BuildAreaCreateEventMethods(MethodToEvent):
|
|||
employee_id=token_dict.selected_company.employee_id
|
||||
).all()
|
||||
if not str(data.build_uu_id) in [str(build.uu_id) for build in build_ids]:
|
||||
BuildArea.raise_http_exception(
|
||||
raise BuildArea.raise_http_exception(
|
||||
status_code="HTTP_403_FORBIDDEN",
|
||||
error_case="UNAUTHORIZED",
|
||||
message=f"Employee can not create build area for {data.build_uu_id}",
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ class BuildSitesListEventMethods(MethodToEvent):
|
|||
)
|
||||
employees_build_list = [build.address_id for build in employees_build.all()]
|
||||
if not employees_build_list:
|
||||
BuildSites.raise_http_exception(
|
||||
raise BuildSites.raise_http_exception(
|
||||
status_code="HTTP_404_NOT_FOUND",
|
||||
error_case="NOT_FOUND",
|
||||
message="Employee has no build sites registered",
|
||||
|
|
@ -86,7 +86,7 @@ class BuildSitesCreateEventMethods(MethodToEvent):
|
|||
):
|
||||
if isinstance(token_dict, OccupantTokenObject):
|
||||
if not token_dict.selected_occupant.build_uuid == data.build_uu_id:
|
||||
BuildSites.raise_http_exception(
|
||||
raise BuildSites.raise_http_exception(
|
||||
status_code="HTTP_403_FORBIDDEN",
|
||||
error_case="UNAUTHORIZED",
|
||||
message=f"Occupant can not create build sites for {data.build_uu_id}",
|
||||
|
|
@ -99,7 +99,7 @@ class BuildSitesCreateEventMethods(MethodToEvent):
|
|||
employee_id=token_dict.selected_company.employee_id
|
||||
).all()
|
||||
if not str(data.build_uu_id) in [str(build.uu_id) for build in build_ids]:
|
||||
BuildSites.raise_http_exception(
|
||||
raise BuildSites.raise_http_exception(
|
||||
status_code="HTTP_403_FORBIDDEN",
|
||||
error_case="UNAUTHORIZED",
|
||||
message=f"Employee can not create build sites for {data.build_uu_id}",
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ class BuildingLivingSpacesListEventMethods(MethodToEvent):
|
|||
Build.id == token_dict.selected_occupant.build_id,
|
||||
).data
|
||||
if not occupants_build_id:
|
||||
Build.raise_http_exception(
|
||||
raise Build.raise_http_exception(
|
||||
status_code="HTTP_403_FORBIDDEN",
|
||||
error_case="UNAUTHORIZED",
|
||||
message=f"Occupant has no build registered in the system. Contact with your company.",
|
||||
|
|
@ -57,7 +57,7 @@ class BuildingLivingSpacesListEventMethods(MethodToEvent):
|
|||
BuildParts.build_id.in_(occupants_build_id.id),
|
||||
).data
|
||||
if not occupants_build_parts:
|
||||
Build.raise_http_exception(
|
||||
raise Build.raise_http_exception(
|
||||
status_code="HTTP_403_FORBIDDEN",
|
||||
error_case="UNAUTHORIZED",
|
||||
message=f"Occupant has no build parts registered in the system. Contact with your company.",
|
||||
|
|
@ -80,7 +80,7 @@ class BuildingLivingSpacesListEventMethods(MethodToEvent):
|
|||
employee_id=token_dict.selected_company.employee_id
|
||||
)
|
||||
if not build_id_list_query:
|
||||
Build.raise_http_exception(
|
||||
raise Build.raise_http_exception(
|
||||
status_code="HTTP_403_FORBIDDEN",
|
||||
error_case="UNAUTHORIZED",
|
||||
message=f"Employee has no build registered in the system. Contact with your supervisor.",
|
||||
|
|
@ -92,7 +92,7 @@ class BuildingLivingSpacesListEventMethods(MethodToEvent):
|
|||
),
|
||||
).data
|
||||
if not build_part_id_list_query:
|
||||
Build.raise_http_exception(
|
||||
raise Build.raise_http_exception(
|
||||
status_code="HTTP_403_FORBIDDEN",
|
||||
error_case="UNAUTHORIZED",
|
||||
message=f"Employee has no build parts registered in the system. Contact with your supervisor.",
|
||||
|
|
@ -142,7 +142,7 @@ class BuildingLivingSpacesCreateEventMethods(MethodToEvent):
|
|||
BuildParts.build_id.in_([build.id for build in build_id_list_query.all()]),
|
||||
).data
|
||||
if not build_part:
|
||||
BuildLivingSpace.raise_http_exception(
|
||||
raise BuildLivingSpace.raise_http_exception(
|
||||
status_code="HTTP_404_NOT_FOUND",
|
||||
error_case="UNAUTHORIZED",
|
||||
message=f"{data.build_parts_uu_id} - Build Part is not found in database. Check build part uu_id",
|
||||
|
|
@ -154,7 +154,7 @@ class BuildingLivingSpacesCreateEventMethods(MethodToEvent):
|
|||
People.uu_id == data.person_uu_id,
|
||||
).data
|
||||
if not life_person:
|
||||
BuildLivingSpace.raise_http_exception(
|
||||
raise BuildLivingSpace.raise_http_exception(
|
||||
status_code="HTTP_404_NOT_FOUND",
|
||||
error_case="UNAUTHORIZED",
|
||||
message=f"{data.person_uu_id} - Living Person is not found in database.",
|
||||
|
|
@ -164,7 +164,7 @@ class BuildingLivingSpacesCreateEventMethods(MethodToEvent):
|
|||
)
|
||||
occupant_type = OccupantTypes.filter_by_one(uu_id=data.occupant_type_uu_id).data
|
||||
if not occupant_type:
|
||||
BuildLivingSpace.raise_http_exception(
|
||||
raise BuildLivingSpace.raise_http_exception(
|
||||
status_code="HTTP_404_NOT_FOUND",
|
||||
error_case="UNAUTHORIZED",
|
||||
message=f"{data.occupant_type_uu_id} - Occupant Type is not found in database. Check occupant type uu_id",
|
||||
|
|
@ -252,7 +252,7 @@ class BuildingLivingSpacesUpdateEventMethods(MethodToEvent):
|
|||
),
|
||||
).data
|
||||
if not build_part:
|
||||
BuildLivingSpace.raise_http_exception(
|
||||
raise BuildLivingSpace.raise_http_exception(
|
||||
status_code="HTTP_403_FORBIDDEN",
|
||||
error_case="UNAUTHORIZED",
|
||||
message=f"{data.life_person_uu_id} - Living Person is not found in database.",
|
||||
|
|
@ -264,7 +264,7 @@ class BuildingLivingSpacesUpdateEventMethods(MethodToEvent):
|
|||
People.uu_id == data.life_person_uu_id or ""
|
||||
).data
|
||||
if not life_person:
|
||||
BuildLivingSpace.raise_http_exception(
|
||||
raise BuildLivingSpace.raise_http_exception(
|
||||
status_code="HTTP_403_FORBIDDEN",
|
||||
error_case="UNAUTHORIZED",
|
||||
message=f"{data.life_person_uu_id} - Living Person is not found in database.",
|
||||
|
|
@ -290,7 +290,7 @@ class BuildingLivingSpacesUpdateEventMethods(MethodToEvent):
|
|||
if data_dict["is_tenant_live"]:
|
||||
owner_person = getattr(last_living_space, "owner_person_id", None)
|
||||
if not owner_person:
|
||||
BuildLivingSpace.raise_http_exception(
|
||||
raise BuildLivingSpace.raise_http_exception(
|
||||
status_code="HTTP_403_FORBIDDEN",
|
||||
error_case="UNAUTHORIZED",
|
||||
message="Owner person of build part is not defined. Please register owner of part first.",
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ from api_objects.auth.token_objects import (
|
|||
OccupantToken,
|
||||
ApplicationToken,
|
||||
)
|
||||
from api_objects.errors.errorHandlers import HTTPExceptionEvyos
|
||||
|
||||
__all__ = [
|
||||
"OccupantTokenObject",
|
||||
|
|
@ -14,4 +15,5 @@ __all__ = [
|
|||
"CompanyToken",
|
||||
"OccupantToken",
|
||||
"ApplicationToken",
|
||||
"HTTPExceptionEvyos",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ class ApplicationToken(BaseModel):
|
|||
|
||||
domain: Optional[str] = "app.evyos.com.tr"
|
||||
lang: Optional[str] = "TR"
|
||||
timezone: Optional[str] = "Europe/Istanbul"
|
||||
timezone: Optional[str] = "GMT+3"
|
||||
|
||||
user_type: int = UserType.occupant.value
|
||||
credentials: dict = None
|
||||
|
|
|
|||
|
|
@ -1,74 +1,6 @@
|
|||
from .errors_dictionary import ErrorMessages
|
||||
|
||||
|
||||
class AlchemyError:
|
||||
ERRORS_DICT = {
|
||||
"100": "HTTP_100_CONTINUE",
|
||||
"101": "HTTP_101_SWITCHING_PROTOCOLS",
|
||||
"102": "HTTP_102_PROCESSING",
|
||||
"103": "HTTP_103_EARLY_HINTS",
|
||||
"200": "HTTP_200_OK",
|
||||
"201": "HTTP_201_CREATED",
|
||||
"202": "HTTP_202_ACCEPTED",
|
||||
"203": "HTTP_203_NON_AUTHORITATIVE_INFORMATION",
|
||||
"204": "HTTP_204_NO_CONTENT",
|
||||
"205": "HTTP_205_RESET_CONTENT",
|
||||
"206": "HTTP_206_PARTIAL_CONTENT",
|
||||
"207": "HTTP_207_MULTI_STATUS",
|
||||
"208": "HTTP_208_ALREADY_REPORTED",
|
||||
"226": "HTTP_226_IM_USED",
|
||||
"300": "HTTP_300_MULTIPLE_CHOICES",
|
||||
"301": "HTTP_301_MOVED_PERMANENTLY",
|
||||
"302": "HTTP_302_FOUND",
|
||||
"303": "HTTP_303_SEE_OTHER",
|
||||
"304": "HTTP_304_NOT_MODIFIED",
|
||||
"305": "HTTP_305_USE_PROXY",
|
||||
"306": "HTTP_306_RESERVED",
|
||||
"307": "HTTP_307_TEMPORARY_REDIRECT",
|
||||
"308": "HTTP_308_PERMANENT_REDIRECT",
|
||||
"400": "HTTP_400_BAD_REQUEST",
|
||||
"401": "HTTP_401_UNAUTHORIZED",
|
||||
"402": "HTTP_402_PAYMENT_REQUIRED",
|
||||
"403": "HTTP_403_FORBIDDEN",
|
||||
"404": "HTTP_404_NOT_FOUND",
|
||||
"405": "HTTP_405_METHOD_NOT_ALLOWED",
|
||||
"406": "HTTP_406_NOT_ACCEPTABLE",
|
||||
"407": "HTTP_407_PROXY_AUTHENTICATION_REQUIRED",
|
||||
"408": "HTTP_408_REQUEST_TIMEOUT",
|
||||
"409": "HTTP_409_CONFLICT",
|
||||
"410": "HTTP_410_GONE",
|
||||
"411": "HTTP_411_LENGTH_REQUIRED",
|
||||
"412": "HTTP_412_PRECONDITION_FAILED",
|
||||
"413": "HTTP_413_REQUEST_ENTITY_TOO_LARGE",
|
||||
"414": "HTTP_414_REQUEST_URI_TOO_LONG",
|
||||
"415": "HTTP_415_UNSUPPORTED_MEDIA_TYPE",
|
||||
"416": "HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE",
|
||||
"417": "HTTP_417_EXPECTATION_FAILED",
|
||||
"418": "HTTP_418_IM_A_TEAPOT",
|
||||
"421": "HTTP_421_MISDIRECTED_REQUEST",
|
||||
"422": "HTTP_422_UNPROCESSABLE_ENTITY",
|
||||
"423": "HTTP_423_LOCKED",
|
||||
"424": "HTTP_424_FAILED_DEPENDENCY",
|
||||
"426": "HTTP_426_UPGRADE_REQUIRED",
|
||||
"428": "HTTP_428_PRECONDITION_REQUIRED",
|
||||
"429": "HTTP_429_TOO_MANY_REQUESTS",
|
||||
"431": "HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE",
|
||||
"451": "HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS",
|
||||
"500": "HTTP_500_INTERNAL_SERVER_ERROR",
|
||||
}
|
||||
ERRORS_KEYS = {
|
||||
"delete": "DeletedRecord",
|
||||
"update": "UpdatedRecord",
|
||||
"create": "CreatedRecord",
|
||||
"list": "ListedRecords",
|
||||
"not_found": "RecordNotFound",
|
||||
"already_exist": "AlreadyExists",
|
||||
"not_deleted": "RecordNotDeleted",
|
||||
"not_updated": "RecordNotUpdated",
|
||||
"not_created": "RecordNotCreated",
|
||||
"not_listed": "RecordsNotListed",
|
||||
"not_confirm": "IsNotConfirmed",
|
||||
}
|
||||
class HTTPExceptionError:
|
||||
|
||||
def __init__(self, lang):
|
||||
self.lang = lang
|
||||
|
|
|
|||
|
|
@ -0,0 +1,60 @@
|
|||
from typing import Any
|
||||
|
||||
|
||||
# class HTTPExceptionInstance:
|
||||
|
||||
# def __init__(self, statuses, exceptions, exceptions_dict, errors_dict, response_model, error_language_dict):
|
||||
# self.EXCEPTIONS = exceptions # from fastapi.exceptions import HTTPException
|
||||
# self.STATUSES = statuses # from fastapi import status
|
||||
# self.EXCEPTION_DICTS: dict = exceptions_dict
|
||||
# self.ERRORS_DICT: dict = errors_dict
|
||||
# self.ERRORS_LANG: dict = error_language_dict
|
||||
# self.RESPONSE_MODEL: Any = response_model
|
||||
|
||||
|
||||
class HTTPExceptionEvyos(Exception):
|
||||
|
||||
def __init__(self, error_code: str, lang: str):
|
||||
self.error_code = error_code
|
||||
self.lang = lang
|
||||
|
||||
|
||||
class HTTPExceptionEvyosHandler:
|
||||
|
||||
def __init__(self, statuses, exceptions, exceptions_dict, errors_dict, response_model, error_language_dict):
|
||||
self.EXCEPTIONS = exceptions # from fastapi.exceptions import HTTPException
|
||||
self.STATUSES = statuses # from fastapi import status
|
||||
self.EXCEPTION_DICTS: dict = exceptions_dict
|
||||
self.ERRORS_DICT: dict = errors_dict
|
||||
self.ERRORS_LANG: dict = error_language_dict
|
||||
self.RESPONSE_MODEL: Any = response_model
|
||||
|
||||
def retrieve_error_status_code(self, exc: HTTPExceptionEvyos):
|
||||
grab_status = self.ERRORS_DICT.get(str(exc.error_code).upper(), "")
|
||||
grab_status_code = self.EXCEPTION_DICTS.get(str(grab_status).upper(), "500")
|
||||
return getattr(self.STATUSES, str(grab_status_code), getattr(self.STATUSES, "HTTP_500_INTERNAL_SERVER_ERROR"))
|
||||
|
||||
def retrieve_error_message(self, exc: HTTPExceptionEvyos):
|
||||
message_by_lang = self.ERRORS_LANG.get(str(exc.lang).lower(), {})
|
||||
message_by_code = message_by_lang.get(str(exc.error_code).upper(), "Unknown error")
|
||||
return message_by_code
|
||||
|
||||
def handle_exception(self, request, exc: HTTPExceptionEvyos):
|
||||
headers = getattr(request, "headers", {})
|
||||
status_code = self.retrieve_error_status_code(exc)
|
||||
error_message = self.retrieve_error_message(exc)
|
||||
return self.RESPONSE_MODEL(
|
||||
status_code=int(status_code),
|
||||
content={"message": error_message, "lang": exc.lang},
|
||||
)
|
||||
|
||||
class HTTPExceptionAnyHandler:
|
||||
|
||||
def __init__(self, response_model):
|
||||
self.RESPONSE_MODEL: Any = response_model
|
||||
|
||||
def any_exception_handler(self, request, exc: Exception):
|
||||
return self.RESPONSE_MODEL(
|
||||
status_code=200,
|
||||
content={"message": str(exc), "lang": None, "status_code": 417},
|
||||
)
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
from .baseErrorCluster import (
|
||||
BASE_ERRORS,
|
||||
BASE_ERROR_LANGUAGE,
|
||||
EXCEPTION_DICTS,
|
||||
)
|
||||
|
||||
ERRORS_LANG = {
|
||||
"tr": {
|
||||
**BASE_ERROR_LANGUAGE["tr"],
|
||||
},
|
||||
"en": {
|
||||
**BASE_ERROR_LANGUAGE["en"],
|
||||
}
|
||||
}
|
||||
ERRORS_DICT = {
|
||||
**BASE_ERRORS,
|
||||
}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
|
||||
BASE_ERRORS = {
|
||||
"NOT_CREATED": 405,
|
||||
"NOT_DELETED": 405,
|
||||
"NOT_UPDATED": 405,
|
||||
"NOT_LISTED": 404,
|
||||
"NOT_FOUND": 404,
|
||||
"ALREADY_EXISTS": 400,
|
||||
"IS_NOT_CONFIRMED": 405,
|
||||
"NOT_AUTHORIZED": 401,
|
||||
"NOT_VALID": 406,
|
||||
"NOT_ACCEPTABLE": 406,
|
||||
"INVALID_DATA": 422,
|
||||
"UNKNOWN_ERROR": 502,
|
||||
}
|
||||
|
||||
BASE_ERROR_LANGUAGE = {
|
||||
"tr": {
|
||||
"NOT_CREATED": "Kayıt oluşturulamadı.",
|
||||
"NOT_DELETED": "Kayıt silinemedi.",
|
||||
"NOT_UPDATED": "Kayıt güncellenemedi.",
|
||||
"NOT_LISTED": "Kayıt listelenemedi.",
|
||||
"NOT_FOUND": "Kayıt bulunamadı.",
|
||||
"ALREADY_EXISTS": "Kayıt zaten mevcut.",
|
||||
"IS_NOT_CONFIRMED": "Kayıt onaylanmadı.",
|
||||
"NOT_AUTHORIZED": "Yetkisiz kullanıcı.",
|
||||
"NOT_VALID": "Gecersiz veri.",
|
||||
"NOT_ACCEPTABLE": "Gecersiz veri.",
|
||||
"INVALID_DATA": "Gecersiz veri.",
|
||||
"UNKNOWN_ERROR": "Bilinmeyen bir hata oluştu.",
|
||||
},
|
||||
"en": {
|
||||
"NOT_CREATED": "Not Created.",
|
||||
"NOT_DELETED": "Not Deleted.",
|
||||
"NOT_UPDATED": "Not Updated.",
|
||||
"NOT_LISTED": "Not Listed.",
|
||||
"NOT_FOUND": "Not Found.",
|
||||
"ALREADY_EXISTS": "Already Exists.",
|
||||
"IS_NOT_CONFIRMED": "Not Confirmed.",
|
||||
"NOT_AUTHORIZED": "Not Authorized.",
|
||||
"NOT_VALID": "Not Valid.",
|
||||
"NOT_ACCEPTABLE": "Not Acceptable.",
|
||||
"INVALID_DATA": "Invalid Data.",
|
||||
"UNKNOWN_ERROR": "Unknown Error occured.",
|
||||
},
|
||||
}
|
||||
|
||||
from fastapi import status
|
||||
EXCEPTION_DICTS = {
|
||||
"100": "HTTP_100_CONTINUE",
|
||||
"101": "HTTP_101_SWITCHING_PROTOCOLS",
|
||||
"102": "HTTP_102_PROCESSING",
|
||||
"103": "HTTP_103_EARLY_HINTS",
|
||||
"200": "HTTP_200_OK",
|
||||
"201": "HTTP_201_CREATED",
|
||||
"202": "HTTP_202_ACCEPTED",
|
||||
"203": "HTTP_203_NON_AUTHORITATIVE_INFORMATION",
|
||||
"204": "HTTP_204_NO_CONTENT",
|
||||
"205": "HTTP_205_RESET_CONTENT",
|
||||
"206": "HTTP_206_PARTIAL_CONTENT",
|
||||
"207": "HTTP_207_MULTI_STATUS",
|
||||
"208": "HTTP_208_ALREADY_REPORTED",
|
||||
"226": "HTTP_226_IM_USED",
|
||||
"300": "HTTP_300_MULTIPLE_CHOICES",
|
||||
"301": "HTTP_301_MOVED_PERMANENTLY",
|
||||
"302": "HTTP_302_FOUND",
|
||||
"303": "HTTP_303_SEE_OTHER",
|
||||
"304": "HTTP_304_NOT_MODIFIED",
|
||||
"305": "HTTP_305_USE_PROXY",
|
||||
"306": "HTTP_306_RESERVED",
|
||||
"307": "HTTP_307_TEMPORARY_REDIRECT",
|
||||
"308": "HTTP_308_PERMANENT_REDIRECT",
|
||||
"400": "HTTP_400_BAD_REQUEST",
|
||||
"401": "HTTP_401_UNAUTHORIZED",
|
||||
"402": "HTTP_402_PAYMENT_REQUIRED",
|
||||
"403": "HTTP_403_FORBIDDEN",
|
||||
"404": "HTTP_404_NOT_FOUND",
|
||||
"405": "HTTP_405_METHOD_NOT_ALLOWED",
|
||||
"406": "HTTP_406_NOT_ACCEPTABLE",
|
||||
"407": "HTTP_407_PROXY_AUTHENTICATION_REQUIRED",
|
||||
"408": "HTTP_408_REQUEST_TIMEOUT",
|
||||
"409": "HTTP_409_CONFLICT",
|
||||
"410": "HTTP_410_GONE",
|
||||
"411": "HTTP_411_LENGTH_REQUIRED",
|
||||
"412": "HTTP_412_PRECONDITION_FAILED",
|
||||
"413": "HTTP_413_REQUEST_ENTITY_TOO_LARGE",
|
||||
"414": "HTTP_414_REQUEST_URI_TOO_LONG",
|
||||
"415": "HTTP_415_UNSUPPORTED_MEDIA_TYPE",
|
||||
"416": "HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE",
|
||||
"417": "HTTP_417_EXPECTATION_FAILED",
|
||||
"418": "HTTP_418_IM_A_TEAPOT",
|
||||
"421": "HTTP_421_MISDIRECTED_REQUEST",
|
||||
"422": "HTTP_422_UNPROCESSABLE_ENTITY",
|
||||
"423": "HTTP_423_LOCKED",
|
||||
"424": "HTTP_424_FAILED_DEPENDENCY",
|
||||
"426": "HTTP_426_UPGRADE_REQUIRED",
|
||||
"428": "HTTP_428_PRECONDITION_REQUIRED",
|
||||
"429": "HTTP_429_TOO_MANY_REQUESTS",
|
||||
"431": "HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE",
|
||||
"451": "HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS",
|
||||
"500": "HTTP_500_INTERNAL_SERVER_ERROR",
|
||||
"502": "HTTP_502_BAD_GATEWAY",
|
||||
}
|
||||
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
from json import loads
|
||||
|
||||
|
||||
class ErrorMessages:
|
||||
__messages__ = {}
|
||||
|
||||
@classmethod
|
||||
def get_message(cls, message_key, lang):
|
||||
return cls.__messages__[lang][message_key]
|
||||
|
||||
|
||||
class ErrorHandlers:
|
||||
def __init__(self, requests, exceptions, response_model, status):
|
||||
self.requests = requests # from fastapi.requests import Request
|
||||
self.exceptions = exceptions # from fastapi.exceptions import HTTPException
|
||||
self.response_model = (
|
||||
response_model # from fastapi.responses import JSONResponse
|
||||
)
|
||||
self.status = status # from fastapi import status
|
||||
|
||||
@classmethod
|
||||
def create(cls, requests, exceptions, response_model, status):
|
||||
return cls(requests, exceptions, response_model, status)
|
||||
|
||||
def exception_handler_http(self, request, exc):
|
||||
exc_detail = getattr(exc, "detail", None)
|
||||
try:
|
||||
detail = loads(str(exc_detail))
|
||||
return self.response_model(
|
||||
status_code=exc.status_code,
|
||||
content={
|
||||
"Data": detail.get("data", {}),
|
||||
"Error": detail.get("error_case", "UNKNOWN"),
|
||||
"Message": detail.get(
|
||||
"message", "An error occurred while processing the request"
|
||||
),
|
||||
},
|
||||
)
|
||||
except Exception as e:
|
||||
return self.response_model(
|
||||
status_code=exc.status_code,
|
||||
content={"Error": str(exc_detail), "Message": f"{str(e)}", "Data": {}},
|
||||
)
|
||||
|
||||
def exception_handler_exception(self, request, exc):
|
||||
return self.response_model(
|
||||
status_code=self.status.HTTP_417_EXPECTATION_FAILED,
|
||||
content={"message": exc.__str__()},
|
||||
)
|
||||
|
|
@ -1,21 +1,22 @@
|
|||
import hashlib
|
||||
import uuid
|
||||
import requests
|
||||
|
||||
import secrets
|
||||
from datetime import timedelta
|
||||
from fastapi.exceptions import HTTPException
|
||||
|
||||
from api_services.redis.functions import RedisActions
|
||||
from databases.no_sql_models.validations import (
|
||||
PasswordHistoryViaUser,
|
||||
AccessHistoryViaUser,
|
||||
)
|
||||
from api_library.date_time_actions.date_functions import system_arrow, client_arrow
|
||||
from api_library.date_time_actions.date_functions import system_arrow
|
||||
from api_configs import ApiStatic, Auth
|
||||
|
||||
|
||||
class PasswordModule:
|
||||
@staticmethod
|
||||
def generate_token(length=32):
|
||||
return uuid.uuid4().__str__()[:length]
|
||||
return secrets.token_urlsafe(length)
|
||||
|
||||
@staticmethod
|
||||
def create_hashed_password(domain: str, id_: str, password: str):
|
||||
|
|
@ -25,6 +26,10 @@ class PasswordModule:
|
|||
def check_password(cls, domain, id_, password, password_hashed):
|
||||
return cls.create_hashed_password(domain, id_, password) == password_hashed
|
||||
|
||||
@classmethod
|
||||
def generate_access_token(cls):
|
||||
return secrets.token_urlsafe(Auth.ACCESS_TOKEN_LENGTH)
|
||||
|
||||
|
||||
class AuthModule(PasswordModule):
|
||||
|
||||
|
|
@ -33,6 +38,7 @@ class AuthModule(PasswordModule):
|
|||
from databases import Users
|
||||
from sqlalchemy import or_
|
||||
from fastapi import status
|
||||
from fastapi.exceptions import HTTPException
|
||||
|
||||
found_user: Users = Users.query.filter(
|
||||
or_(
|
||||
|
|
@ -56,9 +62,6 @@ class AuthModule(PasswordModule):
|
|||
)
|
||||
return found_user
|
||||
|
||||
def generate_access_token(self):
|
||||
return self.generate_token(Auth.ACCESS_TOKEN_LENGTH)
|
||||
|
||||
def remove_refresher_token(self, domain, disconnect: bool = False):
|
||||
from databases import UsersTokens
|
||||
|
||||
|
|
@ -76,6 +79,8 @@ class AuthModule(PasswordModule):
|
|||
UsersTokens.save()
|
||||
|
||||
def check_password_is_different(self, password):
|
||||
from fastapi.exceptions import HTTPException
|
||||
|
||||
main_domain = self.get_main_domain_and_other_domains(get_main_domain=True)
|
||||
if self.hash_password == self.create_hashed_password(
|
||||
domain=main_domain, id_=self.uu_id, password=password
|
||||
|
|
@ -88,9 +93,9 @@ class AuthModule(PasswordModule):
|
|||
@staticmethod
|
||||
def create_password(found_user, password, password_token=None):
|
||||
from databases import MongoQueryIdentity, Users
|
||||
from fastapi.exceptions import HTTPException
|
||||
|
||||
found_user: Users = found_user
|
||||
|
||||
if found_user.password_token:
|
||||
replace_day = 0
|
||||
try:
|
||||
|
|
@ -145,9 +150,7 @@ class AuthModule(PasswordModule):
|
|||
return found_user.password_token
|
||||
|
||||
def generate_refresher_token(self, domain: str, remember_me=False):
|
||||
from databases import (
|
||||
UsersTokens,
|
||||
)
|
||||
from databases import UsersTokens
|
||||
|
||||
if remember_me:
|
||||
refresh_token = self.generate_token(Auth.REFRESHER_TOKEN_LENGTH)
|
||||
|
|
@ -183,6 +186,7 @@ class AuthModule(PasswordModule):
|
|||
|
||||
|
||||
class UserLoginModule(AuthModule):
|
||||
|
||||
@classmethod
|
||||
def set_login_details_to_mongo_database(
|
||||
cls, found_user, headers_request, access_token, record_id
|
||||
|
|
@ -212,8 +216,8 @@ class UserLoginModule(AuthModule):
|
|||
"address": address_package,
|
||||
"user_id": found_user.id,
|
||||
}
|
||||
already_exits = mongo_db.mongo_engine.filter_by(filter_query) or None
|
||||
no_address_validates = mongo_db.mongo_engine.get_all()[0] == 0
|
||||
already_exits = mongo_db.mongo_engine.filter_by(filter_query).data
|
||||
no_address_validates = mongo_db.mongo_engine.get_all().data
|
||||
access_via_user = query_engine.update_access_history_via_user(
|
||||
AccessHistoryViaUser(
|
||||
**{
|
||||
|
|
@ -241,7 +245,6 @@ class UserLoginModule(AuthModule):
|
|||
}
|
||||
},
|
||||
)
|
||||
print("update_mongo", update_mongo)
|
||||
else:
|
||||
insert_mongo = mongo_db.mongo_engine.insert(
|
||||
payload={
|
||||
|
|
@ -257,14 +260,14 @@ class UserLoginModule(AuthModule):
|
|||
"is_first": True if no_address_validates else False,
|
||||
}
|
||||
)
|
||||
print("insert_mongo", insert_mongo)
|
||||
|
||||
@classmethod
|
||||
def login_user_with_credentials(cls, data, request):
|
||||
from databases.sql_models.identity.identity import Users
|
||||
from ApiServices.api_handlers.auth_actions.auth import AuthActions
|
||||
from fastapi.exceptions import HTTPException
|
||||
|
||||
found_user = Users.check_user_exits(
|
||||
found_user: Users = Users.check_user_exits(
|
||||
access_key=data.access_key, domain=data.domain
|
||||
)
|
||||
if not found_user:
|
||||
|
|
@ -291,8 +294,9 @@ class UserLoginModule(AuthModule):
|
|||
domain=data.domain,
|
||||
# remember_me=data.remember_me,
|
||||
)
|
||||
print("access_object_to_redis", access_object_to_redis)
|
||||
access_token = access_object_to_redis.get("access_token")
|
||||
|
||||
access_object_to_redis["user"] = found_user
|
||||
headers_request = dict(request.headers)
|
||||
headers_request["evyos-user-agent"] = headers_request.get("user-agent")
|
||||
headers_request["evyos-platform"] = headers_request.get("user-agent")
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ from sqlalchemy import (
|
|||
Numeric,
|
||||
Integer,
|
||||
)
|
||||
from sqlalchemy.orm import mapped_column, Mapped, relationship
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from api_validations.validations_request import (
|
||||
InsertDecisionBook,
|
||||
|
|
@ -26,6 +26,19 @@ from api_validations.validations_request import (
|
|||
InsertBuildDecisionBookProjects,
|
||||
)
|
||||
from databases.sql_models.core_mixin import CrudCollection
|
||||
from databases.language_models.building.decision_book import (
|
||||
BuildDecisionBookLanguageModel,
|
||||
BuildDecisionBookInvitationsLanguageModel,
|
||||
BuildDecisionBookPersonLanguageModel,
|
||||
BuildDecisionBookPersonOccupantsLanguageModel,
|
||||
BuildDecisionBookItemsLanguageModel,
|
||||
BuildDecisionBookItemsUnapprovedLanguageModel,
|
||||
BuildDecisionBookPaymentsLanguageModel,
|
||||
BuildDecisionBookLegalLanguageModel,
|
||||
BuildDecisionBookProjectsLanguageModel,
|
||||
BuildDecisionBookProjectPersonLanguageModel,
|
||||
BuildDecisionBookProjectItemsLanguageModel,
|
||||
)
|
||||
|
||||
|
||||
class BuildDecisionBook(CrudCollection):
|
||||
|
|
@ -44,6 +57,7 @@ class BuildDecisionBook(CrudCollection):
|
|||
|
||||
__tablename__ = "build_decision_book"
|
||||
__exclude__fields__ = []
|
||||
__language_model__ = BuildDecisionBookLanguageModel
|
||||
|
||||
decision_book_pdf_path: Mapped[str] = mapped_column(
|
||||
String, server_default="", nullable=True
|
||||
|
|
@ -242,6 +256,7 @@ class BuildDecisionBookInvitations(CrudCollection):
|
|||
|
||||
__tablename__ = "build_decision_book_invitations"
|
||||
__exclude__fields__ = []
|
||||
__language_model__ = BuildDecisionBookInvitationsLanguageModel
|
||||
|
||||
build_id: Mapped[int] = mapped_column(Integer, nullable=False)
|
||||
build_uu_id: Mapped[str] = mapped_column(
|
||||
|
|
@ -341,6 +356,7 @@ class BuildDecisionBookPerson(CrudCollection):
|
|||
__tablename__ = "build_decision_book_person"
|
||||
__exclude__fields__ = []
|
||||
__enum_list__ = [("management_typecode", "BuildManagementType", "bm")]
|
||||
__language_model__ = BuildDecisionBookPersonLanguageModel
|
||||
|
||||
dues_percent_discount: Mapped[int] = mapped_column(SmallInteger, server_default="0")
|
||||
dues_fix_discount: Mapped[float] = mapped_column(Numeric(10, 2), server_default="0")
|
||||
|
|
@ -517,6 +533,7 @@ class BuildDecisionBookPersonOccupants(CrudCollection):
|
|||
|
||||
__tablename__ = "build_decision_book_person_occupants"
|
||||
__exclude__fields__ = []
|
||||
__language_model__ = BuildDecisionBookPersonOccupantsLanguageModel
|
||||
|
||||
build_decision_book_person_id: Mapped[int] = mapped_column(
|
||||
ForeignKey("build_decision_book_person.id"), nullable=False
|
||||
|
|
@ -559,6 +576,7 @@ class BuildDecisionBookItems(CrudCollection):
|
|||
|
||||
__tablename__ = "build_decision_book_items"
|
||||
__exclude__fields__ = []
|
||||
__language_model__ = BuildDecisionBookItemsLanguageModel
|
||||
|
||||
item_order: Mapped[int] = mapped_column(
|
||||
SmallInteger, nullable=False, comment="Order Number of Item"
|
||||
|
|
@ -799,6 +817,7 @@ class BuildDecisionBookItemsUnapproved(CrudCollection):
|
|||
|
||||
__tablename__ = "build_decision_book_items_unapproved"
|
||||
__exclude__fields__ = []
|
||||
__language_model__ = BuildDecisionBookItemsUnapprovedLanguageModel
|
||||
|
||||
item_objection: Mapped[str] = mapped_column(
|
||||
Text, nullable=False, comment="Objection Content"
|
||||
|
|
@ -841,6 +860,7 @@ class BuildDecisionBookPayments(CrudCollection):
|
|||
__tablename__ = "build_decision_book_payments"
|
||||
__exclude__fields__ = []
|
||||
__enum_list__ = [("receive_debit", "DebitTypes", "D")]
|
||||
__language_model__ = BuildDecisionBookPaymentsLanguageModel
|
||||
|
||||
payment_plan_time_periods: Mapped[str] = mapped_column(
|
||||
String(10), nullable=False, comment="Payment Plan Time Periods"
|
||||
|
|
@ -951,6 +971,7 @@ class BuildDecisionBookLegal(CrudCollection):
|
|||
|
||||
__tablename__ = "build_decision_book_legal"
|
||||
__exclude__fields__ = []
|
||||
__language_model__ = BuildDecisionBookLegalLanguageModel
|
||||
|
||||
period_start_date: Mapped[TIMESTAMP] = mapped_column(
|
||||
TIMESTAMP(timezone=True), nullable=False, comment="Start Date of Legal Period"
|
||||
|
|
@ -1027,6 +1048,7 @@ class BuildDecisionBookProjects(CrudCollection):
|
|||
|
||||
__tablename__ = "build_decision_book_projects"
|
||||
__exclude__fields__ = []
|
||||
__language_model__ = BuildDecisionBookProjectsLanguageModel
|
||||
|
||||
project_no: Mapped[str] = mapped_column(
|
||||
String(12), nullable=True, comment="Project Number of Decision Book"
|
||||
|
|
@ -1194,6 +1216,7 @@ class BuildDecisionBookProjectPerson(CrudCollection):
|
|||
|
||||
__tablename__ = "build_decision_book_project_person"
|
||||
__exclude__fields__ = []
|
||||
__language_model__ = BuildDecisionBookProjectPersonLanguageModel
|
||||
# __enum_list__ = [("management_typecode", "ProjectTeamTypes", "PTT-EMP")]
|
||||
|
||||
dues_percent_discount: Mapped[int] = mapped_column(SmallInteger, server_default="0")
|
||||
|
|
@ -1226,6 +1249,7 @@ class BuildDecisionBookProjectItems(CrudCollection):
|
|||
|
||||
__tablename__ = "build_decision_book_project_items"
|
||||
__exclude__fields__ = []
|
||||
__language_model__ = BuildDecisionBookProjectItemsLanguageModel
|
||||
|
||||
item_header: Mapped[str] = mapped_column(
|
||||
String, nullable=False, comment="Item Header"
|
||||
|
|
|
|||
|
|
@ -5,6 +5,13 @@ from sqlalchemy import (
|
|||
Numeric,
|
||||
)
|
||||
from sqlalchemy.orm import mapped_column, Mapped
|
||||
|
||||
from databases.language_models.company.employee import (
|
||||
StaffLanguageModel,
|
||||
EmployeesLanguageModel,
|
||||
EmployeeHistoryLanguageModel,
|
||||
EmployeesSalariesLanguageModel,
|
||||
)
|
||||
from databases.sql_models.core_mixin import CrudCollection
|
||||
|
||||
from api_validations.validations_request import InsertCompanyEmployees
|
||||
|
|
@ -14,6 +21,7 @@ class Staff(CrudCollection):
|
|||
|
||||
__tablename__ = "staff"
|
||||
__exclude__fields__ = []
|
||||
__language_model__ = StaffLanguageModel
|
||||
|
||||
staff_description: Mapped[str] = mapped_column(
|
||||
String, server_default="", comment="Staff Description"
|
||||
|
|
@ -61,6 +69,7 @@ class Employees(CrudCollection):
|
|||
|
||||
__tablename__ = "employees"
|
||||
__exclude__fields__ = []
|
||||
__language_model__ = EmployeesLanguageModel
|
||||
|
||||
staff_id: Mapped[int] = mapped_column(ForeignKey("staff.id"))
|
||||
staff_uu_id: Mapped[str] = mapped_column(
|
||||
|
|
@ -81,6 +90,7 @@ class EmployeeHistory(CrudCollection):
|
|||
|
||||
__tablename__ = "employee_history"
|
||||
__exclude__fields__ = []
|
||||
__language_model__ = EmployeeHistoryLanguageModel
|
||||
|
||||
staff_id: Mapped[int] = mapped_column(
|
||||
ForeignKey("staff.id"), nullable=False, comment="Staff ID"
|
||||
|
|
@ -105,6 +115,7 @@ class EmployeesSalaries(CrudCollection):
|
|||
|
||||
__tablename__ = "employee_salaries"
|
||||
__exclude__fields__ = []
|
||||
__language_model__ = EmployeesSalariesLanguageModel
|
||||
|
||||
gross_salary: Mapped[float] = mapped_column(
|
||||
Numeric(20, 6), nullable=False, comment="Gross Salary"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ from sqlalchemy_mixins.serialize import SerializeMixin
|
|||
from sqlalchemy_mixins.repr import ReprMixin
|
||||
from sqlalchemy_mixins.smartquery import SmartQueryMixin
|
||||
|
||||
from api_library import DateTimeLocal, client_arrow, system_arrow
|
||||
from api_library import DateTimeLocal, system_arrow
|
||||
from databases.sql_models.sql_operations import FilterAttributes
|
||||
from databases.sql_models.postgres_database import Base
|
||||
|
||||
|
|
@ -138,14 +138,14 @@ class CrudMixin(Base, SmartQueryMixin, SessionMixin, FilterAttributes):
|
|||
return True, int(val)
|
||||
elif key_ == Mapped[TIMESTAMP]:
|
||||
return True, str(
|
||||
cls.client_arrow.get(str(val)).format("DD-MM-YYYY HH:mm:ss")
|
||||
cls.client_arrow.get(str(val)).format("DD-MM-YYYY HH:mm:ss +0")
|
||||
)
|
||||
elif key_ == Mapped[str]:
|
||||
return True, str(val)
|
||||
else:
|
||||
if isinstance(val, datetime.datetime):
|
||||
return True, str(
|
||||
cls.client_arrow.get(str(val)).format("DD-MM-YYYY HH:mm:ss")
|
||||
cls.client_arrow.get(str(val)).format("DD-MM-YYYY HH:mm:ss +0")
|
||||
)
|
||||
elif isinstance(value_type, bool):
|
||||
return True, bool(val)
|
||||
|
|
|
|||
|
|
@ -122,6 +122,9 @@ class Users(CrudCollection, UserLoginModule, SelectAction):
|
|||
person_uu_id: Mapped[str] = mapped_column(
|
||||
String, server_default="", comment="Person UUID", index=True
|
||||
)
|
||||
local_timezone = mapped_column(
|
||||
String, server_default="GMT+3", comment="Local timezone of user"
|
||||
)
|
||||
person = relationship("People", back_populates="user", foreign_keys=[person_id])
|
||||
|
||||
@property
|
||||
|
|
@ -183,11 +186,6 @@ class Users(CrudCollection, UserLoginModule, SelectAction):
|
|||
@classmethod
|
||||
def credentials(cls):
|
||||
person_object = People.filter_by_one(system=True, id=cls.person_id).data
|
||||
# if not person_object:
|
||||
# raise HTTPException(
|
||||
# status_code=401,
|
||||
# detail="Person not found. Please contact the admin.",
|
||||
# )
|
||||
if person_object:
|
||||
return {
|
||||
"person_id": person_object.id,
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ from databases.sql_models.core_mixin import CrudCollection
|
|||
class ApiEnumDropdown(CrudCollection):
|
||||
__tablename__ = "api_enum_dropdown"
|
||||
__exclude__fields__ = ["enum_class"]
|
||||
__language_model__ = None
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True)
|
||||
uu_id: Mapped[str] = mapped_column(
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
from sqlalchemy import String, Boolean
|
||||
from databases.sql_models.core_mixin import CrudCollection
|
||||
from sqlalchemy import String
|
||||
from sqlalchemy.orm import mapped_column, Mapped
|
||||
|
||||
from databases.language_models.rules.rules import EndpointRestrictionLanguageModel
|
||||
from databases.sql_models.core_mixin import CrudCollection
|
||||
|
||||
|
||||
class EndpointRestriction(CrudCollection):
|
||||
"""
|
||||
|
|
@ -10,6 +12,7 @@ class EndpointRestriction(CrudCollection):
|
|||
|
||||
__tablename__ = "endpoint_restriction"
|
||||
__exclude__fields__ = []
|
||||
__language_model__ = EndpointRestrictionLanguageModel
|
||||
|
||||
endpoint_function: Mapped[str] = mapped_column(
|
||||
String, server_default="", comment="Function name of the API endpoint"
|
||||
|
|
|
|||
|
|
@ -50,18 +50,9 @@ class FilterAttributes:
|
|||
"""Save the data via the metadata."""
|
||||
try:
|
||||
meta_data = getattr(cls, "meta_data", {})
|
||||
meta_data_created = meta_data.get("created", False)
|
||||
if meta_data_created:
|
||||
print("meta_data_created commit", meta_data_created)
|
||||
if meta_data.get("created", False):
|
||||
cls.__session__.commit()
|
||||
print("meta_data_created rollback", meta_data_created)
|
||||
cls.__session__.rollback()
|
||||
# cls.raise_http_exception(
|
||||
# status_code="HTTP_304_NOT_MODIFIED",
|
||||
# error_case=meta_data.get("error_case", "Error on save and commit"),
|
||||
# data={},
|
||||
# message=meta_data.get("message", "Error on save and commit"),
|
||||
# )
|
||||
except SQLAlchemyError as e:
|
||||
cls.raise_http_exception(
|
||||
status_code="HTTP_304_NOT_MODIFIED",
|
||||
|
|
@ -233,8 +224,9 @@ class FilterAttributes:
|
|||
for smart_iter in cls.filter_expr(**filter_list.get("query", {})):
|
||||
if key := arg_left(smart_iter):
|
||||
args = cls.add_new_arg_to_args(args, key, smart_iter)
|
||||
query = cls._query().filter(*args)
|
||||
query = cls._query()
|
||||
cls.total_count = query.count()
|
||||
query = query.filter(*args)
|
||||
if cls.filter_attr:
|
||||
data_query = cls.add_query_to_filter(query, filter_list)
|
||||
cls.filter_attr = None
|
||||
|
|
|
|||
|
|
@ -157,6 +157,6 @@ def create_application_defaults_func(create_address=False):
|
|||
|
||||
if __name__ == "__main__":
|
||||
print("Service App Initial Default Runner is running")
|
||||
# do_alembic()
|
||||
create_application_defaults_func(create_address=True)
|
||||
do_alembic()
|
||||
# create_application_defaults_func(create_address=True)
|
||||
print("Service App Initial Default Runner is completed")
|
||||
|
|
|
|||
Loading…
Reference in New Issue