join tested auth service login/select completed
This commit is contained in:
parent
1d4f00e8b2
commit
cd62d96158
|
|
@ -14,12 +14,14 @@ RUN poetry config virtualenvs.create false && poetry install --no-interaction --
|
||||||
# Copy application code
|
# Copy application code
|
||||||
COPY /api_services/api_initializer /api_initializer
|
COPY /api_services/api_initializer /api_initializer
|
||||||
COPY /api_services/api_controllers /api_controllers
|
COPY /api_services/api_controllers /api_controllers
|
||||||
|
COPY /api_services/api_validations /api_validations
|
||||||
COPY /api_services/schemas /schemas
|
COPY /api_services/schemas /schemas
|
||||||
|
|
||||||
COPY /api_services/api_middlewares /middlewares
|
COPY /api_services/api_middlewares /api_middlewares
|
||||||
COPY /api_services/api_builds/auth-service/endpoints /api_initializer/endpoints
|
COPY /api_services/api_builds/auth-service/endpoints /api_initializer/endpoints
|
||||||
COPY /api_services/api_builds/auth-service/events /api_initializer/events
|
COPY /api_services/api_builds/auth-service/events /api_initializer/events
|
||||||
COPY /api_services/api_builds/auth-service/validations /api_initializer/validations
|
COPY /api_services/api_builds/auth-service/validations /api_initializer/validations
|
||||||
|
COPY /api_services/api_modules /api_modules
|
||||||
|
|
||||||
# Set Python path to include app directory
|
# Set Python path to include app directory
|
||||||
ENV PYTHONPATH=/ PYTHONUNBUFFERED=1 PYTHONDONTWRITEBYTECODE=1
|
ENV PYTHONPATH=/ PYTHONUNBUFFERED=1 PYTHONDONTWRITEBYTECODE=1
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,155 @@
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
|
from fastapi import APIRouter, Request, status, Header, Depends
|
||||||
|
from fastapi.responses import JSONResponse
|
||||||
|
|
||||||
|
from config import api_config
|
||||||
|
from validations.request.auth.validations import (
|
||||||
|
RequestLogin,
|
||||||
|
RequestResetPassword,
|
||||||
|
RequestSelectLiving,
|
||||||
|
RequestSelectEmployee,
|
||||||
|
RequestCreatePassword,
|
||||||
|
RequestChangePassword,
|
||||||
|
RequestForgotPasswordPhone,
|
||||||
|
RequestForgotPasswordEmail,
|
||||||
|
RequestVerifyOTP,
|
||||||
|
RequestApplication,
|
||||||
|
)
|
||||||
|
from events.auth.events import AuthHandlers
|
||||||
|
from endpoints.index import endpoints_index
|
||||||
|
|
||||||
|
from api_validations.defaults.validations import CommonHeaders
|
||||||
|
from api_middlewares.token_provider import TokenProvider
|
||||||
|
|
||||||
|
|
||||||
|
auth_route = APIRouter(prefix="/authentication", tags=["Authentication Cluster"])
|
||||||
|
|
||||||
|
|
||||||
|
auth_route_login = "AuthLoginViaDomainAndCreds"
|
||||||
|
@auth_route.post(
|
||||||
|
path="/login",
|
||||||
|
summary="Login via domain and access key : [email] | [phone]",
|
||||||
|
description="Login Route",
|
||||||
|
operation_id=endpoints_index[auth_route_login]
|
||||||
|
)
|
||||||
|
def login(data: RequestLogin, headers: CommonHeaders = Depends(CommonHeaders.as_dependency)):
|
||||||
|
"""Login via domain and access key : [email] | [phone]"""
|
||||||
|
return AuthHandlers.LoginHandler.authentication_login_with_domain_and_creds(headers=headers, data=data)
|
||||||
|
|
||||||
|
|
||||||
|
auth_route_select_living = "AuthSelectLiving"
|
||||||
|
@auth_route.post(
|
||||||
|
path="/select",
|
||||||
|
summary="Select token object company or occupant type",
|
||||||
|
description="Selection of users company or occupant type",
|
||||||
|
operation_id=endpoints_index[auth_route_select_living]
|
||||||
|
)
|
||||||
|
def select_living(data: Union[RequestSelectLiving, RequestSelectEmployee], headers: CommonHeaders = Depends(CommonHeaders.as_dependency)):
|
||||||
|
"""Select token object company or occupant type"""
|
||||||
|
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
|
||||||
|
return AuthHandlers.LoginHandler.authentication_select_company_or_occupant_type(request=headers.request, data=data)
|
||||||
|
|
||||||
|
|
||||||
|
auth_route_create_password = "AuthCreatePassword"
|
||||||
|
@auth_route.post(
|
||||||
|
path="/password/create",
|
||||||
|
summary="Create password with access token",
|
||||||
|
description="Create password",
|
||||||
|
operation_id=endpoints_index[auth_route_create_password]
|
||||||
|
)
|
||||||
|
def create_password(data: RequestCreatePassword, headers: CommonHeaders = Depends(CommonHeaders.as_dependency)):
|
||||||
|
"""Create password with access token"""
|
||||||
|
# token_object = TokenProvider.get_dict_from_redis(token=headers.token)
|
||||||
|
return AuthHandlers.PasswordHandler.create_password(password=data.password, password_token=data.password_token)
|
||||||
|
|
||||||
|
|
||||||
|
auth_route_change_password = "AuthChangePassword"
|
||||||
|
@auth_route.post(
|
||||||
|
path="/password/change",
|
||||||
|
summary="Change password with access token",
|
||||||
|
description="Change password",
|
||||||
|
operation_id=endpoints_index[auth_route_change_password]
|
||||||
|
)
|
||||||
|
def change_password(data: RequestChangePassword, headers: CommonHeaders = Depends(CommonHeaders.as_dependency)):
|
||||||
|
"""Change password with access token"""
|
||||||
|
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
auth_route_reset_password = "AuthResetPassword"
|
||||||
|
@auth_route.post(
|
||||||
|
path="/password/reset",
|
||||||
|
summary="Reset password with access token",
|
||||||
|
description="Reset password",
|
||||||
|
operation_id=endpoints_index[auth_route_reset_password]
|
||||||
|
)
|
||||||
|
def reset_password(data: RequestResetPassword, headers: CommonHeaders = Depends(CommonHeaders.as_dependency)):
|
||||||
|
"""Reset password with access token"""
|
||||||
|
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
auth_route_logout = "AuthLogout"
|
||||||
|
@auth_route.get(
|
||||||
|
path="/logout",
|
||||||
|
summary="Logout user",
|
||||||
|
description="Logout only single session of user which domain is provided",
|
||||||
|
operation_id=endpoints_index[auth_route_logout]
|
||||||
|
)
|
||||||
|
def logout(headers: CommonHeaders = Depends(CommonHeaders.as_dependency)):
|
||||||
|
"""Logout user"""
|
||||||
|
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
auth_route_disconnect = "AuthDisconnect"
|
||||||
|
@auth_route.get(
|
||||||
|
path="/disconnect",
|
||||||
|
summary="Disconnect all sessions",
|
||||||
|
description="Disconnect all sessions of user in access token",
|
||||||
|
operation_id=endpoints_index[auth_route_disconnect]
|
||||||
|
)
|
||||||
|
def disconnect(headers: CommonHeaders = Depends(CommonHeaders.as_dependency)):
|
||||||
|
"""Disconnect all sessions"""
|
||||||
|
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
auth_route_check_token = "AuthCheckToken"
|
||||||
|
@auth_route.get(
|
||||||
|
path="/token/check",
|
||||||
|
summary="Check if token is valid",
|
||||||
|
description="Check if access token is valid for user",
|
||||||
|
operation_id=endpoints_index[auth_route_check_token]
|
||||||
|
)
|
||||||
|
def check_token(headers: CommonHeaders = Depends(CommonHeaders.as_dependency)):
|
||||||
|
"""Check if token is valid"""
|
||||||
|
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
auth_route_refresh_token = "AuthRefreshToken"
|
||||||
|
@auth_route.get(
|
||||||
|
path="/token/refresh",
|
||||||
|
summary="Refresh if token is valid",
|
||||||
|
description="Refresh if access token is valid for user",
|
||||||
|
operation_id=endpoints_index[auth_route_refresh_token]
|
||||||
|
)
|
||||||
|
def refresh_token(headers: CommonHeaders = Depends(CommonHeaders.as_dependency)):
|
||||||
|
"""Refresh if token is valid"""
|
||||||
|
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
auth_route_verify_otp = "AuthVerifyOTP"
|
||||||
|
@auth_route.get(
|
||||||
|
path="/password/verify-otp",
|
||||||
|
summary="Verify OTP for password reset",
|
||||||
|
description="Verify OTP for password reset",
|
||||||
|
operation_id=endpoints_index[auth_route_verify_otp]
|
||||||
|
)
|
||||||
|
def verify_otp(headers: CommonHeaders = Depends(CommonHeaders.as_dependency)):
|
||||||
|
"""Verify OTP for password reset"""
|
||||||
|
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
|
||||||
|
return None
|
||||||
|
|
@ -1,9 +1,13 @@
|
||||||
|
|
||||||
endpoints_index: dict = {
|
endpoints_index: dict = {
|
||||||
"Name": "d538deb4-38f4-4913-a1af-bbef14cf6873",
|
"AuthLoginViaDomainAndCreds": "1b94a704-7768-436d-bc20-655d92b34d83",
|
||||||
"Slot1": "c0f5ccb1-1e56-4653-af13-ec0bf5e6aa51",
|
"AuthSelectLiving": "585d578e-2b72-4f71-b996-530fc0613568",
|
||||||
"Slot2": "034a7eb7-0186-4f48-bb8c-165c429ad5c1",
|
"AuthCreatePassword": "a4252148-2bac-42df-aa3a-1784f4cbd599",
|
||||||
"Slot3": "ec1f3ec3-3f28-4eaf-b89a-c463632c0b90",
|
"AuthChangePassword": "d55834fa-6d7f-4007-9591-a50d3266b3aa",
|
||||||
"Slot4": "2cf99f10-72f0-4c2b-98be-3082d67b950d",
|
"AuthResetPassword": "29f14043-2a79-4230-bf66-a709ae954dc5",
|
||||||
"Slot5": "15c24c6c-651b-4c5d-9c2b-5c6c6c6c6c6c",
|
"AuthLogout": "616a992a-2a73-4709-a394-f043caa75937",
|
||||||
|
"AuthDisconnect": "55dd1df1-4a00-41f9-92a9-fb776aee1cd3",
|
||||||
|
"AuthCheckToken": "040e7a48-1ce0-432c-9bd9-5b05c2c7aef3",
|
||||||
|
"AuthRefreshToken": "0ca54d41-d9ca-4143-b974-1050d65769b7",
|
||||||
|
"AuthVerifyOTP": "4192e7a5-cf52-4d09-8b51-2088d77271d0",
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,22 @@
|
||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
|
from .auth.router import auth_route
|
||||||
|
|
||||||
|
|
||||||
def get_routes() -> list[APIRouter]:
|
def get_routes() -> list[APIRouter]:
|
||||||
return []
|
"""Get all routes"""
|
||||||
|
return [auth_route]
|
||||||
|
|
||||||
|
|
||||||
def get_safe_endpoint_urls() -> list[tuple[str, str]]:
|
def get_safe_endpoint_urls() -> list[tuple[str, str]]:
|
||||||
|
"""Get all safe endpoint urls"""
|
||||||
return [
|
return [
|
||||||
("/", "GET"),
|
("/", "GET"),
|
||||||
("/docs", "GET"),
|
("/docs", "GET"),
|
||||||
("/redoc", "GET"),
|
("/redoc", "GET"),
|
||||||
("/openapi.json", "GET"),
|
("/openapi.json", "GET"),
|
||||||
("/metrics", "GET"),
|
("/metrics", "GET"),
|
||||||
|
("/authentication/login", "POST"),
|
||||||
|
("/authentication/password/reset", "POST"),
|
||||||
|
("/authentication/password/create", "POST"),
|
||||||
|
("/authentication/password/verify-otp", "POST"),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,599 @@
|
||||||
|
import arrow
|
||||||
|
|
||||||
|
from typing import Any, Dict, Optional, Union
|
||||||
|
from config import api_config
|
||||||
|
from schemas import (
|
||||||
|
Users,
|
||||||
|
People,
|
||||||
|
BuildLivingSpace,
|
||||||
|
BuildParts,
|
||||||
|
OccupantTypes,
|
||||||
|
Employees,
|
||||||
|
Addresses,
|
||||||
|
Companies,
|
||||||
|
Staff,
|
||||||
|
Duty,
|
||||||
|
Duties,
|
||||||
|
Departments,
|
||||||
|
Event2Employee,
|
||||||
|
Application2Occupant,
|
||||||
|
Event2Occupant,
|
||||||
|
Application2Employee,
|
||||||
|
RelationshipEmployee2Build,
|
||||||
|
)
|
||||||
|
from api_modules.token.password_module import PasswordModule
|
||||||
|
from api_controllers.redis.database import RedisActions
|
||||||
|
from api_controllers.mongo.database import mongo_handler
|
||||||
|
from api_validations.token.validations import EmployeeTokenObject, OccupantTokenObject, CompanyToken, OccupantToken, UserType
|
||||||
|
from api_validations.defaults.validations import CommonHeaders
|
||||||
|
from validations.password.validations import PasswordHistoryViaUser
|
||||||
|
|
||||||
|
|
||||||
|
TokenDictType = Union[EmployeeTokenObject, OccupantTokenObject]
|
||||||
|
|
||||||
|
|
||||||
|
class RedisHandlers:
|
||||||
|
|
||||||
|
AUTH_TOKEN: str = "AUTH_TOKEN"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def process_redis_object(cls, redis_object: Dict[str, Any]) -> TokenDictType:
|
||||||
|
"""Process Redis object and return appropriate token object."""
|
||||||
|
if not redis_object.get("selected_company"):
|
||||||
|
redis_object["selected_company"] = None
|
||||||
|
if not redis_object.get("selected_occupant"):
|
||||||
|
redis_object["selected_occupant"] = None
|
||||||
|
if redis_object.get("user_type") == UserType.employee.value:
|
||||||
|
return EmployeeTokenObject(**redis_object)
|
||||||
|
elif redis_object.get("user_type") == UserType.occupant.value:
|
||||||
|
return OccupantTokenObject(**redis_object)
|
||||||
|
raise ValueError("Invalid user type")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_object_from_redis(cls, access_token: str) -> TokenDictType:
|
||||||
|
redis_response = RedisActions.get_json(list_keys=[RedisHandlers.AUTH_TOKEN, access_token, "*"])
|
||||||
|
if not redis_response.status:
|
||||||
|
raise ValueError("EYS_0001")
|
||||||
|
if redis_object := redis_response.first:
|
||||||
|
return cls.process_redis_object(redis_object)
|
||||||
|
raise ValueError("EYS_0002")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def set_object_to_redis(cls, user: Users, token, header_info):
|
||||||
|
result_delete = RedisActions.delete(list_keys=[RedisHandlers.AUTH_TOKEN, "*", str(user.uu_id)])
|
||||||
|
generated_access_token = PasswordModule.generate_access_token()
|
||||||
|
keys = [RedisHandlers.AUTH_TOKEN, generated_access_token, str(user.uu_id)]
|
||||||
|
RedisActions.set_json(list_keys=keys, value={**token, **header_info}, expires={"hours": 1, "minutes": 30})
|
||||||
|
return generated_access_token
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def update_token_at_redis(cls, token: str, add_payload: Union[CompanyToken, OccupantToken]):
|
||||||
|
if already_token_data := RedisActions.get_json(list_keys=[RedisHandlers.AUTH_TOKEN, token, "*"]).first:
|
||||||
|
already_token = cls.process_redis_object(already_token_data)
|
||||||
|
if already_token.is_employee and isinstance(add_payload, CompanyToken):
|
||||||
|
already_token.selected_company = add_payload
|
||||||
|
elif already_token.is_occupant and isinstance(add_payload, OccupantToken):
|
||||||
|
already_token.selected_occupant = add_payload
|
||||||
|
result = RedisActions.set_json(
|
||||||
|
list_keys=[RedisHandlers.AUTH_TOKEN, token, str(already_token.user_uu_id)], value=already_token.model_dump(), expires={"hours": 1, "minutes": 30}
|
||||||
|
)
|
||||||
|
return result.first
|
||||||
|
raise ValueError("Something went wrong")
|
||||||
|
|
||||||
|
|
||||||
|
class UserHandlers:
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def check_user_exists(access_key: str, db_session) -> Users:
|
||||||
|
"""Check if the user exists in the database."""
|
||||||
|
Users.set_session(db_session)
|
||||||
|
if "@" in access_key:
|
||||||
|
found_user: Users = Users.query.filter(Users.email == access_key.lower()).first()
|
||||||
|
else:
|
||||||
|
found_user: Users = Users.query.filter(Users.phone_number == access_key.replace(" ", "")).first()
|
||||||
|
if not found_user:
|
||||||
|
raise ValueError("EYS_0003")
|
||||||
|
return found_user
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def check_password_valid(domain: str, id_: str, password: str, password_hashed: str) -> bool:
|
||||||
|
"""Check if the password is valid."""
|
||||||
|
if PasswordModule.check_password(domain=domain, id_=id_, password=password, password_hashed=password_hashed):
|
||||||
|
return True
|
||||||
|
raise ValueError("EYS_0004")
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def update_password():
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
class LoginHandler:
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def is_occupant(email: str):
|
||||||
|
return not str(email).split("@")[1] == api_config.ACCESS_EMAIL_EXT
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def is_employee(email: str):
|
||||||
|
return str(email).split("@")[1] == api_config.ACCESS_EMAIL_EXT
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def do_employee_login(cls, headers: CommonHeaders, data: Any, db_session):
|
||||||
|
"""Handle employee login."""
|
||||||
|
user_handler, other_domains_list, main_domain = UserHandlers(), [], ""
|
||||||
|
found_user = user_handler.check_user_exists(access_key=data.access_key, db_session=db_session)
|
||||||
|
with mongo_handler.collection(f"{str(found_user.related_company)}*Domain") as collection:
|
||||||
|
result = collection.find_one({"user_uu_id": str(found_user.uu_id)})
|
||||||
|
if not result:
|
||||||
|
raise ValueError("EYS_00087")
|
||||||
|
other_domains_list = result.get("other_domains_list", [])
|
||||||
|
main_domain = result.get("main_domain", None)
|
||||||
|
if headers.domain not in other_domains_list or not main_domain:
|
||||||
|
raise ValueError("EYS_00088")
|
||||||
|
|
||||||
|
if not user_handler.check_password_valid(domain=main_domain, id_=str(found_user.uu_id), password=data.password, password_hashed=found_user.hash_password):
|
||||||
|
raise ValueError("EYS_0005")
|
||||||
|
list_of_returns = (
|
||||||
|
Employees.id, Employees.uu_id, People.id, People.uu_id, Users.id, Users.uu_id, Companies.id, Companies.uu_id,
|
||||||
|
Departments.id, Departments.uu_id, Duty.id, Duty.uu_id, Companies.public_name, Companies.company_type, Duty.duty_name,
|
||||||
|
Addresses.letter_address
|
||||||
|
)
|
||||||
|
|
||||||
|
list_employee_query = db_session.query(*list_of_returns
|
||||||
|
).join(Staff, Staff.id == Employees.staff_id
|
||||||
|
).join(People, People.id == Employees.people_id
|
||||||
|
).join(Duties, Duties.id == Staff.duties_id
|
||||||
|
).join(Duty, Duty.id == Duties.duties_id
|
||||||
|
).join(Departments, Departments.id == Duties.department_id
|
||||||
|
).join(Companies, Companies.id == Departments.company_id
|
||||||
|
).join(Users, Users.person_id == People.id
|
||||||
|
).outerjoin(Addresses, Addresses.id == Companies.official_address_id
|
||||||
|
).filter(Employees.people_id == found_user.person_id)
|
||||||
|
list_employees, list_employees_query_all = [], list_employee_query.all()
|
||||||
|
if not list_employees_query_all:
|
||||||
|
ValueError("No Employee found for this user")
|
||||||
|
|
||||||
|
for employee in list_employees_query_all:
|
||||||
|
single_employee = {}
|
||||||
|
for ix, returns in enumerate(list_of_returns):
|
||||||
|
single_employee[str(returns)] = employee[ix]
|
||||||
|
list_employees.append(single_employee)
|
||||||
|
companies_uu_id_list, companies_id_list, companies_list, duty_uu_id_list, duty_id_list = [], [], [], [], []
|
||||||
|
for list_employee in list_employees:
|
||||||
|
companies_id_list.append(int(list_employee["Companies.id"]))
|
||||||
|
companies_uu_id_list.append(str(list_employee["Companies.uu_id"]))
|
||||||
|
duty_uu_id_list.append(str(list_employee["Duty.uu_id"]))
|
||||||
|
duty_id_list.append(int(list_employee["Duty.id"]))
|
||||||
|
companies_list.append({
|
||||||
|
"uu_id": str(list_employee["Companies.uu_id"]), "public_name": list_employee["Companies.public_name"],
|
||||||
|
"company_type": list_employee["Companies.company_type"], "company_address": list_employee["Addresses.letter_address"],
|
||||||
|
"duty": list_employee["Duty.duty_name"]
|
||||||
|
})
|
||||||
|
model_value = EmployeeTokenObject(
|
||||||
|
user_type=UserType.employee.value,
|
||||||
|
user_uu_id=str(found_user.uu_id),
|
||||||
|
user_id=found_user.id,
|
||||||
|
person_id=found_user.person_id,
|
||||||
|
person_uu_id=str(list_employees[0]["People.uu_id"]),
|
||||||
|
request=dict(headers.request.headers),
|
||||||
|
domain_list=other_domains_list,
|
||||||
|
companies_uu_id_list=companies_uu_id_list,
|
||||||
|
companies_id_list=companies_id_list,
|
||||||
|
duty_uu_id_list=duty_uu_id_list,
|
||||||
|
duty_id_list=duty_id_list,
|
||||||
|
).model_dump()
|
||||||
|
set_to_redis_dict = dict(
|
||||||
|
user=found_user,
|
||||||
|
token=model_value,
|
||||||
|
header_info=dict(language=headers.language, domain=headers.domain, timezone=headers.timezone),
|
||||||
|
)
|
||||||
|
redis_handler = RedisHandlers()
|
||||||
|
user_dict = found_user.get_dict()
|
||||||
|
person_dict = found_user.person.get_dict()
|
||||||
|
if access_token := redis_handler.set_object_to_redis(**set_to_redis_dict):
|
||||||
|
return {
|
||||||
|
"access_token": access_token,
|
||||||
|
"user_type": UserType.employee.name,
|
||||||
|
"user": {
|
||||||
|
"uuid": user_dict["uu_id"],
|
||||||
|
"avatar": user_dict["avatar"],
|
||||||
|
"email": user_dict["email"],
|
||||||
|
"phone_number": user_dict["phone_number"],
|
||||||
|
"user_tag": user_dict["user_tag"],
|
||||||
|
"password_expiry_begins": str(arrow.get(user_dict["password_expiry_begins"]).shift(days=int(user_dict["password_expires_day"]))),
|
||||||
|
"person": {
|
||||||
|
"uuid": person_dict["uu_id"],
|
||||||
|
"firstname": person_dict["firstname"],
|
||||||
|
"surname": person_dict["surname"],
|
||||||
|
"middle_name": person_dict["middle_name"],
|
||||||
|
"sex_code": person_dict["sex_code"],
|
||||||
|
"person_tag": person_dict["person_tag"],
|
||||||
|
"country_code": person_dict["country_code"],
|
||||||
|
"birth_date": person_dict["birth_date"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"selection_list": companies_list,
|
||||||
|
}
|
||||||
|
raise ValueError("Something went wrong")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def do_occupant_login(cls, request: Any, data: Any, db_session, extra_dict: Optional[Dict[str, Any]] = None):
|
||||||
|
"""
|
||||||
|
Handle occupant login.
|
||||||
|
"""
|
||||||
|
language = extra_dict.get("language", "tr")
|
||||||
|
domain = extra_dict.get("domain", None)
|
||||||
|
timezone = extra_dict.get("tz", None) or "GMT+3"
|
||||||
|
|
||||||
|
user_handler = UserHandlers()
|
||||||
|
found_user = user_handler.check_user_exists(
|
||||||
|
access_key=data.access_key, db_session=db_session
|
||||||
|
)
|
||||||
|
other_domains_list, main_domain = [], ""
|
||||||
|
with mongo_handler.collection(
|
||||||
|
f"{str(found_user.related_company)}*Domain"
|
||||||
|
) as collection:
|
||||||
|
result = collection.find_one({"user_uu_id": str(found_user.uu_id)})
|
||||||
|
if not result:
|
||||||
|
raise ValueError("EYS_00087")
|
||||||
|
other_domains_list = result.get("other_domains_list", [])
|
||||||
|
main_domain = result.get("main_domain", None)
|
||||||
|
if domain not in other_domains_list or not main_domain:
|
||||||
|
raise ValueError("EYS_00088")
|
||||||
|
|
||||||
|
if not user_handler.check_password_valid(
|
||||||
|
domain=main_domain,
|
||||||
|
id_=str(found_user.uu_id),
|
||||||
|
password=data.password,
|
||||||
|
password_hashed=found_user.hash_password,
|
||||||
|
):
|
||||||
|
raise ValueError("EYS_0005")
|
||||||
|
|
||||||
|
occupants_selection_dict: Dict[str, Any] = {}
|
||||||
|
living_spaces: list[BuildLivingSpace] = BuildLivingSpace.filter_all(
|
||||||
|
BuildLivingSpace.person_id == found_user.person_id, db=db_session
|
||||||
|
).data
|
||||||
|
|
||||||
|
if not living_spaces:
|
||||||
|
raise ValueError("EYS_0006")
|
||||||
|
for living_space in living_spaces:
|
||||||
|
build_part = BuildParts.filter_one(
|
||||||
|
BuildParts.id == living_space.build_parts_id,
|
||||||
|
db=db_session,
|
||||||
|
).data
|
||||||
|
if not build_part:
|
||||||
|
raise ValueError("EYS_0007")
|
||||||
|
|
||||||
|
build = build_part.buildings
|
||||||
|
occupant_type = OccupantTypes.filter_by_one(
|
||||||
|
id=living_space.occupant_type_id,
|
||||||
|
db=db_session,
|
||||||
|
system=True,
|
||||||
|
).data
|
||||||
|
occupant_data = {
|
||||||
|
"build_living_space_uu_id": str(living_space.uu_id),
|
||||||
|
"part_uu_id": str(build_part.uu_id),
|
||||||
|
"part_name": build_part.part_name(db=db_session),
|
||||||
|
"part_level": build_part.part_level,
|
||||||
|
"occupant_uu_id": str(occupant_type.uu_id),
|
||||||
|
"description": occupant_type.occupant_description,
|
||||||
|
"code": occupant_type.occupant_code,
|
||||||
|
}
|
||||||
|
|
||||||
|
build_key = str(build.uu_id)
|
||||||
|
if build_key not in occupants_selection_dict:
|
||||||
|
occupants_selection_dict[build_key] = {
|
||||||
|
"build_uu_id": build_key,
|
||||||
|
"build_name": build.build_name,
|
||||||
|
"build_no": build.build_no,
|
||||||
|
"occupants": [occupant_data],
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
occupants_selection_dict[build_key]["occupants"].append(occupant_data)
|
||||||
|
|
||||||
|
person = found_user.person
|
||||||
|
model_value = OccupantTokenObject(
|
||||||
|
user_type=UserType.occupant.value,
|
||||||
|
user_uu_id=str(found_user.uu_id),
|
||||||
|
user_id=found_user.id,
|
||||||
|
person_id=person.id,
|
||||||
|
person_uu_id=str(person.uu_id),
|
||||||
|
domain_list=other_domains_list,
|
||||||
|
request=dict(request.headers),
|
||||||
|
available_occupants=occupants_selection_dict,
|
||||||
|
).model_dump()
|
||||||
|
redis_handler = RedisHandlers()
|
||||||
|
if access_token := redis_handler.set_object_to_redis(
|
||||||
|
user=found_user,
|
||||||
|
token=model_value,
|
||||||
|
header_info=dict(language=language, domain=domain, timezone=timezone),
|
||||||
|
):
|
||||||
|
return {
|
||||||
|
"access_token": access_token,
|
||||||
|
"user_type": UserType.occupant.name,
|
||||||
|
"selection_list": occupants_selection_dict,
|
||||||
|
}
|
||||||
|
raise ValueError("Something went wrong")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def authentication_login_with_domain_and_creds(cls, headers: CommonHeaders, data: Any):
|
||||||
|
"""
|
||||||
|
Authenticate user with domain and credentials.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
headers: CommonHeaders object
|
||||||
|
data: Request body containing login credentials
|
||||||
|
{
|
||||||
|
"access_key": "karatay.berkay.sup@evyos.com.tr",
|
||||||
|
"password": "string",
|
||||||
|
"remember_me": false
|
||||||
|
}
|
||||||
|
Returns:
|
||||||
|
SuccessResponse containing authentication token and user info
|
||||||
|
"""
|
||||||
|
|
||||||
|
with Users.new_session() as db_session:
|
||||||
|
if cls.is_employee(data.access_key):
|
||||||
|
return cls.do_employee_login(headers=headers, data=data, db_session=db_session)
|
||||||
|
elif cls.is_occupant(data.access_key):
|
||||||
|
return cls.do_occupant_login(headers=headers, data=data, db_session=db_session)
|
||||||
|
else:
|
||||||
|
raise ValueError("Invalid email format")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def raise_error_if_request_has_no_token(cls, request: Any) -> None:
|
||||||
|
"""Validate request has required token headers."""
|
||||||
|
if not hasattr(request, "headers"):
|
||||||
|
raise ValueError("Request has no headers")
|
||||||
|
if not request.headers.get(api_config.ACCESS_TOKEN_TAG):
|
||||||
|
raise ValueError("Request has no access token")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_access_token_from_request(cls, request: Any) -> str:
|
||||||
|
"""Extract access token from request headers."""
|
||||||
|
cls.raise_error_if_request_has_no_token(request=request)
|
||||||
|
return request.headers.get(api_config.ACCESS_TOKEN_TAG)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def handle_employee_selection(cls, access_token: str, data: Any, token_dict: TokenDictType):
|
||||||
|
with Users.new_session() as db_session:
|
||||||
|
if data.company_uu_id not in token_dict.companies_uu_id_list:
|
||||||
|
ValueError("EYS_0011")
|
||||||
|
list_of_returns = (
|
||||||
|
Employees.id, Employees.uu_id, People.id, People.uu_id, Users.id, Users.uu_id, Companies.id, Companies.uu_id,
|
||||||
|
Departments.id, Departments.uu_id, Duty.id, Duty.uu_id, Addresses.id, Addresses.letter_address, Staff.id, Staff.uu_id,
|
||||||
|
Duties.id, Duties.uu_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
selected_company_query = db_session.query(*list_of_returns
|
||||||
|
).join(Staff, Staff.id == Employees.staff_id
|
||||||
|
).join(People, People.id == Employees.people_id
|
||||||
|
).join(Duties, Duties.id == Staff.duties_id
|
||||||
|
).join(Duty, Duty.id == Duties.duties_id
|
||||||
|
).join(Departments, Departments.id == Duties.department_id
|
||||||
|
).join(Companies, Companies.id == Departments.company_id
|
||||||
|
).join(Users, Users.person_id == People.id
|
||||||
|
).outerjoin(Addresses, Addresses.id == Companies.official_address_id
|
||||||
|
).filter(Companies.uu_id == data.company_uu_id, Users.id == token_dict.user_id)
|
||||||
|
|
||||||
|
selected_company_first = selected_company_query.first()
|
||||||
|
if not selected_company_first:
|
||||||
|
ValueError("Selected company not found")
|
||||||
|
|
||||||
|
result_with_keys_dict = {}
|
||||||
|
for ix, selected_company_item in enumerate(selected_company_first):
|
||||||
|
result_with_keys_dict[str(list_of_returns[ix])] = selected_company_item
|
||||||
|
|
||||||
|
if not selected_company_first:
|
||||||
|
ValueError("EYS_0010")
|
||||||
|
|
||||||
|
# Get reachable events
|
||||||
|
reachable_event_codes = Event2Employee.get_event_codes(employee_id=int(result_with_keys_dict['Employees.id']), db=db_session)
|
||||||
|
# Get reachable applications
|
||||||
|
reachable_app_codes = Application2Employee.get_application_codes(employee_id=int(result_with_keys_dict['Employees.id']), db=db_session)
|
||||||
|
|
||||||
|
company_token = CompanyToken(
|
||||||
|
company_uu_id=str(result_with_keys_dict['Companies.uu_id']),
|
||||||
|
company_id=int(result_with_keys_dict['Companies.id']),
|
||||||
|
department_id=int(result_with_keys_dict['Departments.id']),
|
||||||
|
department_uu_id=str(result_with_keys_dict['Departments.uu_id']),
|
||||||
|
duty_id=int(result_with_keys_dict['Duty.id']),
|
||||||
|
duty_uu_id=str(result_with_keys_dict['Duty.uu_id']),
|
||||||
|
bulk_duties_id=int(result_with_keys_dict['Duties.id']),
|
||||||
|
staff_id=int(result_with_keys_dict['Staff.id']),
|
||||||
|
staff_uu_id=str(result_with_keys_dict['Staff.uu_id']),
|
||||||
|
employee_id=int(result_with_keys_dict['Employees.id']),
|
||||||
|
employee_uu_id=str(result_with_keys_dict['Employees.uu_id']),
|
||||||
|
reachable_event_codes=reachable_event_codes,
|
||||||
|
reachable_app_codes=reachable_app_codes,
|
||||||
|
)
|
||||||
|
redis_handler = RedisHandlers()
|
||||||
|
redis_result = redis_handler.update_token_at_redis(token=access_token, add_payload=company_token)
|
||||||
|
return {"selected_uu_id": data.company_uu_id}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def handle_occupant_selection(cls, access_token: str, data: Any, token_dict: TokenDictType):
|
||||||
|
"""Handle occupant type selection"""
|
||||||
|
with BuildLivingSpace.new_session() as db:
|
||||||
|
# Get selected occupant type
|
||||||
|
selected_build_living_space: BuildLivingSpace = BuildLivingSpace.filter_one(BuildLivingSpace.uu_id == data.build_living_space_uu_id, db=db).data
|
||||||
|
if not selected_build_living_space:
|
||||||
|
raise ValueError("EYS_0012")
|
||||||
|
|
||||||
|
# Get reachable events
|
||||||
|
reachable_event_codes = Event2Occupant.get_event_codes(build_living_space_id=selected_build_living_space.id, db=db)
|
||||||
|
occupant_type = OccupantTypes.filter_one_system(OccupantTypes.id == selected_build_living_space.occupant_type_id, db=db).data
|
||||||
|
build_part = BuildParts.filter_one(BuildParts.id == selected_build_living_space.build_parts_id, db=db)
|
||||||
|
build = build_part.buildings
|
||||||
|
reachable_app_codes = Application2Occupant.get_application_codes(build_living_space_id=selected_build_living_space.id, db=db)
|
||||||
|
# responsible_employee = Employees.filter_one(
|
||||||
|
# Employees.id == build_part.responsible_employee_id,
|
||||||
|
# db=db,
|
||||||
|
# ).data
|
||||||
|
# related_company = RelationshipEmployee2Build.filter_one(
|
||||||
|
# RelationshipEmployee2Build.member_id == build.id,
|
||||||
|
# db=db,
|
||||||
|
# ).data
|
||||||
|
# Get company
|
||||||
|
# company_related = Companies.filter_one(
|
||||||
|
# Companies.id == related_company.company_id,
|
||||||
|
# db=db,
|
||||||
|
# ).data
|
||||||
|
|
||||||
|
# Create occupant token
|
||||||
|
occupant_token = OccupantToken(
|
||||||
|
living_space_id=selected_build_living_space.id,
|
||||||
|
living_space_uu_id=selected_build_living_space.uu_id.__str__(),
|
||||||
|
occupant_type_id=occupant_type.id,
|
||||||
|
occupant_type_uu_id=occupant_type.uu_id.__str__(),
|
||||||
|
occupant_type=occupant_type.occupant_type,
|
||||||
|
build_id=build.id,
|
||||||
|
build_uuid=build.uu_id.__str__(),
|
||||||
|
build_part_id=build_part.id,
|
||||||
|
build_part_uuid=build_part.uu_id.__str__(),
|
||||||
|
# responsible_employee_id=responsible_employee.id,
|
||||||
|
# responsible_employee_uuid=responsible_employee.uu_id.__str__(),
|
||||||
|
# responsible_company_id=company_related.id,
|
||||||
|
# responsible_company_uuid=company_related.uu_id.__str__(),
|
||||||
|
reachable_event_codes=reachable_event_codes,
|
||||||
|
reachable_app_codes=reachable_app_codes,
|
||||||
|
)
|
||||||
|
redis_handler = RedisHandlers()
|
||||||
|
redis_handler.update_token_at_redis(token=access_token, add_payload=occupant_token)
|
||||||
|
return {"selected_uu_id": occupant_token.living_space_uu_id}
|
||||||
|
|
||||||
|
@classmethod # Requires auth context
|
||||||
|
def authentication_select_company_or_occupant_type(cls, request: Any, data: Any):
|
||||||
|
"""
|
||||||
|
Handle selection of company or occupant type
|
||||||
|
{"data": {"build_living_space_uu_id": ""}} | {"data": {"company_uu_id": ""}}
|
||||||
|
{
|
||||||
|
"data": {"company_uu_id": "e9869a25-ba4d-49dc-bb0d-8286343b184b"}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"data": {"build_living_space_uu_id": "e9869a25-ba4d-49dc-bb0d-8286343b184b"}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
access_token = request.headers.get(api_config.ACCESS_TOKEN_TAG, None)
|
||||||
|
if not access_token:
|
||||||
|
raise ValueError("EYS_0001")
|
||||||
|
|
||||||
|
token_object = RedisHandlers.get_object_from_redis(access_token=access_token)
|
||||||
|
if token_object.is_employee:
|
||||||
|
return cls.handle_employee_selection(access_token=access_token, data=data, token_dict=token_object)
|
||||||
|
elif token_object.is_occupant:
|
||||||
|
return cls.handle_occupant_selection(access_token=access_token, data=data, token_dict=token_object)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def authentication_check_token_valid(cls, domain, access_token: str) -> bool:
|
||||||
|
redis_handler = RedisHandlers()
|
||||||
|
if auth_token := redis_handler.get_object_from_redis(access_token=access_token):
|
||||||
|
if auth_token.is_employee:
|
||||||
|
if domain not in auth_token.domain_list:
|
||||||
|
raise ValueError("EYS_00112")
|
||||||
|
return True
|
||||||
|
elif auth_token.is_occupant:
|
||||||
|
if domain not in auth_token.domain_list:
|
||||||
|
raise ValueError("EYS_00113")
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class PasswordHandler:
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def create_password(password, password_token=None):
|
||||||
|
with Users.new_session() as db_session:
|
||||||
|
Users.set_session(db_session)
|
||||||
|
found_user = Users.query.filter(Users.password_token == password_token).first()
|
||||||
|
if not found_user:
|
||||||
|
raise ValueError("EYS_0031")
|
||||||
|
|
||||||
|
if found_user.password_token:
|
||||||
|
replace_day = 0
|
||||||
|
try:
|
||||||
|
replace_day = int(str(found_user.password_expires_day or 0).split(",")[0].replace(" days", ""))
|
||||||
|
except Exception as e:
|
||||||
|
err = e
|
||||||
|
token_is_expired = arrow.now() >= arrow.get(str(found_user.password_expiry_begins)).shift(days=replace_day)
|
||||||
|
if not str(password_token) == str(found_user.password_token) or token_is_expired:
|
||||||
|
raise ValueError("EYS_0032")
|
||||||
|
|
||||||
|
collection_name = f"{found_user.related_company}*Domain"
|
||||||
|
with mongo_handler.collection(collection_name) as mongo_engine:
|
||||||
|
domain_via_user = mongo_engine.find_one({"user_uu_id": str(found_user.uu_id)})
|
||||||
|
if not domain_via_user:
|
||||||
|
raise ValueError("EYS_0024")
|
||||||
|
domain_via_user = domain_via_user.get("main_domain", None)
|
||||||
|
new_password_dict = {
|
||||||
|
"password": PasswordModule.create_hashed_password(domain=domain_via_user, id_=str(found_user.uu_id), password=password),
|
||||||
|
"date": str(arrow.now().date()),
|
||||||
|
}
|
||||||
|
history_dict = PasswordHistoryViaUser(user_uu_id=str(found_user.uu_id), password_add=new_password_dict, access_history_detail={"request": "", "ip": ""})
|
||||||
|
found_user.password_expiry_begins = str(arrow.now())
|
||||||
|
found_user.hash_password = new_password_dict.get("password")
|
||||||
|
found_user.password_token = "" if found_user.password_token else ""
|
||||||
|
|
||||||
|
collection_name = f"{found_user.related_company}*PasswordHistory"
|
||||||
|
with mongo_handler.collection(collection_name) as mongo_engine_sc:
|
||||||
|
password_history_item = mongo_engine_sc.find_one({"user_uu_id": str(found_user.uu_id)})
|
||||||
|
if not password_history_item:
|
||||||
|
mongo_engine_sc.insert_one(document={"user_uu_id": str(found_user.uu_id), "password_history": []})
|
||||||
|
password_history_item = mongo_engine_sc.find_one({"user_uu_id": str(found_user.uu_id)})
|
||||||
|
password_history_list = password_history_item.get("password_history", [])
|
||||||
|
hashed_password = history_dict.password_add.get("password")
|
||||||
|
for password_in_history in password_history_list:
|
||||||
|
print('password_history_list', password_history_list, password_in_history)
|
||||||
|
if str(password_in_history.get("password")) == str(hashed_password):
|
||||||
|
raise ValueError("EYS_0032")
|
||||||
|
if len(password_history_list) > 3:
|
||||||
|
password_history_list.pop(0)
|
||||||
|
password_history_list.append(history_dict.password_add)
|
||||||
|
return mongo_engine_sc.update_one(
|
||||||
|
filter={"user_uu_id": str(found_user.uu_id)},
|
||||||
|
update={"$set": {
|
||||||
|
"password_history": password_history_list, "modified_at": arrow.now().timestamp(), "access_history_detail": history_dict.access_history_detail
|
||||||
|
}}, upsert=True,
|
||||||
|
)
|
||||||
|
found_user.save(db=db_session)
|
||||||
|
return found_user
|
||||||
|
|
||||||
|
|
||||||
|
class PageHandlers:
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def retrieve_valid_page_via_token(cls, access_token: str, page_url: str) -> str:
|
||||||
|
"""
|
||||||
|
Retrieve valid page via token. {access_token: "string", page_url: "string"} | Results: str(application)
|
||||||
|
"""
|
||||||
|
if result := RedisHandlers.get_object_from_redis(access_token=access_token):
|
||||||
|
if result.is_employee:
|
||||||
|
if result.selected_company and result.selected_company.reachable_app_codes:
|
||||||
|
if application := result.selected_company.reachable_app_codes.get(page_url, None):
|
||||||
|
return application
|
||||||
|
elif result.is_occupant:
|
||||||
|
if result.selected_occupant and result.selected_occupant.reachable_app_codes:
|
||||||
|
if application := result.selected_occupant.reachable_app_codes.get(page_url, None):
|
||||||
|
return application
|
||||||
|
raise ValueError("EYS_0013")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def retrieve_valid_sites_via_token(cls, access_token: str) -> list:
|
||||||
|
"""
|
||||||
|
Retrieve valid pages via token. {"access_token": "string"} | Results: list(sites)
|
||||||
|
"""
|
||||||
|
if result := RedisHandlers.get_object_from_redis(access_token=access_token):
|
||||||
|
if result.is_employee:
|
||||||
|
if result.selected_company and result.selected_company.reachable_app_codes:
|
||||||
|
return result.selected_company.reachable_app_codes.keys()
|
||||||
|
elif result.is_occupant:
|
||||||
|
if result.selected_occupant and result.selected_occupant.reachable_app_codes:
|
||||||
|
return result.selected_occupant.reachable_app_codes.keys()
|
||||||
|
raise ValueError("EYS_0013")
|
||||||
|
|
||||||
|
|
||||||
|
class AuthHandlers:
|
||||||
|
|
||||||
|
LoginHandler: LoginHandler = LoginHandler()
|
||||||
|
PasswordHandler: PasswordHandler = PasswordHandler()
|
||||||
|
PageHandlers: PageHandlers = PageHandlers()
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
from typing import Optional
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
|
class DomainViaUser(BaseModel):
|
||||||
|
user_uu_id: str
|
||||||
|
main_domain: str
|
||||||
|
other_domains_list: Optional[list] = None
|
||||||
|
|
||||||
|
|
||||||
|
class PasswordHistoryViaUser(BaseModel):
|
||||||
|
user_uu_id: str
|
||||||
|
password_add: dict
|
||||||
|
access_history_detail: Optional[dict]
|
||||||
|
|
||||||
|
|
||||||
|
class AccessHistoryViaUser(BaseModel):
|
||||||
|
user_uu_id: str
|
||||||
|
access_history: dict
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
from typing import Optional
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class RequestLogin(BaseModel):
|
||||||
|
access_key: str
|
||||||
|
password: str
|
||||||
|
remember_me: Optional[bool]
|
||||||
|
|
||||||
|
|
||||||
|
class RequestVerifyOTP(BaseModel):
|
||||||
|
token: str
|
||||||
|
otp: str
|
||||||
|
|
||||||
|
|
||||||
|
class RequestApplication(BaseModel):
|
||||||
|
page_url: str # /building/create
|
||||||
|
|
||||||
|
|
||||||
|
class RequestSelectEmployee(BaseModel):
|
||||||
|
|
||||||
|
company_uu_id: str
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_employee(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_occupant(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class RequestResetPassword(BaseModel):
|
||||||
|
password_token: str
|
||||||
|
password: str
|
||||||
|
re_password: str
|
||||||
|
|
||||||
|
|
||||||
|
class RequestSelectLiving(BaseModel):
|
||||||
|
|
||||||
|
build_living_space_uu_id: str
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_employee(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_occupant(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class RequestCreatePassword(BaseModel):
|
||||||
|
password_token: str
|
||||||
|
password: str
|
||||||
|
re_password: str
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_valid(self):
|
||||||
|
return self.password == self.re_password
|
||||||
|
|
||||||
|
|
||||||
|
class RequestChangePassword(BaseModel):
|
||||||
|
old_password: str
|
||||||
|
password: str
|
||||||
|
re_password: str
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_valid(self):
|
||||||
|
return self.password == self.re_password
|
||||||
|
|
||||||
|
|
||||||
|
class RequestForgotPasswordEmail(BaseModel):
|
||||||
|
email: str
|
||||||
|
|
||||||
|
|
||||||
|
class RequestForgotPasswordPhone(BaseModel):
|
||||||
|
phone_number: str
|
||||||
|
|
@ -14,6 +14,7 @@ RUN poetry config virtualenvs.create false && poetry install --no-interaction --
|
||||||
# Copy application code
|
# Copy application code
|
||||||
COPY /api_services/api_controllers /api_controllers
|
COPY /api_services/api_controllers /api_controllers
|
||||||
COPY /api_services/schemas /schemas
|
COPY /api_services/schemas /schemas
|
||||||
|
COPY /api_services/api_modules /api_modules
|
||||||
|
|
||||||
COPY /api_services/api_builds/initial-service /initial-service
|
COPY /api_services/api_builds/initial-service /initial-service
|
||||||
COPY /api_services/api_builds/initial-service /
|
COPY /api_services/api_builds/initial-service /
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import arrow
|
import arrow
|
||||||
|
|
||||||
from modules.Token.password_module import PasswordModule
|
from api_modules.token.password_module import PasswordModule
|
||||||
from api_controllers.mongo.database import mongo_handler
|
from api_controllers.mongo.database import mongo_handler
|
||||||
from schemas import (
|
from schemas import (
|
||||||
Companies,
|
Companies,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import arrow
|
import arrow
|
||||||
from modules.Token.password_module import PasswordModule
|
from api_modules.token.password_module import PasswordModule
|
||||||
from api_controllers.mongo.database import mongo_handler
|
from api_controllers.mongo.database import mongo_handler
|
||||||
from schemas import (
|
from schemas import (
|
||||||
Addresses,
|
Addresses,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
endpoints_index: dict = {
|
||||||
|
"AccountRecordsAll": "d538deb4-38f4-4913-a1af-bbef14cf6873",
|
||||||
|
"AccountRecordsMonthly": "c0f5ccb1-1e56-4653-af13-ec0bf5e6aa51",
|
||||||
|
"EventsListAvailable": "034a7eb7-0186-4f48-bb8c-165c429ad5c1",
|
||||||
|
"EventsListAppended": "ec1f3ec3-3f28-4eaf-b89a-c463632c0b90",
|
||||||
|
"EventServiceRegister": "2cf99f10-72f0-4c2b-98be-3082d67b950d",
|
||||||
|
"EventServiceUnRegister": "15c24c6c-651b-4c5d-9c2b-5c6c6c6c6c6c",
|
||||||
|
"EventBindExtraEmployee": "74cafa62-674e-41da-959d-1238ad4a443c",
|
||||||
|
"EventBindExtraOccupant": "480bee12-8dfd-4242-b481-f6807eb9adf7",
|
||||||
|
"ApplicationListAll": "a61169be-a009-47ec-8658-3dd388af5c3e",
|
||||||
|
"ApplicationListAvailable": "bf8d7986-2db7-4ff8-80c2-1935977730a6",
|
||||||
|
"ApplicationListAppended": "ff7bde16-2631-4465-a4c5-349b357dd334",
|
||||||
|
"ApplicationRegisterService": "c77a9f36-c007-4079-83fa-1c995b585a6f",
|
||||||
|
"ApplicationUnRegisterService": "48460f25-fb1e-477f-b641-d5eeacce5e7a",
|
||||||
|
"ApplicationCreate": "a3ec9f67-12a2-4e8a-b977-1acfa0069c12",
|
||||||
|
"ApplicationUpdate": "83281757-696a-41ed-9706-e145ac54c3a9",
|
||||||
|
"ApplicationBindEmployee": "80427237-5ab6-4d17-8084-cdb87bda22a3",
|
||||||
|
"ApplicationBindOccupant": "ae0fb101-cb13-47ab-86bd-233a5dbef269",
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
from fastapi import APIRouter
|
||||||
|
|
||||||
|
|
||||||
|
def get_routes() -> list[APIRouter]:
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def get_safe_endpoint_urls() -> list[tuple[str, str]]:
|
||||||
|
return [
|
||||||
|
("/", "GET"),
|
||||||
|
("/docs", "GET"),
|
||||||
|
("/redoc", "GET"),
|
||||||
|
("/openapi.json", "GET"),
|
||||||
|
("/metrics", "GET"),
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = []
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
|
||||||
|
|
||||||
|
events_index: dict = {
|
||||||
|
"Slot1": "",
|
||||||
|
"Slot2": "",
|
||||||
|
"Slot3": "",
|
||||||
|
"Slot4": "",
|
||||||
|
"Slot5": "",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -1,12 +1,18 @@
|
||||||
import arrow
|
import arrow
|
||||||
|
import datetime
|
||||||
|
|
||||||
from sqlalchemy import Column, Integer, String, Float, ForeignKey, UUID, TIMESTAMP, Boolean, SmallInteger, Numeric, func, text
|
from decimal import Decimal
|
||||||
|
from typing import Any, Optional
|
||||||
|
|
||||||
|
from sqlalchemy import Column, Integer, String, Float, ForeignKey, UUID, TIMESTAMP, Boolean, SmallInteger, Numeric, func, text, NUMERIC
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship
|
||||||
from sqlalchemy.orm import Mapped, mapped_column
|
from sqlalchemy.orm import Mapped, mapped_column
|
||||||
from sqlalchemy_mixins.serialize import SerializeMixin
|
from sqlalchemy_mixins.serialize import SerializeMixin
|
||||||
from sqlalchemy_mixins.repr import ReprMixin
|
from sqlalchemy_mixins.repr import ReprMixin
|
||||||
from sqlalchemy_mixins.smartquery import SmartQueryMixin
|
from sqlalchemy_mixins.smartquery import SmartQueryMixin
|
||||||
from sqlalchemy_mixins.activerecord import ActiveRecordMixin
|
from sqlalchemy_mixins.activerecord import ActiveRecordMixin
|
||||||
|
from sqlalchemy.orm import InstrumentedAttribute, Mapped
|
||||||
|
|
||||||
from api_controllers.postgres.engine import get_db, Base
|
from api_controllers.postgres.engine import get_db, Base
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -26,6 +32,100 @@ class BasicMixin(
|
||||||
"""Get database session."""
|
"""Get database session."""
|
||||||
return get_db()
|
return get_db()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def iterate_over_variables(cls, val: Any, key: str) -> tuple[bool, Optional[Any]]:
|
||||||
|
"""
|
||||||
|
Process a field value based on its type and convert it to the appropriate format.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
val: Field value
|
||||||
|
key: Field name
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Tuple of (should_include, processed_value)
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
key_ = cls.__annotations__.get(key, None)
|
||||||
|
is_primary = key in getattr(cls, "primary_keys", [])
|
||||||
|
row_attr = bool(getattr(getattr(cls, key), "foreign_keys", None))
|
||||||
|
|
||||||
|
# Skip primary keys and foreign keys
|
||||||
|
if is_primary or row_attr:
|
||||||
|
return False, None
|
||||||
|
|
||||||
|
if val is None: # Handle None values
|
||||||
|
return True, None
|
||||||
|
|
||||||
|
if str(key[-5:]).lower() == "uu_id": # Special handling for UUID fields
|
||||||
|
return True, str(val)
|
||||||
|
|
||||||
|
if key_: # Handle typed fields
|
||||||
|
if key_ == Mapped[int]:
|
||||||
|
return True, int(val)
|
||||||
|
elif key_ == Mapped[bool]:
|
||||||
|
return True, bool(val)
|
||||||
|
elif key_ == Mapped[float] or key_ == Mapped[NUMERIC]:
|
||||||
|
return True, round(float(val), 3)
|
||||||
|
elif key_ == Mapped[TIMESTAMP]:
|
||||||
|
return True, str(arrow.get(str(val)).format("YYYY-MM-DD HH:mm:ss"))
|
||||||
|
elif key_ == Mapped[str]:
|
||||||
|
return True, str(val)
|
||||||
|
else: # Handle based on Python types
|
||||||
|
if isinstance(val, datetime.datetime):
|
||||||
|
return True, str(arrow.get(str(val)).format("YYYY-MM-DD HH:mm:ss"))
|
||||||
|
elif isinstance(val, bool):
|
||||||
|
return True, bool(val)
|
||||||
|
elif isinstance(val, (float, Decimal)):
|
||||||
|
return True, round(float(val), 3)
|
||||||
|
elif isinstance(val, int):
|
||||||
|
return True, int(val)
|
||||||
|
elif isinstance(val, str):
|
||||||
|
return True, str(val)
|
||||||
|
elif val is None:
|
||||||
|
return True, None
|
||||||
|
return False, None
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
err = e
|
||||||
|
return False, None
|
||||||
|
|
||||||
|
def get_dict(self, exclude_list: Optional[list[InstrumentedAttribute]] = None) -> dict[str, Any]:
|
||||||
|
"""
|
||||||
|
Convert model instance to dictionary with customizable fields.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
exclude_list: List of fields to exclude from the dictionary
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dictionary representation of the model
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return_dict: Dict[str, Any] = {}
|
||||||
|
exclude_list = exclude_list or []
|
||||||
|
exclude_list = [exclude_arg.key for exclude_arg in exclude_list]
|
||||||
|
|
||||||
|
# Get all column names from the model
|
||||||
|
columns = [col.name for col in self.__table__.columns]
|
||||||
|
columns_set = set(columns)
|
||||||
|
|
||||||
|
# Filter columns
|
||||||
|
columns_list = set([col for col in columns_set if str(col)[-2:] != "id"])
|
||||||
|
columns_extend = set(col for col in columns_set if str(col)[-5:].lower() == "uu_id")
|
||||||
|
columns_list = set(columns_list) | set(columns_extend)
|
||||||
|
columns_list = list(set(columns_list) - set(exclude_list))
|
||||||
|
|
||||||
|
for key in columns_list:
|
||||||
|
val = getattr(self, key)
|
||||||
|
correct, value_of_database = self.iterate_over_variables(val, key)
|
||||||
|
if correct:
|
||||||
|
return_dict[key] = value_of_database
|
||||||
|
|
||||||
|
return return_dict
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
err = e
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
class CrudMixin(BasicMixin):
|
class CrudMixin(BasicMixin):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,9 @@ This module provides a class for managing Redis key-value operations with suppor
|
||||||
|
|
||||||
import arrow
|
import arrow
|
||||||
import json
|
import json
|
||||||
from typing import Union, Dict, List, Optional, Any, TypeVar
|
|
||||||
|
|
||||||
from Controllers.Redis.connection import redis_cli
|
from typing import Union, Dict, List, Optional, Any, TypeVar
|
||||||
|
from .connection import redis_cli
|
||||||
|
|
||||||
|
|
||||||
T = TypeVar("T", Dict[str, Any], List[Any])
|
T = TypeVar("T", Dict[str, Any], List[Any])
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import time
|
||||||
|
|
||||||
from typing import Dict, Any
|
from typing import Dict, Any
|
||||||
from redis import Redis, ConnectionError, TimeoutError, ConnectionPool
|
from redis import Redis, ConnectionError, TimeoutError, ConnectionPool
|
||||||
from Controllers.Redis.config import redis_configs
|
from .config import redis_configs
|
||||||
|
|
||||||
|
|
||||||
class RedisConn:
|
class RedisConn:
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@ import arrow
|
||||||
|
|
||||||
from typing import Optional, List, Dict, Union, Iterator
|
from typing import Optional, List, Dict, Union, Iterator
|
||||||
|
|
||||||
from Controllers.Redis.response import RedisResponse
|
from .response import RedisResponse
|
||||||
from Controllers.Redis.connection import redis_cli
|
from .connection import redis_cli
|
||||||
from Controllers.Redis.base import RedisRow
|
from .base import RedisRow
|
||||||
|
|
||||||
|
|
||||||
class MainConfig:
|
class MainConfig:
|
||||||
|
|
@ -87,9 +87,7 @@ class RedisActions:
|
||||||
return bool(redis_cli.exists(key))
|
return bool(redis_cli.exists(key))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def refresh_ttl(
|
def refresh_ttl(cls, key: Union[str, bytes], expires: Dict[str, int]) -> RedisResponse:
|
||||||
cls, key: Union[str, bytes], expires: Dict[str, int]
|
|
||||||
) -> RedisResponse:
|
|
||||||
"""
|
"""
|
||||||
Refresh TTL for an existing key.
|
Refresh TTL for an existing key.
|
||||||
|
|
||||||
|
|
@ -160,9 +158,7 @@ class RedisActions:
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def delete(
|
def delete(cls, list_keys: List[Union[Optional[str], Optional[bytes]]]) -> RedisResponse:
|
||||||
cls, list_keys: List[Union[Optional[str], Optional[bytes]]]
|
|
||||||
) -> RedisResponse:
|
|
||||||
"""
|
"""
|
||||||
Delete multiple keys matching a pattern.
|
Delete multiple keys matching a pattern.
|
||||||
|
|
||||||
|
|
@ -199,12 +195,7 @@ class RedisActions:
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def set_json(
|
def set_json(cls, list_keys: List[Union[str, bytes]], value: Optional[Union[Dict, List]], expires: Optional[Dict[str, int]] = None) -> RedisResponse:
|
||||||
cls,
|
|
||||||
list_keys: List[Union[str, bytes]],
|
|
||||||
value: Optional[Union[Dict, List]],
|
|
||||||
expires: Optional[Dict[str, int]] = None,
|
|
||||||
) -> RedisResponse:
|
|
||||||
"""
|
"""
|
||||||
Set JSON value in Redis with optional expiry.
|
Set JSON value in Redis with optional expiry.
|
||||||
|
|
||||||
|
|
@ -252,11 +243,7 @@ class RedisActions:
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_json(
|
def get_json(cls, list_keys: List[Union[Optional[str], Optional[bytes]]], limit: Optional[int] = None) -> RedisResponse:
|
||||||
cls,
|
|
||||||
list_keys: List[Union[Optional[str], Optional[bytes]]],
|
|
||||||
limit: Optional[int] = None,
|
|
||||||
) -> RedisResponse:
|
|
||||||
"""
|
"""
|
||||||
Get JSON values from Redis using pattern matching.
|
Get JSON values from Redis using pattern matching.
|
||||||
|
|
||||||
|
|
@ -313,9 +300,7 @@ class RedisActions:
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_json_iterator(
|
def get_json_iterator(cls, list_keys: List[Union[Optional[str], Optional[bytes]]]) -> Iterator[RedisRow]:
|
||||||
cls, list_keys: List[Union[Optional[str], Optional[bytes]]]
|
|
||||||
) -> Iterator[RedisRow]:
|
|
||||||
"""
|
"""
|
||||||
Get JSON values from Redis as an iterator for memory-efficient processing of large datasets.
|
Get JSON values from Redis as an iterator for memory-efficient processing of large datasets.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
from Controllers.Redis.database import RedisActions
|
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
import random
|
import random
|
||||||
import uuid
|
import uuid
|
||||||
import concurrent.futures
|
import concurrent.futures
|
||||||
|
|
||||||
|
from .database import RedisActions
|
||||||
|
|
||||||
|
|
||||||
def example_set_json() -> None:
|
def example_set_json() -> None:
|
||||||
"""Example of setting JSON data in Redis with and without expiry."""
|
"""Example of setting JSON data in Redis with and without expiry."""
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
from typing import Union, Dict, Optional, Any
|
from typing import Union, Dict, Optional, Any
|
||||||
from Controllers.Redis.base import RedisRow
|
from .base import RedisRow
|
||||||
|
|
||||||
|
|
||||||
class RedisResponse:
|
class RedisResponse:
|
||||||
|
|
@ -10,13 +10,7 @@ class RedisResponse:
|
||||||
with tools to convert between different data representations.
|
with tools to convert between different data representations.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(self, status: bool, message: str, data: Any = None, error: Optional[str] = None):
|
||||||
self,
|
|
||||||
status: bool,
|
|
||||||
message: str,
|
|
||||||
data: Any = None,
|
|
||||||
error: Optional[str] = None,
|
|
||||||
):
|
|
||||||
"""
|
"""
|
||||||
Initialize a Redis response.
|
Initialize a Redis response.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,10 @@ from api_initializer.create_app import create_app
|
||||||
|
|
||||||
# from prometheus_fastapi_instrumentator import Instrumentator
|
# from prometheus_fastapi_instrumentator import Instrumentator
|
||||||
|
|
||||||
|
|
||||||
app = create_app() # Create FastAPI application
|
app = create_app() # Create FastAPI application
|
||||||
# Instrumentator().instrument(app=app).expose(app=app) # Setup Prometheus metrics
|
# Instrumentator().instrument(app=app).expose(app=app) # Setup Prometheus metrics
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# Run the application with Uvicorn Server
|
uvicorn_config = uvicorn.Config(**api_config.app_as_dict, workers=1) # Run the application with Uvicorn Server
|
||||||
uvicorn_config = uvicorn.Config(**api_config.app_as_dict)
|
|
||||||
uvicorn.Server(uvicorn_config).run()
|
uvicorn.Server(uvicorn_config).run()
|
||||||
|
|
|
||||||
|
|
@ -3,34 +3,35 @@ from fastapi.middleware.cors import CORSMiddleware
|
||||||
from fastapi.responses import RedirectResponse
|
from fastapi.responses import RedirectResponse
|
||||||
from event_clusters import RouterCluster, EventCluster
|
from event_clusters import RouterCluster, EventCluster
|
||||||
from config import api_config
|
from config import api_config
|
||||||
|
from open_api_creator import create_openapi_schema
|
||||||
|
from create_route import RouteRegisterController
|
||||||
|
|
||||||
|
from api_middlewares.token_middleware import token_middleware
|
||||||
|
from endpoints.routes import get_routes
|
||||||
|
import events
|
||||||
|
|
||||||
|
|
||||||
cluster_is_set = False
|
cluster_is_set = False
|
||||||
|
|
||||||
|
|
||||||
def create_events_if_any_cluster_set():
|
|
||||||
import events
|
|
||||||
|
|
||||||
global cluster_is_set
|
|
||||||
if not events.__all__ or cluster_is_set:
|
|
||||||
return
|
|
||||||
|
|
||||||
router_cluster_stack: list[RouterCluster] = [getattr(events, e, None) for e in events.__all__]
|
|
||||||
for router_cluster in router_cluster_stack:
|
|
||||||
event_cluster_stack: list[EventCluster] = list(router_cluster.event_clusters.values())
|
|
||||||
for event_cluster in event_cluster_stack:
|
|
||||||
try:
|
|
||||||
event_cluster.set_events_to_database()
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error creating event cluster: {e}")
|
|
||||||
|
|
||||||
cluster_is_set = True
|
|
||||||
|
|
||||||
|
|
||||||
def create_app():
|
def create_app():
|
||||||
from open_api_creator import create_openapi_schema
|
|
||||||
from middlewares.token_middleware import token_middleware
|
def create_events_if_any_cluster_set():
|
||||||
from create_route import RouteRegisterController
|
|
||||||
from endpoints.routes import get_routes
|
global cluster_is_set
|
||||||
|
if not events.__all__ or cluster_is_set:
|
||||||
|
return
|
||||||
|
|
||||||
|
router_cluster_stack: list[RouterCluster] = [getattr(events, e, None) for e in events.__all__]
|
||||||
|
for router_cluster in router_cluster_stack:
|
||||||
|
event_cluster_stack: list[EventCluster] = list(router_cluster.event_clusters.values())
|
||||||
|
for event_cluster in event_cluster_stack:
|
||||||
|
try:
|
||||||
|
event_cluster.set_events_to_database()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error creating event cluster: {e}")
|
||||||
|
|
||||||
|
cluster_is_set = True
|
||||||
|
|
||||||
application = FastAPI(**api_config.api_info)
|
application = FastAPI(**api_config.api_info)
|
||||||
application.add_middleware(
|
application.add_middleware(
|
||||||
|
|
|
||||||
|
|
@ -12,44 +12,27 @@ class RouteRegisterController:
|
||||||
def add_router_with_event_to_database(router: APIRouter):
|
def add_router_with_event_to_database(router: APIRouter):
|
||||||
from schemas import EndpointRestriction
|
from schemas import EndpointRestriction
|
||||||
|
|
||||||
# Endpoint operation_id is static now if record exits update() record else create()
|
|
||||||
with EndpointRestriction.new_session() as db_session:
|
with EndpointRestriction.new_session() as db_session:
|
||||||
|
EndpointRestriction.set_session(db_session)
|
||||||
for route in router.routes:
|
for route in router.routes:
|
||||||
route_path = str(getattr(route, "path"))
|
route_path = str(getattr(route, "path"))
|
||||||
route_summary = str(getattr(route, "name"))
|
route_summary = str(getattr(route, "name"))
|
||||||
operation_id = getattr(route, "operation_id", None)
|
operation_id = getattr(route, "operation_id", None)
|
||||||
if not operation_id:
|
if not operation_id:
|
||||||
raise ValueError(f"Route {route_path} operation_id is not found")
|
raise ValueError(f"Route {route_path} operation_id is not found")
|
||||||
|
if not getattr(route, "methods") and isinstance(getattr(route, "methods")):
|
||||||
|
raise ValueError(f"Route {route_path} methods is not found")
|
||||||
|
|
||||||
for route_method in [
|
route_method = [method.lower() for method in getattr(route, "methods")][0]
|
||||||
method.lower() for method in getattr(route, "methods")
|
add_or_update_dict = dict(
|
||||||
]:
|
endpoint_method=route_method, endpoint_name=route_path, endpoint_desc=route_summary.replace("_", " "), endpoint_function=route_summary, is_confirmed=True
|
||||||
methods = [method.lower() for method in getattr(route, "methods")]
|
)
|
||||||
print('methods count : ', len(methods))
|
if to_save_endpoint := EndpointRestriction.query.filter(EndpointRestriction.operation_uu_id == operation_id).first():
|
||||||
print(dict(
|
to_save_endpoint.update(**add_or_update_dict)
|
||||||
route_method=route_method,
|
to_save_endpoint.save()
|
||||||
operation_uu_id=operation_id,
|
else:
|
||||||
route_path=route_path,
|
created_endpoint = EndpointRestriction.create(**add_or_update_dict, operation_uu_id=operation_id)
|
||||||
route_summary=route_summary,
|
created_endpoint.save()
|
||||||
))
|
|
||||||
# add_or_update_dict = dict(
|
|
||||||
# endpoint_method=route_method,
|
|
||||||
# endpoint_name=route_path,
|
|
||||||
# endpoint_desc=route_summary.replace("_", " "),
|
|
||||||
# endpoint_function=route_summary,
|
|
||||||
# operation_uu_id=operation_id,
|
|
||||||
# is_confirmed=True,
|
|
||||||
# )
|
|
||||||
# endpoint_restriction_found = EndpointRestriction.filter_one_system(
|
|
||||||
# EndpointRestriction.operation_uu_id == operation_id, db=db_session,
|
|
||||||
# ).data
|
|
||||||
# if endpoint_restriction_found:
|
|
||||||
# endpoint_restriction_found.update(**add_or_update_dict, db=db_session)
|
|
||||||
# endpoint_restriction_found.save(db=db_session)
|
|
||||||
# else:
|
|
||||||
# restriction = EndpointRestriction.find_or_create(**add_or_update_dict, db=db_session)
|
|
||||||
# if restriction.meta_data.created:
|
|
||||||
# restriction.save(db=db_session)
|
|
||||||
|
|
||||||
def register_routes(self):
|
def register_routes(self):
|
||||||
for router in self.router_list:
|
for router in self.router_list:
|
||||||
|
|
|
||||||
|
|
@ -39,18 +39,23 @@ class EventCluster:
|
||||||
# EndpointRestriction.operation_uu_id == self.endpoint_uu_id,
|
# EndpointRestriction.operation_uu_id == self.endpoint_uu_id,
|
||||||
# db=db_session,
|
# db=db_session,
|
||||||
# ).data:
|
# ).data:
|
||||||
for event in self.events:
|
Events.set_session(db_session)
|
||||||
event_dict_to_save = dict(
|
EndpointRestriction.set_session(db_session)
|
||||||
function_code=event.key,
|
|
||||||
function_class=event.name,
|
if to_save_endpoint := EndpointRestriction.query.filter(EndpointRestriction.operation_uu_id == self.endpoint_uu_id).first():
|
||||||
description=event.description,
|
print('to_save_endpoint', to_save_endpoint)
|
||||||
endpoint_code=self.endpoint_uu_id,
|
for event in self.events:
|
||||||
endpoint_id=to_save_endpoint.id,
|
event_dict_to_save = dict(
|
||||||
endpoint_uu_id=str(to_save_endpoint.uu_id),
|
function_code=event.key,
|
||||||
is_confirmed=True,
|
function_class=event.name,
|
||||||
db=db_session,
|
description=event.description,
|
||||||
)
|
endpoint_code=self.endpoint_uu_id,
|
||||||
print('event_dict_to_save', event_dict_to_save)
|
endpoint_id=to_save_endpoint.id,
|
||||||
|
endpoint_uu_id=str(to_save_endpoint.uu_id),
|
||||||
|
is_confirmed=True,
|
||||||
|
)
|
||||||
|
print('set_events_to_database event_dict_to_save', event_dict_to_save)
|
||||||
|
|
||||||
# event_found = Events.filter_one(
|
# event_found = Events.filter_one(
|
||||||
# Events.function_code == event_dict_to_save["function_code"],
|
# Events.function_code == event_dict_to_save["function_code"],
|
||||||
# db=db_session,
|
# db=db_session,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
import enum
|
||||||
|
|
||||||
|
from typing import Optional, Union, Dict, Any, List
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
from api_controllers.redis.database import RedisActions
|
||||||
|
from api_validations.token.validations import (
|
||||||
|
TokenDictType,
|
||||||
|
OccupantTokenObject,
|
||||||
|
EmployeeTokenObject,
|
||||||
|
UserType,
|
||||||
|
)
|
||||||
|
|
||||||
|
class TokenProvider:
|
||||||
|
|
||||||
|
AUTH_TOKEN: str = "AUTH_TOKEN"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def convert_redis_object_to_token(cls, redis_object: Dict[str, Any]) -> TokenDictType:
|
||||||
|
"""
|
||||||
|
Process Redis object and return appropriate token object.
|
||||||
|
"""
|
||||||
|
if redis_object.get("user_type") == UserType.employee.value:
|
||||||
|
return EmployeeTokenObject(**redis_object)
|
||||||
|
elif redis_object.get("user_type") == UserType.occupant.value:
|
||||||
|
return OccupantTokenObject(**redis_object)
|
||||||
|
raise ValueError("Invalid user type")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_dict_from_redis(cls, token: Optional[str] = None, user_uu_id: Optional[str] = None) -> Union[TokenDictType, List[TokenDictType]]:
|
||||||
|
"""
|
||||||
|
Retrieve token object from Redis using token and user_uu_id
|
||||||
|
"""
|
||||||
|
token_to_use, user_uu_id_to_use = token or "*", user_uu_id or "*"
|
||||||
|
list_of_token_dict, auth_key_list = [], [
|
||||||
|
cls.AUTH_TOKEN,
|
||||||
|
token_to_use,
|
||||||
|
user_uu_id_to_use,
|
||||||
|
]
|
||||||
|
if token:
|
||||||
|
result = RedisActions.get_json(list_keys=auth_key_list, limit=1)
|
||||||
|
if first_record := result.first:
|
||||||
|
return cls.convert_redis_object_to_token(first_record)
|
||||||
|
elif user_uu_id:
|
||||||
|
result = RedisActions.get_json(list_keys=auth_key_list)
|
||||||
|
if all_records := result.all:
|
||||||
|
for all_record in all_records:
|
||||||
|
list_of_token_dict.append(cls.convert_redis_object_to_token(all_record))
|
||||||
|
return list_of_token_dict
|
||||||
|
raise ValueError(
|
||||||
|
"Token not found in Redis. Please check the token or user_uu_id."
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def retrieve_application_codes(cls, page_url: str, token: TokenDictType):
|
||||||
|
"""
|
||||||
|
Retrieve application code from the token object or list of token objects.
|
||||||
|
"""
|
||||||
|
if isinstance(token, EmployeeTokenObject):
|
||||||
|
if application_codes := token.selected_company.reachable_app_codes.get(page_url, None):
|
||||||
|
return application_codes
|
||||||
|
elif isinstance(token, OccupantTokenObject):
|
||||||
|
if application_codes := token.selected_occupant.reachable_app_codes.get(page_url, None):
|
||||||
|
return application_codes
|
||||||
|
raise ValueError("Invalid token type or no application code found.")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def retrieve_event_codes(cls, endpoint_code: str, token: TokenDictType) -> str:
|
||||||
|
"""
|
||||||
|
Retrieve event code from the token object or list of token objects.
|
||||||
|
"""
|
||||||
|
if isinstance(token, EmployeeTokenObject):
|
||||||
|
if event_codes := token.selected_company.reachable_event_codes.get(endpoint_code, None):
|
||||||
|
return event_codes
|
||||||
|
elif isinstance(token, OccupantTokenObject):
|
||||||
|
if event_codes := token.selected_occupant.reachable_event_codes.get(endpoint_code, None):
|
||||||
|
return event_codes
|
||||||
|
raise ValueError("Invalid token type or no event code found.")
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
|
||||||
|
result_with_keys_dict {'Employees.id': 3, 'Employees.uu_id': UUID('2b757a5c-01bb-4213-9cf1-402480e73edc'), 'People.id': 2, 'People.uu_id': UUID('d945d320-2a4e-48db-a18c-6fd024beb517'), 'Users.id': 3, 'Users.uu_id': UUID('bdfa84d9-0e05-418c-9406-d6d1d41ae2a1'), 'Companies.id': 1, 'Companies.uu_id': UUID('da1de172-2f89-42d2-87f3-656b36a79d5b'), 'Departments.id': 3, 'Departments.uu_id': UUID('4edcec87-e072-408d-a780-3a62151b3971'), 'Duty.id': 9, 'Duty.uu_id': UUID('00d29292-c29e-4435-be41-9704ccf4b24d'), 'Addresses.id': None, 'Addresses.letter_address': None}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
from fastapi import Header, Request, Response
|
from fastapi import Header, Request, Response
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
from api_services.api_initializer.config import api_config
|
from config import api_config
|
||||||
|
|
||||||
|
|
||||||
class CommonHeaders(BaseModel):
|
class CommonHeaders(BaseModel):
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,123 @@
|
||||||
|
from enum import Enum
|
||||||
|
from pydantic import BaseModel
|
||||||
|
from typing import Optional, Union
|
||||||
|
|
||||||
|
|
||||||
|
class UserType(Enum):
|
||||||
|
|
||||||
|
employee = 1
|
||||||
|
occupant = 2
|
||||||
|
|
||||||
|
|
||||||
|
class Credentials(BaseModel):
|
||||||
|
|
||||||
|
person_id: int
|
||||||
|
person_name: str
|
||||||
|
|
||||||
|
|
||||||
|
class ApplicationToken(BaseModel):
|
||||||
|
# Application Token Object -> is the main object for the user
|
||||||
|
|
||||||
|
user_type: int = UserType.occupant.value
|
||||||
|
credential_token: str = ""
|
||||||
|
|
||||||
|
user_uu_id: str
|
||||||
|
user_id: int
|
||||||
|
|
||||||
|
person_id: int
|
||||||
|
person_uu_id: str
|
||||||
|
|
||||||
|
request: Optional[dict] = None # Request Info of Client
|
||||||
|
expires_at: Optional[float] = None # Expiry timestamp
|
||||||
|
|
||||||
|
|
||||||
|
class OccupantToken(BaseModel):
|
||||||
|
|
||||||
|
# Selection of the occupant type for a build part is made by the user
|
||||||
|
|
||||||
|
living_space_id: int # Internal use
|
||||||
|
living_space_uu_id: str # Outer use
|
||||||
|
|
||||||
|
occupant_type_id: int
|
||||||
|
occupant_type_uu_id: str
|
||||||
|
occupant_type: str
|
||||||
|
|
||||||
|
build_id: int
|
||||||
|
build_uuid: str
|
||||||
|
build_part_id: int
|
||||||
|
build_part_uuid: str
|
||||||
|
|
||||||
|
responsible_company_id: Optional[int] = None
|
||||||
|
responsible_company_uuid: Optional[str] = None
|
||||||
|
responsible_employee_id: Optional[int] = None
|
||||||
|
responsible_employee_uuid: Optional[str] = None
|
||||||
|
|
||||||
|
# ID list of reachable event codes as "endpoint_code": ["UUID", "UUID"]
|
||||||
|
reachable_event_codes: Optional[dict[str, str]] = None
|
||||||
|
|
||||||
|
# ID list of reachable applications as "page_url": ["UUID", "UUID"]
|
||||||
|
reachable_app_codes: Optional[dict[str, str]] = None
|
||||||
|
|
||||||
|
|
||||||
|
class CompanyToken(BaseModel):
|
||||||
|
|
||||||
|
# Selection of the company for an employee is made by the user
|
||||||
|
company_id: int
|
||||||
|
company_uu_id: str
|
||||||
|
|
||||||
|
department_id: int # ID list of departments
|
||||||
|
department_uu_id: str # ID list of departments
|
||||||
|
|
||||||
|
duty_id: int
|
||||||
|
duty_uu_id: str
|
||||||
|
|
||||||
|
staff_id: int
|
||||||
|
staff_uu_id: str
|
||||||
|
|
||||||
|
employee_id: int
|
||||||
|
employee_uu_id: str
|
||||||
|
bulk_duties_id: int
|
||||||
|
|
||||||
|
# ID list of reachable event codes as "endpoint_code": ["UUID", "UUID"]
|
||||||
|
reachable_event_codes: Optional[dict[str, str]] = None
|
||||||
|
|
||||||
|
# ID list of reachable applications as "page_url": ["UUID", "UUID"]
|
||||||
|
reachable_app_codes: Optional[dict[str, str]] = None
|
||||||
|
|
||||||
|
|
||||||
|
class OccupantTokenObject(ApplicationToken):
|
||||||
|
# Occupant Token Object -> Requires selection of the occupant type for a specific build part
|
||||||
|
|
||||||
|
available_occupants: dict = None
|
||||||
|
selected_occupant: Optional[OccupantToken] = None # Selected Occupant Type
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_employee(self) -> bool:
|
||||||
|
return False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_occupant(self) -> bool:
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class EmployeeTokenObject(ApplicationToken):
|
||||||
|
# Full hierarchy Employee[staff_id] -> Staff -> Duty -> Department -> Company
|
||||||
|
|
||||||
|
companies_id_list: list[int] # List of company objects
|
||||||
|
companies_uu_id_list: list[str] # List of company objects
|
||||||
|
|
||||||
|
duty_id_list: list[int] # List of duty objects
|
||||||
|
duty_uu_id_list: list[str] # List of duty objects
|
||||||
|
|
||||||
|
selected_company: Optional[CompanyToken] = None # Selected Company Object
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_employee(self) -> bool:
|
||||||
|
return True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_occupant(self) -> bool:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
TokenDictType = Union[EmployeeTokenObject, OccupantTokenObject]
|
||||||
|
|
@ -316,27 +316,16 @@ class Event2Employee(CrudCollection):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_event_codes(cls, employee_id: int, db) -> dict[str:str]:
|
def get_event_codes(cls, employee_id: int, db) -> dict[str:str]:
|
||||||
employee_events = cls.filter_all(
|
cls.set_session(db)
|
||||||
cls.employee_id == employee_id,
|
Service2Events.set_session(db)
|
||||||
db=db,
|
Events.set_session(db)
|
||||||
).data
|
Event2EmployeeExtra.set_session(db)
|
||||||
|
employee_events = cls.query.filter(cls.employee_id == employee_id).all()
|
||||||
service_ids = list(set([event.event_service_id for event in employee_events]))
|
service_ids = list(set([event.event_service_id for event in employee_events]))
|
||||||
active_event_ids = Service2Events.filter_all(
|
active_event_ids = Service2Events.query.filter(Service2Events.service_id.in_(service_ids)).all()
|
||||||
Service2Events.service_id.in_(service_ids),
|
active_events = Events.query.filter(Events.id.in_([event.event_id for event in active_event_ids])).all()
|
||||||
db=db,
|
if extra_events := Event2EmployeeExtra.query.filter(Event2EmployeeExtra.employee_id == employee_id).all():
|
||||||
).data
|
events_extra = Events.query.filter(Events.id.in_([event.event_id for event in extra_events]),).all()
|
||||||
active_events = Events.filter_all(
|
|
||||||
Events.id.in_([event.event_id for event in active_event_ids]),
|
|
||||||
db=db,
|
|
||||||
).data
|
|
||||||
if extra_events := Event2EmployeeExtra.filter_all(
|
|
||||||
Event2EmployeeExtra.employee_id == employee_id,
|
|
||||||
db=db,
|
|
||||||
).data:
|
|
||||||
events_extra = Events.filter_all(
|
|
||||||
Events.id.in_([event.event_id for event in extra_events]),
|
|
||||||
db=db,
|
|
||||||
).data
|
|
||||||
active_events.extend(events_extra)
|
active_events.extend(events_extra)
|
||||||
events_dict = {}
|
events_dict = {}
|
||||||
for event in active_events:
|
for event in active_events:
|
||||||
|
|
@ -382,27 +371,15 @@ class Event2Occupant(CrudCollection):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_event_codes(cls, build_living_space_id: int, db) -> dict[str:str]:
|
def get_event_codes(cls, build_living_space_id: int, db) -> dict[str:str]:
|
||||||
occupant_events = cls.filter_all(
|
cls.set_session(db)
|
||||||
cls.build_living_space_id == build_living_space_id,
|
Service2Events.set_session(db)
|
||||||
db=db,
|
Events.set_session(db)
|
||||||
).data
|
occupant_events = cls.query.filter(cls.build_living_space_id == build_living_space_id).all()
|
||||||
service_ids = list(set([event.event_service_id for event in occupant_events]))
|
service_ids = list(set([event.event_service_id for event in occupant_events]))
|
||||||
active_event_ids = Service2Events.filter_all_system(
|
active_event_ids = Service2Events.query.filter(Service2Events.service_id.in_(service_ids)).all()
|
||||||
Service2Events.service_id.in_(service_ids),
|
active_events = Events.query.filter(Events.id.in_([event.event_id for event in active_event_ids])).all()
|
||||||
db=db,
|
if extra_events := Event2OccupantExtra.query.filter(Event2OccupantExtra.build_living_space_id == build_living_space_id).all():
|
||||||
).data
|
events_extra = Events.query.filter(Events.id.in_([event.event_id for event in extra_events])).all()
|
||||||
active_events = Events.filter_all(
|
|
||||||
Events.id.in_([event.event_id for event in active_event_ids]),
|
|
||||||
db=db,
|
|
||||||
).data
|
|
||||||
if extra_events := Event2OccupantExtra.filter_all(
|
|
||||||
Event2OccupantExtra.build_living_space_id == build_living_space_id,
|
|
||||||
db=db,
|
|
||||||
).data:
|
|
||||||
events_extra = Events.filter_all(
|
|
||||||
Events.id.in_([event.event_id for event in extra_events]),
|
|
||||||
db=db,
|
|
||||||
).data
|
|
||||||
active_events.extend(events_extra)
|
active_events.extend(events_extra)
|
||||||
events_dict = {}
|
events_dict = {}
|
||||||
for event in active_events:
|
for event in active_events:
|
||||||
|
|
@ -428,31 +405,16 @@ class Application2Employee(CrudCollection):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_application_codes(cls, employee_id: int, db) -> list[int]:
|
def get_application_codes(cls, employee_id: int, db) -> list[int]:
|
||||||
employee_services = cls.filter_all(
|
cls.set_session(db)
|
||||||
cls.employee_id == employee_id,
|
Service2Application.set_session(db)
|
||||||
db=db,
|
Applications.set_session(db)
|
||||||
).data
|
Application2EmployeeExtra.set_session(db)
|
||||||
|
employee_services = cls.query.filter(cls.employee_id == employee_id).all()
|
||||||
service_ids = [service.service_id for service in employee_services]
|
service_ids = [service.service_id for service in employee_services]
|
||||||
active_applications = Service2Application.filter_all(
|
active_applications = Service2Application.query.filter(Service2Application.service_id.in_(service_ids)).all()
|
||||||
Service2Application.service_id.in_(service_ids),
|
applications = Applications.query.filter(Applications.id.in_([application.application_id for application in active_applications])).all()
|
||||||
db=db,
|
if extra_applications := Application2EmployeeExtra.query.filter(Application2EmployeeExtra.employee_id == employee_id).all():
|
||||||
).data
|
applications_extra = Applications.query.filter(Applications.id.in_([application.application_id for application in extra_applications])).all()
|
||||||
applications = Applications.filter_all(
|
|
||||||
Applications.id.in_(
|
|
||||||
[application.application_id for application in active_applications]
|
|
||||||
),
|
|
||||||
db=db,
|
|
||||||
).data
|
|
||||||
if extra_applications := Application2EmployeeExtra.filter_all(
|
|
||||||
Application2EmployeeExtra.employee_id == employee_id,
|
|
||||||
db=db,
|
|
||||||
).data:
|
|
||||||
applications_extra = Applications.filter_all(
|
|
||||||
Applications.id.in_(
|
|
||||||
[application.application_id for application in extra_applications]
|
|
||||||
),
|
|
||||||
db=db,
|
|
||||||
).data
|
|
||||||
applications.extend(applications_extra)
|
applications.extend(applications_extra)
|
||||||
applications_dict = {}
|
applications_dict = {}
|
||||||
for application in applications:
|
for application in applications:
|
||||||
|
|
@ -492,33 +454,25 @@ class Application2Occupant(CrudCollection):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_application_codes(cls, build_living_space_id: int, db) -> list[int]:
|
def get_application_codes(cls, build_living_space_id: int, db) -> list[int]:
|
||||||
occupant_services = cls.filter_all(
|
cls.set_session(db)
|
||||||
cls.build_living_space_id == build_living_space_id,
|
Service2Application.set_session(db)
|
||||||
db=db,
|
Applications.set_session(db)
|
||||||
).data
|
Application2OccupantExtra.set_session(db)
|
||||||
|
occupant_services = cls.query.filter(cls.build_living_space_id == build_living_space_id).all()
|
||||||
service_ids = [service.service_id for service in occupant_services]
|
service_ids = [service.service_id for service in occupant_services]
|
||||||
active_applications = Service2Application.filter_all(
|
active_applications = Service2Application.query.filter(Service2Application.service_id.in_(service_ids)).all()
|
||||||
Service2Application.service_id.in_(service_ids),
|
applications = Applications.query.filter(Applications.id.in_([application.application_id for application in active_applications])).all()
|
||||||
db=db,
|
if extra_applications := Application2OccupantExtra.query.filter(Application2OccupantExtra.build_living_space_id == build_living_space_id).all():
|
||||||
).data
|
applications_extra = Applications.query.filter(Applications.id.in_([application.application_id for application in extra_applications])).all()
|
||||||
applications = Applications.filter_all(
|
|
||||||
Applications.id.in_(
|
|
||||||
[application.application_id for application in active_applications]
|
|
||||||
),
|
|
||||||
db=db,
|
|
||||||
).data
|
|
||||||
if extra_applications := Application2OccupantExtra.filter_all(
|
|
||||||
Application2OccupantExtra.build_living_space_id == build_living_space_id,
|
|
||||||
db=db,
|
|
||||||
).data:
|
|
||||||
applications_extra = Applications.filter_all(
|
|
||||||
Applications.id.in_(
|
|
||||||
[application.application_id for application in extra_applications]
|
|
||||||
),
|
|
||||||
db=db,
|
|
||||||
).data
|
|
||||||
applications.extend(applications_extra)
|
applications.extend(applications_extra)
|
||||||
applications_dict = {}
|
applications_dict = {}
|
||||||
|
for application in applications:
|
||||||
|
if not application.site_url in applications_dict:
|
||||||
|
applications_dict[str(application.site_url)] = str(application.application_code)
|
||||||
|
else:
|
||||||
|
ValueError("Duplicate application code found for single endpoint")
|
||||||
|
applications.extend(applications_extra)
|
||||||
|
applications_dict = {}
|
||||||
for application in applications:
|
for application in applications:
|
||||||
if not application.site_url in applications_dict:
|
if not application.site_url in applications_dict:
|
||||||
applications_dict[str(application.site_url)] = str(application.application_code)
|
applications_dict[str(application.site_url)] = str(application.application_code)
|
||||||
|
|
|
||||||
|
|
@ -1,30 +1,25 @@
|
||||||
services:
|
services:
|
||||||
# auth_service:
|
auth_service:
|
||||||
# container_name: auth_service
|
container_name: auth_service
|
||||||
# build:
|
build:
|
||||||
# context: .
|
context: .
|
||||||
# dockerfile: api_services/api_builds/auth-service/Dockerfile
|
dockerfile: api_services/api_builds/auth-service/Dockerfile
|
||||||
# env_file:
|
env_file:
|
||||||
# - api_env.env
|
- api_env.env
|
||||||
# environment:
|
environment:
|
||||||
# - API_PATH=app:app
|
- API_PATH=app:app
|
||||||
# - API_HOST=0.0.0.0
|
- API_HOST=0.0.0.0
|
||||||
# - API_PORT=8001
|
- API_PORT=8001
|
||||||
# - API_LOG_LEVEL=info
|
- API_LOG_LEVEL=info
|
||||||
# - API_RELOAD=1
|
- API_RELOAD=1
|
||||||
# - API_APP_NAME=evyos-auth-api-gateway
|
- API_APP_NAME=evyos-auth-api-gateway
|
||||||
# - API_TITLE=WAG API Auth Api Gateway
|
- API_TITLE=WAG API Auth Api Gateway
|
||||||
# - API_FORGOT_LINK=https://auth_service/forgot-password
|
- API_FORGOT_LINK=https://auth_service/forgot-password
|
||||||
# - API_DESCRIPTION=This api is serves as web auth api gateway only to evyos web services.
|
- API_DESCRIPTION=This api is serves as web auth api gateway only to evyos web services.
|
||||||
# - API_APP_URL=https://auth_service
|
- API_APP_URL=https://auth_service
|
||||||
# ports:
|
ports:
|
||||||
# - "8000:8000"
|
- "8001:8001"
|
||||||
# restart: unless-stopped
|
# restart: unless-stopped
|
||||||
# logging:
|
|
||||||
# driver: "json-file"
|
|
||||||
# options:
|
|
||||||
# max-size: "10m"
|
|
||||||
# max-file: "3"
|
|
||||||
|
|
||||||
initializer_service:
|
initializer_service:
|
||||||
container_name: initializer_service
|
container_name: initializer_service
|
||||||
|
|
@ -40,8 +35,6 @@ services:
|
||||||
mem_limit: 512m
|
mem_limit: 512m
|
||||||
cpus: 0.5
|
cpus: 0.5
|
||||||
|
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
wag-services:
|
wag-services:
|
||||||
driver: bridge
|
driver: bridge
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue