first commit

This commit is contained in:
2024-11-07 17:44:29 +03:00
commit 643d6d8f65
247 changed files with 420800 additions and 0 deletions

View File

@@ -0,0 +1,219 @@
import json
import typing
from fastapi import status
from fastapi.exceptions import HTTPException
from api_configs import Auth
from databases import (
BuildLivingSpace,
BuildParts,
Companies,
Duties,
Departments,
Duty,
Employees,
Staff,
)
from api_objects import (
OccupantTokenObject,
EmployeeTokenObject,
UserType,
)
from api_services.redis.conn import redis_cli
from api_services.redis.functions import get_object_via_user_uu_id, get_object_via_access_key
def save_object_to_redis(
access_token, model_object: typing.Union[OccupantTokenObject, EmployeeTokenObject]
) -> bool:
try:
if redis_cli.set(
name=str(access_token) + ":" + str(model_object.user_uu_id),
value=model_object.model_dump_json(),
):
return access_token
except Exception as e:
print("Save Object to Redis Error: ", e)
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail=dict(
message="Headers are not found in request. Invalid request object. Redis Error: Token is not saved."
),
)
def save_access_token_to_redis(
request, found_user, domain: str, access_token: str = None
):
if not found_user:
raise HTTPException(
status_code=400,
detail=dict(message="User is not found."),
headers=request.headers,
)
# Check user is already logged in or has a previous session
already_tokens = get_object_via_user_uu_id(user_id=found_user.uu_id)
for key in already_tokens or []:
token_user = json.loads(redis_cli.get(key).decode() or {})
if token_user.get("domain", "") == domain:
redis_cli.delete(key)
access_token = (
found_user.generate_access_token() if not access_token else access_token
)
# Prepare the user's details to save in Redis Session
if found_user.is_occupant: # Check if user is NOT an occupant
living_spaces: list[BuildLivingSpace] = BuildLivingSpace.filter_active(
BuildLivingSpace.person_id == found_user.person_id, filter_records=False
).data
if not living_spaces:
raise HTTPException(
status_code=400,
detail=dict(
message="NO Living Space is found. This user has no proper account set please contact the admin."
),
headers=request.headers,
)
occupants_selection_dict = {}
for living_space in living_spaces:
build_parts_selection = BuildParts.filter_active(
BuildParts.id == living_space.build_parts_id
)
if not build_parts_selection.data:
raise HTTPException(
status_code=400,
detail=dict(
message="No build Part is found for the living space. Please contact the admin."
),
headers=request.headers,
)
build_part = build_parts_selection.get(1)
occupant_dict = {
"uu_id": str(living_space.occupant_type_uu_id),
"id": living_space.occupant_type,
}
if not str(build_part.uu_id) in occupants_selection_dict:
occupants_selection_dict[str(build_part.uu_id)] = [occupant_dict]
elif str(build_part.uu_id) in occupants_selection_dict:
occupants_selection_dict[str(build_part.uu_id)].append(occupant_dict)
save_object_to_redis(
access_token=access_token,
model_object=OccupantTokenObject(
domain=domain,
user_type=UserType.occupant.value,
user_uu_id=str(found_user.uu_id),
credentials=found_user.credentials(),
user_id=found_user.id,
person_id=found_user.person_id,
person_uu_id=str(found_user.person.uu_id),
request=dict(request.headers),
available_occupants=occupants_selection_dict,
),
)
new_occupants_selection_dict = {}
for key, value in occupants_selection_dict.items():
new_occupants_selection_dict[key] = [
occupant.get("uu_id") for occupant in value
]
return dict(
user_type=UserType.occupant.name,
available_occupants=new_occupants_selection_dict,
)
list_employee = Employees.filter_active(Employees.people_id == found_user.person_id)
companies_uu_id_list, companies_id_list = [], []
duty_uu_id_list, duty_id_list = [], []
for employee in list_employee.data:
staff = Staff.find_one(id=employee.staff_id)
if duties := Duties.find_one(id=staff.duties_id):
if duty_found := Duty.find_one(id=duties.duties_id):
duty_uu_id_list.append(str(duty_found.uu_id))
duty_id_list.append(duty_found.id)
department = Departments.find_one(id=duties.department_id)
if company := Companies.find_one(id=department.company_id):
companies_uu_id_list.append(str(company.uu_id))
companies_id_list.append(company.id)
save_object_to_redis(
access_token=access_token,
model_object=EmployeeTokenObject(
domain=domain,
user_type=UserType.employee.value,
user_uu_id=str(found_user.uu_id),
credentials=found_user.credentials(),
user_id=found_user.id,
person_id=found_user.person_id,
person_uu_id=str(found_user.person.uu_id),
request=dict(request.headers),
companies_uu_id_list=companies_uu_id_list,
companies_id_list=companies_id_list,
duty_uu_id_list=duty_uu_id_list,
duty_id_list=duty_id_list,
),
)
return dict(
user_type=UserType.employee.name,
companies_uu_id_list=companies_uu_id_list,
)
def update_selected_to_redis(request, add_payload):
already_tokens = get_object_via_access_key(request=request)
if not hasattr(request, "headers"):
raise HTTPException(
status_code=401,
detail=dict(
message="Headers are not found in request. Invalid request object."
),
)
access_token = request.headers.get(Auth.ACCESS_TOKEN_TAG)
if already_tokens.user_type == UserType.occupant.value:
already_tokens.selected_occupant = add_payload.model_dump()
return save_object_to_redis(
access_token=access_token,
model_object=OccupantTokenObject(**already_tokens.model_dump()),
)
elif already_tokens.user_type == UserType.employee.value:
already_tokens.selected_company = add_payload.model_dump()
return save_object_to_redis(
access_token=access_token,
model_object=EmployeeTokenObject(**already_tokens.model_dump()),
)
raise HTTPException(
status_code=401,
detail=dict(
message="User type is not found in the token object. Please reach to your administrator."
),
)
def update_access_token_to_redis(request, add_payload):
already_tokens = get_object_via_access_key(request=request)
if not hasattr(request, "headers"):
raise HTTPException(
status_code=401,
detail=dict(
message="Headers are not found in request. Invalid request object."
),
)
payload = {**add_payload, **already_tokens}
access_token = request.headers.get(Auth.ACCESS_TOKEN_TAG)
if payload.get("user_type") == str(UserType.occupant.value):
return save_object_to_redis(
access_token=access_token,
model_object=OccupantTokenObject(**payload),
)
return save_object_to_redis(
access_token=access_token,
model_object=EmployeeTokenObject(**payload),
)

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1,105 @@
from fastapi import HTTPException, status
from fastapi.requests import Request
from database_sql_models import Events
# url_that_not_requires_event_validation = [
# "/authentication/login",
# "/authentication/select",
# "/authentication/valid",
# "/authentication/refresh",
# "/authentication/change_password",
# "/authentication/create_password",
# "/authentication/disconnect",
# "/authentication/logout",
# "/authentication/refresher",
# "/authentication/forgot",
# "/authentication/avatar",
# ]
def parse_token_object_to_dict(request: Request): # from requests import Request
from api_services.redis.functions import get_object_via_access_key
from databases import EndpointRestriction
import api_events.events as events
if valid_token := get_object_via_access_key(request=request):
endpoint_name = str(request.url).replace(str(request.base_url), "/")
endpoint_active = EndpointRestriction.filter_active(
EndpointRestriction.endpoint_name.ilike(f"%{endpoint_name}%")
).data[0]
if not endpoint_active:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="This endpoint is not active for this user, please contact your responsible company for further information.",
)
if valid_token.user_type == 1:
if not valid_token.selected_company:
raise HTTPException(
status_code=status.HTTP_418_IM_A_TEAPOT,
detail="Selected company is not found in the token object.",
)
selected_event = Events.filter_active(
Events.endpoint_id == endpoint_active.id,
Events.id.in_(valid_token.selected_company.reachable_event_list_id),
)
if not selected_event.data:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="This endpoint requires event validation. Please contact your responsible company to use this event.",
)
selected_event = selected_event.data[0]
event_function_class = getattr(selected_event, "function_class", None)
event_function_code = getattr(selected_event, "function_code", None)
function_class = getattr(events, event_function_class, None)
active_function = getattr(
function_class,
function_class.__event_keys__.get(event_function_code, None),
None,
)
if not active_function:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="This endpoint requires event validation. Please contact your responsible company to use this event.",
)
valid_token.available_event = active_function
return valid_token
elif valid_token.user_type == 2:
if not valid_token.selected_occupant:
raise HTTPException(
status_code=status.HTTP_418_IM_A_TEAPOT,
detail="Selected occupant is not found in the token object.",
)
selected_event = Events.filter_active(
Events.endpoint_id == endpoint_active.id,
Events.id.in_(valid_token.selected_occupant.reachable_event_list_id),
)
if not selected_event.data:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="This endpoint requires event validation. Please contact your responsible company to use this event.",
)
selected_event = selected_event.data[0]
event_function_class = getattr(selected_event, "function_class", None)
event_function_code = getattr(selected_event, "function_code", None)
function_class = getattr(events, event_function_class, None)
active_function = getattr(
function_class,
function_class.__event_keys__.get(event_function_code, None),
None,
)
if not active_function:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="This endpoint requires event validation. Please contact your responsible company to use this event.",
)
valid_token.available_event = active_function
return valid_token
valid_token.available_event = None
return valid_token
user_type = "Company" if valid_token.user_type == 1 else "Occupant"
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=f"Token of this user is not valid. Please login and refresh {user_type} selection.",
)

View File

@@ -0,0 +1,31 @@
from redis import Redis
# from configs import WagRedis
from api_configs import WagRedis
class RedisConn:
def __init__(self):
self.redis = Redis(
host=WagRedis.REDIS_HOST,
password=WagRedis.REDIS_PASSWORD,
port=WagRedis.REDIS_PORT,
db=WagRedis.REDIS_DB,
)
if not self.check_connection():
raise Exception("Connection error")
def check_connection(self):
return self.redis.ping()
def set_connection(self, host, password, port, db):
self.redis = Redis(host=host, password=password, port=port, db=db)
return self.redis
try:
redis_conn = RedisConn()
redis_cli = redis_conn.redis
except Exception as e:
print("Redis Connection Error", e)

View File

@@ -0,0 +1,71 @@
import json
import typing
from fastapi import status
from fastapi.exceptions import HTTPException
from .conn import redis_cli
from api_configs import Auth
from api_objects import EmployeeTokenObject, OccupantTokenObject
def get_object_via_access_key(
request,
) -> typing.Union[EmployeeTokenObject, OccupantTokenObject, None]:
if not hasattr(request, "headers"):
raise HTTPException(
status_code=401,
detail=dict(
message="Headers are not found in request. Invalid request object."
),
)
if not request.headers.get(Auth.ACCESS_TOKEN_TAG):
raise HTTPException(
status_code=401,
detail=dict(message="Unauthorized user, please login..."),
)
already_tokens = redis_cli.scan_iter(
match=str(request.headers.get(Auth.ACCESS_TOKEN_TAG) + ":*")
)
if already_tokens := list(already_tokens):
try:
if redis_object := json.loads(
redis_cli.get(already_tokens[0].decode()) or {}
):
if redis_object.get("user_type") == 1:
if not redis_object.get("selected_company", None):
redis_object["selected_company"] = None
return EmployeeTokenObject(**redis_object)
elif redis_object.get("user_type") == 2:
if not redis_object.get("selected_occupant", None):
redis_object["selected_occupant"] = None
return OccupantTokenObject(**redis_object)
raise HTTPException(
status_code=401,
detail=dict(
message="User type is not found in the token object. Please reach to your administrator."
),
)
except Exception as e:
raise HTTPException(
status_code=500,
detail={
"message": "Redis Service raised an exception.",
"error": str(e),
},
)
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid credentials. Please login again.",
)
def get_object_via_user_uu_id(user_id: str) -> typing.Union[list, None]:
already_tokens = redis_cli.scan_iter(match=str("*:" + str(user_id)))
already_tokens = list(already_tokens)
if list(already_tokens):
return list(already_tokens)
return None