new api service and logic implemented

This commit is contained in:
2025-01-23 22:27:25 +03:00
parent d91ecda9df
commit 32022ca521
245 changed files with 28004 additions and 0 deletions

View File

@@ -0,0 +1,16 @@
from ApiLibrary.date_time_actions.date_functions import (
DateTimeLocal,
system_arrow,
client_arrow,
)
from ApiLibrary.extensions.select import SelectActionWithEmployee, SelectAction
from ApiLibrary.common.line_number import get_line_number_for_error
__all__ = [
"DateTimeLocal",
"system_arrow",
"client_arrow",
"get_line_number_for_error",
"SelectActionWithEmployee",
"SelectAction",
]

View File

@@ -0,0 +1,14 @@
"""Utility functions for getting line numbers and file locations."""
from inspect import currentframe, getframeinfo, stack
def get_line_number_for_error() -> str:
"""Get the file name and line number of where an error occurred.
Returns:
str: A string in the format 'filename | line_number' showing where the error occurred
"""
caller = stack()[1] # Get the caller's frame
frameinfo = getframeinfo(caller[0])
return f"{frameinfo.filename} | {frameinfo.lineno}"

View File

@@ -0,0 +1,116 @@
import arrow
import calendar
from AllConfigs.main import MainConfig as Config
class DateTimeLocal:
def __init__(self, timezone: str = None, is_client: bool = True):
if timezone and timezone not in Config.SUPPORTED_TIMEZONES:
raise ValueError(
f"Unsupported timezone: {timezone}. Must be one of {Config.SUPPORTED_TIMEZONES}"
)
self.timezone = Config.SYSTEM_TIMEZONE
if is_client:
self.timezone = (timezone or Config.DEFAULT_TIMEZONE).replace("-", "+")
def find_last_day_of_month(self, date_value):
today = self.get(date_value).date()
_, last_day = calendar.monthrange(today.year, today.month)
return self.get(today.year, today.month, last_day, 23, 59, 59).to(self.timezone)
def find_first_day_of_month(self, date_value):
today = self.get(date_value).date()
return self.get(today.year, today.month, 1).to(self.timezone)
def get(self, *args):
return arrow.get(*args).to(str(self.timezone))
def now(self):
return arrow.now().to(str(self.timezone))
def shift(self, date, **kwargs):
return self.get(date).shift(**kwargs)
def date(self, date):
return self.get(date).date()
def time(self, date):
return self.get(date).time()
def string_date(self, date, splitter: str = "-"):
return str(self.get(date).date()).replace("-", splitter)
def string_time_only(self, date):
return self.get(date).format("HH:mm:ss")
def string_date_only(self, date):
return self.get(date).format("YYYY-MM-DD")
def to_timestamp(self, date):
"""Convert datetime to UTC timestamp"""
return self.get(date).timestamp()
def from_timestamp(self, timestamp):
"""Convert timestamp to timezone-aware datetime"""
return arrow.get(timestamp).to(str(self.timezone))
def is_timezone_aware(self, date):
"""Check if a date is timezone-aware"""
return self.get(date).tzinfo is not None
def standardize_timezone(self, date):
"""Ensure date is in the correct timezone"""
if not self.is_timezone_aware(date):
return self.get(date).to(str(self.timezone))
return self.get(date)
def get_expiry_time(self, **kwargs):
"""Get future time for cache expiry
Example: get_expiry_time(hours=1, minutes=30)
"""
return self.now().shift(**kwargs)
def is_expired(self, timestamp):
"""Check if a timestamp is expired"""
if not timestamp:
return True
return self.from_timestamp(timestamp) < self.now()
def get_cache_key(self, base_key, *args):
"""Generate a cache key with timezone info
Example: get_cache_key('user_profile', user_id, 'details')
"""
components = [str(base_key)]
components.extend(str(arg) for arg in args)
components.append(f"tz_{self.timezone}")
return ":".join(components)
def format_for_db(self, date):
"""Format date for database storage"""
return self.get(date).format("YYYY-MM-DD HH:mm:ss.SSSZZ")
def parse_from_db(self, date_str):
"""Parse date from database format"""
if not date_str:
return None
return self.get(date_str)
def get_day_boundaries(self, date=None):
"""Get start and end of day in current timezone"""
dt = self.get(date) if date else self.now()
start = dt.floor("day")
end = dt.ceil("day")
return start, end
def get_month_boundaries(self, date=None):
"""Get start and end of month in current timezone"""
dt = self.get(date) if date else self.now()
start = dt.floor("month")
end = dt.ceil("month")
return start, end
client_arrow = DateTimeLocal(is_client=True)
system_arrow = DateTimeLocal(is_client=False)

View File

@@ -0,0 +1,76 @@
class SelectorsBase:
@classmethod
def add_confirmed_filter(cls, first_table, second_table) -> tuple:
return (
first_table.active == True,
first_table.is_confirmed == True,
first_table.deleted == False,
second_table.active == True,
second_table.is_confirmed == True,
second_table.deleted == False,
)
class SelectActionWithEmployee:
@classmethod
def select_action(cls, employee_id, filter_expr: list = None):
if filter_expr is not None:
filter_expr = (cls.__many__table__.employee_id == employee_id, *filter_expr)
data = (
cls.session.query(cls.id)
.select_from(cls)
.join(cls.__many__table__, cls.__many__table__.member_id == cls.id)
.filter(
*filter_expr,
*SelectorsBase.add_confirmed_filter(
first_table=cls, second_table=cls.__many__table__
),
)
)
return cls.query.filter(cls.id.in_([comp[0] for comp in data.all()]))
data = (
cls.session.query(cls.id)
.select_from(cls)
.join(cls.__many__table__, cls.__many__table__.member_id == cls.id)
.filter(
cls.__many__table__.employee_id == employee_id,
*SelectorsBase.add_confirmed_filter(
first_table=cls, second_table=cls.__many__table__
),
)
)
return cls.query.filter(cls.id.in_([comp[0] for comp in data.all()]))
class SelectAction:
@classmethod
def select_action(cls, duty_id_list: list, filter_expr: list = None):
if filter_expr is not None:
data = (
cls.session.query(cls.id)
.select_from(cls)
.join(cls.__many__table__, cls.__many__table__.member_id == cls.id)
.filter(
cls.__many__table__.duties_id.in_(duty_id_list),
*SelectorsBase.add_confirmed_filter(
first_table=cls, second_table=cls.__many__table__
),
*filter_expr,
)
)
return cls.query.filter(cls.id.in_([comp[0] for comp in data.all()]))
data = (
cls.session.query(cls.id)
.select_from(cls)
.join(cls.__many__table__, cls.__many__table__.member_id == cls.id)
.filter(
cls.__many__table__.duties_id.in_(duty_id_list),
*SelectorsBase.add_confirmed_filter(
first_table=cls, second_table=cls.__many__table__
),
)
)
return cls.query.filter(cls.id.in_([comp[0] for comp in data.all()]))

View File

@@ -0,0 +1,43 @@
import hashlib
import uuid
import secrets
import random
from AllConfigs.Token.config import Auth
class PasswordModule:
@staticmethod
def generate_random_uu_id(str_std: bool = True):
return str(uuid.uuid4()) if str_std else uuid.uuid4()
@staticmethod
def generate_token(length=32):
letters = "abcdefghijklmnopqrstuvwxyz"
merged_letters = [letter for letter in letters] + [
letter.upper() for letter in letters
]
token_generated = secrets.token_urlsafe(length)
for i in str(token_generated):
if i not in merged_letters:
token_generated = token_generated.replace(
i, random.choice(merged_letters), 1
)
return token_generated
@staticmethod
def generate_access_token():
return secrets.token_urlsafe(Auth.ACCESS_TOKEN_LENGTH)
@staticmethod
def generate_refresher_token():
return secrets.token_urlsafe(Auth.REFRESHER_TOKEN_LENGTH)
@staticmethod
def create_hashed_password(domain: str, id_: str, password: str):
return hashlib.sha256(f"{domain}:{id_}:{password}".encode("utf-8")).hexdigest()
@classmethod
def check_password(cls, domain, id_, password, password_hashed):
return cls.create_hashed_password(domain, id_, password) == password_hashed