Compare commits

..

35 Commits

Author SHA1 Message Date
4d7a6e6ec0 web service tenant first try 2025-05-07 11:41:08 +03:00
aee9d59750 updated all systems 2025-05-06 17:50:24 +03:00
bc43471259 updated client-frontend additions 2025-05-06 17:48:13 +03:00
e0ae1ee80a appender events and applications are updated 2025-05-06 12:03:58 +03:00
dd707b2463 tested appender service to events 2025-05-04 21:24:29 +03:00
0cde34a9bc updated appenders service 2025-05-04 00:21:38 +03:00
01f3e82a54 updated service binders updated 2025-05-03 23:35:03 +03:00
ac8c3fe1c3 updated management service bind 2025-05-03 18:38:50 +03:00
c6b1a2b1e8 updated managment index 2025-05-03 15:24:41 +03:00
734dc59e38 updated mdenu 2025-05-03 15:13:44 +03:00
71c808a5c3 updated components common header layouts 2025-05-03 13:51:02 +03:00
1ce28ec5f0 updated Api Defaults 2025-05-02 20:46:04 +03:00
1920c2a25d updated Identity and managment service 2025-05-01 15:25:15 +03:00
e815251123 event and service sendpoints added 2025-04-30 18:19:31 +03:00
36e63960f8 updated lang change and FormDisplay Components 2025-04-30 14:30:22 +03:00
f2cc7a69b5 components stablized 2025-04-30 00:44:13 +03:00
0052c92974 Card Component implemented 2025-04-29 20:44:39 +03:00
113e43c7d7 updated initilazer 2025-04-29 16:36:42 +03:00
2d418644bb updated pagination commit to carry 2025-04-28 13:19:01 +03:00
ac344773c5 added application page 2025-04-28 02:30:06 +03:00
346b132f4c updated Bank service routine email sender and wag managment application page completed 2025-04-27 21:01:06 +03:00
090567ade8 managment frontend initiated 2025-04-27 14:12:49 +03:00
ba784c40e4 routine crontab service tested and completed added to Readme.md 2025-04-25 16:07:17 +03:00
a886c2f28c updated Dockerfile 2025-04-25 16:01:46 +03:00
f4e43306c1 updated Dockerfile 2025-04-25 15:52:06 +03:00
c553975e82 updated Dockerfile 2025-04-25 15:46:14 +03:00
0bdc0d287e updated Dockerfile 2025-04-25 15:31:22 +03:00
7efd6f8941 updated Dockerfile 2025-04-25 15:22:20 +03:00
9f0c42e57a updated mail Dockerfile with env variables 2025-04-25 15:03:47 +03:00
b9825bb8e8 updated mail config 2025-04-25 14:49:20 +03:00
0bd8ddce4d updated email service 2025-04-24 17:41:14 +03:00
9511f81bc0 created design pattern 2025-04-23 12:26:15 +03:00
e5f88f2eb4 black shift 2025-04-22 11:10:29 +03:00
d7f1da8de8 identity service completed 2025-04-22 01:20:15 +03:00
9069ba0754 updated event and router stacks 2025-04-22 00:57:06 +03:00
462 changed files with 25210 additions and 2599 deletions

View File

@@ -0,0 +1,56 @@
from fastapi import Header, Request, Response
from pydantic import BaseModel
from ApiDefaults.config import api_config
class CommonHeaders(BaseModel):
language: str | None = None
domain: str | None = None
timezone: str | None = None
token: str | None = None
request: Request | None = None
response: Response | None = None
operation_id: str | None = None
model_config = {
"arbitrary_types_allowed": True
}
@classmethod
def as_dependency(
cls,
request: Request,
response: Response,
language: str = Header(None, alias="language"),
domain: str = Header(None, alias="domain"),
tz: str = Header(None, alias="timezone"),
):
token = request.headers.get(api_config.ACCESS_TOKEN_TAG, None)
# Extract operation_id from the route
operation_id = None
if hasattr(request.scope.get("route"), "operation_id"):
operation_id = request.scope.get("route").operation_id
return cls(
language=language,
domain=domain,
timezone=tz,
token=token,
request=request,
response=response,
operation_id=operation_id,
)
def get_headers_dict(self):
"""Convert the headers to a dictionary format used in the application"""
import uuid
return {
"language": self.language or "",
"domain": self.domain or "",
"eys-ext": f"{str(uuid.uuid4())}",
"tz": self.timezone or "GMT+3",
"token": self.token,
}

View File

@@ -0,0 +1,133 @@
from typing import Optional, Type
from pydantic import BaseModel
class EventCluster:
"""
EventCluster
"""
def __repr__(self):
return f"EventCluster(name={self.name})"
def __init__(self, endpoint_uu_id: str, name: str):
self.endpoint_uu_id = endpoint_uu_id
self.name = name
self.events: list["Event"] = []
def add_event(self, event: "Event"):
"""
Add an event to the cluster
"""
if event.key not in [e.key for e in self.events]:
self.events.append(event)
def get_event(self, event_key: str):
"""
Get an event by its key
"""
for event in self.events:
if event.key == event_key:
return event
return None
def set_events_to_database(self):
from Schemas import Events, EndpointRestriction
with Events.new_session() as db_session:
if to_save_endpoint := EndpointRestriction.filter_one(
EndpointRestriction.operation_uu_id == self.endpoint_uu_id,
db=db_session,
).data:
for event in self.events:
event_dict_to_save = dict(
function_code=event.key,
function_class=event.name,
description=event.description,
endpoint_code=self.endpoint_uu_id,
endpoint_id=to_save_endpoint.id,
endpoint_uu_id=str(to_save_endpoint.uu_id),
is_confirmed=True,
db=db_session,
)
event_found = Events.filter_one(
Events.function_code == event_dict_to_save["function_code"],
db=db_session,
).data
if event_found:
event_found.update(**event_dict_to_save)
event_found.save(db=db_session)
else:
event_to_save_database = Events.find_or_create(
**event_dict_to_save,
include_args=[
Events.function_code,
Events.function_class,
Events.endpoint_code,
Events.endpoint_uu_id,
]
)
if event_to_save_database.meta_data.created:
print(f"UUID: {event_to_save_database.uu_id} event is saved to {to_save_endpoint.uu_id}")
event_to_save_database.save(db=db_session)
def match_event(self, event_key: str) -> "Event":
"""
Match an event by its key
"""
if event := self.get_event(event_key=event_key):
return event
raise ValueError("Event key not found")
class Event:
def __init__(
self,
name: str,
key: str,
request_validator: Optional[Type[BaseModel]] = None,
response_validator: Optional[Type[BaseModel]] = None,
description: str = "",
):
self.name = name
self.key = key
self.request_validator = request_validator
self.response_validator = response_validator
self.description = description
def event_callable(self):
"""
Example callable method
"""
print(self.name)
return {}
class RouterCluster:
"""
RouterCluster
"""
def __repr__(self):
return f"RouterCluster(name={self.name})"
def __init__(self, name: str):
self.name = name
self.event_clusters: dict[str, EventCluster] = {}
def set_event_cluster(self, event_cluster: EventCluster):
"""
Add an event cluster to the set
"""
print("Setting event cluster:", event_cluster.name)
if event_cluster.name not in self.event_clusters:
self.event_clusters[event_cluster.name] = event_cluster
def get_event_cluster(self, event_cluster_name: str) -> EventCluster:
"""
Get an event cluster by its name
"""
if event_cluster_name not in self.event_clusters:
raise ValueError("Event cluster not found")
return self.event_clusters[event_cluster_name]

View File

@@ -23,15 +23,22 @@ class RouteRegisterController:
for route_method in [ for route_method in [
method.lower() for method in getattr(route, "methods") method.lower() for method in getattr(route, "methods")
]: ]:
restriction = EndpointRestriction.find_or_create( add_or_update_dict = dict(
endpoint_method=route_method, endpoint_method=route_method,
endpoint_name=route_path, endpoint_name=route_path,
endpoint_desc=route_summary.replace("_", " "), endpoint_desc=route_summary.replace("_", " "),
endpoint_function=route_summary, endpoint_function=route_summary,
operation_uu_id=operation_id, # UUID of the endpoint operation_uu_id=operation_id,
is_confirmed=True, is_confirmed=True,
db=db_session,
) )
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: if restriction.meta_data.created:
restriction.save(db=db_session) restriction.save(db=db_session)

View File

@@ -1,11 +1,11 @@
from fastapi import Request, status from fastapi import Request, status
from fastapi.responses import JSONResponse from fastapi.responses import JSONResponse
from ApiServices.IdentityService.endpoints.routes import get_safe_endpoint_urls from ApiDefaults.config import api_config
from ApiServices.IdentityService.config import api_config
from Endpoints.routes import get_safe_endpoint_urls
async def token_middleware(request: Request, call_next): async def token_middleware(request: Request, call_next):
base_url = request.url.path base_url = request.url.path
safe_endpoints = [_[0] for _ in get_safe_endpoint_urls()] safe_endpoints = [_[0] for _ in get_safe_endpoint_urls()]
if base_url in safe_endpoints: if base_url in safe_endpoints:

View File

@@ -1,7 +1,7 @@
import uvicorn import uvicorn
from config import api_config from ApiDefaults.config import api_config
from create_app import create_app from ApiDefaults.create_app import create_app
# from prometheus_fastapi_instrumentator import Instrumentator # from prometheus_fastapi_instrumentator import Instrumentator

View File

@@ -22,7 +22,7 @@ class Configs(BaseSettings):
EMAIL_HOST: str = "" EMAIL_HOST: str = ""
DATETIME_FORMAT: str = "" DATETIME_FORMAT: str = ""
FORGOT_LINK: str = "" FORGOT_LINK: str = ""
ALLOW_ORIGINS: list = ["http://localhost:3000"] ALLOW_ORIGINS: list = ["http://localhost:3000", "http://localhost:3001"]
VERSION: str = "0.1.001" VERSION: str = "0.1.001"
DESCRIPTION: str = "" DESCRIPTION: str = ""

View File

@@ -1,24 +1,42 @@
from ApiControllers.abstracts.event_clusters import RouterCluster, EventCluster
from fastapi import FastAPI, Request from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import RedirectResponse from fastapi.responses import RedirectResponse
from endpoints.routes import get_routes cluster_is_set = False
from open_api_creator import create_openapi_schema
from middlewares.token_middleware import token_middleware
from initializer.create_route import RouteRegisterController
from config import api_config
def create_events_if_any_cluster_set(): def create_events_if_any_cluster_set():
import events import Events
for event_str in events.__all__: global cluster_is_set
if to_set_events := getattr(events, event_str, None): if not Events.__all__ or cluster_is_set:
to_set_events.set_events_to_database() 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 ApiDefaults.open_api_creator import create_openapi_schema
from ApiDefaults.config import api_config
from ApiControllers.middlewares.token_middleware import token_middleware
from ApiControllers.initializer.create_route import RouteRegisterController
from Endpoints.routes import get_routes
application = FastAPI(**api_config.api_info) application = FastAPI(**api_config.api_info)
# application.mount( # application.mount(
@@ -44,6 +62,7 @@ def create_app():
route_register = RouteRegisterController(app=application, router_list=get_routes()) route_register = RouteRegisterController(app=application, router_list=get_routes())
application = route_register.register_routes() application = route_register.register_routes()
create_events_if_any_cluster_set() create_events_if_any_cluster_set()
application.openapi = lambda _=application: create_openapi_schema(_) application.openapi = lambda _=application: create_openapi_schema(_)
return application return application

View File

@@ -3,8 +3,8 @@ from fastapi import FastAPI
from fastapi.routing import APIRoute from fastapi.routing import APIRoute
from fastapi.openapi.utils import get_openapi from fastapi.openapi.utils import get_openapi
from config import api_config as template_api_config from ApiDefaults.config import api_config as template_api_config
from endpoints.routes import get_safe_endpoint_urls from Endpoints.routes import get_safe_endpoint_urls
class OpenAPISchemaCreator: class OpenAPISchemaCreator:

View File

@@ -22,7 +22,7 @@ class Configs(BaseSettings):
EMAIL_HOST: str = "" EMAIL_HOST: str = ""
DATETIME_FORMAT: str = "" DATETIME_FORMAT: str = ""
FORGOT_LINK: str = "" FORGOT_LINK: str = ""
ALLOW_ORIGINS: list = ["http://localhost:3000"] ALLOW_ORIGINS: list = ["http://localhost:3000", "http://localhost:3001"]
VERSION: str = "0.1.001" VERSION: str = "0.1.001"
DESCRIPTION: str = "" DESCRIPTION: str = ""

View File

@@ -304,7 +304,9 @@ def authentication_token_check_post(
status_code=status.HTTP_406_NOT_ACCEPTABLE, status_code=status.HTTP_406_NOT_ACCEPTABLE,
headers=headers, headers=headers,
) )
if AuthHandlers.LoginHandler.authentication_check_token_valid(access_token=token): if AuthHandlers.LoginHandler.authentication_check_token_valid(
domain=domain, access_token=token
):
return JSONResponse( return JSONResponse(
content={"message": "MSG_0001"}, content={"message": "MSG_0001"},
status_code=status.HTTP_202_ACCEPTED, status_code=status.HTTP_202_ACCEPTED,
@@ -438,7 +440,7 @@ def authentication_page_valid(
summary="Lists all sites that are available for user", summary="Lists all sites that are available for user",
description="Lists all sites that are available for user", description="Lists all sites that are available for user",
) )
def authentication_page_valid( def authentication_get_all_sites_list(
request: Request, request: Request,
language: str = Header(None, alias="language"), language: str = Header(None, alias="language"),
domain: str = Header(None, alias="domain"), domain: str = Header(None, alias="domain"),

View File

@@ -171,8 +171,20 @@ class LoginHandler:
access_key=data.access_key, db_session=db_session 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( if not user_handler.check_password_valid(
domain=domain or "", domain=main_domain,
id_=str(found_user.uu_id), id_=str(found_user.uu_id),
password=data.password, password=data.password,
password_hashed=found_user.hash_password, password_hashed=found_user.hash_password,
@@ -233,6 +245,7 @@ class LoginHandler:
person_id=found_user.person_id, person_id=found_user.person_id,
person_uu_id=str(person.uu_id), person_uu_id=str(person.uu_id),
request=dict(request.headers), request=dict(request.headers),
domain_list=other_domains_list,
companies_uu_id_list=companies_uu_id_list, companies_uu_id_list=companies_uu_id_list,
companies_id_list=companies_id_list, companies_id_list=companies_id_list,
duty_uu_id_list=duty_uu_id_list, duty_uu_id_list=duty_uu_id_list,
@@ -286,8 +299,20 @@ class LoginHandler:
found_user = user_handler.check_user_exists( found_user = user_handler.check_user_exists(
access_key=data.access_key, db_session=db_session 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( if not user_handler.check_password_valid(
domain=domain, domain=main_domain,
id_=str(found_user.uu_id), id_=str(found_user.uu_id),
password=data.password, password=data.password,
password_hashed=found_user.hash_password, password_hashed=found_user.hash_password,
@@ -343,6 +368,7 @@ class LoginHandler:
user_id=found_user.id, user_id=found_user.id,
person_id=person.id, person_id=person.id,
person_uu_id=str(person.uu_id), person_uu_id=str(person.uu_id),
domain_list=other_domains_list,
request=dict(request.headers), request=dict(request.headers),
available_occupants=occupants_selection_dict, available_occupants=occupants_selection_dict,
).model_dump() ).model_dump()
@@ -606,9 +632,16 @@ class LoginHandler:
) )
@classmethod @classmethod
def authentication_check_token_valid(cls, access_token: str) -> bool: def authentication_check_token_valid(cls, domain, access_token: str) -> bool:
redis_handler = RedisHandlers() redis_handler = RedisHandlers()
if redis_handler.get_object_from_redis(access_token=access_token): 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 True
return False return False

View File

@@ -5,6 +5,7 @@ from ..config import api_config
async def token_middleware(request: Request, call_next): async def token_middleware(request: Request, call_next):
print("Token Middleware", dict(request.headers))
base_url = request.url.path base_url = request.url.path
safe_endpoints = [_[0] for _ in get_safe_endpoint_urls()] safe_endpoints = [_[0] for _ in get_safe_endpoint_urls()]
if base_url in safe_endpoints: if base_url in safe_endpoints:

View File

@@ -35,6 +35,7 @@ class ApplicationToken(BaseModel):
person_uu_id: str person_uu_id: str
request: Optional[dict] = None # Request Info of Client request: Optional[dict] = None # Request Info of Client
domain_list: Optional[list[str]] = None
expires_at: Optional[float] = None # Expiry timestamp expires_at: Optional[float] = None # Expiry timestamp

View File

@@ -0,0 +1,29 @@
FROM python:3.12-slim
WORKDIR /
# Install system dependencies and Poetry
RUN apt-get update && apt-get install -y --no-install-recommends gcc && rm -rf /var/lib/apt/lists/* && pip install --no-cache-dir poetry
# Copy Poetry configuration
COPY /pyproject.toml ./pyproject.toml
# Configure Poetry and install dependencies with optimizations
RUN poetry config virtualenvs.create false && poetry install --no-interaction --no-ansi --no-root --only main \
&& pip cache purge && rm -rf ~/.cache/pypoetry
# Copy application code
COPY /ApiControllers /ApiControllers
COPY /ApiDefaults /ApiDefaults
COPY /Controllers /Controllers
COPY /Schemas /Schemas
COPY /ApiServices/BuildingService/Endpoints /ApiDefaults/Endpoints
COPY /ApiServices/BuildingService/Events /ApiDefaults/Events
COPY /ApiServices/BuildingService/Validations /ApiDefaults/Validations
# Set Python path to include app directory
ENV PYTHONPATH=/ PYTHONUNBUFFERED=1 PYTHONDONTWRITEBYTECODE=1
# Run the application using the configured uvicorn server
CMD ["poetry", "run", "python", "ApiDefaults/app.py"]

View File

@@ -0,0 +1,70 @@
from fastapi import APIRouter, Depends
from ApiControllers.abstracts.default_validations import CommonHeaders
from ApiControllers.providers.token_provider import TokenProvider
from Controllers.Postgres.pagination import PaginateOnly
from Events.area.cluster import BuildAreaRouterCluster
area_route = APIRouter(prefix="/building/area", tags=["Building Area"])
@area_route.post(
path="/list",
description="List building area endpoint",
operation_id="f2831efc-5493-448c-bcf6-4d52d744ba7e",
)
def area_list_route(
data: PaginateOnly,
headers: CommonHeaders = Depends(CommonHeaders.as_dependency),
):
"""
List building area endpoint
"""
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
FoundCluster = BuildAreaRouterCluster.get_event_cluster("BuildAreaList")
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
return event_cluster_matched.event_callable(data=data)
@area_route.post(
path="/create",
description="Create building area endpoint",
operation_id="66e8b310-7a5d-41f4-977c-ee5f3b0603da",
)
def area_create_route(
data: dict,
headers: CommonHeaders = Depends(CommonHeaders.as_dependency),
):
"""
Create building area endpoint
"""
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
FoundCluster = BuildAreaRouterCluster.get_event_cluster("BuildAreaCreate")
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
return event_cluster_matched.event_callable(data=data)
@area_route.post(
path="/update",
description="Update building area endpoint",
operation_id="d7769899-156d-49ff-85f4-06e3faa23e30",
)
def area_update_route(
data: dict,
headers: CommonHeaders = Depends(CommonHeaders.as_dependency),
):
"""
Update building area endpoint
"""
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
FoundCluster = BuildAreaRouterCluster.get_event_cluster("BuildAreaUpdate")
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
return event_cluster_matched.event_callable(data=data)

View File

@@ -0,0 +1,70 @@
from fastapi import APIRouter, Depends
from ApiControllers.abstracts.default_validations import CommonHeaders
from ApiControllers.providers.token_provider import TokenProvider
from Controllers.Postgres.pagination import PaginateOnly
from Events.building.cluster import BuildRouterCluster
building_route = APIRouter(prefix="/building", tags=["Building"])
@building_route.post(
path="/list",
description="List buildings endpoint",
operation_id="72003d1f-79cc-43c3-9150-3a94f318186e",
)
def building_list_route(
data: PaginateOnly,
headers: CommonHeaders = Depends(CommonHeaders.as_dependency),
):
"""
List buildings endpoint
"""
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
FoundCluster = BuildRouterCluster.get_event_cluster("BuildList")
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
return event_cluster_matched.event_callable(data=data)
@building_route.post(
path="/create",
description="Create buildings endpoint",
operation_id="13b86c9c-702b-411f-acb9-9ff50ef86507",
)
def building_create_route(
data: dict,
headers: CommonHeaders = Depends(CommonHeaders.as_dependency),
):
"""
Create buildings endpoint
"""
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
FoundCluster = BuildRouterCluster.get_event_cluster("BuildCreate")
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
return event_cluster_matched.event_callable(data=data)
@building_route.post(
path="/update",
description="Update buildings endpoint",
operation_id="b09fb6fd-a6c9-4c03-8637-9af0570a84e8",
)
def building_update_route(
data: dict,
headers: CommonHeaders = Depends(CommonHeaders.as_dependency),
):
"""
Update buildings endpoint
"""
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
FoundCluster = BuildRouterCluster.get_event_cluster("BuildUpdate")
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
return event_cluster_matched.event_callable(data=data)

View File

@@ -0,0 +1,29 @@
from fastapi import APIRouter
def get_routes() -> list[APIRouter]:
from .building.route import building_route
from .area.route import area_route
from .sites.route import sites_route
from .parts.route import parts_route
from .spaces.route import spaces_route
from .type.route import build_types_route
return [
building_route,
area_route,
sites_route,
parts_route,
spaces_route,
build_types_route,
]
def get_safe_endpoint_urls() -> list[tuple[str, str]]:
return [
("/", "GET"),
("/docs", "GET"),
("/redoc", "GET"),
("/openapi.json", "GET"),
("/metrics", "GET"),
]

View File

@@ -0,0 +1,70 @@
from fastapi import APIRouter, Depends
from ApiControllers.abstracts.default_validations import CommonHeaders
from ApiControllers.providers.token_provider import TokenProvider
from Controllers.Postgres.pagination import PaginateOnly
from Events.sites.cluster import BuildSitesRouterCluster
sites_route = APIRouter(prefix="/building/sites", tags=["Build Sites"])
@sites_route.post(
path="/list",
description="List build sites endpoint",
operation_id="b64a2479-4160-43bf-9676-cd762a48bf62",
)
def sites_list_route(
data: PaginateOnly,
headers: CommonHeaders = Depends(CommonHeaders.as_dependency),
):
"""
List build sites endpoint
"""
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
FoundCluster = BuildSitesRouterCluster.get_event_cluster("BuildSitesList")
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
return event_cluster_matched.event_callable(data=data)
@sites_route.post(
path="/create",
description="Create build sites endpoint",
operation_id="e63dab4b-d446-430c-ac7d-0cb47a66390c",
)
def sites_create_route(
data: dict,
headers: CommonHeaders = Depends(CommonHeaders.as_dependency),
):
"""
Create build sites endpoint
"""
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
FoundCluster = BuildSitesRouterCluster.get_event_cluster("BuildSitesCreate")
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
return event_cluster_matched.event_callable(data=data)
@sites_route.post(
path="/update",
description="Update build sites endpoint",
operation_id="34ec902c-5ebe-41f6-8294-dfe634d47d98",
)
def sites_update_route(
data: dict,
headers: CommonHeaders = Depends(CommonHeaders.as_dependency),
):
"""
Update build sites endpoint
"""
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
FoundCluster = BuildSitesRouterCluster.get_event_cluster("BuildSitesUpdate")
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
return event_cluster_matched.event_callable(data=data)

View File

@@ -0,0 +1,76 @@
from fastapi import APIRouter, Depends
from ApiControllers.abstracts.default_validations import CommonHeaders
from ApiControllers.providers.token_provider import TokenProvider
from Controllers.Postgres.pagination import PaginateOnly
from Events.spaces.cluster import BuildLivingSpaceRouterCluster
spaces_route = APIRouter(prefix="/building/spaces", tags=["Build Spaces"])
@spaces_route.post(
path="/list",
description="List build spaces endpoint",
operation_id="9d072fd3-d727-4f71-bf0c-fd74e25ba507",
)
def spaces_list_route(
data: PaginateOnly,
headers: CommonHeaders = Depends(CommonHeaders.as_dependency),
):
"""
List build spaces endpoint
"""
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
FoundCluster = BuildLivingSpaceRouterCluster.get_event_cluster(
"BuildLivingSpaceList"
)
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
return event_cluster_matched.event_callable(data=data)
@spaces_route.post(
path="/create",
description="Create build spaces endpoint",
operation_id="4520cfb7-ed45-44d2-a706-e2a8be777419",
)
def spaces_create_route(
data: dict,
headers: CommonHeaders = Depends(CommonHeaders.as_dependency),
):
"""
Create build spaces endpoint
"""
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
FoundCluster = BuildLivingSpaceRouterCluster.get_event_cluster(
"BuildLivingSpaceCreate"
)
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
return event_cluster_matched.event_callable(data=data)
@spaces_route.post(
path="/update",
description="Update build spaces endpoint",
operation_id="d8c90f64-0a4c-4a7c-a685-0e1894cbe1c4",
)
def spaces_update_route(
data: dict,
headers: CommonHeaders = Depends(CommonHeaders.as_dependency),
):
"""
Update build spaces endpoint
"""
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
FoundCluster = BuildLivingSpaceRouterCluster.get_event_cluster(
"BuildLivingSpaceUpdate"
)
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
return event_cluster_matched.event_callable(data=data)

View File

@@ -0,0 +1,70 @@
from fastapi import APIRouter, Depends
from ApiControllers.abstracts.default_validations import CommonHeaders
from ApiControllers.providers.token_provider import TokenProvider
from Controllers.Postgres.pagination import PaginateOnly
from Events.type.cluster import BuildTypeRouterCluster
build_types_route = APIRouter(prefix="/building/types", tags=["Build Types"])
@build_types_route.post(
path="/list",
description="List build types endpoint",
operation_id="916d2e02-ee83-4099-ba02-63e2a3f83ec4",
)
def build_types_list_route(
data: PaginateOnly,
headers: CommonHeaders = Depends(CommonHeaders.as_dependency),
):
"""
List build types endpoint
"""
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
FoundCluster = BuildTypeRouterCluster.get_event_cluster("BuildTypeList")
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
return event_cluster_matched.event_callable(data=data)
@build_types_route.post(
path="/create",
description="Create build types endpoint",
operation_id="ae7d9e5d-3933-4613-a686-c887d74b85b3",
)
def build_types_create_route(
data: dict,
headers: CommonHeaders = Depends(CommonHeaders.as_dependency),
):
"""
Create build types endpoint
"""
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
FoundCluster = BuildTypeRouterCluster.get_event_cluster("BuildTypeCreate")
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
return event_cluster_matched.event_callable(data=data)
@build_types_route.post(
path="/update",
description="Update build types endpoint",
operation_id="0f304075-efb0-4f9d-a3b2-e60eeb4d9a87",
)
def build_types_update_route(
data: dict,
headers: CommonHeaders = Depends(CommonHeaders.as_dependency),
):
"""
Update build types endpoint
"""
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
FoundCluster = BuildTypeRouterCluster.get_event_cluster("BuildTypeUpdate")
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
return event_cluster_matched.event_callable(data=data)

View File

@@ -0,0 +1,15 @@
from .building.cluster import BuildRouterCluster
from .area.cluster import BuildAreaRouterCluster
from .parts.cluster import BuildPartsRouterCluster
from .spaces.cluster import BuildLivingSpaceRouterCluster
from .type.cluster import BuildTypeRouterCluster
from .sites.cluster import BuildSitesRouterCluster
__all__ = [
"BuildRouterCluster",
"BuildAreaRouterCluster",
"BuildPartsRouterCluster",
"BuildLivingSpaceRouterCluster",
"BuildTypeRouterCluster",
"BuildSitesRouterCluster",
]

View File

@@ -0,0 +1,26 @@
from ApiControllers.abstracts.event_clusters import EventCluster, RouterCluster
from .supers_events import (
BuildAreaListEvent,
BuildAreaCreateEvent,
BuildAreaUpdateEvent,
)
BuildAreaRouterCluster = RouterCluster(name="BuildAreaRouterCluster")
BuildAreaEventClusterList = EventCluster(
name="BuildAreaList", endpoint_uu_id="cc487a4f-9a45-4072-89c1-a1ad504c79ad"
)
BuildAreaEventClusterCreate = EventCluster(
name="BuildAreaCreate", endpoint_uu_id="bdd58d68-3a7c-4150-9f5b-e322db35b804"
)
BuildAreaEventClusterUpdate = EventCluster(
name="BuildAreaUpdate", endpoint_uu_id="cad0c4e2-36e3-4f80-9ad2-b06bf8cd8d1c"
)
BuildAreaEventClusterList.add_event(BuildAreaListEvent)
BuildAreaEventClusterCreate.add_event(BuildAreaCreateEvent)
BuildAreaEventClusterUpdate.add_event(BuildAreaUpdateEvent)
BuildAreaRouterCluster.set_event_cluster(BuildAreaEventClusterList)
BuildAreaRouterCluster.set_event_cluster(BuildAreaEventClusterCreate)
BuildAreaRouterCluster.set_event_cluster(BuildAreaEventClusterUpdate)

View File

@@ -0,0 +1,96 @@
from ApiControllers.abstracts.event_clusters import Event
from Controllers.Postgres.pagination import Pagination, PaginationResult, PaginateOnly
from Controllers.Postgres.response import EndpointResponse
from Schemas import BuildArea
# List endpoint
BuildAreaListEvent = Event(
name="build_area_list",
key="306e6e11-21da-4fbb-b3d6-3a5179ecfe71",
request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator
description="List events of build area endpoint",
)
# Create endpoint
BuildAreaCreateEvent = Event(
name="build_area_create",
key="aa173f0f-7a97-4e91-97da-173626dd3257",
request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator
description="Create events of build area endpoint",
)
# Update endpoint
BuildAreaUpdateEvent = Event(
name="build_area_update",
key="358404d0-fb80-4d58-8907-0c04948b364e",
request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator
description="Update events of build area endpoint",
)
def build_area_list_callable(list_options: PaginateOnly):
"""
Example callable method
"""
list_options = PaginateOnly(**list_options.model_dump())
with BuildArea.new_session() as db_session:
if list_options.query:
buildings_list = BuildArea.filter_all(
*BuildArea.convert(list_options.query), db=db_session
)
else:
buildings_list = BuildArea.filter_all(db=db_session)
pagination = Pagination(data=buildings_list)
pagination.change(**list_options.model_dump())
pagination_result = PaginationResult(
data=buildings_list,
pagination=pagination,
# response_model="",
).pagination.as_dict
return EndpointResponse(
message="MSG0003-LIST",
pagination_result=pagination_result,
).response
BuildAreaListEvent.event_callable = build_area_list_callable
def build_area_create_callable(data: dict):
"""
Example callable method
"""
with BuildArea.new_session() as db_session:
return {
"completed": True,
"message": "Example callable method 2",
"info": {
"host": "example_host",
"user_agent": "example_user_agent",
},
}
BuildAreaCreateEvent.event_callable = build_area_create_callable
def build_area_update_callable(data: dict):
"""
Example callable method
"""
with BuildArea.new_session() as db_session:
return {
"completed": True,
"message": "Example callable method 2",
"info": {
"host": "example_host",
"user_agent": "example_user_agent",
},
}
BuildAreaUpdateEvent.event_callable = build_area_update_callable

View File

@@ -0,0 +1,27 @@
from ApiControllers.abstracts.event_clusters import EventCluster, RouterCluster
from .supers_events import (
BuildingListEvent,
BuildingCreateEvent,
BuildingUpdateEvent,
)
BuildRouterCluster = RouterCluster(name="BuildRouterCluster")
BuildEventClusterList = EventCluster(
name="BuildList", endpoint_uu_id="1a186985-ed2a-434b-af28-22d6773382e9"
)
BuildEventClusterList.add_event(BuildingListEvent)
BuildEventClusterCreate = EventCluster(
name="BuildCreate", endpoint_uu_id="d545c5a9-bbbf-4795-a4de-467db0809a04"
)
BuildEventClusterCreate.add_event(BuildingCreateEvent)
BuildEventClusterUpdate = EventCluster(
name="BuildUpdate", endpoint_uu_id="6166a28e-8da8-4a2c-96c8-0a1651739cf3"
)
BuildEventClusterUpdate.add_event(BuildingUpdateEvent)
BuildRouterCluster.set_event_cluster(BuildEventClusterList)
BuildRouterCluster.set_event_cluster(BuildEventClusterCreate)
BuildRouterCluster.set_event_cluster(BuildEventClusterUpdate)

View File

@@ -0,0 +1,98 @@
from ApiControllers.abstracts.event_clusters import Event
from Validations.building.building.validations import (
REQUESTEWFAZCDMPVZHIWOKZEJBIEUDAFBNXFEEAEGSELVGGCDMWLQPYMRAEEABSRQJUFBIMFEEADXK,
)
from Controllers.Postgres.pagination import Pagination, PaginationResult, PaginateOnly
from Controllers.Postgres.response import EndpointResponse
from Schemas import Build
# List endpoint
BuildingListEvent = Event(
name="building_list",
key="e675d36a-6772-44a8-b153-9a8d55e0f560",
request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator
description="List events of buildings endpoint",
)
# Create endpoint
BuildingCreateEvent = Event(
name="building_create",
key="d79e3bdc-8f75-41d0-8eeb-dd9893d7ea0d",
request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator
description="Create events of buildings endpoint",
)
# Update endpoint
BuildingUpdateEvent = Event(
name="building_update",
key="45e1bb8c-c521-4013-9e99-d3a58204bc5f",
request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator
description="Update events of buildings endpoint",
)
def building_list_callable(list_options: PaginateOnly):
"""
Example callable method
"""
list_options = PaginateOnly(**list_options.model_dump())
with Build.new_session() as db_session:
if list_options.query:
buildings_list = Build.filter_all(
*Build.convert(list_options.query), db=db_session
)
else:
buildings_list = Build.filter_all(db=db_session)
pagination = Pagination(data=buildings_list)
pagination.change(**list_options.model_dump())
pagination_result = PaginationResult(
data=buildings_list,
pagination=pagination,
# response_model="",
).pagination.as_dict
return EndpointResponse(
message="MSG0003-LIST",
pagination_result=pagination_result,
request=REQUESTEWFAZCDMPVZHIWOKZEJBIEUDAFBNXFEEAEGSELVGGCDMWLQPYMRAEEABSRQJUFBIMFEEADXK,
).response
BuildingListEvent.event_callable = building_list_callable
def building_create_callable():
"""
Example callable method
"""
return {
"completed": True,
"message": "Example callable method 2",
"info": {
"host": "example_host",
"user_agent": "example_user_agent",
},
}
BuildingCreateEvent.event_callable = building_create_callable
def building_update_callable():
"""
Example callable method
"""
return {
"completed": True,
"message": "Example callable method 2",
"info": {
"host": "example_host",
"user_agent": "example_user_agent",
},
}
BuildingUpdateEvent.event_callable = building_update_callable

View File

@@ -0,0 +1,27 @@
from ApiControllers.abstracts.event_clusters import EventCluster, RouterCluster
from .supers_events import (
BuildSitesListEvent,
BuildSitesCreateEvent,
BuildSitesUpdateEvent,
)
BuildSitesRouterCluster = RouterCluster(name="BuildSitesRouterCluster")
BuildSitesEventClusterList = EventCluster(
name="BuildSitesList", endpoint_uu_id="1159fb39-ad5d-46fb-8b6b-461021a39da3"
)
BuildSitesEventClusterList.add_event(BuildSitesListEvent)
BuildSitesEventClusterCreate = EventCluster(
name="BuildCreate", endpoint_uu_id="bc71d276-fd51-43bb-90f2-6f4245b59d72"
)
BuildSitesEventClusterCreate.add_event(BuildSitesCreateEvent)
BuildSitesEventClusterUpdate = EventCluster(
name="BuildUpdate", endpoint_uu_id="eca87985-3074-44cb-a947-f01e30769019"
)
BuildSitesEventClusterUpdate.add_event(BuildSitesUpdateEvent)
BuildSitesRouterCluster.set_event_cluster(BuildSitesEventClusterList)
BuildSitesRouterCluster.set_event_cluster(BuildSitesEventClusterCreate)
BuildSitesRouterCluster.set_event_cluster(BuildSitesEventClusterUpdate)

View File

@@ -0,0 +1,96 @@
from ApiControllers.abstracts.event_clusters import Event
from Controllers.Postgres.pagination import Pagination, PaginationResult, PaginateOnly
from Controllers.Postgres.response import EndpointResponse
from Schemas import BuildSites
# List endpoint
BuildSitesListEvent = Event(
name="build_sites_list",
key="d16c692f-5597-493a-90fe-b2bfe0d1c163",
request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator
description="List events of build sites endpoint",
)
# Create endpoint
BuildSitesCreateEvent = Event(
name="build_sites_create",
key="8ed0929e-9c96-4e81-b073-e3578ca13f37",
request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator
description="Create events of build sites endpoint",
)
# Update endpoint
BuildSitesUpdateEvent = Event(
name="build_sites_update",
key="ece55fa6-afba-4c34-bd2e-f39a4cdd6b5c",
request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator
description="Update events of build sites endpoint",
)
def build_sites_list_callable(list_options: PaginateOnly):
"""
Example callable method
"""
list_options = PaginateOnly(**list_options.model_dump())
with BuildSites.new_session() as db_session:
if list_options.query:
buildings_list = BuildSites.filter_all(
*BuildSites.convert(list_options.query), db=db_session
)
else:
buildings_list = BuildSites.filter_all(db=db_session)
pagination = Pagination(data=buildings_list)
pagination.change(**list_options.model_dump())
pagination_result = PaginationResult(
data=buildings_list,
pagination=pagination,
# response_model="",
).pagination.as_dict
return EndpointResponse(
message="MSG0003-LIST",
pagination_result=pagination_result,
).response
BuildSitesListEvent.event_callable = build_sites_list_callable
def build_sites_create_callable(data: dict):
"""
Example callable method
"""
with BuildSites.new_session() as db_session:
return {
"completed": True,
"message": "Example callable method 2",
"info": {
"host": "example_host",
"user_agent": "example_user_agent",
},
}
BuildSitesCreateEvent.event_callable = build_sites_create_callable
def build_sites_update_callable(data: dict):
"""
Example callable method
"""
with BuildSites.new_session() as db_session:
return {
"completed": True,
"message": "Example callable method 2",
"info": {
"host": "example_host",
"user_agent": "example_user_agent",
},
}
BuildSitesUpdateEvent.event_callable = build_sites_update_callable

View File

@@ -0,0 +1,27 @@
from ApiControllers.abstracts.event_clusters import EventCluster, RouterCluster
from .supers_events import (
BuildLivingSpaceListEvent,
BuildLivingSpaceCreateEvent,
BuildLivingSpaceUpdateEvent,
)
BuildLivingSpaceRouterCluster = RouterCluster(name="BuildLivingSpaceRouterCluster")
BuildLivingSpaceEventClusterList = EventCluster(
name="BuildLivingSpaceList", endpoint_uu_id="ad17c019-3050-4c41-ab6f-9ce43290e81a"
)
BuildLivingSpaceEventClusterList.add_event(BuildLivingSpaceListEvent)
BuildLivingSpaceEventClusterCreate = EventCluster(
name="BuildCreate", endpoint_uu_id="ed9a0303-14e2-46fe-bec0-d395c29801ff"
)
BuildLivingSpaceEventClusterCreate.add_event(BuildLivingSpaceCreateEvent)
BuildLivingSpaceEventClusterUpdate = EventCluster(
name="BuildUpdate", endpoint_uu_id="c62bb3dc-03c0-406c-8bbc-0e1f75a6420c"
)
BuildLivingSpaceEventClusterUpdate.add_event(BuildLivingSpaceUpdateEvent)
BuildLivingSpaceRouterCluster.set_event_cluster(BuildLivingSpaceEventClusterList)
BuildLivingSpaceRouterCluster.set_event_cluster(BuildLivingSpaceEventClusterCreate)
BuildLivingSpaceRouterCluster.set_event_cluster(BuildLivingSpaceEventClusterUpdate)

View File

@@ -0,0 +1,96 @@
from ApiControllers.abstracts.event_clusters import Event
from Controllers.Postgres.pagination import Pagination, PaginationResult, PaginateOnly
from Controllers.Postgres.response import EndpointResponse
from Schemas import BuildLivingSpace
# List endpoint
BuildLivingSpaceListEvent = Event(
name="build_living_space_list",
key="d16c692f-5597-493a-90fe-b2bfe0d1c163",
request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator
description="List events of build living spaces endpoint",
)
# Create endpoint
BuildLivingSpaceCreateEvent = Event(
name="build_living_space_create",
key="8ed0929e-9c96-4e81-b073-e3578ca13f37",
request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator
description="Create events of build living spaces endpoint",
)
# Update endpoint
BuildLivingSpaceUpdateEvent = Event(
name="build_living_space_update",
key="ece55fa6-afba-4c34-bd2e-f39a4cdd6b5c",
request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator
description="Update events of build living spaces endpoint",
)
def build_living_space_list_callable(list_options: PaginateOnly):
"""
List callable method
"""
list_options = PaginateOnly(**list_options.model_dump())
with BuildLivingSpace.new_session() as db_session:
if list_options.query:
buildings_list = BuildLivingSpace.filter_all(
*BuildLivingSpace.convert(list_options.query), db=db_session
)
else:
buildings_list = BuildLivingSpace.filter_all(db=db_session)
pagination = Pagination(data=buildings_list)
pagination.change(**list_options.model_dump())
pagination_result = PaginationResult(
data=buildings_list,
pagination=pagination,
# response_model="",
).pagination.as_dict
return EndpointResponse(
message="MSG0003-LIST",
pagination_result=pagination_result,
).response
BuildLivingSpaceListEvent.event_callable = build_living_space_list_callable
def build_living_space_create_callable(data: dict):
"""
Create callable method
"""
with BuildLivingSpace.new_session() as db_session:
return {
"completed": True,
"message": "Build living space created",
"info": {
"host": "example_host",
"user_agent": "example_user_agent",
},
}
BuildLivingSpaceCreateEvent.event_callable = build_living_space_create_callable
def build_living_space_update_callable(data: dict):
"""
Update callable method
"""
with BuildLivingSpace.new_session() as db_session:
return {
"completed": True,
"message": "Build living space updated",
"info": {
"host": "example_host",
"user_agent": "example_user_agent",
},
}
BuildLivingSpaceUpdateEvent.event_callable = build_living_space_update_callable

View File

@@ -0,0 +1,27 @@
from ApiControllers.abstracts.event_clusters import EventCluster, RouterCluster
from .supers_events import (
BuildTypeListEvent,
BuildTypeCreateEvent,
BuildTypeUpdateEvent,
)
BuildTypeRouterCluster = RouterCluster(name="BuildTypeRouterCluster")
BuildTypeEventClusterList = EventCluster(
name="BuildTypeList", endpoint_uu_id="14f076c2-b118-4cfb-b679-9f2168a2658c"
)
BuildTypeEventClusterList.add_event(BuildTypeListEvent)
BuildTypeEventClusterCreate = EventCluster(
name="BuildCreate", endpoint_uu_id="4c90c4cf-8873-479a-a56b-d12f276efa9d"
)
BuildTypeEventClusterCreate.add_event(BuildTypeCreateEvent)
BuildTypeEventClusterUpdate = EventCluster(
name="BuildUpdate", endpoint_uu_id="cde9db69-6795-4562-802d-540d0b03ceaa"
)
BuildTypeEventClusterUpdate.add_event(BuildTypeUpdateEvent)
BuildTypeRouterCluster.set_event_cluster(BuildTypeEventClusterList)
BuildTypeRouterCluster.set_event_cluster(BuildTypeEventClusterCreate)
BuildTypeRouterCluster.set_event_cluster(BuildTypeEventClusterUpdate)

View File

@@ -0,0 +1,96 @@
from ApiControllers.abstracts.event_clusters import Event
from Controllers.Postgres.pagination import Pagination, PaginationResult, PaginateOnly
from Controllers.Postgres.response import EndpointResponse
from Schemas import BuildTypes
# List endpoint
BuildTypeListEvent = Event(
name="build_type_list",
key="e013b43e-3845-4a95-b5b0-409343659c5f",
request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator
description="List events of build types endpoint",
)
# Create endpoint
BuildTypeCreateEvent = Event(
name="build_type_create",
key="8119a07e-bbb2-4d4c-b529-f923e8cdcc60",
request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator
description="Create events of build types endpoint",
)
# Update endpoint
BuildTypeUpdateEvent = Event(
name="build_type_update",
key="6b7b89d5-6406-4614-aba4-c942f0c081ac",
request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator
description="Update events of build types endpoint",
)
def build_type_list_callable(list_options: PaginateOnly):
"""
List callable method
"""
list_options = PaginateOnly(**list_options.model_dump())
with BuildTypes.new_session() as db_session:
if list_options.query:
buildings_list = BuildTypes.filter_all(
*BuildTypes.convert(list_options.query), db=db_session
)
else:
buildings_list = BuildTypes.filter_all(db=db_session)
pagination = Pagination(data=buildings_list)
pagination.change(**list_options.model_dump())
pagination_result = PaginationResult(
data=buildings_list,
pagination=pagination,
# response_model="",
).pagination.as_dict
return EndpointResponse(
message="MSG0003-LIST",
pagination_result=pagination_result,
).response
BuildTypeListEvent.event_callable = build_type_list_callable
def build_type_create_callable(data: dict):
"""
Create callable method
"""
with BuildTypes.new_session() as db_session:
return {
"completed": True,
"message": "Build type created",
"info": {
"host": "example_host",
"user_agent": "example_user_agent",
},
}
BuildTypeCreateEvent.event_callable = build_type_create_callable
def build_type_update_callable(data: dict):
"""
Update callable method
"""
with BuildTypes.new_session() as db_session:
return {
"completed": True,
"message": "Build type updated",
"info": {
"host": "example_host",
"user_agent": "example_user_agent",
},
}
BuildTypeUpdateEvent.event_callable = build_type_update_callable

View File

@@ -0,0 +1,37 @@
from pydantic import BaseModel
from typing import Optional
class REQUESTEWFAZCDMPVZHIWOKZEJBIEUDAFBNXFEEAEGSELVGGCDMWLQPYMRAEEABSRQJUFBIMFEEADXK(
BaseModel
):
gov_address_code: str
build_name: str
build_no: str
max_floor: int
underground_floor: int
build_date: str
decision_period_date: str
tax_no: str
lift_count: int
heating_system: bool
cooling_system: bool
hot_water_system: bool
block_service_man_count: int
security_service_man_count: int
garage_count: int
management_room_id: int
site_uu_id: str
address_uu_id: str
class REQUESTOCARDAJXLDANCXQAJWDBDIWXHUAEKQNUOSBZOCWXDAFGLAAVRBSADHUBDXAREUSESYGNGKBR(
BaseModel
):
pass
class REQUESTAEKUDAILSFMCCLOERBHBFRCIKFCSNCBOSENCAEOIDACPRFZCCWGEDBHBFBMZBFCJHCBVKEFC(
BaseModel
):
pass

View File

@@ -1,12 +1,12 @@
from Controllers.Postgres.database import get_db from Controllers.Postgres.database import get_db
from Schemas import Users, Employees, BuildLivingSpace from Schemas import Users, Employees, BuildLivingSpace, Services
from init_service_to_events import init_service_to_event_matches_for_super_user from init_service_to_events import init_service_to_event_matches_for_super_user
from init_applications import ( from init_applications import (
init_applications_for_super_user, init_applications_for_super_user,
init_applications_for_general_manager, # init_applications_for_general_manager,
init_applications_for_build_manager, # init_applications_for_build_manager,
init_applications_for_owner, # init_applications_for_owner,
init_applications_for_tenant, # init_applications_for_tenant,
) )
@@ -16,62 +16,59 @@ if __name__ == "__main__":
Set Events to service | Set Service to employee Set Events to service | Set Service to employee
""" """
with get_db() as db_session: with get_db() as db_session:
if super_man := Users.filter_one( service_super_user = Services.filter_one(Services.service_code == "SRE-SUE", db=db_session).data
Users.email == "karatay.berkay.sup@evyos.com.tr", db=db_session user_super_user = Users.filter_one(Users.email == "karatay.berkay.sup@evyos.com.tr", db=db_session).data
).data: employee_super_user = Employees.filter_one(Employees.people_id == user_super_user.person_id, db=db_session).data
super_employee = Employees.filter_one( if service_super_user and user_super_user and employee_super_user:
Employees.people_id == super_man.person_id, db=db_session
).data
init_service_to_event_matches_for_super_user( init_service_to_event_matches_for_super_user(
super_user=super_employee, db_session=db_session service_match=service_super_user, employee_match=employee_super_user, db_session=db_session
) )
init_applications_for_super_user( init_applications_for_super_user(
super_user=super_employee, db_session=db_session service_match=service_super_user, employee_match=employee_super_user, db_session=db_session
) )
with get_db() as db_session: # with get_db() as db_session:
print("Createing GM") # print("Createing GM")
if gen_man := Users.filter_one( # if gen_man := Users.filter_one(
Users.email == "example.general@evyos.com.tr", db=db_session # Users.email == "example.general@evyos.com.tr", db=db_session
).data: # ).data:
gen_man_employee = Employees.filter_one( # gen_man_employee = Employees.filter_one(
Employees.people_id == gen_man.person_id, db=db_session # Employees.people_id == gen_man.person_id, db=db_session
).data # ).data
print("General Manager : ", gen_man_employee) # print("General Manager : ", gen_man_employee)
init_applications_for_general_manager( # init_applications_for_general_manager(
super_user=gen_man_employee, db_session=db_session # super_user=gen_man_employee, db_session=db_session
) # )
with get_db() as db_session: # with get_db() as db_session:
if build_man := Users.filter_one( # if build_man := Users.filter_one(
Users.email == "example.build.manager@gmail.com", db=db_session # Users.email == "example.build.manager@gmail.com", db=db_session
).data: # ).data:
build_man_employee = BuildLivingSpace.filter_one( # build_man_employee = BuildLivingSpace.filter_one(
BuildLivingSpace.person_id == build_man.person_id, db=db_session # BuildLivingSpace.person_id == build_man.person_id, db=db_session
).data # ).data
init_applications_for_build_manager( # init_applications_for_build_manager(
super_user=build_man_employee, db_session=db_session # super_user=build_man_employee, db_session=db_session
) # )
with get_db() as db_session: # with get_db() as db_session:
if own_flt := Users.filter_one( # if own_flt := Users.filter_one(
Users.email == "example.owner@gmail.com", db=db_session # Users.email == "example.owner@gmail.com", db=db_session
).data: # ).data:
own_flt_employee = BuildLivingSpace.filter_one( # own_flt_employee = BuildLivingSpace.filter_one(
BuildLivingSpace.person_id == own_flt.person_id, db=db_session # BuildLivingSpace.person_id == own_flt.person_id, db=db_session
).data # ).data
init_applications_for_owner( # init_applications_for_owner(
super_user=own_flt_employee, db_session=db_session # super_user=own_flt_employee, db_session=db_session
) # )
with get_db() as db_session: # with get_db() as db_session:
if ten_flt := Users.filter_one( # if ten_flt := Users.filter_one(
Users.email == "example.tenant@gmail.com", db=db_session # Users.email == "example.tenant@gmail.com", db=db_session
).data: # ).data:
ten_flt_employee = BuildLivingSpace.filter_one( # ten_flt_employee = BuildLivingSpace.filter_one(
BuildLivingSpace.person_id == ten_flt.person_id, db=db_session # BuildLivingSpace.person_id == ten_flt.person_id, db=db_session
).data # ).data
init_applications_for_tenant( # init_applications_for_tenant(
super_user=ten_flt_employee, db_session=db_session # super_user=ten_flt_employee, db_session=db_session
) # )

View File

@@ -4,223 +4,193 @@ from Schemas import (
Application2Occupant, Application2Occupant,
Employees, Employees,
BuildLivingSpace, BuildLivingSpace,
Services,
Service2Application,
) )
def init_applications_for_super_user(super_user: Employees, db_session=None) -> None: def init_applications_for_super_user(service_match: Services, employee_match: Employees, db_session=None) -> None:
list_of_created_apps = [ list_of_all_events = Applications.filter_all(db=db_session).data
dict( Service2Application.filter_all(db=db_session).query.delete()
name="Dashboard1", Service2Application.save(db=db_session)
application_code="app000001",
site_url="/dashboard",
application_type="info",
description="Dashboard Page",
),
dict(
name="Individual",
application_code="app000003",
site_url="/individual",
application_type="Dash",
description="Individual Page for people",
),
dict(
name="User",
application_code="app000004",
site_url="/user",
application_type="Dash",
description="Individual Page for user",
),
dict(
name="Build",
application_code="app000005",
site_url="/build",
application_type="Dash",
description="Individual Page for build",
),
dict(
name="BuildParts",
application_code="app000006",
site_url="/build/parts",
application_type="Dash",
description="Individual Page for build parts",
),
dict(
name="BuildArea",
application_code="app000007",
site_url="/build/area",
application_type="Dash",
description="Individual Page for build area",
),
dict(
name="ManagementAccounting",
application_code="app000008",
site_url="/management/accounting",
application_type="Dash",
description="Individual Page for management accounting",
),
dict(
name="ManagementBudget",
application_code="app000009",
site_url="/management/budget",
application_type="Dash",
description="Individual Page for management accounting2",
),
dict(
name="ManagementMeetingClose",
application_code="app000010",
site_url="/annual/meeting/close",
application_type="Dash",
description="Individual Page for management accounting3",
),
dict(
name="EmergencyMeeting",
application_code="app000011",
site_url="/emergency/meeting",
application_type="Dash",
description="Individual Page for management accounting4",
),
dict(
name="EmergencyMeetingClose",
application_code="app000012",
site_url="/emergency/meeting/close",
application_type="Dash",
description="Individual Page for management accounting5",
),
dict(
name="MeetingParticipation",
application_code="app000013",
site_url="/meeting/participation",
application_type="Dash",
description="Individual Page for management accounting6",
),
]
for list_of_created_app in list_of_created_apps:
created_page = Applications.find_or_create(
**list_of_created_app,
db=db_session,
is_confirmed=True,
)
if created_page.meta_data.created:
created_page.save(db=db_session)
application_employee_created = Application2Employee.find_or_create( for list_of_event_code in list_of_all_events:
employee_id=super_user.id, service_to_event_found = Service2Application.filter_one_system(
employee_uu_id=str(super_user.uu_id), Service2Application.application_id == list_of_event_code.id,
site_url=created_page.site_url, Service2Application.service_id == service_match.id,
application_code=created_page.application_code, db=db_session,
application_id=created_page.id, )
application_uu_id=str(created_page.uu_id), if service_to_event_found.data:
service_to_event_found.destroy(db=db_session)
print(
f"UUID: {service_to_event_found.uu_id} application is deleted from {service_match.service_description}"
)
employee_added_application = Service2Application.find_or_create(
service_id=service_match.id,
service_uu_id=str(service_match.uu_id),
application_id=list_of_event_code.id,
application_uu_id=str(list_of_event_code.uu_id),
application_code=list_of_event_code.application_code,
site_url=list_of_event_code.site_url,
is_confirmed=True,
active=True,
db=db_session,
)
if employee_added_application.meta_data.created:
employee_added_application.save(db=db_session)
print(
f"UUID: {employee_added_application.uu_id} application is saved to {service_match.service_description}"
)
employee_added_service = Application2Employee.find_or_create(
service_id=service_match.id,
service_uu_id=str(service_match.uu_id),
employee_id=employee_match.id,
employee_uu_id=str(employee_match.uu_id),
is_confirmed=True, is_confirmed=True,
db=db_session, db=db_session,
) )
if application_employee_created.meta_data.created: if employee_added_service.meta_data.created:
application_employee_created.save(db=db_session) employee_added_service.save(db=db_session)
print(
f"UUID: {employee_added_service.uu_id} service is saved to {employee_match.uu_id}"
def init_applications_for_general_manager(
super_user: Employees, db_session=None
) -> None:
list_of_created_apps = [
dict(
name="Dashboard1",
application_code="app000001",
site_url="/dashboard",
application_type="info",
description="Dashboard Page",
),
dict(
name="ManagementAccounting",
application_code="app000008",
site_url="/management/accounting",
application_type="Dash",
description="Individual Page for management accounting",
),
]
for list_of_created_app in list_of_created_apps:
created_page = Applications.find_or_create(
**list_of_created_app,
db=db_session,
) )
print("Application : ", created_page)
if created_page.meta_data.created:
created_page.save(db=db_session)
application_employee_created = Application2Employee.find_or_create(
employee_id=super_user.id,
employee_uu_id=str(super_user.uu_id),
site_url=created_page.site_url,
application_code=created_page.application_code,
application_id=created_page.id,
application_uu_id=str(created_page.uu_id),
is_confirmed=True,
db=db_session,
)
print("Application Employee : ", application_employee_created)
if application_employee_created.meta_data.created:
application_employee_created.save(db=db_session)
def init_applications_for_build_manager( # def init_applications_for_general_manager(
super_user: BuildLivingSpace, db_session=None # super_user: Employees, db_session=None
) -> None: # ) -> None:
list_of_created_apps = [] # list_of_created_apps = Applications.filter_all_system(db=db_session).data
# if not list_of_created_apps:
# raise Exception("No applications found")
# for list_of_created_app in list_of_created_apps:
# application_employee_created = Application2Employee.find_or_create(
# employee_id=super_user.id,
# employee_uu_id=str(super_user.uu_id),
# site_url=list_of_created_app.site_url,
# application_code=list_of_created_app.application_code,
# application_id=list_of_created_app.id,
# application_uu_id=str(list_of_created_app.uu_id),
# is_confirmed=True,
# db=db_session,
# )
# if application_employee_created.meta_data.created:
# application_employee_created.save(db=db_session)
def init_applications_for_owner(super_user: BuildLivingSpace, db_session=None) -> None:
pass # def init_applications_for_build_manager(
# super_user: BuildLivingSpace, db_session=None
# ) -> None:
# list_of_created_apps = Applications.filter_all_system(db=db_session).data
# if not list_of_created_apps:
# raise Exception("No applications found")
# for list_of_created_app in list_of_created_apps:
# application_employee_created = Application2Employee.find_or_create(
# employee_id=super_user.id,
# employee_uu_id=str(super_user.uu_id),
# site_url=list_of_created_app.site_url,
# application_code=list_of_created_app.application_code,
# application_id=list_of_created_app.id,
# application_uu_id=str(list_of_created_app.uu_id),
# is_confirmed=True,
# db=db_session,
# )
# if application_employee_created.meta_data.created:
# application_employee_created.save(db=db_session)
def init_applications_for_tenant(super_user: BuildLivingSpace, db_session=None) -> None: # def init_applications_for_owner(super_user: BuildLivingSpace, db_session=None) -> None:
list_of_created_apps = [ # list_of_created_apps = Applications.filter_all_system(db=db_session).data
dict( # if not list_of_created_apps:
name="Dashboard1", # raise Exception("No applications found")
application_code="app000001",
site_url="/dashboard",
application_type="info",
description="Dashboard Page",
),
dict(
name="TenantSendMessageToBuildManager",
application_code="app000022",
site_url="/tenant/messageToBM",
application_type="Dash",
description="Individual Page for tenant send message to build manager",
),
dict(
name="TenantSendMessageToOwner",
application_code="app000018",
site_url="/tenant/messageToOwner",
application_type="Dash",
description="Individual Page for tenant send message to owner",
),
dict(
name="TenantAccountView",
application_code="app000019",
site_url="/tenant/accounting",
application_type="Dash",
description="Individual Page for tenant account view",
),
] # for list_of_created_app in list_of_created_apps:
# application_employee_created = Application2Employee.find_or_create(
# employee_id=super_user.id,
# employee_uu_id=str(super_user.uu_id),
# site_url=list_of_created_app.site_url,
# application_code=list_of_created_app.application_code,
# application_id=list_of_created_app.id,
# application_uu_id=str(list_of_created_app.uu_id),
# is_confirmed=True,
# db=db_session,
# )
# if application_employee_created.meta_data.created:
# application_employee_created.save(db=db_session)
for list_of_created_app in list_of_created_apps:
created_page = Applications.find_or_create(
**list_of_created_app,
db=db_session,
is_confirmed=True,
)
if created_page.meta_data.created:
created_page.save(db=db_session)
application_occupant_created = Application2Occupant.find_or_create( # def init_applications_for_tenant(super_user: BuildLivingSpace, db_session=None) -> None:
build_living_space_id=super_user.id, # list_of_created_apps = Applications.filter_all_system(db=db_session).data
build_living_space_uu_id=str(super_user.uu_id), # if not list_of_created_apps:
site_url=created_page.site_url, # raise Exception("No applications found")
application_code=created_page.application_code,
application_id=created_page.id, # for list_of_created_app in list_of_created_apps:
application_uu_id=str(created_page.uu_id), # application_employee_created = Application2Employee.find_or_create(
is_confirmed=True, # employee_id=super_user.id,
db=db_session, # employee_uu_id=str(super_user.uu_id),
) # site_url=list_of_created_app.site_url,
if application_occupant_created.meta_data.created: # application_code=list_of_created_app.application_code,
application_occupant_created.save(db=db_session) # application_id=list_of_created_app.id,
# application_uu_id=str(list_of_created_app.uu_id),
# is_confirmed=True,
# db=db_session,
# )
# if application_employee_created.meta_data.created:
# application_employee_created.save(db=db_session)
# list_of_created_apps = [
# dict(
# name="Dashboard1",
# application_code="app000001",
# site_url="/dashboard",
# application_type="info",
# description="Dashboard Page",
# ),
# dict(
# name="TenantSendMessageToBuildManager",
# application_code="app000022",
# site_url="/tenant/messageToBM",
# application_type="Dash",
# description="Individual Page for tenant send message to build manager",
# ),
# dict(
# name="TenantSendMessageToOwner",
# application_code="app000018",
# site_url="/tenant/messageToOwner",
# application_type="Dash",
# description="Individual Page for tenant send message to owner",
# ),
# dict(
# name="TenantAccountView",
# application_code="app000019",
# site_url="/tenant/accounting",
# application_type="Dash",
# description="Individual Page for tenant account view",
# ),
# ]
# for list_of_created_app in list_of_created_apps:
# created_page = Applications.find_or_create(
# **list_of_created_app,
# db=db_session,
# is_confirmed=True,
# )
# if created_page.meta_data.created:
# created_page.save(db=db_session)
# application_occupant_created = Application2Occupant.find_or_create(
# build_living_space_id=super_user.id,
# build_living_space_uu_id=str(super_user.uu_id),
# site_url=created_page.site_url,
# application_code=created_page.application_code,
# application_id=created_page.id,
# application_uu_id=str(created_page.uu_id),
# is_confirmed=True,
# db=db_session,
# )
# if application_occupant_created.meta_data.created:
# application_occupant_created.save(db=db_session)

View File

@@ -11,14 +11,23 @@ from Schemas import (
) )
def init_service_to_event_matches_for_super_user(super_user, db_session=None) -> None: def init_service_to_event_matches_for_super_user(service_match: Services, employee_match: Employees, db_session=None) -> None:
service_match = Services.filter_one(
Services.service_name == "Super User",
db=db_session,
).data
list_of_all_events = Events.filter_all(db=db_session).data list_of_all_events = Events.filter_all(db=db_session).data
Service2Events.filter_all(db=db_session).query.delete()
Service2Events.save(db=db_session)
for list_of_event_code in list_of_all_events: for list_of_event_code in list_of_all_events:
created_service = Service2Events.find_or_create( service_to_event_found = Service2Events.filter_one_system(
Service2Events.event_id == list_of_event_code.id,
Service2Events.service_id == service_match.id,
db=db_session,
)
if service_to_event_found.data:
service_to_event_found.destroy(db=db_session)
print(
f"UUID: {service_to_event_found.uu_id} event is deleted from {service_match.service_description}"
)
added_service = Service2Events.find_or_create(
service_id=service_match.id, service_id=service_match.id,
service_uu_id=str(service_match.uu_id), service_uu_id=str(service_match.uu_id),
event_id=list_of_event_code.id, event_id=list_of_event_code.id,
@@ -27,22 +36,22 @@ def init_service_to_event_matches_for_super_user(super_user, db_session=None) ->
active=True, active=True,
db=db_session, db=db_session,
) )
if created_service.meta_data.created: if added_service.meta_data.created:
created_service.save(db=db_session) added_service.save(db=db_session)
print( print(
f"UUID: {created_service.uu_id} event is saved to {service_match.uu_id}" f"UUID: {added_service.uu_id} event is saved to {service_match.service_description}"
) )
employee_added_service = Event2Employee.find_or_create( employee_added_service = Event2Employee.find_or_create(
event_service_id=service_match.id, event_service_id=service_match.id,
event_service_uu_id=str(service_match.uu_id), event_service_uu_id=str(service_match.uu_id),
employee_id=super_user.id, employee_id=employee_match.id,
employee_uu_id=str(super_user.uu_id), employee_uu_id=str(employee_match.uu_id),
is_confirmed=True, is_confirmed=True,
db=db_session, db=db_session,
) )
if employee_added_service.meta_data.created: if employee_added_service.meta_data.created:
employee_added_service.save(db=db_session) employee_added_service.save(db=db_session)
print( print(
f"UUID: {employee_added_service.uu_id} event is saved to {super_user.uu_id}" f"UUID: {employee_added_service.uu_id} event is saved to employee {employee_match.uu_id}"
) )

View File

@@ -3,24 +3,27 @@ FROM python:3.12-slim
WORKDIR / WORKDIR /
# Install system dependencies and Poetry # Install system dependencies and Poetry
RUN apt-get update && apt-get install -y --no-install-recommends gcc \ RUN apt-get update && apt-get install -y --no-install-recommends gcc && rm -rf /var/lib/apt/lists/* && pip install --no-cache-dir poetry
&& rm -rf /var/lib/apt/lists/* && pip install --no-cache-dir poetry
# Copy Poetry configuration # Copy Poetry configuration
COPY /pyproject.toml ./pyproject.toml COPY /pyproject.toml ./pyproject.toml
# Configure Poetry and install dependencies with optimizations # Configure Poetry and install dependencies with optimizations
RUN poetry config virtualenvs.create false \ RUN poetry config virtualenvs.create false && poetry install --no-interaction --no-ansi --no-root --only main \
&& poetry install --no-interaction --no-ansi --no-root --only main \ && pip cache purge && rm -rf ~/.cache/pypoetry
&& pip cache purge && rm -rf ~/.cache/pypoetry
# Copy application code # Copy application code
COPY /ApiServices/IdentityService /ApiServices/IdentityService COPY /ApiControllers /ApiControllers
COPY /ApiDefaults /ApiDefaults
COPY /Controllers /Controllers COPY /Controllers /Controllers
COPY /Schemas /Schemas COPY /Schemas /Schemas
COPY /ApiServices/IdentityService/Endpoints /ApiDefaults/Endpoints
COPY /ApiServices/IdentityService/Events /ApiDefaults/Events
COPY /ApiServices/IdentityService/Validations /ApiDefaults/Validations
# 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
# Run the application using the configured uvicorn server # Run the application using the configured uvicorn server
CMD ["poetry", "run", "python", "ApiServices/IdentityService/app.py"] CMD ["poetry", "run", "python", "ApiDefaults/app.py"]

View File

@@ -0,0 +1,67 @@
from fastapi import APIRouter, Depends
from ApiControllers.abstracts.default_validations import CommonHeaders
from ApiControllers.providers.token_provider import TokenProvider
from Controllers.Postgres.pagination import PaginateOnly
from Events.people.cluster import PeopleRouterCluster
people_route = APIRouter(prefix="/people", tags=["People"])
@people_route.post(
path="/list",
description="List people endpoint",
operation_id="f102db46-031a-43e4-966a-dae6896f985b",
)
def people_route_list(
data: PaginateOnly,
headers: CommonHeaders = Depends(CommonHeaders.as_dependency),
):
"""
List people endpoint
"""
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
FoundCluster = PeopleRouterCluster.get_event_cluster("PeopleList")
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
return event_cluster_matched.event_callable(data=data)
@people_route.post(
path="/create",
description="Create people endpoint",
operation_id="eb465fde-337f-4b81-94cf-28c6d4f2b1b6",
)
def people_route_create(
headers: CommonHeaders = Depends(CommonHeaders.as_dependency),
):
"""
Create people endpoint
"""
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
FoundCluster = PeopleRouterCluster.get_event_cluster("PeopleCreate")
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
return event_cluster_matched.event_callable()
@people_route.post(
path="/update",
description="Update people endpoint",
operation_id="c9e5ba69-6915-43f5-8f9c-a5c2aa865b89",
)
def people_route_update(
headers: CommonHeaders = Depends(CommonHeaders.as_dependency),
):
"""
Update people endpoint
"""
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
FoundCluster = PeopleRouterCluster.get_event_cluster("PeopleUpdate")
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
return event_cluster_matched.event_callable()

View File

@@ -1,14 +1,11 @@
from fastapi import APIRouter from fastapi import APIRouter
# from .user.route import user_route
from .people.route import people_route
def get_routes() -> list[APIRouter]: def get_routes() -> list[APIRouter]:
return [ from .people.route import people_route
# user_route, from .user.route import user_route
people_route
] return [user_route, people_route]
def get_safe_endpoint_urls() -> list[tuple[str, str]]: def get_safe_endpoint_urls() -> list[tuple[str, str]]:

View File

@@ -0,0 +1,72 @@
import uuid
from fastapi import APIRouter, Header
from typing import Any
from ApiDefaults.config import api_config
from Events.user.cluster import UserRouterCluster
from ApiControllers.providers.token_provider import TokenProvider
from ApiControllers.abstracts.default_validations import CommonHeaders
from Controllers.Postgres.pagination import PaginateOnly
user_route = APIRouter(prefix="/user", tags=["User"])
@user_route.post(
path="/list",
description="List users endpoint",
operation_id="1aca3094-fe80-4e0f-a460-1a506419082a",
)
def user_list_route(
data: PaginateOnly,
headers: CommonHeaders,
):
"""
List users endpoint
"""
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
FoundCluster = UserRouterCluster.get_event_cluster("UserList")
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
return event_cluster_matched.event_callable(data=data)
@user_route.post(
path="/create",
description="Create users endpoint",
operation_id="9686211f-4260-485d-8076-186c22c053aa",
)
def user_create_route(
data: Any,
headers: CommonHeaders,
):
"""
Create users endpoint
"""
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
FoundCluster = UserRouterCluster.get_event_cluster("UserCreate")
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
return event_cluster_matched.event_callable(data=data)
@user_route.post(
path="/update",
description="Update users endpoint",
operation_id="268e887b-5ff5-4f99-b1be-7e127e28a198",
)
def user_update_route(
data: Any,
headers: CommonHeaders,
):
"""
Update users endpoint
"""
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
FoundCluster = UserRouterCluster.get_event_cluster("UserUpdate")
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
return event_cluster_matched.event_callable(data=data)

View File

@@ -0,0 +1,8 @@
from .people.cluster import PeopleRouterCluster
from .user.cluster import UserRouterCluster
__all__ = [
"PeopleRouterCluster",
"UserRouterCluster",
]

View File

@@ -0,0 +1,25 @@
from ApiControllers.abstracts.event_clusters import EventCluster, RouterCluster
from .supers_events import (
SupersPeopleCreateEvent,
SupersPeopleUpdateEvent,
SupersPeopleListEvent,
)
PeopleRouterCluster = RouterCluster(name="PeopleRouterCluster")
PeopleEventClusterList = EventCluster(
name="PeopleList", endpoint_uu_id="f102db46-031a-43e4-966a-dae6896f985b"
)
PeopleEventClusterList.add_event(SupersPeopleListEvent)
PeopleEventClusterCreate = EventCluster(
name="PeopleCreate", endpoint_uu_id="eb465fde-337f-4b81-94cf-28c6d4f2b1b6"
)
PeopleEventClusterCreate.add_event(SupersPeopleCreateEvent)
PeopleEventClusterUpdate = EventCluster(
name="PeopleUpdate", endpoint_uu_id="c9e5ba69-6915-43f5-8f9c-a5c2aa865b89"
)
PeopleEventClusterUpdate.add_event(SupersPeopleUpdateEvent)
PeopleRouterCluster.set_event_cluster(PeopleEventClusterList)
PeopleRouterCluster.set_event_cluster(PeopleEventClusterCreate)
PeopleRouterCluster.set_event_cluster(PeopleEventClusterUpdate)

View File

@@ -1,23 +1,45 @@
from ApiServices.IdentityService.initializer.event_clusters import EventCluster, Event from ApiControllers.abstracts.event_clusters import Event
from ApiServices.IdentityService.validations.people.validations import ( from Validations.people.validations import (
REQUESTAWMXNTKMGPPOJWRCTZUBADNFLQDBDYVQAORFAVCSXUUHEBQHCEPCSKFBADBODFDBPYKOVINV, REQUESTAWMXNTKMGPPOJWRCTZUBADNFLQDBDYVQAORFAVCSXUUHEBQHCEPCSKFBADBODFDBPYKOVINV,
) )
from Controllers.Postgres.pagination import Pagination, PaginationResult, PaginateOnly from Controllers.Postgres.pagination import (
ListOptions,
Pagination,
PaginationResult,
PaginateOnly,
)
from Controllers.Postgres.response import EndpointResponse from Controllers.Postgres.response import EndpointResponse
from Schemas.identity.identity import People from Schemas import People
# Create endpoint SupersPeopleCreateEvent = Event(
supers_people_create = Event( name="supers_people_create",
name="supers_people_list",
key="ec4c2404-a61b-46c7-bbdf-ce3357e6cf41", key="ec4c2404-a61b-46c7-bbdf-ce3357e6cf41",
request_validator=None, # TODO: Add request validator request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator response_validator=None, # TODO: Add response validator
description="Create events of people endpoint", description="Super Users Create events of people endpoint",
)
# Update endpoint
SupersPeopleUpdateEvent = Event(
name="supers_people_update",
key="91e77de4-9f29-4309-b121-4aad256d440c",
request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator
description="Super Users Update events of people endpoint",
)
# List endpoint
SupersPeopleListEvent = Event(
name="supers_people_list",
key="6828d280-e587-400d-a622-c318277386c3",
request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator
description="Super Users List events of people endpoint",
) )
def supers_people_create_callable(list_options): def supers_people_create_callable():
""" """
Example callable method Example callable method
""" """
@@ -32,21 +54,7 @@ def supers_people_create_callable(list_options):
} }
supers_people_create.event_callable = supers_people_create_callable SupersPeopleCreateEvent.event_callable = supers_people_create_callable
people_event_cluster_create = EventCluster(
endpoint_uu_id="eb465fde-337f-4b81-94cf-28c6d4f2b1b6"
)
people_event_cluster_create.add_event([supers_people_create])
# Update endpoint
supers_people_update = Event(
name="supers_people_update",
key="91e77de4-9f29-4309-b121-4aad256d440c",
request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator
description="Update events of people endpoint",
)
def supers_people_update_callable(): def supers_people_update_callable():
@@ -64,33 +72,15 @@ def supers_people_update_callable():
} }
supers_people_update.event_callable = supers_people_update_callable SupersPeopleUpdateEvent.event_callable = supers_people_update_callable
people_event_cluster_update = EventCluster(
endpoint_uu_id="c9e5ba69-6915-43f5-8f9c-a5c2aa865b89"
)
people_event_cluster_update.add_event([supers_people_update])
# List endpoint def supers_people_list_callable(data: PaginateOnly):
supers_people_list = Event(
name="supers_people_list",
key="6828d280-e587-400d-a622-c318277386c3",
request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator
description="List events of people endpoint",
)
def supers_people_list_callable(list_options: PaginateOnly):
""" """
Example callable method Example callable method
""" """
list_options = PaginateOnly(**list_options.model_dump()) list_options = PaginateOnly(**data.model_dump())
with People.new_session() as db_session: with People.new_session() as db_session:
People.pre_query = People.filter_all(
People.firstname.ilike("%B%"), db=db_session
).query
if list_options.query: if list_options.query:
people_list = People.filter_all( people_list = People.filter_all(
*People.convert(list_options.query), db=db_session *People.convert(list_options.query), db=db_session
@@ -110,19 +100,4 @@ def supers_people_list_callable(list_options: PaginateOnly):
).response ).response
supers_people_list.event_callable = supers_people_list_callable SupersPeopleListEvent.event_callable = supers_people_list_callable
people_event_cluster_list = EventCluster(
endpoint_uu_id="f102db46-031a-43e4-966a-dae6896f985b"
)
people_event_cluster_list.add_event([supers_people_list])
class PeopleCluster:
"""
People Clusters
"""
PeopleListCluster = people_event_cluster_list
PeopleCreateCluster = people_event_cluster_create
PeopleUpdateCluster = people_event_cluster_update

View File

@@ -0,0 +1,27 @@
from ApiControllers.abstracts.event_clusters import EventCluster, RouterCluster
from .supers_events import (
SuperUsersListEvent,
SuperUsersCreateEvent,
SuperUsersUpdateEvent,
)
UserRouterCluster = RouterCluster(name="UserRouterCluster")
UserEventClusterList = EventCluster(
name="UserList", endpoint_uu_id="1aca3094-fe80-4e0f-a460-1a506419082a"
)
UserEventClusterList.add_event(SuperUsersListEvent)
UserEventClusterCreate = EventCluster(
name="UserCreate", endpoint_uu_id="9686211f-4260-485d-8076-186c22c053aa"
)
UserEventClusterCreate.add_event(SuperUsersCreateEvent)
UserEventClusterUpdate = EventCluster(
name="UserUpdate", endpoint_uu_id="268e887b-5ff5-4f99-b1be-7e127e28a198"
)
UserEventClusterUpdate.add_event(SuperUsersUpdateEvent)
UserRouterCluster.set_event_cluster(UserEventClusterList)
UserRouterCluster.set_event_cluster(UserEventClusterCreate)
UserRouterCluster.set_event_cluster(UserEventClusterUpdate)

View File

@@ -0,0 +1,94 @@
from ApiControllers.abstracts.event_clusters import Event
from Controllers.Postgres.pagination import Pagination, PaginationResult, PaginateOnly
from Controllers.Postgres.response import EndpointResponse
from Schemas import Users
# List endpoint
SuperUsersListEvent = Event(
name="supers_users_list",
key="341b394f-9f11-4abb-99e7-4b27fa6bf012",
request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator
description="Super User List events of users endpoint",
)
# Create endpoint
SuperUsersCreateEvent = Event(
name="supers_users_create",
key="4e7e189e-e015-4ff8-902d-60138cbc77a6",
request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator
description="Super User Create events of users endpoint",
)
# Update endpoint
SuperUsersUpdateEvent = Event(
name="supers_users_update",
key="efa4aa4a-d414-4391-91ee-97eb617b7755",
request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator
description="Super User Update events of users endpoint",
)
def supers_users_list_callable(list_options: PaginateOnly):
"""
Example callable method
"""
list_options = PaginateOnly(**list_options.model_dump())
with Users.new_session() as db_session:
if list_options.query:
users_list = Users.filter_all(
*Users.convert(list_options.query), db=db_session
)
else:
users_list = Users.filter_all(db=db_session)
pagination = Pagination(data=users_list)
pagination.change(**list_options.model_dump())
pagination_result = PaginationResult(
data=users_list,
pagination=pagination,
# response_model="",
).pagination.as_dict
return EndpointResponse(
message="MSG0003-LIST",
pagination_result=pagination_result,
).response
SuperUsersListEvent.event_callable = supers_users_list_callable
def supers_users_create_callable():
"""
Example callable method
"""
return {
"completed": True,
"message": "Example callable method 2",
"info": {
"host": "example_host",
"user_agent": "example_user_agent",
},
}
SuperUsersCreateEvent.event_callable = supers_users_create_callable
def supers_users_update_callable():
"""
Example callable method
"""
return {
"completed": True,
"message": "Example callable method 2",
"info": {
"host": "example_host",
"user_agent": "example_user_agent",
},
}
SuperUsersUpdateEvent.event_callable = supers_users_update_callable

View File

@@ -0,0 +1,26 @@
from pydantic import BaseModel
from typing import Optional
class ListOptions(BaseModel):
"""
Query for list option abilities
"""
page: Optional[int] = 1
size: Optional[int] = 10
order_field: Optional[str] = "id"
order_type: Optional[str] = "asc"
# include_joins: Optional[list] = None
query: Optional[dict] = None
class PaginateOnly(BaseModel):
"""
Query for list option abilities
"""
page: Optional[int] = 1
size: Optional[int] = 10
order_field: Optional[str] = "id"
order_type: Optional[str] = "asc"

View File

@@ -0,0 +1,24 @@
from pydantic import BaseModel
class REQUESTAWMXNTKMGPPOJWRCTZUBADNFLQDBDYVQAORFAVCSXUUHEBQHCEPCSKFBADBODFDBPYKOVINV(
BaseModel
):
uu_id: str
created_at: str
updated_at: str
person_tag: str
expiry_starts: str
expiry_ends: str
firstname: str
middle_name: str
surname: str
birth_date: str
birth_place: str
sex_code: str
country_code: str
tax_no: str
active: bool
deleted: bool
is_confirmed: bool
is_notification_send: bool

View File

@@ -1,123 +0,0 @@
import uuid
from fastapi import APIRouter, Request, Response, Header
from ApiServices.IdentityService.config import api_config
from ApiServices.IdentityService.events.people.event import PeopleCluster
from ApiServices.IdentityService.providers.token_provider import TokenProvider
from Controllers.Postgres.pagination import PaginateOnly
people_route = APIRouter(prefix="/people", tags=["People"])
@people_route.post(
path="/list",
description="Test Template Route",
operation_id="f102db46-031a-43e4-966a-dae6896f985b",
)
def people_route_list(
request: Request,
response: Response,
data: PaginateOnly,
language: str = Header(None, alias="language"),
domain: str = Header(None, alias="domain"),
tz: str = Header(None, alias="timezone"),
):
"""
Test Template Route
"""
endpoint_code = "f102db46-031a-43e4-966a-dae6896f985b"
token = request.headers.get(api_config.ACCESS_TOKEN_TAG, None)
headers = {
"language": language or "",
"domain": domain or "",
"eys-ext": f"{str(uuid.uuid4())}",
"tz": tz or "GMT+3",
"token": token,
}
token_object = TokenProvider.get_dict_from_redis(token=token)
event_key = TokenProvider.retrieve_event_codes(
endpoint_code=endpoint_code, token=token_object
)
event_cluster_matched = PeopleCluster.PeopleListCluster.match_event(
event_key=event_key
)
response.headers["X-Header"] = "Test Header GET"
if runner_callable := event_cluster_matched.event_callable(list_options=data):
return runner_callable
raise ValueError("Event key not found or multiple matches found")
@people_route.post(
path="/create",
description="Test Template Route with Post Method",
operation_id="eb465fde-337f-4b81-94cf-28c6d4f2b1b6",
)
def test_template_post(
request: Request,
response: Response,
language: str = Header(None, alias="language"),
domain: str = Header(None, alias="domain"),
tz: str = Header(None, alias="timezone"),
):
"""
Test Template Route with Post Method
"""
endpoint_code = "eb465fde-337f-4b81-94cf-28c6d4f2b1b6"
token = request.headers.get(api_config.ACCESS_TOKEN_TAG, None)
headers = {
"language": language or "",
"domain": domain or "",
"eys-ext": f"{str(uuid.uuid4())}",
"tz": tz or "GMT+3",
"token": token,
}
token_object = TokenProvider.get_dict_from_redis(token=token)
event_key = TokenProvider.retrieve_event_codes(
endpoint_code=endpoint_code, token=token_object
)
event_cluster_matched = PeopleCluster.PeopleCreateCluster.match_event(
event_key=event_key
)
response.headers["X-Header"] = "Test Header POST"
if runner_callable := event_cluster_matched.event_callable():
return runner_callable
raise ValueError("Event key not found or multiple matches found")
@people_route.post(
path="/update",
description="Test Template Route with Post Method",
operation_id="c9e5ba69-6915-43f5-8f9c-a5c2aa865b89",
)
def test_template_post(
request: Request,
response: Response,
language: str = Header(None, alias="language"),
domain: str = Header(None, alias="domain"),
tz: str = Header(None, alias="timezone"),
):
"""
Test Template Route with Post Method
"""
token = request.headers.get(api_config.ACCESS_TOKEN_TAG, None)
endpoint_code = "c9e5ba69-6915-43f5-8f9c-a5c2aa865b89"
headers = {
"language": language or "",
"domain": domain or "",
"eys-ext": f"{str(uuid.uuid4())}",
"tz": tz or "GMT+3",
"token": token,
}
token_object = TokenProvider.get_dict_from_redis(token=token)
event_key = TokenProvider.retrieve_event_codes(
endpoint_code=endpoint_code, token=token_object
)
event_cluster_matched = PeopleCluster.PeopleUpdateCluster.match_event(
event_key=event_key
)
response.headers["X-Header"] = "Test Header POST"
if runner_callable := event_cluster_matched.event_callable():
return runner_callable
raise ValueError("Event key not found or multiple matches found")

View File

@@ -1,90 +0,0 @@
import uuid
from fastapi import APIRouter, Request, Response, Header
from ApiServices.IdentityService.config import api_config
from ApiServices.IdentityService.events.user.event import supers_users_list
user_route = APIRouter(prefix="/user", tags=["User"])
@user_route.post(
path="/list",
description="Test Template Route",
operation_id="5bc09312-d3f2-4f47-baba-17c928706da8",
)
def test_template(
request: Request,
response: Response,
language: str = Header(None, alias="language"),
domain: str = Header(None, alias="domain"),
tz: str = Header(None, alias="timezone"),
):
"""
Test Template Route
"""
event_code = "bb20c8c6-a289-4cab-9da7-34ca8a36c8e5"
token = request.headers.get(api_config.ACCESS_TOKEN_TAG, None)
headers = {
"language": language or "",
"domain": domain or "",
"eys-ext": f"{str(uuid.uuid4())}",
"tz": tz or "GMT+3",
"token": token,
}
event_cluster_matched = supers_users_list.match_event(
event_keys=[
"3f510dcf-9f84-4eb9-b919-f582f30adab1",
"9f403034-deba-4e1f-b43e-b25d3c808d39",
"b8ec6e64-286a-4f60-8554-7a3865454944",
]
)
response.headers["X-Header"] = "Test Header GET"
if runner_callable := event_cluster_matched.example_callable():
return runner_callable
raise ValueError("Event key not found or multiple matches found")
@user_route.post(
path="/create",
description="Test Template Route with Post Method",
operation_id="08d4b572-1584-47bb-aa42-8d068e5514e7",
)
def test_template_post(request: Request, response: Response):
"""
Test Template Route with Post Method
"""
event_cluster_matched = supers_users_list.match_event(
event_keys=[
"3f510dcf-9f84-4eb9-b919-f582f30adab1",
"9f403034-deba-4e1f-b43e-b25d3c808d39",
"b8ec6e64-286a-4f60-8554-7a3865454944",
]
)
response.headers["X-Header"] = "Test Header POST"
if runner_callable := event_cluster_matched.example_callable():
return runner_callable
raise ValueError("Event key not found or multiple matches found")
@user_route.post(
path="/update",
description="Test Template Route with Post Method",
operation_id="b641236a-928d-4f19-a1d2-5edf611d1e56",
)
def test_template_post(request: Request, response: Response):
"""
Test Template Route with Post Method
"""
event_cluster_matched = supers_users_list.match_event(
event_keys=[
"3f510dcf-9f84-4eb9-b919-f582f30adab1",
"9f403034-deba-4e1f-b43e-b25d3c808d39",
"b8ec6e64-286a-4f60-8554-7a3865454944",
]
)
response.headers["X-Header"] = "Test Header POST"
if runner_callable := event_cluster_matched.example_callable():
return runner_callable
raise ValueError("Event key not found or multiple matches found")

View File

@@ -1,12 +0,0 @@
from .people.event import (
people_event_cluster_list,
people_event_cluster_update,
people_event_cluster_create,
)
__all__ = [
"people_event_cluster_list",
"people_event_cluster_update",
"people_event_cluster_create",
]

View File

@@ -1,33 +0,0 @@
from ApiServices.IdentityService.initializer.event_clusters import EventCluster, Event
supers_users_list = Event(
name="supers_people_list",
key="341b394f-9f11-4abb-99e7-4b27fa6bf012",
request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator
description="Example event description",
)
def supers_people_list_callable():
"""
Example callable method
"""
return {
"completed": True,
"message": "Example callable method 2",
"info": {
"host": "example_host",
"user_agent": "example_user_agent",
},
}
supers_users_list.event_callable = supers_people_list_callable
people_event_cluster_list = EventCluster(
endpoint_uu_id="f102db46-031a-43e4-966a-dae6896f985b"
)
people_event_cluster_list.add_event([supers_users_list])

View File

@@ -1,53 +0,0 @@
from pydantic import BaseModel
"""
"sex_code": "M",
"country_code": "TR",
"created_at": "2025-04-13 10:03:32 +00:00",
"father_name": "Father",
"birth_place": "Ankara",
"updated_credentials_token": null,
"cryp_uu_id": null,
"mother_name": "Mother",
"expiry_starts": "2025-04-13 10:03:32 +00:00",
"confirmed_credentials_token": null,
"surname": "Karatay",
"firstname": "Berkay Super User",
"birth_date": "1990-01-07 00:00:00 +00:00",
"expiry_ends": "2099-12-31 00:00:00 +00:00",
"is_confirmed": true,
"is_email_send": false,
"tax_no": "1231231232",
"person_ref": "",
"active": true,
"deleted": false,
"updated_at": "2025-04-13 10:03:32 +00:00",
"uu_id": "b5b6e68f-a4d0-4d64-aa18-634671cb1299",
"middle_name": "",
"created_credentials_token": null,
"person_tag": "BSU-System",
"is_notification_send": false
"""
class REQUESTAWMXNTKMGPPOJWRCTZUBADNFLQDBDYVQAORFAVCSXUUHEBQHCEPCSKFBADBODFDBPYKOVINV(
BaseModel
):
uu_id: str
created_at: str
updated_at: str
person_tag: str
expiry_starts: str
expiry_ends: str
firstname: str
middle_name: str
surname: str
birth_date: str
birth_place: str
sex_code: str
country_code: str
tax_no: str
active: bool
deleted: bool
is_confirmed: bool
is_notification_send: bool

View File

@@ -9,17 +9,35 @@ from init_services import create_modules_and_services_and_actions
from init_address import create_one_address from init_address import create_one_address
from init_occ_defaults import create_occupant_defaults from init_occ_defaults import create_occupant_defaults
set_alembic = bool(os.getenv("set_alembic", 0)) set_alembic = bool(int(os.getenv("SET_ALEMBIC"), 0))
if __name__ == "__main__": if __name__ == "__main__":
print(f"Set alembic: {set_alembic}")
with get_db() as db_session: with get_db() as db_session:
if set_alembic: if set_alembic:
generate_alembic(session=db_session) generate_alembic(session=db_session)
try:
create_one_address(db_session=db_session) create_one_address(db_session=db_session)
except Exception as e:
print(f"Error creating address: {e}")
try:
init_api_enums_build_types(db_session=db_session) init_api_enums_build_types(db_session=db_session)
except Exception as e:
print(f"Error creating enums: {e}")
try:
create_application_defaults(db_session=db_session) create_application_defaults(db_session=db_session)
except Exception as e:
print(f"Error creating application defaults: {e}")
try:
create_occupant_types_defaults(db_session=db_session) create_occupant_types_defaults(db_session=db_session)
except Exception as e:
print(f"Error creating occupant types defaults: {e}")
try:
create_modules_and_services_and_actions(db_session=db_session) create_modules_and_services_and_actions(db_session=db_session)
except Exception as e:
print(f"Error creating modules and services and actions: {e}")
try:
create_occupant_defaults(db_session=db_session) create_occupant_defaults(db_session=db_session)
except Exception as e:
print(f"Error creating occupant defaults: {e}")

View File

@@ -444,6 +444,10 @@ def create_application_defaults(db_session):
f"{str(company_management.uu_id)}*Domain", f"{str(company_management.uu_id)}*Domain",
) )
with mongo_handler.collection(collection_name) as mongo_engine: with mongo_handler.collection(collection_name) as mongo_engine:
existing_record = mongo_engine.find_one(
{"user_uu_id": str(gen_manager_user.uu_id)}
)
if not existing_record:
mongo_engine.insert_one( mongo_engine.insert_one(
document={ document={
"user_uu_id": str(gen_manager_user.uu_id), "user_uu_id": str(gen_manager_user.uu_id),
@@ -452,6 +456,17 @@ def create_application_defaults(db_session):
"modified_at": arrow.now().timestamp(), "modified_at": arrow.now().timestamp(),
} }
) )
else:
mongo_engine.update_one(
{"user_uu_id": str(gen_manager_user.uu_id)},
{
"$set": {
"other_domains_list": [main_domain],
"main_domain": main_domain,
"modified_at": arrow.now().timestamp(),
}
},
)
app_manager_user = Users.find_or_create( app_manager_user = Users.find_or_create(
person_id=app_manager.id, person_id=app_manager.id,
@@ -472,6 +487,10 @@ def create_application_defaults(db_session):
app_manager_user.password_token = PasswordModule.generate_refresher_token() app_manager_user.password_token = PasswordModule.generate_refresher_token()
with mongo_handler.collection(collection_name) as mongo_engine: with mongo_handler.collection(collection_name) as mongo_engine:
existing_record = mongo_engine.find_one(
{"user_uu_id": str(app_manager_user.uu_id)}
)
if not existing_record:
mongo_engine.insert_one( mongo_engine.insert_one(
document={ document={
"user_uu_id": str(app_manager_user.uu_id), "user_uu_id": str(app_manager_user.uu_id),
@@ -480,6 +499,17 @@ def create_application_defaults(db_session):
"modified_at": arrow.now().timestamp(), "modified_at": arrow.now().timestamp(),
} }
) )
else:
mongo_engine.update_one(
{"user_uu_id": str(app_manager_user.uu_id)},
{
"$set": {
"other_domains_list": [main_domain],
"main_domain": main_domain,
"modified_at": arrow.now().timestamp(),
}
},
)
sup_manager_employee = Users.find_or_create( sup_manager_employee = Users.find_or_create(
person_id=sup_manager.id, person_id=sup_manager.id,
@@ -502,14 +532,32 @@ def create_application_defaults(db_session):
sup_manager_employee.password_expiry_begins = str(arrow.now()) sup_manager_employee.password_expiry_begins = str(arrow.now())
sup_manager_employee.password_token = PasswordModule.generate_refresher_token() sup_manager_employee.password_token = PasswordModule.generate_refresher_token()
with mongo_handler.collection(collection_name) as mongo_engine: with mongo_handler.collection(collection_name) as mongo_engine:
existing_record = mongo_engine.find_one(
{"user_uu_id": str(sup_manager_employee.uu_id)}
)
if not existing_record:
print("insert sup existing record", existing_record)
mongo_engine.insert_one( mongo_engine.insert_one(
document={ document={
"user_uu_id": str(sup_manager_employee.uu_id), "user_uu_id": str(sup_manager_employee.uu_id),
"other_domains_list": [main_domain], "other_domains_list": [main_domain, "management.com.tr"],
"main_domain": main_domain, "main_domain": main_domain,
"modified_at": arrow.now().timestamp(), "modified_at": arrow.now().timestamp(),
} }
) )
else:
print("update sup existing record", existing_record)
# Optionally update the existing record if needed
mongo_engine.update_one(
{"user_uu_id": str(sup_manager_employee.uu_id)},
{
"$set": {
"other_domains_list": [main_domain, "management.com.tr"],
"main_domain": main_domain,
"modified_at": arrow.now().timestamp(),
}
},
)
db_session.commit() db_session.commit()
print("All Defaults Create is now completed") print("All Defaults Create is now completed")

View File

@@ -239,6 +239,10 @@ def create_occupant_defaults(db_session):
user_tenant.password_token = PasswordModule.generate_refresher_token() user_tenant.password_token = PasswordModule.generate_refresher_token()
with mongo_handler.collection(collection_name) as mongo_engine: with mongo_handler.collection(collection_name) as mongo_engine:
existing_record = mongo_engine.find_one(
{"user_uu_id": str(user_build_manager.uu_id)}
)
if not existing_record:
mongo_engine.insert_one( mongo_engine.insert_one(
document={ document={
"user_uu_id": str(user_build_manager.uu_id), "user_uu_id": str(user_build_manager.uu_id),
@@ -247,8 +251,21 @@ def create_occupant_defaults(db_session):
"modified_at": arrow.now().timestamp(), "modified_at": arrow.now().timestamp(),
} }
) )
else:
mongo_engine.update_one(
{"user_uu_id": str(user_build_manager.uu_id)},
{
"$set": {
"other_domains_list": [main_domain],
"main_domain": main_domain,
"modified_at": arrow.now().timestamp(),
}
},
)
with mongo_handler.collection(collection_name) as mongo_engine: with mongo_handler.collection(collection_name) as mongo_engine:
existing_record = mongo_engine.find_one({"user_uu_id": str(user_owner.uu_id)})
if not existing_record:
mongo_engine.insert_one( mongo_engine.insert_one(
document={ document={
"user_uu_id": str(user_owner.uu_id), "user_uu_id": str(user_owner.uu_id),
@@ -257,8 +274,21 @@ def create_occupant_defaults(db_session):
"modified_at": arrow.now().timestamp(), "modified_at": arrow.now().timestamp(),
} }
) )
else:
mongo_engine.update_one(
{"user_uu_id": str(user_owner.uu_id)},
{
"$set": {
"other_domains_list": [main_domain],
"main_domain": main_domain,
"modified_at": arrow.now().timestamp(),
}
},
)
with mongo_handler.collection(collection_name) as mongo_engine: with mongo_handler.collection(collection_name) as mongo_engine:
existing_record = mongo_engine.find_one({"user_uu_id": str(user_tenant.uu_id)})
if not existing_record:
mongo_engine.insert_one( mongo_engine.insert_one(
document={ document={
"user_uu_id": str(user_tenant.uu_id), "user_uu_id": str(user_tenant.uu_id),
@@ -267,6 +297,17 @@ def create_occupant_defaults(db_session):
"modified_at": arrow.now().timestamp(), "modified_at": arrow.now().timestamp(),
} }
) )
else:
mongo_engine.update_one(
{"user_uu_id": str(user_tenant.uu_id)},
{
"$set": {
"other_domains_list": [main_domain],
"main_domain": main_domain,
"modified_at": arrow.now().timestamp(),
}
},
)
created_build_living_space_prs = BuildLivingSpace.find_or_create( created_build_living_space_prs = BuildLivingSpace.find_or_create(
build_id=created_build.id, build_id=created_build.id,

View File

@@ -0,0 +1,29 @@
FROM python:3.12-slim
WORKDIR /
# Install system dependencies and Poetry
RUN apt-get update && apt-get install -y --no-install-recommends gcc && rm -rf /var/lib/apt/lists/* && pip install --no-cache-dir poetry
# Copy Poetry configuration
COPY /pyproject.toml ./pyproject.toml
# Configure Poetry and install dependencies with optimizations
RUN poetry config virtualenvs.create false && poetry install --no-interaction --no-ansi --no-root --only main \
&& pip cache purge && rm -rf ~/.cache/pypoetry
# Copy application code
COPY /ApiControllers /ApiControllers
COPY /ApiDefaults /ApiDefaults
COPY /Controllers /Controllers
COPY /Schemas /Schemas
COPY /ApiServices/ManagementService/Endpoints /ApiDefaults/Endpoints
COPY /ApiServices/ManagementService/Events /ApiDefaults/Events
COPY /ApiServices/ManagementService/Validations /ApiDefaults/Validations
# Set Python path to include app directory
ENV PYTHONPATH=/ PYTHONUNBUFFERED=1 PYTHONDONTWRITEBYTECODE=1
# Run the application using the configured uvicorn server
CMD ["poetry", "run", "python", "ApiDefaults/app.py"]

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1,197 @@
from fastapi import APIRouter, Depends
from typing import Any
from ApiControllers.abstracts.default_validations import CommonHeaders
from ApiControllers.providers.token_provider import TokenProvider
from Controllers.Postgres.pagination import PaginateOnly, Pagination, PaginationResult
from Controllers.Postgres.response import EndpointResponse, CreateEndpointResponse
from Schemas import Applications
from Validations.application.validations import RequestApplication
from Events.application.cluster import ApplicationRouterCluster
from Validations.application.validations import AddRemoveService
# Create API router
application_route = APIRouter(prefix="/application", tags=["Application Management"])
@application_route.post(
path="/list/all",
description="List all applications endpoint",
operation_id="fe30481d-802c-4490-897f-a4e95310e6bc",
)
def application_list_all_route(
data: PaginateOnly,
headers: CommonHeaders = Depends(CommonHeaders.as_dependency),
):
"""
List all applications with pagination and filtering options
"""
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
FoundCluster = ApplicationRouterCluster.get_event_cluster("ApplicationListAll")
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
return event_cluster_matched.event_callable(list_options=data)
@application_route.post(
path="/list/available",
description="List available applications endpoint",
operation_id="7492bb02-a074-4320-b58c-4bc7d9fba3a6",
)
def application_list_available_route(
data: PaginateOnly,
headers: CommonHeaders = Depends(CommonHeaders.as_dependency),
):
"""
List available applications with pagination and filtering options
"""
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
FoundCluster = ApplicationRouterCluster.get_event_cluster("ApplicationListAvailable")
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
return event_cluster_matched.event_callable(list_options=data)
@application_route.post(
path="/list/appended",
description="List appended applications endpoint",
operation_id="ea7bbd58-da09-407c-a630-c324e0272385",
)
def application_list_appended_route(
data: PaginateOnly,
headers: CommonHeaders = Depends(CommonHeaders.as_dependency),
):
"""
List appended applications with pagination and filtering options
"""
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
FoundCluster = ApplicationRouterCluster.get_event_cluster("ApplicationListAppended")
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
return event_cluster_matched.event_callable(list_options=data)
@application_route.post(
path="/register/service",
description="Register event to service endpoint",
operation_id="92e0870f-f8bb-4879-ba03-c2901cc70ecc",
)
def application_register_service_route(
data: AddRemoveService,
headers: CommonHeaders = Depends(CommonHeaders.as_dependency),
):
"""
Register event to service
"""
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
FoundCluster = ApplicationRouterCluster.get_event_cluster("ApplicationRegisterService")
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
return event_cluster_matched.event_callable(data=data)
@application_route.post(
path="/unregister/service",
description="Unregister event from service endpoint",
operation_id="7fa1a183-4c99-4746-b675-148f65ad7ba7",
)
def application_unregister_service_route(
data: AddRemoveService,
headers: CommonHeaders = Depends(CommonHeaders.as_dependency),
):
"""
Unregister event from service
"""
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
FoundCluster = ApplicationRouterCluster.get_event_cluster("ApplicationUnRegisterService")
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
return event_cluster_matched.event_callable(data=data)
@application_route.post(
path="/create",
description="Create application endpoint",
operation_id="5570be78-030a-438e-8674-7e751447608b",
)
def application_create_route(
data: RequestApplication,
headers: CommonHeaders = Depends(CommonHeaders.as_dependency),
):
"""
Create a new application
"""
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
FoundCluster = ApplicationRouterCluster.get_event_cluster("ApplicationCreate")
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
return event_cluster_matched.event_callable(data=data)
@application_route.post(
path="/update/{application_uuid}",
description="Update application endpoint",
operation_id="87cd4515-73dd-4d11-a01f-562e221d973c",
)
def application_update_route(
data: RequestApplication,
application_uuid: str,
headers: CommonHeaders = Depends(CommonHeaders.as_dependency),
):
"""
Update an existing application
"""
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
FoundCluster = ApplicationRouterCluster.get_event_cluster("ApplicationUpdate")
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
return event_cluster_matched.event_callable(data=data, uu_id=application_uuid)
@application_route.post(
path="/bind/employee",
description="Bind application to employee endpoint",
operation_id="2bab94fa-becb-4d8e-80f1-f4631119a521",
)
def application_bind_employee_route(
data: Any,
headers: CommonHeaders,
):
"""
Bind application to employee endpoint
"""
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
FoundCluster = ApplicationRouterCluster.get_event_cluster("ApplicationBindEmployee")
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
return event_cluster_matched.event_callable(data=data)
@application_route.post(
path="/bind/occupant",
description="Bind application to occupant endpoint",
operation_id="fccf1a59-0650-4e5c-ba8d-f389dadce01c",
)
def application_bind_occupant_route(
data: Any,
headers: CommonHeaders,
):
"""
Bind application to occupant endpoint
"""
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
FoundCluster = ApplicationRouterCluster.get_event_cluster("ApplicationBindOccupant")
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
return event_cluster_matched.event_callable(data=data)

View File

@@ -0,0 +1,142 @@
from typing import Any
from fastapi import APIRouter, Depends
from ApiControllers.abstracts.default_validations import CommonHeaders
from ApiControllers.providers.token_provider import TokenProvider
from Controllers.Postgres.pagination import PaginateOnly, Pagination, PaginationResult
from Controllers.Postgres.response import EndpointResponse
from Validations.service_endpoints.validations import (
Event2Employee,
Event2Occupant,
AddRemoveService,
)
from Events.event_endpoints.cluster import EventsEndpointRouterCluster
# Create API router
event_endpoint_route = APIRouter(prefix="/events", tags=["Event Actions"])
@event_endpoint_route.post(
path="/list/available",
description="List available events endpoint",
operation_id="0659d5e4-671f-466c-a84f-47a1290a6f0d",
)
def event_list_available_route(
data: PaginateOnly,
headers: CommonHeaders = Depends(CommonHeaders.as_dependency),
):
"""
List available events with pagination and filtering options
"""
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
FoundCluster = EventsEndpointRouterCluster.get_event_cluster("EventsListAvailable")
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
return event_cluster_matched.event_callable(list_options=data)
@event_endpoint_route.post(
path="/list/appended",
description="List appended events endpoint",
operation_id="4d563973-cdcd-44e1-94e0-4262ffb456a1",
)
def event_list_appended_route(
data: PaginateOnly,
headers: CommonHeaders = Depends(CommonHeaders.as_dependency),
):
"""
List events with pagination and filtering options
"""
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
FoundCluster = EventsEndpointRouterCluster.get_event_cluster("EventsListAppended")
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
return event_cluster_matched.event_callable(list_options=data)
@event_endpoint_route.post(
path="/register/service",
description="Register event to service endpoint",
operation_id="c89a2150-db4d-4a8f-b6ec-9e0f09625f76",
)
def event_register_service_route(
data: AddRemoveService,
headers: CommonHeaders = Depends(CommonHeaders.as_dependency),
):
"""
Register event to service
"""
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
FoundCluster = EventsEndpointRouterCluster.get_event_cluster("EventRegisterService")
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
return event_cluster_matched.event_callable(data=data)
@event_endpoint_route.post(
path="/unregister/service",
description="Unregister event from service endpoint",
operation_id="2f16dc9e-de02-449d-9c3f-1a21f87e8794",
)
def event_unregister_service_route(
data: AddRemoveService,
headers: CommonHeaders = Depends(CommonHeaders.as_dependency),
):
"""
Unregister event from service
"""
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
FoundCluster = EventsEndpointRouterCluster.get_event_cluster(
"EventUnregisterService"
)
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
return event_cluster_matched.event_callable(data=data)
@event_endpoint_route.post(
path="/bind/extra/employee",
description="Bind event to employee extra endpoint",
operation_id="58ef3640-04ec-43f9-8f3e-f86be3ce4a24",
)
def event_bind_employee_extra_route(
data: Any,
headers: CommonHeaders = Depends(CommonHeaders.as_dependency),
):
"""
Bind event to employee extra
"""
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
FoundCluster = EventsEndpointRouterCluster.get_event_cluster(
"EventBindEmployeeExtra"
)
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
return event_cluster_matched.event_callable(data=data)
@event_endpoint_route.post(
path="/bind/extra/occupant",
description="Bind event to occupant extra endpoint",
operation_id="7794a550-3073-43e3-b0c5-80128f8d3e4b",
)
def event_bind_occupant_extra_route(
data: Any,
headers: CommonHeaders = Depends(CommonHeaders.as_dependency),
):
"""
Bind event to occupant extra
"""
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
FoundCluster = EventsEndpointRouterCluster.get_event_cluster(
"EventBindOccupantExtra"
)
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
return event_cluster_matched.event_callable(data=data)

View File

@@ -0,0 +1,25 @@
from fastapi import APIRouter
def get_routes() -> list[APIRouter]:
from .application.route import application_route
from .service_endpoints.route import service_endpoint_route
from .service_managements.route import service_management_route
from .event_endpoints.route import event_endpoint_route
return [
application_route,
service_endpoint_route,
service_management_route,
event_endpoint_route,
]
def get_safe_endpoint_urls() -> list[tuple[str, str]]:
return [
("/", "GET"),
("/docs", "GET"),
("/redoc", "GET"),
("/openapi.json", "GET"),
("/metrics", "GET"),
]

View File

@@ -0,0 +1,52 @@
from fastapi import APIRouter, Depends
from ApiControllers.abstracts.default_validations import CommonHeaders
from ApiControllers.providers.token_provider import TokenProvider
from Controllers.Postgres.pagination import PaginateOnly, Pagination, PaginationResult
from Controllers.Postgres.response import EndpointResponse
from Events.service_endpoints.cluster import ServiceEndpointRouterCluster
# Create API router
service_endpoint_route = APIRouter(prefix="/service", tags=["Service Actions"])
@service_endpoint_route.post(
path="/list",
description="List services endpoint",
operation_id="f4e4d332-70b1-4121-9fcc-a08850b72aaa",
)
def service_list_route(
data: PaginateOnly,
headers: CommonHeaders = Depends(CommonHeaders.as_dependency),
):
"""
List services with pagination and filtering options
"""
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
FoundCluster = ServiceEndpointRouterCluster.get_event_cluster("ServiceList")
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
return event_cluster_matched.event_callable(data=data)
@service_endpoint_route.post(
path="/to/events",
description="List events of a service endpoint given service UUID",
operation_id="7b6b0c6a-e3db-4353-a7df-ea49d2a67f8a",
)
def service_to_events_route(
data: PaginateOnly,
headers: CommonHeaders = Depends(CommonHeaders.as_dependency),
):
"""
List events of a service given service UUID
"""
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
FoundCluster = ServiceEndpointRouterCluster.get_event_cluster("ServiceToEvents")
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
return event_cluster_matched.event_callable(data=data)

View File

@@ -0,0 +1,26 @@
from fastapi import APIRouter, Depends
from ApiControllers.abstracts.default_validations import CommonHeaders
from ApiControllers.providers.token_provider import TokenProvider
from Controllers.Postgres.pagination import PaginateOnly, Pagination, PaginationResult
from Controllers.Postgres.response import EndpointResponse
from Schemas import (
Services,
Employees,
Event2Employee,
Users,
Events,
Service2Events,
Applications,
Application2Employee,
Application2Occupant,
)
from Validations.application.validations import (
RequestApplication,
)
# Create API router
service_management_route = APIRouter(
prefix="/managements/service", tags=["Service Management"]
)

View File

@@ -0,0 +1,9 @@
from .service_endpoints.cluster import ServiceEndpointRouterCluster
from .event_endpoints.cluster import EventsEndpointRouterCluster
from .application.cluster import ApplicationRouterCluster
__all__ = [
"ServiceEndpointRouterCluster",
"EventsEndpointRouterCluster",
"ApplicationRouterCluster",
]

View File

@@ -0,0 +1,55 @@
from ApiControllers.abstracts.event_clusters import EventCluster, RouterCluster
from .supers_events import (
ApplicationListAllEvent,
ApplicationListAvailableEvent,
ApplicationListAppendedEvent,
ApplicationRegisterServiceEvent,
ApplicationUnRegisterServiceEvent,
ApplicationCreateEvent,
ApplicationUpdateEvent,
)
ApplicationRouterCluster = RouterCluster(name="ApplicationRouterCluster")
ApplicationEventClusterListAll = EventCluster(
name="ApplicationListAll", endpoint_uu_id="fe30481d-802c-4490-897f-a4e95310e6bc"
)
ApplicationEventClusterListAll.add_event(ApplicationListAllEvent)
ApplicationEventClusterListAvailable = EventCluster(
name="ApplicationListAvailable", endpoint_uu_id="7492bb02-a074-4320-b58c-4bc7d9fba3a6"
)
ApplicationEventClusterListAvailable.add_event(ApplicationListAvailableEvent)
ApplicationEventClusterListAppended = EventCluster(
name="ApplicationListAppended", endpoint_uu_id="ea7bbd58-da09-407c-a630-c324e0272385"
)
ApplicationEventClusterListAppended.add_event(ApplicationListAppendedEvent)
ApplicationEventClusterRegisterService = EventCluster(
name="ApplicationRegisterService", endpoint_uu_id="92e0870f-f8bb-4879-ba03-c2901cc70ecc"
)
ApplicationEventClusterRegisterService.add_event(ApplicationRegisterServiceEvent)
ApplicationEventClusterUnregisterService = EventCluster(
name="ApplicationUnRegisterService", endpoint_uu_id="7fa1a183-4c99-4746-b675-148f65ad7ba7"
)
ApplicationEventClusterUnregisterService.add_event(ApplicationUnRegisterServiceEvent)
ApplicationEventClusterCreate = EventCluster(
name="ApplicationCreate", endpoint_uu_id="5570be78-030a-438e-8674-7e751447608b"
)
ApplicationEventClusterCreate.add_event(ApplicationCreateEvent)
ApplicationEventClusterUpdate = EventCluster(
name="ApplicationUpdate", endpoint_uu_id="87cd4515-73dd-4d11-a01f-562e221d973c"
)
ApplicationEventClusterUpdate.add_event(ApplicationUpdateEvent)
ApplicationRouterCluster.set_event_cluster(ApplicationEventClusterListAvailable)
ApplicationRouterCluster.set_event_cluster(ApplicationEventClusterListAppended)
ApplicationRouterCluster.set_event_cluster(ApplicationEventClusterListAll)
ApplicationRouterCluster.set_event_cluster(ApplicationEventClusterRegisterService)
ApplicationRouterCluster.set_event_cluster(ApplicationEventClusterUnregisterService)
ApplicationRouterCluster.set_event_cluster(ApplicationEventClusterCreate)
ApplicationRouterCluster.set_event_cluster(ApplicationEventClusterUpdate)

View File

@@ -0,0 +1,320 @@
from typing import Any
from ApiControllers.abstracts.event_clusters import Event
from Controllers.Postgres.pagination import Pagination, PaginationResult, PaginateOnly
from Controllers.Postgres.response import EndpointResponse
from Schemas import (
Applications,
Application2Employee,
Application2Occupant,
Service2Application,
Services,
)
# List all endpoint
ApplicationListAllEvent = Event(
name="application_list_all",
key="1971ce4d-4f59-4aa8-83e2-ca19d7da6d11",
request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator
description="Super Users List all applications endpoint",
)
# List available endpoint
ApplicationListAvailableEvent = Event(
name="application_list_available",
key="d8e733f5-b53a-4c36-9082-12579bf9cc4a",
request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator
description="Super Users List available applications endpoint",
)
# List appended endpoint
ApplicationListAppendedEvent = Event(
name="application_list_appended",
key="ea7bbd58-da09-407c-a630-c324e0272385",
request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator
description="Super Users List appended applications endpoint",
)
# Register application to service endpoint
ApplicationRegisterServiceEvent = Event(
name="application_register_service",
key="47d7cfc8-6004-4442-8357-16ceac5d9d18",
request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator
description="Super Users Register application to service endpoint",
)
# Unregister application to service endpoint
ApplicationUnRegisterServiceEvent = Event(
name="application_unregister_service",
key="d228ab26-0b74-440f-8f1f-8f40be5a22f2",
request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator
description="Super Users Unregister application to service endpoint",
)
# Create endpoint
ApplicationCreateEvent = Event(
name="application_create",
key="f53ca9aa-5536-4d77-9129-78d67e61db4a",
request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator
description="Super Users Create applications endpoint",
)
# Update endpoint
ApplicationUpdateEvent = Event(
name="application_update",
key="0e9a855e-4e69-44b5-8ac2-825daa32840c",
request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator
description="Super Users Update applications endpoint",
)
def application_list_all_callable(list_options: PaginateOnly):
list_options = PaginateOnly(**list_options.model_dump())
with Applications.new_session() as db_session:
if list_options.query:
applications_list = Applications.filter_all(*Applications.convert(list_options.query), db=db_session)
else:
applications_list = Applications.filter_all(db=db_session)
pagination = Pagination(data=applications_list)
pagination.change(**list_options.model_dump())
pagination_result = PaginationResult(data=applications_list, pagination=pagination)
return EndpointResponse(message="MSG0003-LIST", pagination_result=pagination_result).response
ApplicationListAllEvent.event_callable = application_list_all_callable
def application_list_available_callable(list_options: PaginateOnly):
"""
Example callable method
"""
list_options = PaginateOnly(**list_options.model_dump())
service_uu_id = list_options.query.get("service_uu_id__ilike", None)
if not service_uu_id:
return {
"message": "MSG0003-PARAM-MISSING",
"data": list_options.query,
"completed": False,
}
list_options.query.pop("service_uu_id__ilike", None)
list_options.query.pop("service_uu_id", None)
with Applications.new_session() as db_session:
service2applications = Service2Application.filter_all(
*Service2Application.convert({"service_uu_id__ilike": service_uu_id}),
db=db_session,
)
already_events = [
service_to_application.application_id for service_to_application in service2applications.data
]
if list_options.query:
applications_list = Applications.filter_all(
*Applications.convert(list_options.query), Applications.id.not_in(already_events), db=db_session
)
else:
applications_list = Applications.filter_all(Applications.id.not_in(already_events), db=db_session)
pagination = Pagination(data=applications_list)
pagination.change(**list_options.model_dump())
pagination_result = PaginationResult(data=applications_list, pagination=pagination)
return EndpointResponse(message="MSG0003-LIST", pagination_result=pagination_result).response
ApplicationListAvailableEvent.event_callable = application_list_available_callable
def application_list_appended_callable(list_options: PaginateOnly):
"""
Example callable method
"""
list_options = PaginateOnly(**list_options.model_dump())
service_uu_id = list_options.query.get("service_uu_id__ilike", None)
if not service_uu_id:
return {
"message": "MSG0003-PARAM-MISSING",
"data": list_options.query,
"completed": False,
}
list_options.query.pop("service_uu_id__ilike", None)
list_options.query.pop("service_uu_id", None)
with Applications.new_session() as db_session:
service2applications = Service2Application.filter_all(
*Service2Application.convert({"service_uu_id__ilike": service_uu_id}),
db=db_session,
)
already_events = [
service_to_application.application_id for service_to_application in service2applications.data
]
if list_options.query:
applications_list = Applications.filter_all(
*Applications.convert(list_options.query), Applications.id.in_(already_events), db=db_session
)
else:
applications_list = Applications.filter_all(Applications.id.in_(already_events), db=db_session)
pagination = Pagination(data=applications_list)
pagination.change(**list_options.model_dump())
pagination_result = PaginationResult(data=applications_list, pagination=pagination)
return EndpointResponse(message="MSG0003-LIST", pagination_result=pagination_result).response
ApplicationListAppendedEvent.event_callable = application_list_appended_callable
def application_create_callable(data: Any):
"""
Create a new application
"""
with Applications.new_session() as db_session:
created_application_dict = data.model_dump()
created_application = Applications.find_or_create(
db=db_session,
include_args=[Applications.application_for, Applications.application_code, Applications.site_url],
**created_application_dict,
)
if created_application.meta_data.created:
created_application.save(db=db_session)
return {
"completed": True,
"message": "MSG0001-INSERT",
"data": created_application,
}
return {
"completed": False,
"message": "MSG0002-ERROR",
"data": created_application,
}
ApplicationCreateEvent.event_callable = application_create_callable
def application_update_callable(data: Any, uu_id: str):
"""
Update an existing application
"""
with Applications.new_session() as db_session:
updated_application_dict = data.model_dump(
exclude_unset=True, exclude_none=True
)
found_application = Applications.filter_one(
Applications.uu_id == uu_id, db=db_session
).data
if not found_application:
return {
"completed": False,
"message": "MSG0002-FOUND",
"data": found_application,
}
updated_application = found_application.update(
db=db_session, **updated_application_dict
)
updated_application.save(db_session)
if updated_application.meta_data.updated:
return {
"completed": True,
"message": "MSG0003-UPDATE",
"data": updated_application,
}
return {
"completed": False,
"message": "MSG0003-UPDATE",
"data": updated_application,
}
ApplicationUpdateEvent.event_callable = application_update_callable
def application_register_service_callable(data: Any):
"""
Register an application to a service
"""
with Applications.new_session() as db_session:
event = Applications.filter_one_system(Applications.uu_id == data.application_uu_id, db=db_session)
if not event.data:
return {
"message": "MSG0003-NOT-FOUND",
"data": data.model_dump(),
"completed": False,
}
service = Services.filter_one_system(Services.uu_id == data.service_uu_id, db=db_session)
if not service.data:
return {
"message": "MSG0003-NOT-FOUND",
"data": data.model_dump(),
"completed": False,
}
service_to_application = Service2Application.find_or_create(
db=db_session,
include_args=[Service2Application.service_uu_id, Service2Application.application_uu_id],
service_id=service.data.id,
service_uu_id=str(service.data.uu_id),
application_id=event.data.id,
application_uu_id=str(event.data.uu_id),
application_code=event.data.application_code,
site_url=event.data.site_url,
is_confirmed=True,
)
if not service_to_application.meta_data.created:
return {
"message": "MSG0003-ALREADY-FOUND",
"data": data.model_dump(),
"completed": False,
}
service_to_application.save(db=db_session)
return {
"message": "MSG0003-REGISTER",
"data": data.model_dump(),
"completed": True,
}
ApplicationRegisterServiceEvent.event_callable = application_register_service_callable
def application_unregister_service_callable(data: Any):
"""
Unregister an application from a service
"""
with Applications.new_session() as db_session:
application = Applications.filter_one_system(Applications.uu_id == data.application_uu_id, db=db_session)
if not application.data:
return {
"message": "MSG0003-NOT-FOUND",
"data": data.model_dump(),
"completed": False,
}
service = Services.filter_one_system(Services.uu_id == data.service_uu_id, db=db_session)
if not service.data:
return {
"message": "MSG0003-NOT-FOUND",
"data": data.model_dump(),
"completed": False,
}
service_to_application = Service2Application.filter_one_system(
Service2Application.service_id == service.data.id,
Service2Application.application_id == application.data.id,
db=db_session,
)
if not service_to_application.data:
return {
"message": "MSG0003-NOT-FOUND",
"data": data.model_dump(),
"completed": False,
}
service_to_application.query.delete()
db_session.commit()
return {
"message": "MSG0003-UNREGISTER",
"data": data.model_dump(),
"completed": True,
}
ApplicationUnRegisterServiceEvent.event_callable = application_unregister_service_callable

View File

@@ -0,0 +1,54 @@
from ApiControllers.abstracts.event_clusters import EventCluster, RouterCluster
from .supers_events import (
EventsListAvailableEvent,
EventsListAppendedEvent,
EventRegisterServiceEvent,
EventUnRegisterServiceEvent,
EventBindEmployeeExtraEvent,
EventBindOccupantExtraEvent,
)
EventsEndpointRouterCluster = RouterCluster(name="EventsEndpointRouterCluster")
EventsEndpointEventClusterListAvailable = EventCluster(
name="EventsListAvailable", endpoint_uu_id="0659d5e4-671f-466c-a84f-47a1290a6f0d"
)
EventsEndpointEventClusterListAvailable.add_event(EventsListAvailableEvent)
EventsEndpointEventClusterListAppended = EventCluster(
name="EventsListAppended", endpoint_uu_id="4d563973-cdcd-44e1-94e0-4262ffb456a1"
)
EventsEndpointEventClusterListAppended.add_event(EventsListAppendedEvent)
EventsEndpointEventClusterRegisterService = EventCluster(
name="EventRegisterService", endpoint_uu_id="c89a2150-db4d-4a8f-b6ec-9e0f09625f76"
)
EventsEndpointEventClusterRegisterService.add_event(EventRegisterServiceEvent)
EventsEndpointEventClusterUnregisterService = EventCluster(
name="EventUnregisterService", endpoint_uu_id="2f16dc9e-de02-449d-9c3f-1a21f87e8794"
)
EventsEndpointEventClusterUnregisterService.add_event(EventUnRegisterServiceEvent)
EventsEndpointEventClusterBindEmployeeExtra = EventCluster(
name="EventBindEmployeeExtra", endpoint_uu_id="58ef3640-04ec-43f9-8f3e-f86be3ce4a24"
)
EventsEndpointEventClusterBindEmployeeExtra.add_event(EventBindEmployeeExtraEvent)
EventsEndpointEventClusterBindOccupantExtra = EventCluster(
name="EventBindOccupantExtra", endpoint_uu_id="7794a550-3073-43e3-b0c5-80128f8d3e4b"
)
EventsEndpointEventClusterBindOccupantExtra.add_event(EventBindOccupantExtraEvent)
EventsEndpointRouterCluster.set_event_cluster(EventsEndpointEventClusterListAvailable)
EventsEndpointRouterCluster.set_event_cluster(EventsEndpointEventClusterListAppended)
EventsEndpointRouterCluster.set_event_cluster(EventsEndpointEventClusterRegisterService)
EventsEndpointRouterCluster.set_event_cluster(
EventsEndpointEventClusterUnregisterService
)
EventsEndpointRouterCluster.set_event_cluster(
EventsEndpointEventClusterBindEmployeeExtra
)
EventsEndpointRouterCluster.set_event_cluster(
EventsEndpointEventClusterBindOccupantExtra
)

View File

@@ -0,0 +1,280 @@
from ApiControllers.abstracts.event_clusters import Event
from Controllers.Postgres.pagination import Pagination, PaginationResult, PaginateOnly
from Controllers.Postgres.response import EndpointResponse
from typing import Any
from Schemas import (
Events,
Event2Employee,
Event2Occupant,
Event2EmployeeExtra,
Event2OccupantExtra,
Service2Events,
Services,
)
# List available events endpoint
EventsListAvailableEvent = Event(
name="event_endpoint_list_available",
key="d39af512-ec71-4c0f-9b35-e53b0d06d3a4",
request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator
description="Super Users List available events endpoint",
)
# List appended events endpoint
EventsListAppendedEvent = Event(
name="event_endpoint_list_appended",
key="bea77d6a-d99f-468b-9002-b3bda6bb6ad0",
request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator
description="Super Users List appended events endpoint",
)
# Event Register endpoint
EventRegisterServiceEvent = Event(
name="event_endpoint_register_service",
key="e18e7f89-5708-4a15-9258-99b0903ed43d",
request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator
description="Super Users Register service endpoint",
)
# Event Unregister endpoint
EventUnRegisterServiceEvent = Event(
name="service_endpoint_unregister_service",
key="4d693774-4857-435b-a63c-c39baebfe916",
request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator
description="Super Users Unregister service endpoint",
)
# Bind employee extra endpoint
EventBindEmployeeExtraEvent = Event(
name="service_endpoint_bind_employee_extra",
key="cd452928-4256-4fb4-b81e-0ca41d723616",
request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator
description="Super Users Bind service to employee extra endpoint",
)
# Bind occupant extra endpoint
EventBindOccupantExtraEvent = Event(
name="service_endpoint_bind_occupant_extra",
key="cb11a150-8049-45c9-8cf3-d5290ffd2e4a",
request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator
description="Super Users Bind service to occupant extra endpoint",
)
def events_list_available_callable(list_options: PaginateOnly):
"""
List available events with pagination and filtering options
"""
list_options = PaginateOnly(**list_options.model_dump())
service_uu_id = list_options.query.get("service_uu_id__ilike", None)
if not service_uu_id:
return {
"message": "MSG0003-PARAM-MISSING",
"data": list_options.query,
"completed": False,
}
list_options.query.pop("service_uu_id__ilike", None)
list_options.query.pop("service_uu_id", None)
with Events.new_session() as db_session:
service2events = Service2Events.filter_all(
*Service2Events.convert({"service_uu_id__ilike": service_uu_id}),
db=db_session,
)
already_events = [
service_to_event.event_id for service_to_event in service2events.data
]
if list_options.query:
events_list = Events.filter_all(
*Events.convert(list_options.query),
Events.id.not_in(already_events),
db=db_session,
)
else:
events_list = Events.filter_all(
Events.id.not_in(already_events), db=db_session
)
pagination = Pagination(data=events_list)
pagination.change(**list_options.model_dump())
pagination_result = PaginationResult(data=events_list, pagination=pagination)
return EndpointResponse(
message="MSG0003-LIST",
pagination_result=pagination_result,
).response
EventsListAvailableEvent.event_callable = events_list_available_callable
def events_list_appended_callable(list_options: PaginateOnly):
"""
List appended events with pagination and filtering options
"""
list_options = PaginateOnly(**list_options.model_dump())
service_uu_id = list_options.query.get("service_uu_id__ilike", None)
if not service_uu_id:
return {
"message": "MSG0003-PARAM-MISSING",
"data": list_options.query,
"completed": False,
}
list_options.query.pop("service_uu_id__ilike", None)
list_options.query.pop("service_uu_id", None)
with Events.new_session() as db_session:
service2events = Service2Events.filter_all(
*Service2Events.convert({"service_uu_id__ilike": service_uu_id}),
db=db_session,
)
already_events = [
service_to_event.event_id for service_to_event in service2events.data
]
if list_options.query:
events_list = Events.filter_all(
*Events.convert(list_options.query),
Events.id.in_(already_events),
db=db_session,
)
else:
events_list = Events.filter_all(
Events.id.in_(already_events), db=db_session
)
pagination = Pagination(data=events_list)
pagination.change(**list_options.model_dump())
pagination_result = PaginationResult(data=events_list, pagination=pagination)
return EndpointResponse(
message="MSG0003-LIST",
pagination_result=pagination_result,
).response
EventsListAppendedEvent.event_callable = events_list_appended_callable
def event_register_service_callable(data: Any):
"""
Register event to service
"""
with Events.new_session() as db_session:
event = Events.filter_one_system(
Events.uu_id == data.event_uu_id, db=db_session
)
if not event.data:
return {
"message": "MSG0003-NOT-FOUND",
"data": data.model_dump(),
"completed": False,
}
service = Services.filter_one_system(
Services.uu_id == data.service_uu_id, db=db_session
)
if not service.data:
return {
"message": "MSG0003-NOT-FOUND",
"data": data.model_dump(),
"completed": False,
}
service_to_event = Service2Events.find_or_create(
db=db_session,
include_args=[
Service2Events.service_uu_id,
Service2Events.event_uu_id,
],
service_id=service.data.id,
event_id=event.data.id,
is_confirmed=True,
service_uu_id=str(service.data.uu_id),
event_uu_id=str(event.data.uu_id),
)
if not service_to_event.meta_data.created:
return {
"message": "MSG0003-ALREADY-FOUND",
"data": data.model_dump(),
"completed": False,
}
service_to_event.save(db=db_session)
return {
"message": "MSG0003-REGISTER",
"data": data.model_dump(),
"completed": True,
}
EventRegisterServiceEvent.event_callable = event_register_service_callable
def event_unregister_service_callable(data: Any):
"""
Unregister event from service
"""
with Events.new_session() as db_session:
event = Events.filter_one_system(
Events.uu_id == data.event_uu_id, db=db_session
)
if not event.data:
return {
"message": "MSG0003-NOT-FOUND",
"data": data.model_dump(),
"completed": False,
}
service = Services.filter_one_system(
Services.uu_id == data.service_uu_id, db=db_session
)
if not service.data:
return {
"message": "MSG0003-NOT-FOUND",
"data": data.model_dump(),
"completed": False,
}
service_to_event = Service2Events.filter_one_system(
Service2Events.service_id == service.data.id,
Service2Events.event_id == event.data.id,
db=db_session,
)
if not service_to_event.data:
return {
"message": "MSG0003-NOT-FOUND",
"data": data.model_dump(),
"completed": False,
}
service_to_event.query.delete()
db_session.commit()
return {
"message": "MSG0003-UNREGISTER",
"data": data.model_dump(),
"completed": True,
}
EventUnRegisterServiceEvent.event_callable = event_unregister_service_callable
def event_bind_employee_extra_callable(data: Any):
"""
Bind event to employee extra
"""
return {
"message": "MSG0003-BIND",
"data": data.model_dump(),
"completed": True,
}
EventBindEmployeeExtraEvent.event_callable = event_bind_employee_extra_callable
def event_bind_occupant_extra_callable(data: Any):
"""
Bind event to occupant extra
"""
return EndpointResponse(
message="MSG0003-BIND",
).response
EventBindOccupantExtraEvent.event_callable = event_bind_occupant_extra_callable

View File

@@ -0,0 +1,19 @@
from ApiControllers.abstracts.event_clusters import EventCluster, RouterCluster
from .supers_events import (
ServiceEndpointListEvent,
ServiceEndpointToEventsEvent,
)
ServiceEndpointRouterCluster = RouterCluster(name="ServiceEndpointRouterCluster")
ServiceEndpointEventClusterList = EventCluster(
name="ServiceList", endpoint_uu_id="f4e4d332-70b1-4121-9fcc-a08850b72aaa"
)
ServiceEndpointEventClusterList.add_event(ServiceEndpointListEvent)
ServiceEndpointEventClusterToService = EventCluster(
name="ServiceToEvents", endpoint_uu_id="7b6b0c6a-e3db-4353-a7df-ea49d2a67f8a"
)
ServiceEndpointEventClusterToService.add_event(ServiceEndpointToEventsEvent)
ServiceEndpointRouterCluster.set_event_cluster(ServiceEndpointEventClusterList)
ServiceEndpointRouterCluster.set_event_cluster(ServiceEndpointEventClusterToService)

View File

@@ -0,0 +1,69 @@
from ApiControllers.abstracts.event_clusters import Event
from Controllers.Postgres.pagination import Pagination, PaginationResult, PaginateOnly
from Controllers.Postgres.response import EndpointResponse
from Schemas import Services, Service2Events
# List endpoint
ServiceEndpointListEvent = Event(
name="service_endpoint_list",
key="7da6ceac-925a-4faa-9cc5-3f34396b5684",
request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator
description="Super Users List services endpoint",
)
def service_endpoint_list_callable(data: PaginateOnly):
"""
List services endpoint callable method
"""
list_options = PaginateOnly(**data.model_dump())
with Services.new_session() as db_session:
if data.query:
services_list = Services.filter_all_system(
*Services.convert(data.query), db=db_session
)
else:
services_list = Services.filter_all_system(db=db_session)
pagination = Pagination(data=services_list)
pagination.change(**data.model_dump())
pagination_result = PaginationResult(data=services_list, pagination=pagination)
return EndpointResponse(
message="MSG0003-LIST", pagination_result=pagination_result
).response
ServiceEndpointListEvent.event_callable = service_endpoint_list_callable
# To events endpoint
ServiceEndpointToEventsEvent = Event(
name="service_endpoint_to_events",
key="7b6b0c6a-e3db-4353-a7df-ea49d2a67f8a",
request_validator=None, # TODO: Add request validator
response_validator=None, # TODO: Add response validator
description="Super Users List events of a service endpoint given service UUID",
)
def service_endpoint_to_events_callable(data: PaginateOnly):
"""
List events of a service given service UUID
"""
list_options = PaginateOnly(**data.model_dump())
with Service2Events.new_session() as db_session:
if data.query:
services_list = Service2Events.filter_all_system(
*Service2Events.convert(data.query), db=db_session
)
else:
services_list = Service2Events.filter_all_system(db=db_session)
pagination = Pagination(data=services_list)
pagination.change(**data.model_dump())
pagination_result = PaginationResult(data=services_list, pagination=pagination)
return EndpointResponse(
message="MSG0003-LIST", pagination_result=pagination_result
).response
ServiceEndpointToEventsEvent.event_callable = service_endpoint_to_events_callable

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1,22 @@
from pydantic import BaseModel, Field
from typing import Optional
class RequestApplication(BaseModel):
"""Base model for application data"""
name: str = Field(..., description="Application name")
application_code: str = Field(..., description="Unique application code")
site_url: str = Field(..., description="Application site URL")
application_type: str = Field(
..., description="Application type (info, Dash, Admin)"
)
application_for: str = Field(..., description="Application for (EMP, OCC)")
description: Optional[str] = Field(None, description="Application description")
class AddRemoveService(BaseModel):
"""Base model for add/remove service data"""
application_uu_id: str = Field(..., description="Application UUID")
service_uu_id: str = Field(..., description="Service UUID")

View File

@@ -0,0 +1,14 @@
from pydantic import BaseModel
class Event2Employee(BaseModel):
pass
class Event2Occupant(BaseModel):
pass
class AddRemoveService(BaseModel):
event_uu_id: str
service_uu_id: str

View File

@@ -0,0 +1,13 @@
from fastapi import APIRouter
# Import all routes
from ApiServices.ManagementService.Endpoints.application.route import application_route
# Create main router for ManagementService
management_service_router = APIRouter(prefix="/management", tags=["Management Service"])
# Include all routes
management_service_router.include_router(application_route)
# Export the router
__all__ = ["management_service_router"]

View File

@@ -1,5 +0,0 @@
from .template.event import template_event_cluster
__all__ = [
"template_event_cluster",
]

View File

@@ -1,88 +0,0 @@
class EventCluster:
def __init__(self, endpoint_uu_id: str):
self.endpoint_uu_id = endpoint_uu_id
self.events = []
def add_event(self, list_of_events: list["Event"]):
"""
Add an event to the cluster
"""
for event in list_of_events:
self.events.append(event)
self.events = list(set(self.events))
def get_event(self, event_key: str):
"""
Get an event by its key
"""
for event in self.events:
if event.key == event_key:
return event
return None
def set_events_to_database(self):
from Schemas import Events, EndpointRestriction
with Events.new_session() as db_session:
if to_save_endpoint := EndpointRestriction.filter_one(
EndpointRestriction.operation_uu_id == self.endpoint_uu_id,
db=db_session,
).data:
for event in self.events:
event_to_save_database = Events.find_or_create(
function_code=event.key,
function_class=event.name,
description=event.description,
endpoint_code=self.endpoint_uu_id,
endpoint_id=to_save_endpoint.id,
endpoint_uu_id=str(to_save_endpoint.uu_id),
is_confirmed=True,
active=True,
db=db_session,
)
if event_to_save_database.meta_data.created:
event_to_save_database.save(db=db_session)
print(
f"UUID: {event_to_save_database.uu_id} event is saved to {to_save_endpoint.uu_id}"
)
def match_event(self, event_keys: list[str]) -> "Event":
"""
Match an event by its key
"""
# print('set(event_keys)', set(event_keys))
# print('event.keys', set([event.key for event in self.events]))
intersection_of_key: set[str] = set(event_keys) & set(
[event.key for event in self.events]
)
if not len(intersection_of_key) == 1:
raise ValueError(
f"Event key not found or multiple matches found: {intersection_of_key}"
)
return self.get_event(event_key=list(intersection_of_key)[0])
class Event:
def __init__(
self,
name: str,
key: str,
request_validator: str = None,
response_validator: str = None,
description: str = "",
):
self.name = name
self.key = key
self.request_validator = request_validator
self.response_validator = response_validator
self.description = description
def event_callable(self):
"""
Example callable method
"""
print(self.name)
return {}

View File

@@ -43,28 +43,28 @@ class EmailProcessingContext:
if exc_type is not None or not self.success: if exc_type is not None or not self.success:
# If an exception occurred or processing wasn't successful, mark as unread # If an exception occurred or processing wasn't successful, mark as unread
try: try:
if hasattr(self.email_message, 'mark_as_unread'): if hasattr(self.email_message, "mark_as_unread"):
self.email_message.mark_as_unread() self.email_message.mark_as_unread()
print(f"[EMAIL_SERVICE] Marked email as UNREAD due to processing error: {exc_val if exc_val else 'Unknown error'}") print(
f"[EMAIL_SERVICE] Marked email as UNREAD due to processing error: {exc_val if exc_val else 'Unknown error'}"
)
except Exception as e: except Exception as e:
print(f"[EMAIL_SERVICE] Failed to mark email as unread: {str(e)}") print(f"[EMAIL_SERVICE] Failed to mark email as unread: {str(e)}")
elif self.mark_as_read: elif self.mark_as_read:
# If processing was successful and mark_as_read is True, ensure it's marked as read # If processing was successful and mark_as_read is True, ensure it's marked as read
try: try:
if hasattr(self.email_message, 'mark_as_read'): if hasattr(self.email_message, "mark_as_read"):
self.email_message.mark_as_read() self.email_message.mark_as_read()
except Exception as e: except Exception as e:
print(f"[EMAIL_SERVICE] Failed to mark email as read: {str(e)}") print(f"[EMAIL_SERVICE] Failed to mark email as read: {str(e)}")
return False # Don't suppress exceptions return False # Don't suppress exceptions
def publish_payload_to_redis( def publish_payload_to_redis(payload, filename: str, mail_info: dict) -> bool:
payload, filename: str, mail_info: dict
) -> bool:
# Create message document # Create message document
# Use base64 encoding for binary payloads to ensure proper transmission # Use base64 encoding for binary payloads to ensure proper transmission
if isinstance(payload, bytes): if isinstance(payload, bytes):
encoded_payload = base64.b64encode(payload).decode('utf-8') encoded_payload = base64.b64encode(payload).decode("utf-8")
is_base64 = True is_base64 = True
else: else:
encoded_payload = payload encoded_payload = payload
@@ -84,7 +84,9 @@ def publish_payload_to_redis(
result = redis_pubsub.publisher.publish(REDIS_CHANNEL, message) result = redis_pubsub.publisher.publish(REDIS_CHANNEL, message)
if result.status: if result.status:
print(f"[EMAIL_SERVICE] Published message with filename: {filename} to channel: {REDIS_CHANNEL}") print(
f"[EMAIL_SERVICE] Published message with filename: {filename} to channel: {REDIS_CHANNEL}"
)
return True return True
else: else:
print(f"[EMAIL_SERVICE] Publish error: {result.error}") print(f"[EMAIL_SERVICE] Publish error: {result.error}")
@@ -144,32 +146,42 @@ def app():
try: try:
if os.path.exists(last_run_file): if os.path.exists(last_run_file):
with open(last_run_file, 'r') as f: with open(last_run_file, "r") as f:
last_run_data = json.load(f) last_run_data = json.load(f)
last_run_date = last_run_data.get('last_run_date') last_run_date = last_run_data.get("last_run_date")
# If this is the first run of a new day, check 90 days # If this is the first run of a new day, check 90 days
if last_run_date != current_date: if last_run_date != current_date:
days_to_check = full_check days_to_check = full_check
print(f"[EMAIL_SERVICE] First run of the day. Checking emails from the past {days_to_check} days") print(
f"[EMAIL_SERVICE] First run of the day. Checking emails from the past {days_to_check} days"
)
else: else:
print(f"[EMAIL_SERVICE] Subsequent run today. Checking emails from the past {days_to_check} days") print(
f"[EMAIL_SERVICE] Subsequent run today. Checking emails from the past {days_to_check} days"
)
else: else:
# If no last run file exists, this is the first run ever - check 90 days # If no last run file exists, this is the first run ever - check 90 days
days_to_check = full_check days_to_check = full_check
print(f"[EMAIL_SERVICE] First run detected. Checking emails from the past {days_to_check} days") print(
f"[EMAIL_SERVICE] First run detected. Checking emails from the past {days_to_check} days"
)
except Exception as e: except Exception as e:
print(f"[EMAIL_SERVICE] Error reading last run file: {str(e)}. Using default of {days_to_check} days") print(
f"[EMAIL_SERVICE] Error reading last run file: {str(e)}. Using default of {days_to_check} days"
)
# Update the last run file # Update the last run file
try: try:
with open(last_run_file, 'w') as f: with open(last_run_file, "w") as f:
json.dump({'last_run_date': current_date}, f) json.dump({"last_run_date": current_date}, f)
except Exception as e: except Exception as e:
print(f"[EMAIL_SERVICE] Error writing last run file: {str(e)}") print(f"[EMAIL_SERVICE] Error writing last run file: {str(e)}")
# Calculate the date to check from # Calculate the date to check from
check_since_date = (datetime.now() - timedelta(days=days_to_check)).strftime("%d-%b-%Y") check_since_date = (datetime.now() - timedelta(days=days_to_check)).strftime(
"%d-%b-%Y"
)
for folder in mail_folders: for folder in mail_folders:
if folder.name == "INBOX": if folder.name == "INBOX":
@@ -184,7 +196,9 @@ def app():
# Use context manager to handle errors and mark email as unread if needed # Use context manager to handle errors and mark email as unread if needed
with EmailProcessingContext(banks_mail) as ctx: with EmailProcessingContext(banks_mail) as ctx:
try: try:
headers = {k.lower(): v for k, v in banks_mail.headers.items()} headers = {
k.lower(): v for k, v in banks_mail.headers.items()
}
mail_info = { mail_info = {
"from": headers["from"], "from": headers["from"],
"to": headers["to"], "to": headers["to"],
@@ -201,9 +215,13 @@ def app():
ctx.success = success ctx.success = success
if success: if success:
print(f"[EMAIL_SERVICE] Successfully processed email with subject: {mail_info['subject']}") print(
f"[EMAIL_SERVICE] Successfully processed email with subject: {mail_info['subject']}"
)
else: else:
print(f"[EMAIL_SERVICE] No matching attachments found in email with subject: {mail_info['subject']}") print(
f"[EMAIL_SERVICE] No matching attachments found in email with subject: {mail_info['subject']}"
)
except Exception as e: except Exception as e:
print(f"[EMAIL_SERVICE] Error processing email: {str(e)}") print(f"[EMAIL_SERVICE] Error processing email: {str(e)}")

View File

@@ -18,7 +18,9 @@ REDIS_CHANNEL_OUT = "parser" # Publish to Parser Service channel
delimiter = "|" delimiter = "|"
def publish_parsed_data_to_redis(data, collected_data_dict: list[dict], filename: str) -> bool: def publish_parsed_data_to_redis(
data, collected_data_dict: list[dict], filename: str
) -> bool:
"""Publish parsed data to Redis. """Publish parsed data to Redis.
Args: Args:
@@ -49,7 +51,9 @@ def publish_parsed_data_to_redis(data, collected_data_dict: list[dict], filename
result = redis_pubsub.publisher.publish(REDIS_CHANNEL_OUT, message) result = redis_pubsub.publisher.publish(REDIS_CHANNEL_OUT, message)
if result.status: if result.status:
print(f"[PARSER_SERVICE] Published parsed data for {filename} with stage: {message['stage']}") print(
f"[PARSER_SERVICE] Published parsed data for {filename} with stage: {message['stage']}"
)
return True return True
else: else:
print(f"[PARSER_SERVICE] Publish error: {result.error}") print(f"[PARSER_SERVICE] Publish error: {result.error}")
@@ -76,13 +80,17 @@ def parse_excel_file(excel_frame: DataFrame) -> list[dict]:
dict( dict(
iban=str(iban), iban=str(iban),
bank_date=arrow.get( bank_date=arrow.get(
datetime.datetime.strptime(str(row[1]), "%d/%m/%Y-%H:%M:%S") datetime.datetime.strptime(
str(row[1]), "%d/%m/%Y-%H:%M:%S"
)
).__str__(), ).__str__(),
channel_branch=unidecode(str(row[3])), channel_branch=unidecode(str(row[3])),
currency_value=( currency_value=(
float(str(row[4]).replace(",", "")) if row[4] else 0 float(str(row[4]).replace(",", "")) if row[4] else 0
), ),
balance=float(str(row[5]).replace(",", "")) if row[5] else 0, balance=(
float(str(row[5]).replace(",", "")) if row[5] else 0
),
additional_balance=( additional_balance=(
float(str(row[6]).replace(",", "")) if row[6] else 0 float(str(row[6]).replace(",", "")) if row[6] else 0
), ),
@@ -92,7 +100,9 @@ def parse_excel_file(excel_frame: DataFrame) -> list[dict]:
bank_reference_code=str(row[15]), bank_reference_code=str(row[15]),
) )
) )
print(f"[PARSER_SERVICE] Successfully parsed {len(data_list)} records from Excel file") print(
f"[PARSER_SERVICE] Successfully parsed {len(data_list)} records from Excel file"
)
except Exception as e: except Exception as e:
print(f"[PARSER_SERVICE] Error parsing Excel file: {str(e)}") print(f"[PARSER_SERVICE] Error parsing Excel file: {str(e)}")
return data_list return data_list
@@ -128,12 +138,14 @@ def process_message(message):
try: try:
# Decode base64 string to bytes # Decode base64 string to bytes
payload = base64.b64decode(payload) payload = base64.b64decode(payload)
print(f"[PARSER_SERVICE] Successfully decoded base64 payload, size: {len(payload)} bytes") print(
f"[PARSER_SERVICE] Successfully decoded base64 payload, size: {len(payload)} bytes"
)
except Exception as e: except Exception as e:
print(f"[PARSER_SERVICE] Error decoding base64 payload: {str(e)}") print(f"[PARSER_SERVICE] Error decoding base64 payload: {str(e)}")
# Convert regular string payload to bytes if needed # Convert regular string payload to bytes if needed
elif isinstance(payload, str): elif isinstance(payload, str):
payload = payload.encode('utf-8') payload = payload.encode("utf-8")
# Create an in-memory file-like object and try multiple approaches # Create an in-memory file-like object and try multiple approaches
excel_frame = None excel_frame = None
@@ -142,20 +154,32 @@ def process_message(message):
# Save payload to a temporary file for debugging if needed # Save payload to a temporary file for debugging if needed
temp_file_path = f"/tmp/{filename}" temp_file_path = f"/tmp/{filename}"
try: try:
with open(temp_file_path, 'wb') as f: with open(temp_file_path, "wb") as f:
f.write(payload) f.write(payload)
print(f"[PARSER_SERVICE] Saved payload to {temp_file_path} for debugging") print(
f"[PARSER_SERVICE] Saved payload to {temp_file_path} for debugging"
)
except Exception as e: except Exception as e:
print(f"[PARSER_SERVICE] Could not save debug file: {str(e)}") print(f"[PARSER_SERVICE] Could not save debug file: {str(e)}")
# Try different approaches to read the Excel file # Try different approaches to read the Excel file
approaches = [ approaches = [
# Approach 1: Try xlrd for .xls files # Approach 1: Try xlrd for .xls files
lambda: DataFrame(read_excel(io.BytesIO(payload), engine='xlrd')) if filename.lower().endswith('.xls') else None, lambda: (
DataFrame(read_excel(io.BytesIO(payload), engine="xlrd"))
if filename.lower().endswith(".xls")
else None
),
# Approach 2: Try openpyxl for .xlsx files # Approach 2: Try openpyxl for .xlsx files
lambda: DataFrame(read_excel(io.BytesIO(payload), engine='openpyxl')) if filename.lower().endswith('.xlsx') else None, lambda: (
DataFrame(read_excel(io.BytesIO(payload), engine="openpyxl"))
if filename.lower().endswith(".xlsx")
else None
),
# Approach 3: Try xlrd with explicit sheet name # Approach 3: Try xlrd with explicit sheet name
lambda: DataFrame(read_excel(io.BytesIO(payload), engine='xlrd', sheet_name=0)), lambda: DataFrame(
read_excel(io.BytesIO(payload), engine="xlrd", sheet_name=0)
),
# Approach 4: Try with temporary file # Approach 4: Try with temporary file
lambda: DataFrame(read_excel(temp_file_path)), lambda: DataFrame(read_excel(temp_file_path)),
] ]
@@ -166,7 +190,9 @@ def process_message(message):
result = approach() result = approach()
if result is not None: if result is not None:
excel_frame = result excel_frame = result
print(f"[PARSER_SERVICE] Successfully read Excel file using approach {i+1}") print(
f"[PARSER_SERVICE] Successfully read Excel file using approach {i+1}"
)
break break
except Exception as e: except Exception as e:
errors.append(f"Approach {i+1}: {str(e)}") errors.append(f"Approach {i+1}: {str(e)}")
@@ -174,21 +200,23 @@ def process_message(message):
# If all approaches failed, raise an exception # If all approaches failed, raise an exception
if excel_frame is None: if excel_frame is None:
error_details = "\n".join(errors) error_details = "\n".join(errors)
raise Exception(f"Failed to read Excel file using all approaches:\n{error_details}") raise Exception(
f"Failed to read Excel file using all approaches:\n{error_details}"
)
# Extract data from the Excel file # Extract data from the Excel file
collected_data_dict = parse_excel_file(excel_frame) collected_data_dict = parse_excel_file(excel_frame)
# Publish parsed data to Redis # Publish parsed data to Redis
publish_parsed_data_to_redis( publish_parsed_data_to_redis(
data=data, data=data, collected_data_dict=collected_data_dict, filename=filename
collected_data_dict=collected_data_dict,
filename=filename
) )
except Exception as e: except Exception as e:
print(f"[PARSER_SERVICE] Error processing message: {str(e)}") print(f"[PARSER_SERVICE] Error processing message: {str(e)}")
else: else:
print(f"[PARSER_SERVICE] Skipped message with UUID: {data.get('uuid')} (stage is not 'red')") print(
f"[PARSER_SERVICE] Skipped message with UUID: {data.get('uuid')} (stage is not 'red')"
)
def app(): def app():

View File

@@ -14,12 +14,12 @@ RUN poetry config virtualenvs.create false && poetry install --no-interaction --
# Install cron for scheduling tasks # Install cron for scheduling tasks
RUN apt-get update && apt-get install -y cron RUN apt-get update && apt-get install -y cron
# 11:00 Istanbul Time (UTC+3) system time is 08:00 UTC
RUN echo "0 8 * * * /usr/local/bin/python /app.py >> /var/log/cron.log 2>&1" > /tmp/crontab_list && crontab /tmp/crontab_list
# Copy application code # Copy application code
COPY /BankServices/RoutineEmailService / COPY /BankServices/RoutineEmailService /
# Make run_app.sh executable
RUN chmod +x /run_app.sh
COPY /Schemas /Schemas COPY /Schemas /Schemas
COPY /Controllers /Controllers COPY /Controllers /Controllers
COPY /BankServices/ServiceDepends / COPY /BankServices/ServiceDepends /
@@ -30,5 +30,8 @@ ENV PYTHONPATH=/ PYTHONUNBUFFERED=1 PYTHONDONTWRITEBYTECODE=1
# Create log file to grab cron logs # Create log file to grab cron logs
RUN touch /var/log/cron.log RUN touch /var/log/cron.log
# Run cron setup and tail the log file for user to monitor logs # Make entrypoint script executable
CMD cron && tail -f /var/log/cron.log RUN chmod +x /entrypoint.sh
# Use entrypoint script to update run_app.sh with environment variables and start cron
ENTRYPOINT ["/entrypoint.sh"]

View File

@@ -0,0 +1,69 @@
# Routine Email Service
## Overview
This service sends automated email reports about account records at scheduled times using cron. It retrieves account records from a PostgreSQL database, formats them into an HTML email, and sends them to specified recipients.
## Environment Setup
The service requires the following environment variables:
### Email Configuration
- `EMAIL_HOST`: SMTP server address (e.g., "10.10.2.34")
- `EMAIL_USERNAME`: Email sender address (e.g., "example@domain.com")
- `EMAIL_PASSWORD`: Email password (sensitive)
- `EMAIL_PORT`: SMTP port (e.g., 587)
- `EMAIL_SEND`: Flag to enable/disable email sending (1 = enabled)
### Database Configuration
- `DB_HOST`: PostgreSQL server address (e.g., "10.10.2.14")
- `DB_USER`: Database username (e.g., "postgres")
- `DB_PASSWORD`: Database password (sensitive)
- `DB_PORT`: Database port (e.g., 5432)
- `DB_NAME`: Database name (e.g., "postgres")
## Cron Job Configuration
The service is configured to run daily at 11:00 Istanbul Time (08:00 UTC). This is set up in the entrypoint.sh script.
## Docker Container Setup
### Key Files
1. **Dockerfile**: Defines the container image with Python and cron
2. **entrypoint.sh**: Container entrypoint script that:
- Creates an environment file (/env.sh) with all configuration variables
- Sets up the crontab to run run_app.sh at the scheduled time
- Starts the cron service
- Tails the log file for monitoring
3. **run_app.sh**: Script executed by cron that:
- Sources the environment file to get all configuration
- Exports variables to make them available to the Python script
- Runs the Python application
- Logs environment and execution results
### Environment Variable Handling
Cron jobs run with a minimal environment that doesn't automatically include Docker container environment variables. Our solution:
1. Captures all environment variables from Docker to a file at container startup
2. Has the run_app.sh script source this file before execution
3. Explicitly exports all variables to ensure they're available to the Python script
## Logs
Logs are written to `/var/log/cron.log` and can be viewed with:
```bash
docker exec routine_email_service tail -f /var/log/cron.log
```
## Manual Execution
To run the service manually:
```bash
docker exec routine_email_service /run_app.sh
```
## Docker Compose Configuration
In the docker-compose.yml file, the service needs an explicit entrypoint configuration:
```yaml
entrypoint: ["/entrypoint.sh"]
```
This ensures the entrypoint script runs when the container starts.

View File

@@ -35,8 +35,7 @@ def render_email_template(
today=str(arrow.now().date()), today=str(arrow.now().date()),
) )
except Exception as e: except Exception as e:
print('Exception render template:',e) print("Exception render template:", e)
err = e
raise raise
@@ -59,17 +58,16 @@ def send_email_to_given_address(send_to: str, html_template: str) -> bool:
subject=subject, subject=subject,
html=html_template, html=html_template,
receivers=[send_to], receivers=[send_to],
text=f"Gunes Apt. Cari Durum Bilgilendirme Raporu - {today.date()}" text=f"Gunes Apt. Cari Durum Bilgilendirme Raporu - {today.date()}",
) )
try: try:
# Use the context manager to handle connection errors # Use the context manager to handle connection errors
with EmailService.new_session() as email_session: with EmailService.new_session() as email_session:
# Send email through the service # Send email through the service
EmailService.send_email(email_session, email_params) return EmailService.send_email(email_session, email_params)
return True
except Exception as e: except Exception as e:
print(f'Exception send email: {e}') print(f"Exception send email: {e}")
return False return False
@@ -88,10 +86,10 @@ def set_account_records_to_send_email() -> bool:
account_records_query = AccountRecords.filter_all(db=db_session).query account_records_query = AccountRecords.filter_all(db=db_session).query
# Get the 3 most recent records # Get the 3 most recent records
account_records: List[AccountRecords] | [] = ( account_records: List[AccountRecords] = (
account_records_query.order_by( account_records_query.order_by(
AccountRecords.bank_date.desc(), AccountRecords.bank_date.desc(),
AccountRecords.bank_reference_code.desc() AccountRecords.iban.desc(),
) )
.limit(3) .limit(3)
.all() .all()
@@ -99,29 +97,43 @@ def set_account_records_to_send_email() -> bool:
# Check if we have enough records # Check if we have enough records
if len(account_records) < 2: if len(account_records) < 2:
print(f"Not enough records found: {len(account_records)}")
return False return False
# Check for balance discrepancy # Check for balance discrepancy
first_record, second_record = account_records[0], account_records[1] first_record, second_record = account_records[0], account_records[1]
expected_second_balance = first_record.bank_balance - first_record.currency_value expected_second_balance = (
first_record.bank_balance - first_record.currency_value
)
balance_error = expected_second_balance != second_record.bank_balance balance_error = expected_second_balance != second_record.bank_balance
if balance_error: if balance_error:
return False print(
f"Balance error detected {expected_second_balance} != {second_record.bank_balance}"
)
# Format rows for the email template # Format rows for the email template
list_of_rows = [] list_of_rows = []
for record in account_records: for record in account_records:
list_of_rows.append([ list_of_rows.append(
[
record.bank_date.strftime("%d/%m/%Y %H:%M"), record.bank_date.strftime("%d/%m/%Y %H:%M"),
record.process_comment, record.process_comment,
f"{record.currency_value:,.2f}", f"{record.currency_value:,.2f}",
f"{record.bank_balance:,.2f}" f"{record.bank_balance:,.2f}",
]) ]
)
# Get the most recent bank balance # Get the most recent bank balance
last_bank_balance = sorted(account_records, key=lambda x: x.bank_date, reverse=True)[0].bank_balance last_bank_balance = sorted(
account_records, key=lambda x: x.bank_date, reverse=True
)[0].bank_balance
# Define headers for the table # Define headers for the table
headers = ["Ulaştığı Tarih", "Banka Transaksiyonu Ek Bilgi", "Aktarım Değeri", "Banka Bakiyesi"] headers = [
"Ulaştığı Tarih",
"Banka Transaksiyonu Ek Bilgi",
"Aktarım Değeri",
"Banka Bakiyesi",
]
# Recipient email address # Recipient email address
send_to = "karatay@mehmetkaratay.com.tr" send_to = "karatay@mehmetkaratay.com.tr"
@@ -140,5 +152,6 @@ def set_account_records_to_send_email() -> bool:
if __name__ == "__main__": if __name__ == "__main__":
success = set_account_records_to_send_email() success = set_account_records_to_send_email()
print("Email sent successfully" if success else "Failed to send email")
exit_code = 0 if success else 1 exit_code = 0 if success else 1
exit(exit_code) exit(exit_code)

View File

@@ -0,0 +1,29 @@
#!/bin/bash
# Create environment file that will be available to cron jobs
echo "# Environment variables for cron jobs" > /env.sh
echo "EMAIL_HOST=\"$EMAIL_HOST\"" >> /env.sh
echo "EMAIL_USERNAME=\"$EMAIL_USERNAME\"" >> /env.sh
echo "EMAIL_PASSWORD=\"$EMAIL_PASSWORD\"" >> /env.sh
echo "EMAIL_PORT=$EMAIL_PORT" >> /env.sh
echo "EMAIL_SEND=$EMAIL_SEND" >> /env.sh
echo "DB_HOST=\"$DB_HOST\"" >> /env.sh
echo "DB_USER=\"$DB_USER\"" >> /env.sh
echo "DB_PASSWORD=\"$DB_PASSWORD\"" >> /env.sh
echo "DB_PORT=$DB_PORT" >> /env.sh
echo "DB_NAME=\"$DB_NAME\"" >> /env.sh
# Add Python environment variables
echo "PYTHONPATH=/" >> /env.sh
echo "PYTHONUNBUFFERED=1" >> /env.sh
echo "PYTHONDONTWRITEBYTECODE=1" >> /env.sh
# Make the environment file available to cron
echo "0 8 * * * /run_app.sh >> /var/log/cron.log 2>&1" > /tmp/crontab_list
crontab /tmp/crontab_list
# Start cron
cron
# Tail the log file
tail -f /var/log/cron.log

View File

@@ -0,0 +1,24 @@
#!/bin/bash
# Source the environment file directly
. /env.sh
# Re-export all variables to ensure they're available to the Python script
export EMAIL_HOST
export EMAIL_USERNAME
export EMAIL_PASSWORD
export EMAIL_PORT
export EMAIL_SEND
export DB_HOST
export DB_USER
export DB_PASSWORD
export DB_PORT
export DB_NAME
# Python environment variables
export PYTHONPATH
export PYTHONUNBUFFERED
export PYTHONDONTWRITEBYTECODE
env >> /var/log/cron.log
/usr/local/bin/python /app.py

View File

@@ -35,11 +35,13 @@ def render_email_template(
today=str(arrow.now().date()), today=str(arrow.now().date()),
) )
except Exception as e: except Exception as e:
print(f'Template rendering failed: {e}') print(f"Template rendering failed: {e}")
raise raise
def send_email_to_given_address(send_to: str, html_template: str, count_of_records: int) -> bool: def send_email_to_given_address(
send_to: str, html_template: str, count_of_records: int
) -> bool:
""" """
Send email with the rendered HTML template to the specified address. Send email with the rendered HTML template to the specified address.
@@ -58,7 +60,7 @@ def send_email_to_given_address(send_to: str, html_template: str, count_of_recor
subject=subject + f" ({count_of_records} kayıt)", subject=subject + f" ({count_of_records} kayıt)",
html=html_template, html=html_template,
receivers=[send_to], receivers=[send_to],
text=f"Gunes Apt. Cari Durum Kayıt Giriş Raporu - {today.date()}" text=f"Gunes Apt. Cari Durum Kayıt Giriş Raporu - {today.date()}",
) )
try: try:
@@ -69,7 +71,7 @@ def send_email_to_given_address(send_to: str, html_template: str, count_of_recor
print(f"Email successfully sent to: {send_to}") print(f"Email successfully sent to: {send_to}")
return True return True
except Exception as e: except Exception as e:
print(f'Failed to send email: {e}') print(f"Failed to send email: {e}")
return False return False
@@ -87,10 +89,14 @@ def process_unsent_email_records() -> bool:
# Use the context manager to handle database connections # Use the context manager to handle database connections
with AccountRecords.new_session() as db_session: with AccountRecords.new_session() as db_session:
# Query un-sent mail rows - with limit for display only # Query un-sent mail rows - with limit for display only
account_records_query = AccountRecords.filter_all( account_records_query = (
AccountRecords.filter_all(
AccountRecords.is_email_send == False, AccountRecords.is_email_send == False,
db=db_session, db=db_session,
).query.order_by(AccountRecords.bank_date.asc()).limit(20) )
.query.order_by(AccountRecords.bank_date.asc())
.limit(20)
)
account_records: List[AccountRecords] = account_records_query.all() account_records: List[AccountRecords] = account_records_query.all()
if not account_records: if not account_records:
@@ -99,27 +105,35 @@ def process_unsent_email_records() -> bool:
# Get the IDs of the records we're processing # Get the IDs of the records we're processing
record_ids = [record.id for record in account_records] record_ids = [record.id for record in account_records]
print(f"Found {len(account_records)} unsent email records") print(f"Found {len(account_records)} unsent email records")
# Format rows for the email template # Format rows for the email template
list_of_rows = [] list_of_rows = []
for record in account_records: for record in account_records:
list_of_rows.append([ list_of_rows.append(
[
record.bank_date.strftime("%d/%m/%Y %H:%M"), record.bank_date.strftime("%d/%m/%Y %H:%M"),
record.process_comment, record.process_comment,
f"{record.currency_value:,.2f}", f"{record.currency_value:,.2f}",
f"{record.bank_balance:,.2f}" f"{record.bank_balance:,.2f}",
]) ]
)
# Reverse list by date # Reverse list by date
list_of_rows = list_of_rows[::-1] list_of_rows = list_of_rows[::-1]
# Get the most recent bank balance # Get the most recent bank balance
last_bank_balance = sorted(account_records, key=lambda x: x.bank_date, reverse=True)[0].bank_balance last_bank_balance = sorted(
account_records, key=lambda x: x.bank_date, reverse=True
)[0].bank_balance
# Define headers for the table # Define headers for the table
headers = ["Ulaştığı Tarih", "Banka Transaksiyonu Ek Bilgi", "Aktarım Değeri", "Banka Bakiyesi"] headers = [
"Ulaştığı Tarih",
"Banka Transaksiyonu Ek Bilgi",
"Aktarım Değeri",
"Banka Bakiyesi",
]
# Recipient email address # Recipient email address
send_to = "karatay@mehmetkaratay.com.tr" send_to = "karatay@mehmetkaratay.com.tr"
@@ -133,11 +147,14 @@ def process_unsent_email_records() -> bool:
) )
# Send the email # Send the email
if send_email_to_given_address(send_to=send_to, html_template=html_template, count_of_records=len(list_of_rows)): if send_email_to_given_address(
send_to=send_to,
html_template=html_template,
count_of_records=len(list_of_rows),
):
# Create a new query without limit for updating # Create a new query without limit for updating
update_query = AccountRecords.filter_all( update_query = AccountRecords.filter_all(
AccountRecords.id.in_(record_ids), AccountRecords.id.in_(record_ids), db=db_session
db=db_session
).query ).query
# Update records as sent # Update records as sent
@@ -150,7 +167,7 @@ def process_unsent_email_records() -> bool:
return False return False
except Exception as e: except Exception as e:
print(f'Error processing unsent email records: {e}') print(f"Error processing unsent email records: {e}")
return False return False

View File

@@ -39,7 +39,9 @@ def publish_written_data_to_redis(data: Dict[str, Any], file_name: str) -> bool:
result = redis_pubsub.publisher.publish(REDIS_CHANNEL_OUT, message) result = redis_pubsub.publisher.publish(REDIS_CHANNEL_OUT, message)
if result.status: if result.status:
print(f"[WRITER_SERVICE] Published written status for {file_name} with stage: written") print(
f"[WRITER_SERVICE] Published written status for {file_name} with stage: written"
)
return True return True
else: else:
print(f"[WRITER_SERVICE] Publish error: {result.error}") print(f"[WRITER_SERVICE] Publish error: {result.error}")
@@ -61,7 +63,7 @@ def write_parsed_data_to_account_records(data_dict: dict, file_name: str) -> boo
data_dict["bank_balance"] = data_dict.pop("balance") data_dict["bank_balance"] = data_dict.pop("balance")
data_dict["import_file_name"] = file_name data_dict["import_file_name"] = file_name
data_dict = BankReceive(**data_dict).model_dump() data_dict = BankReceive(**data_dict).model_dump()
print('data_dict', data_dict) print("data_dict", data_dict)
# Process date fields # Process date fields
bank_date = arrow.get(str(data_dict["bank_date"])) bank_date = arrow.get(str(data_dict["bank_date"]))
@@ -90,16 +92,20 @@ def write_parsed_data_to_account_records(data_dict: dict, file_name: str) -> boo
AccountRecords.bank_date, AccountRecords.bank_date,
AccountRecords.iban, AccountRecords.iban,
AccountRecords.bank_reference_code, AccountRecords.bank_reference_code,
AccountRecords.bank_balance AccountRecords.bank_balance,
] ],
) )
if new_account_record.meta_data.created: if new_account_record.meta_data.created:
new_account_record.is_confirmed = True new_account_record.is_confirmed = True
new_account_record.save(db=db_session) new_account_record.save(db=db_session)
print(f"[WRITER_SERVICE] Created new record in database: {new_account_record.id}") print(
f"[WRITER_SERVICE] Created new record in database: {new_account_record.id}"
)
return True return True
else: else:
print(f"[WRITER_SERVICE] Record already exists in database: {new_account_record.id}") print(
f"[WRITER_SERVICE] Record already exists in database: {new_account_record.id}"
)
return False return False
except Exception as e: except Exception as e:
print(f"[WRITER_SERVICE] Error writing to database: {str(e)}") print(f"[WRITER_SERVICE] Error writing to database: {str(e)}")
@@ -138,7 +144,9 @@ def process_message(message):
# Process each parsed data item # Process each parsed data item
success = True success = True
for item in parsed_data: for item in parsed_data:
result = write_parsed_data_to_account_records(data_dict=item, file_name=file_name) result = write_parsed_data_to_account_records(
data_dict=item, file_name=file_name
)
if not result: if not result:
success = False success = False
@@ -148,7 +156,9 @@ def process_message(message):
except Exception as e: except Exception as e:
print(f"[WRITER_SERVICE] Error processing message: {str(e)}") print(f"[WRITER_SERVICE] Error processing message: {str(e)}")
else: else:
print(f"[WRITER_SERVICE] Skipped message with UUID: {data.get('uuid')} (stage is not 'parsed')") print(
f"[WRITER_SERVICE] Skipped message with UUID: {data.get('uuid')} (stage is not 'parsed')"
)
def app(): def app():

View File

@@ -10,7 +10,7 @@ class Configs(BaseSettings):
USERNAME: str = "" USERNAME: str = ""
PASSWORD: str = "" PASSWORD: str = ""
PORT: int = 0 PORT: int = 0
SEND: bool = 0 SEND: bool = True
@property @property
def is_send(self): def is_send(self):

View File

@@ -27,6 +27,13 @@ class EmailSession:
print("Email sending is disabled", params) print("Email sending is disabled", params)
return False return False
receivers = [email_configs.USERNAME] receivers = [email_configs.USERNAME]
# Ensure connection is established before sending
try:
# Check if connection exists, if not establish it
if not hasattr(self.email_sender, '_connected') or not self.email_sender._connected:
self.email_sender.connect()
self.email_sender.send( self.email_sender.send(
subject=params.subject, subject=params.subject,
receivers=receivers, receivers=receivers,
@@ -38,6 +45,9 @@ class EmailSession:
attachments=params.attachments or {}, attachments=params.attachments or {},
) )
return True return True
except Exception as e:
print(f"Error sending email: {e}")
raise
class EmailService: class EmailService:
@@ -54,14 +64,25 @@ class EmailService:
"""Create and yield a new email session with active connection.""" """Create and yield a new email session with active connection."""
email_sender = EmailSender(**email_configs.as_dict()) email_sender = EmailSender(**email_configs.as_dict())
session = EmailSession(email_sender) session = EmailSession(email_sender)
connection_established = False
try: try:
# Establish connection and set flag
email_sender.connect() email_sender.connect()
# Set a flag to track connection state
email_sender._connected = True
connection_established = True
yield session yield session
except Exception as e: except Exception as e:
print(f"Error with email connection: {e}") print(f"Error with email connection: {e}")
raise raise
finally: finally:
# Only close if connection was successfully established
if connection_established:
try:
email_sender.close() email_sender.close()
email_sender._connected = False
except Exception as e:
print(f"Error closing email connection: {e}")
@classmethod @classmethod
def send_email(cls, session: EmailSession, params: EmailSendModel) -> bool: def send_email(cls, session: EmailSession, params: EmailSendModel) -> bool:

View File

@@ -135,7 +135,9 @@ class CollectionContext:
try: try:
# Create a new client connection # Create a new client connection
self.client = MongoClient(self.db_handler.uri, **self.db_handler.client_options) self.client = MongoClient(
self.db_handler.uri, **self.db_handler.client_options
)
if self.db_handler._debug_mode: if self.db_handler._debug_mode:
# In debug mode, we explicitly use the configured DB # In debug mode, we explicitly use the configured DB
@@ -164,8 +166,12 @@ class CollectionContext:
# Try a direct connection without authentication for testing # Try a direct connection without authentication for testing
direct_uri = f"mongodb://{mongo_configs.HOST}:{mongo_configs.PORT}/{mongo_configs.DB}" direct_uri = f"mongodb://{mongo_configs.HOST}:{mongo_configs.PORT}/{mongo_configs.DB}"
print(f"Trying direct connection: {direct_uri}") print(f"Trying direct connection: {direct_uri}")
self.client = MongoClient(direct_uri, **self.db_handler.client_options) self.client = MongoClient(
self.collection = self.client[mongo_configs.DB][self.collection_name] direct_uri, **self.db_handler.client_options
)
self.collection = self.client[mongo_configs.DB][
self.collection_name
]
self._add_retry_capabilities() self._add_retry_capabilities()
return self.collection return self.collection
except Exception as inner_e: except Exception as inner_e:
@@ -197,10 +203,12 @@ class CollectionContext:
if self.db_handler._mock_mode: if self.db_handler._mock_mode:
print(f"MOCK MODE: Using mock collection '{self.collection_name}'") print(f"MOCK MODE: Using mock collection '{self.collection_name}'")
else: else:
print(f"Using mock MongoDB collection '{self.collection_name}' for graceful degradation") print(
f"Using mock MongoDB collection '{self.collection_name}' for graceful degradation"
)
# Create in-memory storage for this mock collection # Create in-memory storage for this mock collection
if not hasattr(self.db_handler, '_mock_storage'): if not hasattr(self.db_handler, "_mock_storage"):
self.db_handler._mock_storage = {} self.db_handler._mock_storage = {}
if self.collection_name not in self.db_handler._mock_storage: if self.collection_name not in self.db_handler._mock_storage:
@@ -222,11 +230,11 @@ class CollectionContext:
def mock_insert_one(document, *args, **kwargs): def mock_insert_one(document, *args, **kwargs):
# Add _id if not present # Add _id if not present
if '_id' not in document: if "_id" not in document:
document['_id'] = f"mock_id_{len(mock_data)}" document["_id"] = f"mock_id_{len(mock_data)}"
mock_data.append(document) mock_data.append(document)
result = MagicMock() result = MagicMock()
result.inserted_id = document['_id'] result.inserted_id = document["_id"]
return result return result
def mock_insert_many(documents, *args, **kwargs): def mock_insert_many(documents, *args, **kwargs):
@@ -328,9 +336,17 @@ class CollectionContext:
""" """
# List of common MongoDB collection methods to add retry capabilities to # List of common MongoDB collection methods to add retry capabilities to
methods = [ methods = [
'insert_one', 'insert_many', 'find_one', 'find', "insert_one",
'update_one', 'update_many', 'delete_one', 'delete_many', "insert_many",
'replace_one', 'count_documents', 'aggregate' "find_one",
"find",
"update_one",
"update_many",
"delete_one",
"delete_many",
"replace_one",
"count_documents",
"aggregate",
] ]
# Add retry decorator to each method # Add retry decorator to each method
@@ -340,7 +356,7 @@ class CollectionContext:
setattr( setattr(
mock_collection, mock_collection,
method_name, method_name,
retry_operation(max_retries=1, retry_interval=0)(original_method) retry_operation(max_retries=1, retry_interval=0)(original_method),
) )
def __exit__(self, exc_type, exc_val, exc_tb): def __exit__(self, exc_type, exc_val, exc_tb):

Some files were not shown because too many files have changed in this diff Show More