Web service initiated
|
|
@ -17,9 +17,8 @@ RUN poetry config virtualenvs.create false \
|
|||
# Copy application code
|
||||
COPY /ApiServices/AuthService /ApiServices/AuthService
|
||||
COPY /Controllers /Controllers
|
||||
COPY /Schemas/building /Schemas/building
|
||||
COPY /Schemas/company /Schemas/company
|
||||
COPY /Schemas/identity /Schemas/identity
|
||||
COPY /Modules /Modules
|
||||
COPY /Schemas /Schemas
|
||||
|
||||
# Set Python path to include app directory
|
||||
ENV PYTHONPATH=/ PYTHONUNBUFFERED=1 PYTHONDONTWRITEBYTECODE=1
|
||||
|
|
|
|||
|
|
@ -8,10 +8,7 @@ class RouteRegisterController:
|
|||
self.router_list = router_list
|
||||
self.app = app
|
||||
|
||||
|
||||
|
||||
def register_routes(self):
|
||||
for router in self.router_list:
|
||||
self.app.include_router(router)
|
||||
self.add_router_to_database(router)
|
||||
return self.app
|
||||
|
|
|
|||
|
|
@ -13,13 +13,12 @@ from ApiServices.AuthService.validations.request.authentication.login_post impor
|
|||
RequestChangePassword,
|
||||
RequestForgotPasswordPhone,
|
||||
RequestForgotPasswordEmail,
|
||||
RequestVerifyOTP,
|
||||
)
|
||||
from ApiServices.AuthService.events.auth.auth import AuthHandlers
|
||||
|
||||
|
||||
auth_route = APIRouter(
|
||||
prefix="/authentication",
|
||||
tags=["Authentication Cluster"],
|
||||
)
|
||||
auth_route = APIRouter(prefix="/authentication", tags=["Authentication Cluster"])
|
||||
|
||||
|
||||
@auth_route.post(
|
||||
|
|
@ -49,8 +48,12 @@ def authentication_login_post(
|
|||
status_code=status.HTTP_406_NOT_ACCEPTABLE,
|
||||
headers=headers,
|
||||
)
|
||||
result = AuthHandlers.LoginHandler.authentication_login_with_domain_and_creds(
|
||||
request=request,
|
||||
data=data,
|
||||
)
|
||||
return JSONResponse(
|
||||
content={**data.model_dump()},
|
||||
content=result,
|
||||
status_code=status.HTTP_202_ACCEPTED,
|
||||
headers=headers,
|
||||
)
|
||||
|
|
@ -84,9 +87,12 @@ def authentication_select_post(
|
|||
status_code=status.HTTP_406_NOT_ACCEPTABLE,
|
||||
headers=headers,
|
||||
)
|
||||
|
||||
result = AuthHandlers.LoginHandler.authentication_select_company_or_occupant_type(
|
||||
request=request,
|
||||
data=data,
|
||||
)
|
||||
return JSONResponse(
|
||||
content=data.model_dump(),
|
||||
content=result,
|
||||
status_code=status.HTTP_202_ACCEPTED,
|
||||
headers=headers,
|
||||
)
|
||||
|
|
@ -107,13 +113,15 @@ def authentication_password_create_post(
|
|||
"""
|
||||
Authentication create password Route with Post Method
|
||||
"""
|
||||
token = request.headers.get(api_config.ACCESS_TOKEN_TAG, None)
|
||||
headers = {
|
||||
"language": language or "",
|
||||
"domain": domain or "",
|
||||
"eys-ext": f"{str(uuid.uuid4())}",
|
||||
"token": token,
|
||||
}
|
||||
result = AuthHandlers.PasswordHandler.create_password(
|
||||
password=data.password,
|
||||
password_token=data.password_token,
|
||||
)
|
||||
if not domain or not language:
|
||||
return JSONResponse(
|
||||
content={"error": "EYS_0001"},
|
||||
|
|
@ -121,7 +129,7 @@ def authentication_password_create_post(
|
|||
headers=headers,
|
||||
)
|
||||
return JSONResponse(
|
||||
content={**data.model_dump()},
|
||||
content={},
|
||||
status_code=status.HTTP_202_ACCEPTED,
|
||||
headers=headers,
|
||||
)
|
||||
|
|
@ -333,3 +341,41 @@ def authentication_token_refresh_post(
|
|||
status_code=status.HTTP_202_ACCEPTED,
|
||||
headers=headers,
|
||||
)
|
||||
|
||||
|
||||
@auth_route.get(
|
||||
path="/password/verify-otp",
|
||||
summary="Verify OTP for password reset",
|
||||
description="Verify OTP for password reset",
|
||||
)
|
||||
def authentication_password_verify_otp(
|
||||
request: Request,
|
||||
data: RequestVerifyOTP,
|
||||
language: str = Header(None, alias="language"),
|
||||
domain: str = Header(None, alias="domain"),
|
||||
tz: str = Header(None, alias="timezone"),
|
||||
):
|
||||
"""
|
||||
Verify OTP for password reset
|
||||
"""
|
||||
|
||||
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,
|
||||
}
|
||||
print('Token&OTP : ', data.otp, data.token)
|
||||
if not domain or not language:
|
||||
return JSONResponse(
|
||||
content={"error": "EYS_0003"},
|
||||
status_code=status.HTTP_406_NOT_ACCEPTABLE,
|
||||
headers=headers,
|
||||
)
|
||||
return JSONResponse(
|
||||
content={},
|
||||
status_code=status.HTTP_202_ACCEPTED,
|
||||
headers=headers,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -16,4 +16,7 @@ def get_safe_endpoint_urls() -> list[tuple[str, str]]:
|
|||
("/auth/login", "POST"),
|
||||
("/metrics", "GET"),
|
||||
("/authentication/login", "POST"),
|
||||
("/authentication/password/reset", "POST"),
|
||||
("/authentication/password/create", "POST"),
|
||||
("/authentication/password/verify-otp", "POST"),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
from typing import Any, List, Dict, Optional, Union
|
||||
import arrow
|
||||
|
||||
from typing import Any, Dict, Optional, Union
|
||||
from ApiServices.AuthService.events.auth.model import PasswordHistoryViaUser
|
||||
from ApiServices.AuthService.validations.custom.token import (
|
||||
EmployeeTokenObject,
|
||||
OccupantTokenObject,
|
||||
|
|
@ -6,7 +9,7 @@ from ApiServices.AuthService.validations.custom.token import (
|
|||
OccupantToken,
|
||||
UserType,
|
||||
)
|
||||
from ApiServices.TemplateService.config import api_config
|
||||
from ApiServices.AuthService.config import api_config
|
||||
from Schemas import (
|
||||
Users,
|
||||
People,
|
||||
|
|
@ -25,12 +28,14 @@ from Schemas import (
|
|||
Event2Employee,
|
||||
)
|
||||
from Modules.Token.password_module import PasswordModule
|
||||
from Controllers.Redis.database import RedisActions
|
||||
from Schemas.building.build import RelationshipEmployee2Build
|
||||
from Schemas.event.event import Event2Occupant
|
||||
from Controllers.Redis.database import RedisActions
|
||||
from Controllers.Mongo.database import mongo_handler
|
||||
|
||||
TokenDictType = Union[EmployeeTokenObject, OccupantTokenObject]
|
||||
|
||||
|
||||
class RedisHandlers:
|
||||
AUTH_TOKEN: str = "AUTH_TOKEN"
|
||||
|
||||
|
|
@ -63,7 +68,7 @@ class RedisHandlers:
|
|||
result_delete = RedisActions.delete(
|
||||
list_keys=[RedisHandlers.AUTH_TOKEN, "*", str(user.uu_id)]
|
||||
)
|
||||
print('result_delete', result_delete)
|
||||
print("result_delete", result_delete)
|
||||
generated_access_token = PasswordModule.generate_access_token()
|
||||
keys = [RedisHandlers.AUTH_TOKEN, generated_access_token, str(user.uu_id)]
|
||||
RedisActions.set_json(
|
||||
|
|
@ -74,20 +79,27 @@ class RedisHandlers:
|
|||
return generated_access_token
|
||||
|
||||
@classmethod
|
||||
def update_token_at_redis(cls, token: str, add_payload: Union[CompanyToken, OccupantToken]):
|
||||
def update_token_at_redis(
|
||||
cls, token: str, add_payload: Union[CompanyToken, OccupantToken]
|
||||
):
|
||||
if already_token_data := RedisActions.get_json(
|
||||
list_keys=[RedisHandlers.AUTH_TOKEN, token, "*"]
|
||||
).first:
|
||||
already_token = cls.process_redis_object(**already_token_data)
|
||||
if already_token.is_employee:
|
||||
already_token = cls.process_redis_object(already_token_data)
|
||||
if already_token.is_employee and isinstance(add_payload, CompanyToken):
|
||||
already_token.selected_company = add_payload
|
||||
elif already_token.is_occupant:
|
||||
elif already_token.is_occupant and isinstance(add_payload, OccupantToken):
|
||||
already_token.selected_occupant = add_payload
|
||||
result = RedisActions.set_json(
|
||||
list_keys=[RedisHandlers.AUTH_TOKEN, token, str(already_token.user_uu_id)],
|
||||
list_keys=[
|
||||
RedisHandlers.AUTH_TOKEN,
|
||||
token,
|
||||
str(already_token.user_uu_id),
|
||||
],
|
||||
value=already_token.model_dump(),
|
||||
expires={"hours": 1, "minutes": 30},
|
||||
)
|
||||
print("result.first", result.first)
|
||||
return result.first
|
||||
raise ValueError("Something went wrong")
|
||||
|
||||
|
|
@ -118,6 +130,14 @@ class UserHandlers:
|
|||
"""
|
||||
Check if the password is valid.
|
||||
"""
|
||||
print(
|
||||
dict(
|
||||
domain=domain,
|
||||
id_=id_,
|
||||
password=password,
|
||||
password_hashed=password_hashed,
|
||||
)
|
||||
)
|
||||
if PasswordModule.check_password(
|
||||
domain=domain, id_=id_, password=password, password_hashed=password_hashed
|
||||
):
|
||||
|
|
@ -135,7 +155,6 @@ class LoginHandler:
|
|||
def is_employee(email: str):
|
||||
return str(email).split("@")[1] == api_config.ACCESS_EMAIL_EXT
|
||||
|
||||
|
||||
@classmethod
|
||||
def do_employee_login(
|
||||
cls, request: Any, data: Any, extra_dict: Optional[Dict[str, Any]] = None
|
||||
|
|
@ -154,10 +173,10 @@ class LoginHandler:
|
|||
)
|
||||
|
||||
if not user_handler.check_password_valid(
|
||||
domain=data.domain,
|
||||
domain=domain or "",
|
||||
id_=str(found_user.uu_id),
|
||||
password=data.password,
|
||||
password_hashed=found_user.hash_password
|
||||
password_hashed=found_user.hash_password,
|
||||
):
|
||||
raise ValueError("EYS_0005")
|
||||
|
||||
|
|
@ -230,6 +249,20 @@ class LoginHandler:
|
|||
return {
|
||||
"access_token": access_token,
|
||||
"user_type": UserType.employee.name,
|
||||
"user": found_user.get_dict(
|
||||
exclude_list=[
|
||||
Users.hash_password,
|
||||
Users.cryp_uu_id,
|
||||
Users.password_token,
|
||||
Users.created_credentials_token,
|
||||
Users.updated_credentials_token,
|
||||
Users.confirmed_credentials_token,
|
||||
Users.is_confirmed,
|
||||
Users.is_notification_send,
|
||||
Users.is_email_send,
|
||||
Users.remember_me,
|
||||
]
|
||||
),
|
||||
"selection_list": companies_list,
|
||||
}
|
||||
raise ValueError("Something went wrong")
|
||||
|
|
@ -254,7 +287,7 @@ class LoginHandler:
|
|||
domain=data.domain,
|
||||
id_=str(found_user.uu_id),
|
||||
password=data.password,
|
||||
password_hashed=found_user.hash_password
|
||||
password_hashed=found_user.hash_password,
|
||||
):
|
||||
raise ValueError("EYS_0005")
|
||||
|
||||
|
|
@ -300,7 +333,9 @@ class LoginHandler:
|
|||
"occupants": [occupant_data],
|
||||
}
|
||||
else:
|
||||
occupants_selection_dict[build_key]["occupants"].append(occupant_data)
|
||||
occupants_selection_dict[build_key]["occupants"].append(
|
||||
occupant_data
|
||||
)
|
||||
|
||||
person = found_user.person
|
||||
model_value = OccupantTokenObject(
|
||||
|
|
@ -344,9 +379,9 @@ class LoginHandler:
|
|||
Returns:
|
||||
SuccessResponse containing authentication token and user info
|
||||
"""
|
||||
language = request.headers("language", "tr")
|
||||
domain = request.headers("domain", None)
|
||||
timezone = request.headers("tz", None) or "GMT+3"
|
||||
language = request.headers.get("language", "tr")
|
||||
domain = request.headers.get("domain", None)
|
||||
timezone = request.headers.get("tz", None) or "GMT+3"
|
||||
|
||||
if cls.is_employee(data.access_key):
|
||||
return cls.do_employee_login(
|
||||
|
|
@ -386,7 +421,9 @@ class LoginHandler:
|
|||
return request.headers.get(api_config.ACCESS_TOKEN_TAG)
|
||||
|
||||
@classmethod
|
||||
def handle_employee_selection(cls, access_token: str, data: Any, token_dict: TokenDictType):
|
||||
def handle_employee_selection(
|
||||
cls, access_token: str, data: Any, token_dict: TokenDictType
|
||||
):
|
||||
with Users.new_session() as db:
|
||||
if data.company_uu_id not in token_dict.companies_uu_id_list:
|
||||
ValueError("EYS_0011")
|
||||
|
|
@ -407,7 +444,9 @@ class LoginHandler:
|
|||
# Get staff IDs
|
||||
staff_ids = [
|
||||
staff.id
|
||||
for staff in Staff.filter_all(Staff.duties_id.in_(duties_ids), db=db).data
|
||||
for staff in Staff.filter_all(
|
||||
Staff.duties_id.in_(duties_ids), db=db
|
||||
).data
|
||||
]
|
||||
|
||||
# Get employee
|
||||
|
|
@ -456,13 +495,12 @@ class LoginHandler:
|
|||
reachable_event_codes=reachable_event_codes,
|
||||
)
|
||||
redis_handler = RedisHandlers()
|
||||
try: # Update Redis
|
||||
return redis_handler.update_token_at_redis(
|
||||
redis_result = redis_handler.update_token_at_redis(
|
||||
token=access_token, add_payload=company_token
|
||||
)
|
||||
except Exception as e:
|
||||
err = e
|
||||
ValueError("EYS_0008")
|
||||
return {
|
||||
"selected_uu_id": data.company_uu_id,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def handle_occupant_selection(
|
||||
|
|
@ -526,12 +564,12 @@ class LoginHandler:
|
|||
reachable_event_codes=reachable_event_codes,
|
||||
)
|
||||
redis_handler = RedisHandlers()
|
||||
try: # Update Redis
|
||||
return redis_handler.update_token_at_redis(
|
||||
redis_handler.update_token_at_redis(
|
||||
token=access_token, add_payload=occupant_token
|
||||
)
|
||||
except Exception as e:
|
||||
raise ValueError("EYS_0008")
|
||||
return {
|
||||
"selected_uu_id": data.company_uu_id,
|
||||
}
|
||||
|
||||
@classmethod # Requires auth context
|
||||
def authentication_select_company_or_occupant_type(cls, request: Any, data: Any):
|
||||
|
|
@ -549,16 +587,119 @@ class LoginHandler:
|
|||
if not access_token:
|
||||
raise ValueError("EYS_0001")
|
||||
|
||||
token_object = RedisHandlers().get_object_from_redis(access_token=access_token)
|
||||
if token_object.is_employee and isinstance(data, CompanyToken):
|
||||
token_object = RedisHandlers.get_object_from_redis(access_token=access_token)
|
||||
if token_object.is_employee:
|
||||
return cls.handle_employee_selection(
|
||||
access_token=access_token, data=data, token_dict=token_object,
|
||||
access_token=access_token,
|
||||
data=data,
|
||||
token_dict=token_object,
|
||||
)
|
||||
elif token_object.is_occupant and isinstance(data, OccupantToken):
|
||||
elif token_object.is_occupant:
|
||||
return cls.handle_occupant_selection(
|
||||
access_token=access_token, data=data, token_dict=token_object,
|
||||
access_token=access_token,
|
||||
data=data,
|
||||
token_dict=token_object,
|
||||
)
|
||||
|
||||
|
||||
class PasswordHandler:
|
||||
|
||||
@staticmethod
|
||||
def create_password(password, password_token=None):
|
||||
with Users.new_session() as db_session:
|
||||
found_user = Users.filter_one(
|
||||
Users.password_token == password_token, db=db_session
|
||||
).data
|
||||
if not found_user:
|
||||
raise ValueError("EYS_0031")
|
||||
|
||||
if found_user.password_token:
|
||||
replace_day = 0
|
||||
try:
|
||||
replace_day = int(
|
||||
str(found_user.password_expires_day or 0)
|
||||
.split(",")[0]
|
||||
.replace(" days", "")
|
||||
)
|
||||
except Exception as e:
|
||||
err = e
|
||||
token_is_expired = arrow.now() >= arrow.get(
|
||||
str(found_user.password_expiry_begins)
|
||||
).shift(days=replace_day)
|
||||
|
||||
if not password_token == found_user.password_token and token_is_expired:
|
||||
raise ValueError("")
|
||||
|
||||
collection_name = f"{found_user.related_company}*Domain"
|
||||
print("collection_name", collection_name)
|
||||
with mongo_handler.collection(collection_name) as mongo_engine:
|
||||
print({"user_uu_id": str(found_user.uu_id)})
|
||||
domain_via_user = mongo_engine.find_one(
|
||||
{"user_uu_id": str(found_user.uu_id)}
|
||||
)
|
||||
print("domain_via_user", domain_via_user)
|
||||
if not domain_via_user:
|
||||
raise ValueError("EYS_0024")
|
||||
domain_via_user = domain_via_user.get("main_domain", None)
|
||||
new_password_dict = {
|
||||
"password": PasswordModule.create_hashed_password(
|
||||
domain=domain_via_user,
|
||||
id_=str(found_user.uu_id),
|
||||
password=password,
|
||||
),
|
||||
"date": str(arrow.now().date()),
|
||||
}
|
||||
history_dict = PasswordHistoryViaUser(
|
||||
user_uu_id=str(found_user.uu_id),
|
||||
password_add=new_password_dict,
|
||||
access_history_detail={"request": "", "ip": ""},
|
||||
)
|
||||
found_user.password_expiry_begins = str(arrow.now())
|
||||
found_user.hash_password = new_password_dict.get("password")
|
||||
found_user.password_token = "" if found_user.password_token else ""
|
||||
|
||||
collection_name = f"{found_user.related_company}*PasswordHistory"
|
||||
with mongo_handler.collection(collection_name) as mongo_engine_sc:
|
||||
password_history_item = mongo_engine_sc.find_one(
|
||||
{"user_uu_id": str(found_user.uu_id)}
|
||||
)
|
||||
if not password_history_item:
|
||||
mongo_engine_sc.insert_one(
|
||||
document={
|
||||
"user_uu_id": str(found_user.uu_id),
|
||||
"password_history": [],
|
||||
}
|
||||
)
|
||||
password_history_item = mongo_engine_sc.find_one(
|
||||
{"user_uu_id": str(found_user.uu_id)}
|
||||
)
|
||||
password_history_list = password_history_item.get(
|
||||
"password_history", []
|
||||
)
|
||||
hashed_password = history_dict.password_add.get("password")
|
||||
for password_in_history in password_history_list:
|
||||
if str(password_in_history.get("password")) == str(
|
||||
hashed_password
|
||||
):
|
||||
raise ValueError("EYS_0032")
|
||||
if len(password_history_list) > 3:
|
||||
password_history_list.pop(0)
|
||||
password_history_list.append(history_dict.password_add)
|
||||
return mongo_engine_sc.update_one(
|
||||
filter={"user_uu_id": str(found_user.uu_id)},
|
||||
update={
|
||||
"$set": {
|
||||
"password_history": password_history_list,
|
||||
"modified_at": arrow.now().timestamp(),
|
||||
"access_history_detail": history_dict.access_history_detail,
|
||||
}
|
||||
},
|
||||
upsert=True,
|
||||
)
|
||||
found_user.save(db=db_session)
|
||||
return found_user
|
||||
|
||||
|
||||
class AuthHandlers:
|
||||
LoginHandler: LoginHandler = LoginHandler()
|
||||
PasswordHandler: PasswordHandler = PasswordHandler()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
from typing import Optional
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class DomainViaUser(BaseModel):
|
||||
user_uu_id: str
|
||||
main_domain: str
|
||||
other_domains_list: Optional[list] = None
|
||||
|
||||
|
||||
class PasswordHistoryViaUser(BaseModel):
|
||||
user_uu_id: str
|
||||
password_add: dict
|
||||
access_history_detail: Optional[dict]
|
||||
|
||||
|
||||
class AccessHistoryViaUser(BaseModel):
|
||||
user_uu_id: str
|
||||
access_history: dict
|
||||
|
|
@ -5,8 +5,7 @@ from ..config import api_config
|
|||
|
||||
|
||||
async def token_middleware(request: Request, call_next):
|
||||
|
||||
base_url = "/".join(request.url.path.split("/")[:3])
|
||||
base_url = request.url.path
|
||||
safe_endpoints = [_[0] for _ in get_safe_endpoint_urls()]
|
||||
if base_url in safe_endpoints:
|
||||
return await call_next(request)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,11 @@ class RequestLogin(BaseModel):
|
|||
remember_me: Optional[bool]
|
||||
|
||||
|
||||
class RequestVerifyOTP(BaseModel):
|
||||
token: str
|
||||
otp: str
|
||||
|
||||
|
||||
class RequestSelectOccupant(BaseModel):
|
||||
|
||||
company_uu_id: str
|
||||
|
|
|
|||
|
|
@ -16,10 +16,10 @@ RUN poetry config virtualenvs.create false \
|
|||
|
||||
# Copy application code
|
||||
COPY /ApiServices/InitialService /ApiServices/InitialService
|
||||
COPY /ApiServices/InitialService /
|
||||
COPY /Controllers /Controllers
|
||||
COPY /Schemas/building /Schemas/building
|
||||
COPY /Schemas/company /Schemas/company
|
||||
COPY /Schemas/identity /Schemas/identity
|
||||
COPY /Modules /Modules
|
||||
COPY /Schemas /Schemas
|
||||
|
||||
# Set Python path to include app directory
|
||||
ENV PYTHONPATH=/ PYTHONUNBUFFERED=1 PYTHONDONTWRITEBYTECODE=1
|
||||
|
|
|
|||
|
|
@ -0,0 +1,119 @@
|
|||
# A generic, single database configuration.
|
||||
|
||||
[alembic]
|
||||
# path to migration scripts
|
||||
# Use forward slashes (/) also on windows to provide an os agnostic path
|
||||
script_location = alembic
|
||||
|
||||
# template used to generate migration file names; The default value is %%(rev)s_%%(slug)s
|
||||
# Uncomment the line below if you want the files to be prepended with date and time
|
||||
# see https://alembic.sqlalchemy.org/en/latest/tutorial.html#editing-the-ini-file
|
||||
# for all available tokens
|
||||
# file_template = %%(year)d_%%(month).2d_%%(day).2d_%%(hour).2d%%(minute).2d-%%(rev)s_%%(slug)s
|
||||
|
||||
# sys.path path, will be prepended to sys.path if present.
|
||||
# defaults to the current working directory.
|
||||
prepend_sys_path = .
|
||||
|
||||
# timezone to use when rendering the date within the migration file
|
||||
# as well as the filename.
|
||||
# If specified, requires the python>=3.9 or backports.zoneinfo library and tzdata library.
|
||||
# Any required deps can installed by adding `alembic[tz]` to the pip requirements
|
||||
# string value is passed to ZoneInfo()
|
||||
# leave blank for localtime
|
||||
# timezone =
|
||||
|
||||
# max length of characters to apply to the "slug" field
|
||||
# truncate_slug_length = 40
|
||||
|
||||
# set to 'true' to run the environment during
|
||||
# the 'revision' command, regardless of autogenerate
|
||||
# revision_environment = false
|
||||
|
||||
# set to 'true' to allow .pyc and .pyo files without
|
||||
# a source .py file to be detected as revisions in the
|
||||
# versions/ directory
|
||||
# sourceless = false
|
||||
|
||||
# version location specification; This defaults
|
||||
# to alembic/versions. When using multiple version
|
||||
# directories, initial revisions must be specified with --version-path.
|
||||
# The path separator used here should be the separator specified by "version_path_separator" below.
|
||||
# version_locations = %(here)s/bar:%(here)s/bat:alembic/versions
|
||||
|
||||
# version path separator; As mentioned above, this is the character used to split
|
||||
# version_locations. The default within new alembic.ini files is "os", which uses os.pathsep.
|
||||
# If this key is omitted entirely, it falls back to the legacy behavior of splitting on spaces and/or commas.
|
||||
# Valid values for version_path_separator are:
|
||||
#
|
||||
# version_path_separator = :
|
||||
# version_path_separator = ;
|
||||
# version_path_separator = space
|
||||
# version_path_separator = newline
|
||||
#
|
||||
# Use os.pathsep. Default configuration used for new projects.
|
||||
version_path_separator = os
|
||||
|
||||
# set to 'true' to search source files recursively
|
||||
# in each "version_locations" directory
|
||||
# new in Alembic version 1.10
|
||||
# recursive_version_locations = false
|
||||
|
||||
# the output encoding used when revision files
|
||||
# are written from script.py.mako
|
||||
# output_encoding = utf-8
|
||||
|
||||
sqlalchemy.url = postgresql+psycopg2://berkay_wag_user:berkay_wag_user_password@postgres-service:5432/wag_database
|
||||
|
||||
|
||||
[post_write_hooks]
|
||||
# post_write_hooks defines scripts or Python functions that are run
|
||||
# on newly generated revision scripts. See the documentation for further
|
||||
# detail and examples
|
||||
|
||||
# format using "black" - use the console_scripts runner, against the "black" entrypoint
|
||||
# hooks = black
|
||||
# black.type = console_scripts
|
||||
# black.entrypoint = black
|
||||
# black.options = -l 79 REVISION_SCRIPT_FILENAME
|
||||
|
||||
# lint with attempts to fix using "ruff" - use the exec runner, execute a binary
|
||||
# hooks = ruff
|
||||
# ruff.type = exec
|
||||
# ruff.executable = %(here)s/.venv/bin/ruff
|
||||
# ruff.options = check --fix REVISION_SCRIPT_FILENAME
|
||||
|
||||
# Logging configuration
|
||||
[loggers]
|
||||
keys = root,sqlalchemy,alembic
|
||||
|
||||
[handlers]
|
||||
keys = console
|
||||
|
||||
[formatters]
|
||||
keys = generic
|
||||
|
||||
[logger_root]
|
||||
level = WARNING
|
||||
handlers = console
|
||||
qualname =
|
||||
|
||||
[logger_sqlalchemy]
|
||||
level = WARNING
|
||||
handlers =
|
||||
qualname = sqlalchemy.engine
|
||||
|
||||
[logger_alembic]
|
||||
level = INFO
|
||||
handlers =
|
||||
qualname = alembic
|
||||
|
||||
[handler_console]
|
||||
class = StreamHandler
|
||||
args = (sys.stderr,)
|
||||
level = NOTSET
|
||||
formatter = generic
|
||||
|
||||
[formatter_generic]
|
||||
format = %(levelname)-5.5s [%(name)s] %(message)s
|
||||
datefmt = %H:%M:%S
|
||||
|
|
@ -0,0 +1 @@
|
|||
Generic single-database configuration.
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
from logging.config import fileConfig
|
||||
|
||||
from sqlalchemy import engine_from_config
|
||||
from sqlalchemy import pool
|
||||
|
||||
from alembic import context
|
||||
from Schemas import *
|
||||
from Controllers.Postgres.database import Base
|
||||
|
||||
# this is the Alembic Config object, which provides
|
||||
# access to the values within the .ini file in use.
|
||||
config = context.config
|
||||
|
||||
# Interpret the config file for Python logging.
|
||||
# This line sets up loggers basically.
|
||||
if config.config_file_name is not None:
|
||||
fileConfig(config.config_file_name)
|
||||
|
||||
target_metadata = Base.metadata
|
||||
|
||||
# other values from the config, defined by the needs of env.py,
|
||||
# can be acquired:
|
||||
# my_important_option = config.get_main_option("my_important_option")
|
||||
# ... etc.
|
||||
|
||||
|
||||
def run_migrations_offline() -> None:
|
||||
"""Run migrations in 'offline' mode.
|
||||
|
||||
This configures the context with just a URL
|
||||
and not an Engine, though an Engine is acceptable
|
||||
here as well. By skipping the Engine creation
|
||||
we don't even need a DBAPI to be available.
|
||||
|
||||
Calls to context.execute() here emit the given string to the
|
||||
script output.
|
||||
|
||||
"""
|
||||
url = config.get_main_option("sqlalchemy.url")
|
||||
context.configure(
|
||||
url=url,
|
||||
target_metadata=target_metadata,
|
||||
literal_binds=True,
|
||||
dialect_opts={"paramstyle": "named"},
|
||||
)
|
||||
|
||||
with context.begin_transaction():
|
||||
context.run_migrations()
|
||||
|
||||
|
||||
def run_migrations_online() -> None:
|
||||
"""Run migrations in 'online' mode.
|
||||
|
||||
In this scenario we need to create an Engine
|
||||
and associate a connection with the context.
|
||||
|
||||
"""
|
||||
connectable = engine_from_config(
|
||||
config.get_section(config.config_ini_section, {}),
|
||||
prefix="sqlalchemy.",
|
||||
poolclass=pool.NullPool,
|
||||
)
|
||||
|
||||
with connectable.connect() as connection:
|
||||
context.configure(connection=connection, target_metadata=target_metadata)
|
||||
|
||||
with context.begin_transaction():
|
||||
context.run_migrations()
|
||||
|
||||
|
||||
if context.is_offline_mode():
|
||||
run_migrations_offline()
|
||||
else:
|
||||
run_migrations_online()
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
"""${message}
|
||||
|
||||
Revision ID: ${up_revision}
|
||||
Revises: ${down_revision | comma,n}
|
||||
Create Date: ${create_date}
|
||||
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
${imports if imports else ""}
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = ${repr(up_revision)}
|
||||
down_revision: Union[str, None] = ${repr(down_revision)}
|
||||
branch_labels: Union[str, Sequence[str], None] = ${repr(branch_labels)}
|
||||
depends_on: Union[str, Sequence[str], None] = ${repr(depends_on)}
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
"""Upgrade schema."""
|
||||
${upgrades if upgrades else "pass"}
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
"""Downgrade schema."""
|
||||
${downgrades if downgrades else "pass"}
|
||||
|
|
@ -1,18 +1,21 @@
|
|||
from Schemas import (
|
||||
BuildLivingSpace,
|
||||
BuildParts,
|
||||
Companies,
|
||||
Departments,
|
||||
Duties,
|
||||
Duty,
|
||||
Staff,
|
||||
Employees,
|
||||
Event2Employee,
|
||||
Event2Occupant,
|
||||
OccupantTypes,
|
||||
Users,
|
||||
UsersTokens,
|
||||
)
|
||||
from Controllers.Postgres.database import get_db
|
||||
|
||||
from init_app_defaults import create_application_defaults
|
||||
from init_enums import init_api_enums_build_types
|
||||
from init_alembic import generate_alembic
|
||||
from init_occupant_types import create_occupant_types_defaults
|
||||
from init_services import create_modules_and_services_and_actions
|
||||
from init_address import create_one_address
|
||||
|
||||
set_alembic = True
|
||||
|
||||
if __name__ == "__main__":
|
||||
pass
|
||||
|
||||
with get_db() as db_session:
|
||||
if set_alembic:
|
||||
generate_alembic(session=db_session)
|
||||
init_api_enums_build_types(db_session=db_session)
|
||||
create_application_defaults(db_session=db_session)
|
||||
create_occupant_types_defaults(db_session=db_session)
|
||||
create_modules_and_services_and_actions(db_session=db_session)
|
||||
create_one_address(db_session=db_session)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,83 @@
|
|||
from Schemas import (
|
||||
AddressCity,
|
||||
AddressStreet,
|
||||
AddressLocality,
|
||||
AddressDistrict,
|
||||
AddressNeighborhood,
|
||||
AddressState,
|
||||
AddressCountry,
|
||||
)
|
||||
|
||||
|
||||
def create_one_address(db_session):
|
||||
|
||||
address_list = []
|
||||
country = AddressCountry.find_or_create(
|
||||
country_name="TÜRKİYE", country_code="TR", db=db_session, is_confirmed=True
|
||||
)
|
||||
address_list.append(country)
|
||||
state = AddressState.find_or_create(
|
||||
state_name="TÜRKİYE",
|
||||
state_code="TR",
|
||||
phone_code="90",
|
||||
country_id=country.id,
|
||||
country_uu_id=str(country.uu_id),
|
||||
is_confirmed=True,
|
||||
db=db_session,
|
||||
)
|
||||
address_list.append(state)
|
||||
city = AddressCity.find_or_create(
|
||||
city_name="ANKARA",
|
||||
city_code="6",
|
||||
licence_plate="06",
|
||||
state_id=state.id,
|
||||
state_uu_id=str(state.uu_id),
|
||||
is_confirmed=True,
|
||||
db=db_session,
|
||||
)
|
||||
address_list.append(city)
|
||||
district = AddressDistrict.find_or_create(
|
||||
district_name="ÇANKAYA",
|
||||
district_code="1231",
|
||||
city_id=city.id,
|
||||
city_uu_id=str(city.uu_id),
|
||||
is_confirmed=True,
|
||||
db=db_session,
|
||||
)
|
||||
address_list.append(district)
|
||||
locality = AddressLocality.find_or_create(
|
||||
locality_name="MERKEZ",
|
||||
locality_code="2431",
|
||||
type_code="3",
|
||||
type_description=None,
|
||||
district_id=district.id,
|
||||
district_uu_id=str(district.uu_id),
|
||||
is_confirmed=True,
|
||||
db=db_session,
|
||||
)
|
||||
address_list.append(locality)
|
||||
neighborhood = AddressNeighborhood.find_or_create(
|
||||
neighborhood_name="AYRANCI MAHALLESİ",
|
||||
neighborhood_code="1522",
|
||||
type_code="1",
|
||||
type_description="MAHALLESİ",
|
||||
locality_id=locality.id,
|
||||
locality_uu_id=str(locality.uu_id),
|
||||
is_confirmed=True,
|
||||
db=db_session,
|
||||
)
|
||||
address_list.append(neighborhood)
|
||||
street = AddressStreet.find_or_create(
|
||||
street_name="REŞAT NURİ CADDESİ",
|
||||
type_description="CADDESİ",
|
||||
type_code="3",
|
||||
street_code="52270",
|
||||
neighborhood_id=neighborhood.id,
|
||||
neighborhood_uu_id=str(neighborhood.uu_id),
|
||||
is_confirmed=True,
|
||||
db=db_session,
|
||||
)
|
||||
address_list.append(street)
|
||||
for address_single in address_list:
|
||||
address_single.save(db=db_session)
|
||||
return
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
import os
|
||||
|
||||
|
||||
def generate_alembic(session):
|
||||
from sqlalchemy import text
|
||||
|
||||
try:
|
||||
result = session.execute(
|
||||
text(
|
||||
"SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = "
|
||||
"'alembic_version') AS table_existence;"
|
||||
)
|
||||
)
|
||||
if result.first()[0]:
|
||||
session.execute(text("delete from alembic_version;"))
|
||||
session.commit()
|
||||
except Exception as e:
|
||||
print(e)
|
||||
finally:
|
||||
run_command = "python -m alembic stamp head;"
|
||||
run_command += (
|
||||
"python -m alembic revision --autogenerate;python -m alembic upgrade head;"
|
||||
)
|
||||
os.system(run_command)
|
||||
|
|
@ -0,0 +1,410 @@
|
|||
import arrow
|
||||
|
||||
from Modules.Token.password_module import PasswordModule
|
||||
from Controllers.Mongo.database import mongo_handler
|
||||
|
||||
|
||||
def create_application_defaults(db_session):
|
||||
|
||||
from Schemas import (
|
||||
Companies,
|
||||
Departments,
|
||||
Duty,
|
||||
Duties,
|
||||
Employees,
|
||||
People,
|
||||
Users,
|
||||
Staff,
|
||||
RelationshipDutyCompany,
|
||||
)
|
||||
|
||||
created_list = []
|
||||
created_by, confirmed_by = "System", "System"
|
||||
company_management = Companies.find_or_create(
|
||||
**{
|
||||
"formal_name": "Evyos LTD",
|
||||
"public_name": "Evyos Verimlilik Sistemleri",
|
||||
"company_type": "LTD",
|
||||
"commercial_type": "Commercial",
|
||||
"tax_no": "123132123132",
|
||||
"company_tag": "Evyos",
|
||||
"default_lang_type": "TR",
|
||||
"default_money_type": "TL",
|
||||
"is_commercial": True,
|
||||
"is_confirmed": True,
|
||||
},
|
||||
db=db_session,
|
||||
)
|
||||
created_list.append(company_management)
|
||||
active_row = dict(
|
||||
is_confirmed=True, active=True, deleted=False, is_notification_send=True
|
||||
)
|
||||
company_id, company_uu_id = company_management.id, str(company_management.uu_id)
|
||||
created_list = []
|
||||
execution = Departments.find_or_create(
|
||||
department_name="Execution Office",
|
||||
department_code="EO001",
|
||||
company_id=company_id,
|
||||
company_uu_id=str(company_uu_id),
|
||||
**active_row,
|
||||
db=db_session,
|
||||
)
|
||||
created_list.append(execution)
|
||||
it_dept = Departments.find_or_create(
|
||||
department_name="IT Department",
|
||||
department_code="ITD001",
|
||||
company_id=company_id,
|
||||
company_uu_id=str(company_uu_id),
|
||||
**active_row,
|
||||
db=db_session,
|
||||
)
|
||||
created_list.append(it_dept)
|
||||
bm_duty = Duty.find_or_create(
|
||||
duty_name="Business Manager",
|
||||
duty_code="BM0001",
|
||||
duty_description="Business Manager",
|
||||
**active_row,
|
||||
db=db_session,
|
||||
)
|
||||
created_list.append(bm_duty)
|
||||
it_duty = Duty.find_or_create(
|
||||
duty_name="IT Manager",
|
||||
duty_code="IT0001",
|
||||
duty_description="IT Manager",
|
||||
**active_row,
|
||||
db=db_session,
|
||||
)
|
||||
created_list.append(it_duty)
|
||||
bulk_duty = Duty.find_or_create(
|
||||
duty_name="BULK",
|
||||
duty_code="BULK",
|
||||
duty_description="BULK RECORDS OF THE COMPANY",
|
||||
**active_row,
|
||||
db=db_session,
|
||||
)
|
||||
created_list.append(bulk_duty)
|
||||
occu_duty = Duty.find_or_create(
|
||||
duty_name="OCCUPANT",
|
||||
duty_code="OCCUPANT",
|
||||
duty_description="OCCUPANT RECORDS OF THE COMPANY",
|
||||
**active_row,
|
||||
db=db_session,
|
||||
)
|
||||
created_list.append(occu_duty)
|
||||
duties_created_bm = Duties.find_or_create(
|
||||
company_id=company_id,
|
||||
company_uu_id=str(company_uu_id),
|
||||
duties_id=bm_duty.id,
|
||||
duties_uu_id=str(bm_duty.uu_id),
|
||||
department_id=execution.id,
|
||||
department_uu_id=str(execution.uu_id),
|
||||
**active_row,
|
||||
db=db_session,
|
||||
)
|
||||
created_list.append(duties_created_bm)
|
||||
duties_created_it = Duties.find_or_create(
|
||||
company_id=company_id,
|
||||
company_uu_id=str(company_uu_id),
|
||||
duties_id=it_duty.id,
|
||||
duties_uu_id=str(it_duty.uu_id),
|
||||
department_id=it_dept.id,
|
||||
department_uu_id=str(it_dept.uu_id),
|
||||
**active_row,
|
||||
db=db_session,
|
||||
)
|
||||
created_list.append(duties_created_it)
|
||||
duties_created__ex = Duties.find_or_create(
|
||||
company_id=company_id,
|
||||
company_uu_id=str(company_uu_id),
|
||||
duties_id=bulk_duty.id,
|
||||
duties_uu_id=str(bulk_duty.uu_id),
|
||||
department_id=execution.id,
|
||||
department_uu_id=str(execution.uu_id),
|
||||
**active_row,
|
||||
db=db_session,
|
||||
)
|
||||
created_list.append(duties_created__ex)
|
||||
duties_created_at = Duties.find_or_create(
|
||||
company_id=company_id,
|
||||
company_uu_id=str(company_uu_id),
|
||||
duties_id=occu_duty.id,
|
||||
duties_uu_id=str(occu_duty.uu_id),
|
||||
department_id=execution.id,
|
||||
department_uu_id=str(execution.uu_id),
|
||||
**active_row,
|
||||
db=db_session,
|
||||
)
|
||||
created_list.append(duties_created_at)
|
||||
bulk_duty = Duty.filter_by_one(system=True, duty_code="BULK", db=db_session).data
|
||||
|
||||
it_dept = Departments.filter_by_one(
|
||||
system=True,
|
||||
department_name="IT Department",
|
||||
department_code="ITD001",
|
||||
company_id=company_management.id,
|
||||
company_uu_id=str(company_management.uu_id),
|
||||
db=db_session,
|
||||
).data
|
||||
|
||||
created_duty = Duty.find_or_create(
|
||||
duty_name="Database Manager",
|
||||
duty_code="DM",
|
||||
duty_description="Database Manager",
|
||||
created_by=created_by,
|
||||
confirmed_by=confirmed_by,
|
||||
is_confirmed=True,
|
||||
active=True,
|
||||
deleted=False,
|
||||
is_notification_send=True,
|
||||
db=db_session,
|
||||
)
|
||||
created_list.append(created_duty)
|
||||
|
||||
created_duty = Duty.find_or_create(
|
||||
duty_name="Network Manager",
|
||||
duty_code="NM",
|
||||
duty_description="Network Manager",
|
||||
created_by=created_by,
|
||||
confirmed_by=confirmed_by,
|
||||
is_confirmed=True,
|
||||
active=True,
|
||||
deleted=False,
|
||||
is_notification_send=True,
|
||||
db=db_session,
|
||||
)
|
||||
created_list.append(created_duty)
|
||||
|
||||
application_manager_duty = Duty.find_or_create(
|
||||
duty_name="Application Manager",
|
||||
duty_code="AM",
|
||||
duty_description="Application Manager",
|
||||
created_by=created_by,
|
||||
confirmed_by=confirmed_by,
|
||||
is_confirmed=True,
|
||||
active=True,
|
||||
deleted=False,
|
||||
is_notification_send=True,
|
||||
db=db_session,
|
||||
)
|
||||
created_list.append(application_manager_duty)
|
||||
application_super_user_duty = Duty.find_or_create(
|
||||
duty_name="Super User",
|
||||
duty_code="SUE",
|
||||
duty_description="Super User",
|
||||
created_by=created_by,
|
||||
confirmed_by=confirmed_by,
|
||||
is_confirmed=True,
|
||||
active=True,
|
||||
deleted=False,
|
||||
is_notification_send=True,
|
||||
db=db_session,
|
||||
)
|
||||
created_list.append(application_super_user_duty)
|
||||
application_manager_duties = Duties.find_or_create(
|
||||
department_id=it_dept.id,
|
||||
department_uu_id=str(it_dept.uu_id),
|
||||
duties_id=application_manager_duty.id,
|
||||
duties_uu_id=str(application_manager_duty.uu_id),
|
||||
company_id=company_management.id,
|
||||
company_uu_id=str(company_management.uu_id),
|
||||
is_confirmed=True,
|
||||
active=True,
|
||||
deleted=False,
|
||||
is_notification_send=True,
|
||||
db=db_session,
|
||||
)
|
||||
created_list.append(application_manager_duties)
|
||||
super_user_duties = Duties.find_or_create(
|
||||
department_id=it_dept.id,
|
||||
department_uu_id=str(it_dept.uu_id),
|
||||
duties_id=application_super_user_duty.id,
|
||||
duties_uu_id=str(application_manager_duty.uu_id),
|
||||
company_id=company_management.id,
|
||||
company_uu_id=str(company_management.uu_id),
|
||||
is_confirmed=True,
|
||||
active=True,
|
||||
deleted=False,
|
||||
is_notification_send=True,
|
||||
db=db_session,
|
||||
)
|
||||
created_list.append(super_user_duties)
|
||||
RelationshipDutyCompany.find_or_create(
|
||||
duties_id=application_manager_duties.id,
|
||||
owner_id=company_management.id,
|
||||
member_id=company_management.id,
|
||||
parent_id=None,
|
||||
child_count=0,
|
||||
is_confirmed=True,
|
||||
active=True,
|
||||
deleted=False,
|
||||
is_notification_send=True,
|
||||
db=db_session,
|
||||
)
|
||||
created_list.append(application_manager_duties)
|
||||
RelationshipDutyCompany.find_or_create(
|
||||
duties_id=super_user_duties.id,
|
||||
owner_id=company_management.id,
|
||||
member_id=company_management.id,
|
||||
parent_id=None,
|
||||
child_count=0,
|
||||
is_confirmed=True,
|
||||
active=True,
|
||||
deleted=False,
|
||||
is_notification_send=True,
|
||||
db=db_session,
|
||||
)
|
||||
created_list.append(super_user_duties)
|
||||
|
||||
app_manager = People.find_or_create(
|
||||
**{
|
||||
"person_tag": "BAM-System",
|
||||
"firstname": "Berkay Application Manager",
|
||||
"surname": "Karatay",
|
||||
"sex_code": "M",
|
||||
"middle_name": "",
|
||||
"father_name": "Father",
|
||||
"mother_name": "Mother",
|
||||
"country_code": "TR",
|
||||
"national_identity_id": "12312312312",
|
||||
"birth_place": "Ankara",
|
||||
"birth_date": "01.07.1990",
|
||||
"tax_no": "1231231231",
|
||||
"is_confirmed": True,
|
||||
},
|
||||
db=db_session,
|
||||
)
|
||||
created_list.append(app_manager)
|
||||
sup_manager = People.find_or_create(
|
||||
**{
|
||||
"person_tag": "BSU-System",
|
||||
"firstname": "Berkay Super User",
|
||||
"surname": "Karatay",
|
||||
"sex_code": "M",
|
||||
"middle_name": "",
|
||||
"father_name": "Father",
|
||||
"mother_name": "Mother",
|
||||
"country_code": "TR",
|
||||
"national_identity_id": "12312312313",
|
||||
"birth_place": "Ankara",
|
||||
"birth_date": "01.07.1990",
|
||||
"tax_no": "1231231232",
|
||||
},
|
||||
db=db_session,
|
||||
)
|
||||
created_list.append(sup_manager)
|
||||
application_manager_staff = Staff.find_or_create(
|
||||
staff_description="Application Manager",
|
||||
staff_name="Application Manager Employee",
|
||||
staff_code="AME",
|
||||
duties_id=application_manager_duties.id,
|
||||
duties_uu_id=str(application_manager_duty.uu_id),
|
||||
is_confirmed=True,
|
||||
active=True,
|
||||
deleted=False,
|
||||
is_notification_send=True,
|
||||
db=db_session,
|
||||
)
|
||||
created_list.append(application_manager_staff)
|
||||
super_user_staff = Staff.find_or_create(
|
||||
staff_description="Super User",
|
||||
staff_name="Super User Employee",
|
||||
staff_code="SUE",
|
||||
duties_id=super_user_duties.id,
|
||||
duties_uu_id=str(application_manager_duty.uu_id),
|
||||
is_confirmed=True,
|
||||
active=True,
|
||||
deleted=False,
|
||||
is_notification_send=True,
|
||||
db=db_session,
|
||||
)
|
||||
created_list.append(super_user_staff)
|
||||
app_manager_employee = Employees.find_or_create(
|
||||
staff_id=application_manager_staff.id,
|
||||
staff_uu_id=str(application_manager_staff.uu_id),
|
||||
people_id=app_manager.id,
|
||||
people_uu_id=str(app_manager.uu_id),
|
||||
is_confirmed=True,
|
||||
active=True,
|
||||
deleted=False,
|
||||
is_notification_send=True,
|
||||
db=db_session,
|
||||
)
|
||||
created_list.append(app_manager_employee)
|
||||
|
||||
super_user_employee = Employees.find_or_create(
|
||||
staff_id=super_user_staff.id,
|
||||
staff_uu_id=str(super_user_staff.uu_id),
|
||||
people_id=sup_manager.id,
|
||||
people_uu_id=str(sup_manager.uu_id),
|
||||
is_confirmed=True,
|
||||
active=True,
|
||||
deleted=False,
|
||||
is_notification_send=True,
|
||||
db=db_session,
|
||||
)
|
||||
created_list.append(super_user_employee)
|
||||
|
||||
app_manager_user = Users.find_or_create(
|
||||
person_id=app_manager.id,
|
||||
person_uu_id=str(app_manager.uu_id),
|
||||
user_tag=app_manager.person_tag,
|
||||
email="karatay.berkay.man@evyos.com.tr",
|
||||
phone_number="+901111111111",
|
||||
avatar="https://s.tmimgcdn.com/scr/800x500/276800/building-home-nature-logo-vector-template-3_276851-original.jpg",
|
||||
related_company=str(company_management.uu_id),
|
||||
is_confirmed=True,
|
||||
active=True,
|
||||
deleted=False,
|
||||
is_notification_send=True,
|
||||
db=db_session,
|
||||
)
|
||||
created_list.append(app_manager_user)
|
||||
app_manager_user.password_expiry_begins = str(arrow.now())
|
||||
app_manager_user.password_token = PasswordModule.generate_refresher_token()
|
||||
|
||||
main_domain, collection_name = (
|
||||
"evyos.com.tr",
|
||||
f"{str(company_management.uu_id)}*Domain",
|
||||
)
|
||||
with mongo_handler.collection(collection_name) as mongo_engine:
|
||||
mongo_engine.insert_one(
|
||||
document={
|
||||
"user_uu_id": str(app_manager_user.uu_id),
|
||||
"other_domains_list": [main_domain],
|
||||
"main_domain": main_domain,
|
||||
"modified_at": arrow.now().timestamp(),
|
||||
}
|
||||
)
|
||||
|
||||
sup_manager_employee = Users.find_or_create(
|
||||
person_id=sup_manager.id,
|
||||
person_uu_id=str(sup_manager.uu_id),
|
||||
user_tag=sup_manager.person_tag,
|
||||
email="karatay.berkay.sup@evyos.com.tr",
|
||||
phone_number="+901111111112",
|
||||
avatar="https://s.tmimgcdn.com/scr/800x500/276800/building-home-nature-logo-vector-template-3_276851-original.jpg",
|
||||
created_by=created_by,
|
||||
confirmed_by=confirmed_by,
|
||||
related_company=str(company_management.uu_id),
|
||||
is_confirmed=True,
|
||||
active=True,
|
||||
deleted=False,
|
||||
is_notification_send=True,
|
||||
db=db_session,
|
||||
)
|
||||
created_list.append(sup_manager_employee)
|
||||
|
||||
sup_manager_employee.password_expiry_begins = str(arrow.now())
|
||||
sup_manager_employee.password_token = PasswordModule.generate_refresher_token()
|
||||
with mongo_handler.collection(collection_name) as mongo_engine:
|
||||
mongo_engine.insert_one(
|
||||
document={
|
||||
"user_uu_id": str(sup_manager_employee.uu_id),
|
||||
"other_domains_list": [main_domain],
|
||||
"main_domain": main_domain,
|
||||
"modified_at": arrow.now().timestamp(),
|
||||
}
|
||||
)
|
||||
db_session.commit()
|
||||
|
||||
print("All Defaults Create is now completed")
|
||||
|
|
@ -0,0 +1,253 @@
|
|||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class InsertBuildTypes(BaseModel):
|
||||
function_code: str
|
||||
type_code: str
|
||||
lang: str
|
||||
type_name: str
|
||||
|
||||
|
||||
def init_api_enums_build_types(db_session):
|
||||
from Schemas import BuildTypes, ApiEnumDropdown
|
||||
|
||||
insert_types = [
|
||||
{
|
||||
"function_code": "EVYOS",
|
||||
"type_code": "APT_KZN",
|
||||
"type_name": "Apartman Kazan Dairesi",
|
||||
"lang": "TR",
|
||||
},
|
||||
{
|
||||
"function_code": "EVYOS",
|
||||
"type_code": "APT_GRJ",
|
||||
"type_name": "Apartman Garaj",
|
||||
"lang": "TR",
|
||||
},
|
||||
{
|
||||
"function_code": "EVYOS",
|
||||
"type_code": "APT_DP",
|
||||
"type_name": "Apartman Depo",
|
||||
"lang": "TR",
|
||||
},
|
||||
{
|
||||
"function_code": "EVYOS",
|
||||
"type_code": "DAIRE",
|
||||
"type_name": "Apartman Dairesi",
|
||||
"lang": "TR",
|
||||
},
|
||||
{
|
||||
"function_code": "EVYOS",
|
||||
"type_code": "APT",
|
||||
"type_name": "Apartman Binası",
|
||||
"lang": "TR",
|
||||
},
|
||||
{
|
||||
"function_code": "EVYOS",
|
||||
"type_code": "APT_YNT",
|
||||
"type_name": "Apartman Yönetimi",
|
||||
"lang": "TR",
|
||||
},
|
||||
{
|
||||
"function_code": "EVYOS",
|
||||
"type_code": "APT_PRK",
|
||||
"type_name": "Apartman Açık Park Alanı",
|
||||
"lang": "TR",
|
||||
},
|
||||
{
|
||||
"function_code": "EVYOS",
|
||||
"type_code": "APT_YSL",
|
||||
"type_name": "Apartman Yeşil Alan",
|
||||
"lang": "TR",
|
||||
},
|
||||
{
|
||||
"function_code": "EVYOS",
|
||||
"type_code": "APT_YOL",
|
||||
"type_name": "Apartman Ara Yol",
|
||||
"lang": "TR",
|
||||
},
|
||||
]
|
||||
for insert_type in insert_types:
|
||||
build_types = InsertBuildTypes(
|
||||
function_code="EVYOS",
|
||||
lang=insert_type["lang"],
|
||||
type_code=str(insert_type["type_code"]).upper(),
|
||||
type_name=insert_type["type_name"],
|
||||
)
|
||||
created_build_type = BuildTypes.find_or_create(
|
||||
**build_types.model_dump(), is_confirmed=True, db=db_session
|
||||
)
|
||||
created_build_type.save(db=db_session)
|
||||
|
||||
insert_enums = [
|
||||
{"enum_class": "BuildDuesTypes", "type_code": "BDT-D", "type_name": "Debit"},
|
||||
{
|
||||
"enum_class": "BuildDuesTypes",
|
||||
"type_code": "BDT-A",
|
||||
"type_name": "Add Debit",
|
||||
},
|
||||
{
|
||||
"enum_class": "BuildDuesTypes",
|
||||
"type_code": "BDT-R",
|
||||
"type_name": "Renovation",
|
||||
},
|
||||
{
|
||||
"enum_class": "BuildDuesTypes",
|
||||
"type_code": "BDT-L",
|
||||
"type_name": "Lawyer expence",
|
||||
},
|
||||
{
|
||||
"enum_class": "BuildDuesTypes",
|
||||
"type_code": "BDT-S",
|
||||
"type_name": "Service fee",
|
||||
},
|
||||
{
|
||||
"enum_class": "BuildDuesTypes",
|
||||
"type_code": "BDT-I",
|
||||
"type_name": "Information",
|
||||
},
|
||||
{
|
||||
"enum_class": "AccountingReceiptTypes",
|
||||
"type_code": "ART-A",
|
||||
"type_name": "Kasa Tahsil Fişi",
|
||||
},
|
||||
{
|
||||
"enum_class": "AccountingReceiptTypes",
|
||||
"type_code": "ART-E",
|
||||
"type_name": "Kasa Tediye Fişi",
|
||||
},
|
||||
{
|
||||
"enum_class": "AccountingReceiptTypes",
|
||||
"type_code": "ART-M",
|
||||
"type_name": "Mahsup Fişi",
|
||||
},
|
||||
{
|
||||
"enum_class": "AccountingReceiptTypes",
|
||||
"type_code": "ART-O",
|
||||
"type_name": "Açılış Fişi",
|
||||
},
|
||||
{
|
||||
"enum_class": "AccountingReceiptTypes",
|
||||
"type_code": "ART-C",
|
||||
"type_name": "Kapanış Fişi",
|
||||
},
|
||||
{"enum_class": "IbanBudgetType", "type_code": "IBT-I", "type_name": "Iban"},
|
||||
{"enum_class": "IbanBudgetType", "type_code": "IBT-B", "type_name": "Budget"},
|
||||
{
|
||||
"enum_class": "IbanBudgetType",
|
||||
"type_code": "IBT-TR",
|
||||
"type_name": "Transaction records",
|
||||
},
|
||||
{"enum_class": "ProjectTypes", "type_code": "R", "type_name": "Tadilat"},
|
||||
{
|
||||
"enum_class": "ProjectTypes",
|
||||
"type_code": "PT-C",
|
||||
"type_name": "Mahkeme süreçleri",
|
||||
},
|
||||
{
|
||||
"enum_class": "ProjectTypes",
|
||||
"type_code": "PT-Z",
|
||||
"type_name": "Sıfır Bakiye",
|
||||
},
|
||||
{
|
||||
"enum_class": "EdmBudgetType",
|
||||
"type_code": "PT-B",
|
||||
"type_name": "Banka records",
|
||||
},
|
||||
{
|
||||
"enum_class": "EdmBudgetType",
|
||||
"type_code": "PT-S",
|
||||
"type_name": "Sistem kaydı",
|
||||
},
|
||||
{
|
||||
"enum_class": "EdmBudgetType",
|
||||
"type_code": "EBT-C",
|
||||
"type_name": "Build, Flat or Site records",
|
||||
},
|
||||
{"enum_class": "ExpireType", "type_code": "1", "type_name": "daily"},
|
||||
{"enum_class": "ExpireType", "type_code": "7", "type_name": "weekly"},
|
||||
{"enum_class": "ExpireType", "type_code": "30", "type_name": "monthly"},
|
||||
{"enum_class": "ExpireType", "type_code": "90", "type_name": "quarter"},
|
||||
{"enum_class": "ExpireType", "type_code": "180", "type_name": "six_month"},
|
||||
{"enum_class": "ExpireType", "type_code": "365", "type_name": "yearly"},
|
||||
{"enum_class": "PhoneType", "type_code": "M", "type_name": "cep tel"},
|
||||
{"enum_class": "PhoneType", "type_code": "L", "type_name": "sabit telefon"},
|
||||
{"enum_class": "PhoneType", "type_code": "F", "type_name": "fax"},
|
||||
{"enum_class": "PhoneType", "type_code": "C", "type_name": "santral"},
|
||||
{
|
||||
"enum_class": "PhoneType",
|
||||
"type_code": "G",
|
||||
"type_name": "ülke genelindeki hatlar 444",
|
||||
},
|
||||
{"enum_class": "PerComType", "type_code": "1", "type_name": "Person"},
|
||||
{"enum_class": "PerComType", "type_code": "2", "type_name": "Company"},
|
||||
{"enum_class": "Directions", "type_code": "NN", "type_name": "North"},
|
||||
{"enum_class": "Directions", "type_code": "EE", "type_name": "East"},
|
||||
{"enum_class": "Directions", "type_code": "SS", "type_name": "South"},
|
||||
{"enum_class": "Directions", "type_code": "WW", "type_name": "West"},
|
||||
{"enum_class": "Directions", "type_code": "NE", "type_name": "North East"},
|
||||
{"enum_class": "Directions", "type_code": "NW", "type_name": "North West"},
|
||||
{"enum_class": "Directions", "type_code": "SE", "type_name": "South East"},
|
||||
{"enum_class": "Directions", "type_code": "SW", "type_name": "South West"},
|
||||
{
|
||||
"enum_class": "MeetingTypes",
|
||||
"type_code": "MT-RBM",
|
||||
"type_name": "Regular Building Meeting",
|
||||
},
|
||||
{
|
||||
"enum_class": "MeetingTypes",
|
||||
"type_code": "MT-DBM",
|
||||
"type_name": "Disaster Building Meeting",
|
||||
},
|
||||
{
|
||||
"enum_class": "MeetingTypes",
|
||||
"type_code": "MT-EBM",
|
||||
"type_name": "Emergency Building Meeting",
|
||||
},
|
||||
{
|
||||
"enum_class": "DebitTypes",
|
||||
"type_code": "DT-D",
|
||||
"type_name": "Debit Sender",
|
||||
},
|
||||
{
|
||||
"enum_class": "DebitTypes",
|
||||
"type_code": "DT-R",
|
||||
"type_name": "Credit Receiver",
|
||||
},
|
||||
{
|
||||
"enum_class": "DebitTypes",
|
||||
"type_code": "DT-Z",
|
||||
"type_name": "Zero Balance",
|
||||
},
|
||||
{
|
||||
"enum_class": "TimePeriod",
|
||||
"type_code": "TP-W",
|
||||
"type_name": "Weekly",
|
||||
},
|
||||
{
|
||||
"enum_class": "TimePeriod",
|
||||
"type_code": "TP-M",
|
||||
"type_name": "Monthly",
|
||||
},
|
||||
{
|
||||
"enum_class": "TimePeriod",
|
||||
"type_code": "TP-Q",
|
||||
"type_name": "Quarterly",
|
||||
},
|
||||
{
|
||||
"enum_class": "TimePeriod",
|
||||
"type_code": "TP-Y",
|
||||
"type_name": "Yearly",
|
||||
},
|
||||
]
|
||||
|
||||
for insert_enum in insert_enums:
|
||||
created_api_enum = ApiEnumDropdown.find_or_create(
|
||||
enum_class=insert_enum["enum_class"],
|
||||
value=insert_enum["type_name"],
|
||||
key=str(insert_enum["type_code"]).upper(),
|
||||
description=insert_enum["type_name"],
|
||||
is_confirmed=True,
|
||||
db=db_session,
|
||||
)
|
||||
created_api_enum.save(db=db_session)
|
||||
|
|
@ -0,0 +1,218 @@
|
|||
def create_occupant_types_defaults(db_session):
|
||||
from Schemas import OccupantTypes
|
||||
|
||||
"""
|
||||
occupant_category = mapped_column(String, server_default="")
|
||||
occupant_category_type = mapped_column(String, server_default="")
|
||||
occupant_is_unique = mapped_column(Boolean, server_default="0")
|
||||
"""
|
||||
list_occupant_types = [
|
||||
{
|
||||
"occupant_type": "Toplantı Başkanı",
|
||||
"occupant_description": "Toplantı Başkanı",
|
||||
"occupant_code": "MT-PRS",
|
||||
"occupant_category": "Toplantı",
|
||||
"occupant_category_type": "MT",
|
||||
"occupant_is_unique": True,
|
||||
},
|
||||
{
|
||||
"occupant_type": "Toplantı Katip",
|
||||
"occupant_description": "Toplantıda tutanak tutan kişi",
|
||||
"occupant_code": "MT-WRT",
|
||||
"occupant_category": "Toplantı",
|
||||
"occupant_category_type": "MT",
|
||||
"occupant_is_unique": True,
|
||||
},
|
||||
{
|
||||
"occupant_type": "Toplantı Katılımcısı",
|
||||
"occupant_description": "Toplantıda sadece katılan kişi",
|
||||
"occupant_code": "MT-ATT",
|
||||
"occupant_category": "Toplantı",
|
||||
"occupant_category_type": "MT",
|
||||
"occupant_is_unique": False,
|
||||
},
|
||||
{
|
||||
"occupant_type": "Toplantı Danışman",
|
||||
"occupant_description": "Toplantıda danışmanlık yapan kişi",
|
||||
"occupant_code": "MT-ADV",
|
||||
"occupant_category": "Toplantı",
|
||||
"occupant_category_type": "MT",
|
||||
"occupant_is_unique": False,
|
||||
},
|
||||
{
|
||||
"occupant_type": "Toplantı Seçilmiş Başkanı",
|
||||
"occupant_description": "Toplantı Seçilmiş Başkanı",
|
||||
"occupant_code": "MT-VPR",
|
||||
"occupant_category": "Toplantı",
|
||||
"occupant_category_type": "MT",
|
||||
"occupant_is_unique": True,
|
||||
},
|
||||
{
|
||||
"occupant_type": "Daire Sahibi",
|
||||
"occupant_description": "Daire Sahibi",
|
||||
"occupant_code": "FL-OWN",
|
||||
"occupant_category": "Daire",
|
||||
"occupant_category_type": "FL",
|
||||
"occupant_is_unique": True,
|
||||
},
|
||||
{
|
||||
"occupant_type": "Daire Kiracısı",
|
||||
"occupant_description": "Daire Kiracısı",
|
||||
"occupant_code": "FL-TEN",
|
||||
"occupant_category": "Daire",
|
||||
"occupant_category_type": "FL",
|
||||
"occupant_is_unique": True,
|
||||
},
|
||||
{
|
||||
"occupant_type": "Daire Sakini",
|
||||
"occupant_description": "Daire Sakini",
|
||||
"occupant_code": "FL-RES",
|
||||
"occupant_category": "Daire",
|
||||
"occupant_category_type": "FL",
|
||||
"occupant_is_unique": False,
|
||||
},
|
||||
{
|
||||
"occupant_type": "Daire Sakini Vekili",
|
||||
"occupant_description": "Daire Sakini Vekili",
|
||||
"occupant_code": "FL-REP",
|
||||
"occupant_category": "Daire",
|
||||
"occupant_category_type": "FL",
|
||||
"occupant_is_unique": False,
|
||||
},
|
||||
{
|
||||
"occupant_type": "Bina Avukatı",
|
||||
"occupant_description": "Bina Avukatı",
|
||||
"occupant_code": "BU-ATT",
|
||||
"occupant_category": "Bina",
|
||||
"occupant_category_type": "BU",
|
||||
"occupant_is_unique": False,
|
||||
},
|
||||
{
|
||||
"occupant_type": "Bina Avukatı Yardımcısı",
|
||||
"occupant_description": "Bina Avukatı Yardımcısı",
|
||||
"occupant_code": "BU-ATA",
|
||||
"occupant_category": "Bina",
|
||||
"occupant_category_type": "BU",
|
||||
"occupant_is_unique": False,
|
||||
},
|
||||
{
|
||||
"occupant_type": "Bina Denetmen Yardımcısı",
|
||||
"occupant_description": "Bina Denetmen Yardımcısı",
|
||||
"occupant_code": "BU-SPA",
|
||||
"occupant_category": "Bina",
|
||||
"occupant_category_type": "BU",
|
||||
"occupant_is_unique": False,
|
||||
},
|
||||
{
|
||||
"occupant_type": "Bina Denetmeni",
|
||||
"occupant_description": "Bina Denetmeni",
|
||||
"occupant_code": "BU-SPV",
|
||||
"occupant_category": "Bina",
|
||||
"occupant_category_type": "BU",
|
||||
"occupant_is_unique": False,
|
||||
},
|
||||
{
|
||||
"occupant_type": "Bina Yönetici Yardımcısı",
|
||||
"occupant_description": "Bina Yönetici Yardımcısı",
|
||||
"occupant_code": "BU-MNA",
|
||||
"occupant_category": "Bina",
|
||||
"occupant_category_type": "BU",
|
||||
"occupant_is_unique": False,
|
||||
},
|
||||
{
|
||||
"occupant_type": "Bina Yöneticisi",
|
||||
"occupant_description": "Bina Yöneticisi",
|
||||
"occupant_code": "BU-MNG",
|
||||
"occupant_category": "Bina",
|
||||
"occupant_category_type": "BU",
|
||||
"occupant_is_unique": True,
|
||||
},
|
||||
{
|
||||
"occupant_type": "Bina Muhasabecisi",
|
||||
"occupant_description": "Bina Muhasabecisi",
|
||||
"occupant_code": "BU-ACC",
|
||||
"occupant_category": "Bina",
|
||||
"occupant_category_type": "BU",
|
||||
"occupant_is_unique": False,
|
||||
},
|
||||
{
|
||||
"occupant_type": "Proje Lideri",
|
||||
"occupant_description": "Proje Lideri",
|
||||
"occupant_code": "PRJ-LDR",
|
||||
"occupant_category": "Proje",
|
||||
"occupant_category_type": "PRJ",
|
||||
"occupant_is_unique": False,
|
||||
},
|
||||
{
|
||||
"occupant_type": "Proje Sorumlusu",
|
||||
"occupant_description": "Proje Sorumlusu",
|
||||
"occupant_code": "PRJ-RES",
|
||||
"occupant_category": "Proje",
|
||||
"occupant_category_type": "PRJ",
|
||||
"occupant_is_unique": False,
|
||||
},
|
||||
{
|
||||
"occupant_type": "Proje Ekibi",
|
||||
"occupant_description": "Proje Ekibi",
|
||||
"occupant_code": "PRJ-EMP",
|
||||
"occupant_category": "Proje",
|
||||
"occupant_category_type": "PRJ",
|
||||
"occupant_is_unique": False,
|
||||
},
|
||||
{
|
||||
"occupant_type": "Proje Finans Sorumlusu",
|
||||
"occupant_description": "Proje Finans Sorumlusu",
|
||||
"occupant_code": "PRJ-FIN",
|
||||
"occupant_category": "Proje",
|
||||
"occupant_category_type": "PRJ",
|
||||
"occupant_is_unique": False,
|
||||
},
|
||||
{
|
||||
"occupant_type": "Proje Teknik Sorumlusu",
|
||||
"occupant_description": "Proje Teknik Sorumlusu",
|
||||
"occupant_code": "PRJ-TEC",
|
||||
"occupant_category": "Proje",
|
||||
"occupant_category_type": "PRJ",
|
||||
"occupant_is_unique": False,
|
||||
},
|
||||
{
|
||||
"occupant_type": "Daire Mülkiyet Vekili",
|
||||
"occupant_description": "Daire Mülkiyet Vekili",
|
||||
"occupant_code": "FL-DEP", # deputy
|
||||
"occupant_category": "Daire",
|
||||
"occupant_category_type": "FL",
|
||||
"occupant_is_unique": False,
|
||||
},
|
||||
{
|
||||
"occupant_type": "Bina Teknik Sorumlusu",
|
||||
"occupant_description": "Bina Teknik Sorumlusu",
|
||||
"occupant_code": "BU-TEC",
|
||||
"occupant_category": "Bina",
|
||||
"occupant_category_type": "BU",
|
||||
"occupant_is_unique": False,
|
||||
},
|
||||
{
|
||||
"occupant_type": "Bina Teknik Elemanı",
|
||||
"occupant_description": "Bina Teknik Elemanı",
|
||||
"occupant_code": "BU-EMP",
|
||||
"occupant_category": "Bina",
|
||||
"occupant_category_type": "BU",
|
||||
"occupant_is_unique": False,
|
||||
},
|
||||
{
|
||||
"occupant_type": "Bina Teknik Freelancer",
|
||||
"occupant_description": "Bina Teknik Freelancer",
|
||||
"occupant_code": "BU-FLC",
|
||||
"occupant_category": "Bina",
|
||||
"occupant_category_type": "BU",
|
||||
"occupant_is_unique": False,
|
||||
},
|
||||
]
|
||||
for list_occupant_type in list_occupant_types:
|
||||
try:
|
||||
created_type = OccupantTypes.find_or_create(
|
||||
**list_occupant_type, is_confirmed=True, db=db_session
|
||||
)
|
||||
created_type.save(db=db_session)
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
def create_modules_and_services_and_actions(db_session):
|
||||
from Schemas import (
|
||||
Duty,
|
||||
OccupantTypes,
|
||||
Modules,
|
||||
Services,
|
||||
)
|
||||
|
||||
erp_module = Modules.find_or_create(
|
||||
**{
|
||||
"module_name": "EVYOS ERP",
|
||||
"module_description": "EVYOS Enterprise Resource Planning",
|
||||
"module_code": "EVYOS-ERP",
|
||||
"module_layer": 1,
|
||||
"is_default_module": False,
|
||||
"is_confirmed": True,
|
||||
},
|
||||
db=db_session,
|
||||
)
|
||||
erp_module.save(db=db_session)
|
||||
|
||||
build_module = Modules.find_or_create(
|
||||
**{
|
||||
"module_name": "Bina Yönetim Modülü",
|
||||
"module_description": "Building Management Module",
|
||||
"module_code": "BLD-MNG",
|
||||
"module_layer": 1,
|
||||
"is_default_module": False,
|
||||
"is_confirmed": True,
|
||||
},
|
||||
db=db_session,
|
||||
)
|
||||
build_module.save(db=db_session)
|
||||
|
||||
user_module = Modules.find_or_create(
|
||||
**{
|
||||
"module_name": "Kullancı Modülü",
|
||||
"module_description": "Kullanıcı Genel Modülü",
|
||||
"module_code": "USR-PUB",
|
||||
"module_layer": 1,
|
||||
"is_default_module": True,
|
||||
"is_confirmed": True,
|
||||
},
|
||||
db=db_session,
|
||||
)
|
||||
user_module.save(db=db_session)
|
||||
|
||||
erp_module_module_dict = dict(
|
||||
module_id=erp_module.id,
|
||||
module_uu_id=str(erp_module.uu_id),
|
||||
)
|
||||
build_module_module_dict = dict(
|
||||
module_id=build_module.id,
|
||||
module_uu_id=str(build_module.uu_id),
|
||||
)
|
||||
duty_objects = Duty.filter_all(
|
||||
Duty.duty_code.notin_(["BULK", "OCCUPANT", "BM0001"]),
|
||||
db=db_session,
|
||||
).data
|
||||
for duty_object in duty_objects:
|
||||
created_service = Services.find_or_create(
|
||||
**erp_module_module_dict,
|
||||
service_name=duty_object.duty_name,
|
||||
service_description=duty_object.duty_description,
|
||||
service_code=f"SRE-{duty_object.duty_code}",
|
||||
related_responsibility=duty_object.duty_code,
|
||||
is_confirmed=True,
|
||||
db=db_session,
|
||||
)
|
||||
created_service.save(db=db_session)
|
||||
|
||||
occupant_types = OccupantTypes.filter_all(db=db_session).data
|
||||
for occupant_type in occupant_types:
|
||||
created_service = Services.find_or_create(
|
||||
**build_module_module_dict,
|
||||
service_name=occupant_type.occupant_type,
|
||||
service_description=occupant_type.occupant_description,
|
||||
service_code=f"SRO-{occupant_type.occupant_code}",
|
||||
related_responsibility=occupant_type.occupant_code,
|
||||
is_confirmed=True,
|
||||
db=db_session,
|
||||
)
|
||||
created_service.save(db=db_session)
|
||||
|
|
@ -8,9 +8,9 @@ class Configs(BaseSettings):
|
|||
"""
|
||||
|
||||
PATH: str = ""
|
||||
HOST: str = ("",)
|
||||
PORT: int = (0,)
|
||||
LOG_LEVEL: str = ("info",)
|
||||
HOST: str = ""
|
||||
PORT: int = 0
|
||||
LOG_LEVEL: str = "info"
|
||||
RELOAD: int = 0
|
||||
ACCESS_TOKEN_TAG: str = ""
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,14 @@ from ApiServices.TemplateService.initializer.create_route import RouteRegisterCo
|
|||
from .config import api_config
|
||||
|
||||
|
||||
def create_events_if_any_cluster_set():
|
||||
import events
|
||||
|
||||
for event_str in events.__all__:
|
||||
if to_set_events := getattr(events, event_str, None):
|
||||
to_set_events.set_events_to_database()
|
||||
|
||||
|
||||
def create_app():
|
||||
|
||||
application = FastAPI(**api_config.api_info)
|
||||
|
|
@ -36,6 +44,6 @@ def create_app():
|
|||
|
||||
route_register = RouteRegisterController(app=application, router_list=get_routes())
|
||||
application = route_register.register_routes()
|
||||
|
||||
create_events_if_any_cluster_set()
|
||||
application.openapi = lambda _=application: create_openapi_schema(_)
|
||||
return application
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
from fastapi import APIRouter, Request, Response
|
||||
|
||||
from ApiServices.TemplateService.events.events_setter import event_cluster
|
||||
from ApiServices.TemplateService.events.template.event import template_event_cluster
|
||||
|
||||
test_template_route = APIRouter(prefix="/test", tags=["Test"])
|
||||
|
||||
|
|
@ -8,30 +8,23 @@ test_template_route = APIRouter(prefix="/test", tags=["Test"])
|
|||
@test_template_route.get(
|
||||
path="/template",
|
||||
description="Test Template Route",
|
||||
operation_id="bb20c8c6-a289-4cab-9da7-34ca8a36c8e5"
|
||||
operation_id="bb20c8c6-a289-4cab-9da7-34ca8a36c8e5",
|
||||
)
|
||||
def test_template(request: Request, response: Response):
|
||||
"""
|
||||
Test Template Route
|
||||
"""
|
||||
headers = dict(request.headers)
|
||||
event_cluster_matched = event_cluster.match_event(
|
||||
event_cluster_matched = template_event_cluster.match_event(
|
||||
event_keys=[
|
||||
"3f510dcf-9f84-4eb9-b919-f582f30adab1",
|
||||
"9f403034-deba-4e1f-b43e-b25d3c808d39",
|
||||
"b8ec6e64-286a-4f60-8554-7a3865454944"
|
||||
"b8ec6e64-286a-4f60-8554-7a3865454944",
|
||||
]
|
||||
)
|
||||
event_cluster_matched.example_callable()
|
||||
response.headers["X-Header"] = "Test Header GET"
|
||||
return {
|
||||
"completed": True,
|
||||
"message": "Test Template Route",
|
||||
"info": {
|
||||
"host": headers.get("host", "Not Found"),
|
||||
"user_agent": headers.get("user-agent", "Not Found"),
|
||||
},
|
||||
}
|
||||
if runner_callable := event_cluster_matched.example_callable():
|
||||
return runner_callable
|
||||
raise ValueError("Event key not found or multiple matches found")
|
||||
|
||||
|
||||
@test_template_route.post(
|
||||
|
|
@ -42,13 +35,14 @@ def test_template_post(request: Request, response: Response):
|
|||
"""
|
||||
Test Template Route with Post Method
|
||||
"""
|
||||
headers = dict(request.headers)
|
||||
event_cluster_matched = template_event_cluster.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"
|
||||
return {
|
||||
"completed": True,
|
||||
"message": "Test Template Route with Post Method",
|
||||
"info": {
|
||||
"host": headers.get("host", "Not Found"),
|
||||
"user_agent": headers.get("user-agent", "Not Found"),
|
||||
},
|
||||
}
|
||||
if runner_callable := event_cluster_matched.example_callable():
|
||||
return runner_callable
|
||||
raise ValueError("Event key not found or multiple matches found")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
from .template.event import template_event_cluster
|
||||
|
||||
__all__ = [
|
||||
"template_event_cluster",
|
||||
]
|
||||
|
|
@ -9,6 +9,7 @@ single_event = Event(
|
|||
description="Example event description",
|
||||
)
|
||||
|
||||
|
||||
def example_callable():
|
||||
"""
|
||||
Example callable method
|
||||
|
|
@ -21,6 +22,8 @@ def example_callable():
|
|||
"user_agent": "example_user_agent",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
single_event.event_callable = example_callable
|
||||
|
||||
other_event = Event(
|
||||
|
|
@ -30,6 +33,8 @@ other_event = Event(
|
|||
response_validator=None, # TODO: Add response validator
|
||||
description="Example event 2 description",
|
||||
)
|
||||
|
||||
|
||||
def example_callable_other():
|
||||
"""
|
||||
Example callable method
|
||||
|
|
@ -42,6 +47,8 @@ def example_callable_other():
|
|||
"user_agent": "example_user_agent",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
other_event.event_callable = example_callable_other
|
||||
|
||||
tokens_in_redis = [
|
||||
|
|
@ -49,9 +56,11 @@ tokens_in_redis = [
|
|||
"9f403034-deba-4e1f-b43e-b25d3c808d39",
|
||||
"b8ec6e64-286a-4f60-8554-7a3865454944",
|
||||
"176b829c-7622-4cf2-b474-421e5acb637c",
|
||||
]
|
||||
template_event_cluster = EventCluster(endpoint_uu_id="bb20c8c6-a289-4cab-9da7-34ca8a36c8e5")
|
||||
]
|
||||
template_event_cluster = EventCluster(
|
||||
endpoint_uu_id="bb20c8c6-a289-4cab-9da7-34ca8a36c8e5"
|
||||
)
|
||||
template_event_cluster.add_event([single_event, other_event])
|
||||
matched_event = template_event_cluster.match_event(event_keys=tokens_in_redis)
|
||||
# matched_event = template_event_cluster.match_event(event_keys=tokens_in_redis)
|
||||
|
||||
print('event_callable', matched_event.event_callable())
|
||||
# print('event_callable', matched_event.event_callable())
|
||||
|
|
|
|||
|
|
@ -9,29 +9,30 @@ class RouteRegisterController:
|
|||
self.app = app
|
||||
|
||||
@staticmethod
|
||||
def add_router_with_event_to_database(route: APIRouter):
|
||||
def add_router_with_event_to_database(router: APIRouter):
|
||||
from Schemas import EndpointRestriction
|
||||
|
||||
with EndpointRestriction.new_session() as db_session:
|
||||
for route in router.routes:
|
||||
route_path = str(getattr(route, "path"))
|
||||
route_summary = str(getattr(route, "name")) or ""
|
||||
operation_id = str(getattr(route, "operation_id")) or ""
|
||||
route_summary = str(getattr(route, "name"))
|
||||
operation_id = getattr(route, "operation_id", None)
|
||||
if not operation_id:
|
||||
return
|
||||
continue
|
||||
|
||||
for route_method in [method.lower() for method in getattr(route, "methods")]:
|
||||
for route_method in [
|
||||
method.lower() for method in getattr(route, "methods")
|
||||
]:
|
||||
restriction = EndpointRestriction.find_or_create(
|
||||
**dict(
|
||||
endpoint_method=route_method,
|
||||
endpoint_name=route_path,
|
||||
endpoint_desc=route_summary.replace("_", " "),
|
||||
endpoint_function=route_summary,
|
||||
operation_uu_id=operation_id, # UUID of the endpoint
|
||||
is_confirmed=True,
|
||||
db=db_session,
|
||||
)
|
||||
)
|
||||
if not restriction.meta_data.created:
|
||||
restriction.endpoint_code = f"AR{str(restriction.id).zfill(3)}"
|
||||
if restriction.meta_data.created:
|
||||
restriction.save(db=db_session)
|
||||
|
||||
def register_routes(self):
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
class EventCluster:
|
||||
|
||||
def __init__(self, endpoint_uu_id: str):
|
||||
|
|
@ -25,33 +24,39 @@ class EventCluster:
|
|||
|
||||
def set_events_to_database(self):
|
||||
from Schemas import Events, EndpointRestriction
|
||||
with Events.new_session() as db_session:
|
||||
|
||||
with Events.new_session() as db_session:
|
||||
if to_save_endpoint := EndpointRestriction.filter_one(
|
||||
EndpointRestriction.uu_id == self.endpoint_uu_id,
|
||||
EndpointRestriction.operation_uu_id == self.endpoint_uu_id,
|
||||
db=db_session,
|
||||
).data:
|
||||
for event in self.events:
|
||||
event_obj = Events.find_or_create(
|
||||
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,
|
||||
)
|
||||
event_obj.save()
|
||||
print(f'UUID: {event_obj.uu_id} event is saved to {to_save_endpoint.uu_id}')
|
||||
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])
|
||||
# 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}"
|
||||
|
|
@ -75,7 +80,6 @@ class Event:
|
|||
self.response_validator = response_validator
|
||||
self.description = description
|
||||
|
||||
|
||||
def event_callable(self):
|
||||
"""
|
||||
Example callable method
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ from ..config import api_config
|
|||
|
||||
async def token_middleware(request: Request, call_next):
|
||||
|
||||
base_url = "/".join(request.url.path.split("/")[:3])
|
||||
base_url = request.url.path
|
||||
safe_endpoints = [_[0] for _ in get_safe_endpoint_urls()]
|
||||
if base_url in safe_endpoints:
|
||||
return await call_next(request)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ from fastapi import FastAPI
|
|||
from fastapi.routing import APIRoute
|
||||
from fastapi.openapi.utils import get_openapi
|
||||
|
||||
from ApiServices.TemplateService.config import template_api_config
|
||||
from .config import api_config as template_api_config
|
||||
from ApiServices.TemplateService.endpoints.routes import get_safe_endpoint_urls
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||
|
||||
|
||||
class Configs(BaseSettings):
|
||||
"""
|
||||
Email configuration settings.
|
||||
"""
|
||||
|
||||
HOST: str = ""
|
||||
USERNAME: str = ""
|
||||
PASSWORD: str = ""
|
||||
PORT: int = 0
|
||||
SEND: bool = False
|
||||
|
||||
@property
|
||||
def is_send(self):
|
||||
return bool(self.SEND)
|
||||
|
||||
@classmethod
|
||||
def as_dict(cls):
|
||||
return dict(
|
||||
host=cls.EMAIL_HOST,
|
||||
port=cls.EMAIL_PORT,
|
||||
username=cls.EMAIL_USERNAME,
|
||||
password=cls.EMAIL_PASSWORD,
|
||||
)
|
||||
|
||||
model_config = SettingsConfigDict(env_prefix="EMAIL_")
|
||||
|
||||
|
||||
# singleton instance of the POSTGRESQL configuration settings
|
||||
email_configs = Configs()
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
from send_email import EmailService, EmailSendModel
|
||||
|
||||
|
||||
# Create email parameters
|
||||
email_params = EmailSendModel(
|
||||
subject="Test Email",
|
||||
html="<p>Hello world!</p>",
|
||||
receivers=["recipient@example.com"],
|
||||
text="Hello world!",
|
||||
)
|
||||
|
||||
another_email_params = EmailSendModel(
|
||||
subject="Test Email2",
|
||||
html="<p>Hello world!2</p>",
|
||||
receivers=["recipient@example.com"],
|
||||
text="Hello world!2",
|
||||
)
|
||||
|
||||
|
||||
# The context manager handles connection errors
|
||||
with EmailService.new_session() as email_session:
|
||||
# Send email - any exceptions here will propagate up
|
||||
EmailService.send_email(email_session, email_params)
|
||||
|
||||
# Or send directly through the session
|
||||
email_session.send(email_params)
|
||||
|
||||
# Send more emails in the same session if needed
|
||||
EmailService.send_email(email_session, another_email_params)
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
from redmail import EmailSender
|
||||
from typing import List, Optional, Dict
|
||||
from pydantic import BaseModel
|
||||
from config import Configs
|
||||
from contextlib import contextmanager
|
||||
|
||||
|
||||
class EmailSendModel(BaseModel):
|
||||
subject: str
|
||||
html: str = ""
|
||||
receivers: List[str]
|
||||
text: Optional[str] = ""
|
||||
cc: Optional[List[str]] = None
|
||||
bcc: Optional[List[str]] = None
|
||||
headers: Optional[Dict] = None
|
||||
attachments: Optional[Dict] = None
|
||||
|
||||
|
||||
class EmailSession:
|
||||
|
||||
def __init__(self, email_sender):
|
||||
self.email_sender = email_sender
|
||||
|
||||
def send(self, params: EmailSendModel) -> bool:
|
||||
"""Send email using this session."""
|
||||
if not Configs.is_send:
|
||||
print("Email sending is disabled", params)
|
||||
return False
|
||||
|
||||
receivers = [Configs.USERNAME]
|
||||
self.email_sender.send(
|
||||
subject=params.subject,
|
||||
receivers=receivers,
|
||||
text=params.text + f" : Gonderilen [{str(receivers)}]",
|
||||
html=params.html,
|
||||
cc=params.cc,
|
||||
bcc=params.bcc,
|
||||
headers=params.headers or {},
|
||||
attachments=params.attachments or {},
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
class EmailService:
|
||||
_instance = None
|
||||
|
||||
def __new__(cls):
|
||||
if cls._instance is None:
|
||||
cls._instance = super(EmailService, cls).__new__(cls)
|
||||
return cls._instance
|
||||
|
||||
@classmethod
|
||||
@contextmanager
|
||||
def new_session(cls):
|
||||
"""Create and yield a new email session with active connection."""
|
||||
email_sender = EmailSender(**Configs.as_dict())
|
||||
session = EmailSession(email_sender)
|
||||
try:
|
||||
email_sender.connect()
|
||||
yield session
|
||||
except Exception as e:
|
||||
print(f"Error with email connection: {e}")
|
||||
raise
|
||||
finally:
|
||||
email_sender.close()
|
||||
|
||||
@classmethod
|
||||
def send_email(cls, session: EmailSession, params: EmailSendModel) -> bool:
|
||||
"""Send email using the provided session."""
|
||||
return session.send(params)
|
||||
|
|
@ -23,4 +23,3 @@ class Configs(BaseSettings):
|
|||
|
||||
|
||||
redis_configs = Configs() # singleton instance of the REDIS configuration settings
|
||||
print(redis_configs.as_dict())
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import uuid
|
|||
import secrets
|
||||
import random
|
||||
|
||||
from config import token_config
|
||||
from .config import token_config
|
||||
|
||||
|
||||
class PasswordModule:
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ from sqlalchemy import (
|
|||
from sqlalchemy.orm import mapped_column, relationship, Mapped
|
||||
|
||||
from Controllers.Postgres.mixin import CrudCollection
|
||||
from Schemas import Duties, Addresses
|
||||
|
||||
|
||||
class RelationshipDutyCompany(CrudCollection):
|
||||
|
|
@ -60,6 +59,8 @@ class RelationshipDutyCompany(CrudCollection):
|
|||
|
||||
@classmethod
|
||||
def match_company_to_company_commercial(cls, data: Any, token):
|
||||
from Schemas import Duties
|
||||
|
||||
with cls.new_session() as db_session:
|
||||
token_duties_id, token_company_id = token.get("duty_id"), token.get(
|
||||
"company_id"
|
||||
|
|
@ -108,6 +109,8 @@ class RelationshipDutyCompany(CrudCollection):
|
|||
|
||||
@classmethod
|
||||
def match_company_to_company_organization(cls, data: Any, token):
|
||||
from Schemas import Duties
|
||||
|
||||
with cls.new_session() as db_session:
|
||||
token_duties_id, token_company_id = token.get("duty_id"), token.get(
|
||||
"company_id"
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ from sqlalchemy import (
|
|||
)
|
||||
from sqlalchemy.orm import mapped_column, Mapped
|
||||
from Controllers.Postgres.mixin import CrudCollection
|
||||
from Schemas import OccupantTypes
|
||||
|
||||
|
||||
class Events(CrudCollection):
|
||||
|
|
@ -21,26 +20,24 @@ class Events(CrudCollection):
|
|||
__tablename__ = "events"
|
||||
__exclude__fields__ = []
|
||||
|
||||
event_type: Mapped[str] = mapped_column(
|
||||
String, nullable=False, comment="Event Type"
|
||||
)
|
||||
function_code: Mapped[str] = mapped_column(
|
||||
String, nullable=False, comment="function code"
|
||||
String, nullable=False, comment="function code", unique=True
|
||||
)
|
||||
function_class: Mapped[str] = mapped_column(
|
||||
String, nullable=False, comment="class name"
|
||||
)
|
||||
|
||||
# name: Mapped[str] = mapped_column(String, nullable=True) # form or page title
|
||||
description: Mapped[str] = mapped_column(
|
||||
String, server_default=""
|
||||
) # form or page description
|
||||
description: Mapped[str] = mapped_column(String, server_default="")
|
||||
property_description: Mapped[str] = mapped_column(String, server_default="")
|
||||
|
||||
marketing_layer = mapped_column(SmallInteger, server_default="3")
|
||||
cost: Mapped[float] = mapped_column(Numeric(20, 2), server_default="0.00")
|
||||
unit_price: Mapped[float] = mapped_column(Numeric(20, 2), server_default="0.00")
|
||||
|
||||
endpoint_code: Mapped[str] = mapped_column(
|
||||
String, nullable=False, comment="Event Type"
|
||||
)
|
||||
endpoint_id: Mapped[int] = mapped_column(
|
||||
ForeignKey("endpoint_restriction.id"), nullable=True
|
||||
)
|
||||
|
|
@ -108,6 +105,8 @@ class Services(CrudCollection):
|
|||
|
||||
@classmethod
|
||||
def retrieve_service_via_occupant_code(cls, occupant_code):
|
||||
from Schemas import OccupantTypes
|
||||
|
||||
with cls.new_session() as db_session:
|
||||
occupant_type = OccupantTypes.filter_by_one(
|
||||
system=True, occupant_code=occupant_code, db=db_session
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ class UsersTokens(CrudCollection):
|
|||
domain: Mapped[str] = mapped_column(String, server_default="")
|
||||
expires_at: Mapped[TIMESTAMP] = mapped_column(
|
||||
TIMESTAMP(timezone=True),
|
||||
default=str(arrow.now().shift(date=arrow.now(), days=3)),
|
||||
default=str(arrow.now().shift(days=3)),
|
||||
)
|
||||
|
||||
# users = relationship("Users", back_populates="tokens", foreign_keys=[user_id])
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ class EndpointRestriction(CrudCollection):
|
|||
__exclude__fields__ = []
|
||||
|
||||
operation_uu_id: Mapped[UUID] = mapped_column(
|
||||
String, comment="UUID of the operation",
|
||||
String, comment="UUID of the operation", nullable=False, unique=True
|
||||
)
|
||||
endpoint_function: Mapped[str] = mapped_column(
|
||||
String, server_default="", comment="Function name of the API endpoint"
|
||||
|
|
@ -33,6 +33,3 @@ class EndpointRestriction(CrudCollection):
|
|||
endpoint_desc: Mapped[str] = mapped_column(
|
||||
String, server_default="", comment="Description of the endpoint"
|
||||
)
|
||||
endpoint_code: Mapped[str] = mapped_column(
|
||||
String, server_default="", unique=True, comment="Unique code for the endpoint"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
## Next-js service serves with other api services
|
||||
|
||||
### Client-Frontend
|
||||
|
||||
4 Client use only
|
||||
|
||||
### Management-Backend
|
||||
|
||||
4 Management use only
|
||||
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.*
|
||||
.yarn/*
|
||||
!.yarn/patches
|
||||
!.yarn/plugins
|
||||
!.yarn/releases
|
||||
!.yarn/versions
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# env files (can opt-in for committing if needed)
|
||||
.env*
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
FROM node:18-alpine
|
||||
|
||||
WORKDIR /
|
||||
|
||||
# Copy package.json and package-lock.json
|
||||
COPY /WebServices/client-frontend/package*.json ./WebServices/client-frontend/
|
||||
|
||||
# Install dependencies
|
||||
RUN cd ./WebServices/client-frontend && npm install
|
||||
|
||||
# Copy the rest of the application
|
||||
COPY /WebServices/client-frontend ./WebServices/client-frontend
|
||||
|
||||
## Build the Next.js app
|
||||
#RUN cd ./WebServices/client-frontend && npm run dev
|
||||
|
||||
# Expose the port the app runs on
|
||||
EXPOSE 3000
|
||||
|
||||
# Command to run the app
|
||||
CMD ["sh", "-c", "cd /WebServices/client-frontend && npm run dev"]
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
|
||||
|
||||
## Getting Started
|
||||
|
||||
First, run the development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
# or
|
||||
yarn dev
|
||||
# or
|
||||
pnpm dev
|
||||
# or
|
||||
bun dev
|
||||
```
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
|
||||
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
||||
|
||||
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
|
||||
|
||||
## Learn More
|
||||
|
||||
To learn more about Next.js, take a look at the following resources:
|
||||
|
||||
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
||||
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
||||
|
||||
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
|
||||
|
||||
## Deploy on Vercel
|
||||
|
||||
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
||||
|
||||
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
import type { NextConfig } from "next";
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
/* config options here */
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"name": "client-frontend",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"next": "15.2.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
"@tailwindcss/postcss": "^4",
|
||||
"tailwindcss": "^4"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
const config = {
|
||||
plugins: ["@tailwindcss/postcss"],
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
|
@ -0,0 +1 @@
|
|||
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>
|
||||
|
After Width: | Height: | Size: 391 B |
|
|
@ -0,0 +1 @@
|
|||
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
|
|
@ -0,0 +1 @@
|
|||
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>
|
||||
|
After Width: | Height: | Size: 128 B |
|
|
@ -0,0 +1 @@
|
|||
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>
|
||||
|
After Width: | Height: | Size: 385 B |
|
After Width: | Height: | Size: 25 KiB |
|
|
@ -0,0 +1,26 @@
|
|||
@import "tailwindcss";
|
||||
|
||||
:root {
|
||||
--background: #ffffff;
|
||||
--foreground: #171717;
|
||||
}
|
||||
|
||||
@theme inline {
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
--font-sans: var(--font-geist-sans);
|
||||
--font-mono: var(--font-geist-mono);
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--background: #0a0a0a;
|
||||
--foreground: #ededed;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
background: var(--background);
|
||||
color: var(--foreground);
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
import type { Metadata } from "next";
|
||||
import { Geist, Geist_Mono } from "next/font/google";
|
||||
import "./globals.css";
|
||||
|
||||
const geistSans = Geist({
|
||||
variable: "--font-geist-sans",
|
||||
subsets: ["latin"],
|
||||
});
|
||||
|
||||
const geistMono = Geist_Mono({
|
||||
variable: "--font-geist-mono",
|
||||
subsets: ["latin"],
|
||||
});
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Create Next App",
|
||||
description: "Generated by create next app",
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body
|
||||
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
|
||||
>
|
||||
{children}
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
import Image from "next/image";
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-geist-sans)]">
|
||||
<main className="flex flex-col gap-[32px] row-start-2 items-center sm:items-start">
|
||||
<Image
|
||||
className="dark:invert"
|
||||
src="/next.svg"
|
||||
alt="Next.js logo"
|
||||
width={180}
|
||||
height={38}
|
||||
priority
|
||||
/>
|
||||
<ol className="list-inside list-decimal text-sm/6 text-center sm:text-left font-[family-name:var(--font-geist-mono)]">
|
||||
<li className="mb-2 tracking-[-.01em]">
|
||||
Get started by editing{" "}
|
||||
<code className="bg-black/[.05] dark:bg-white/[.06] px-1 py-0.5 rounded font-[family-name:var(--font-geist-mono)] font-semibold">
|
||||
src/app/page.tsx
|
||||
</code>
|
||||
.
|
||||
</li>
|
||||
<li className="tracking-[-.01em]">
|
||||
Save and see your changes instantly.
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<div className="flex gap-4 items-center flex-col sm:flex-row">
|
||||
<a
|
||||
className="rounded-full border border-solid border-transparent transition-colors flex items-center justify-center bg-foreground text-background gap-2 hover:bg-[#383838] dark:hover:bg-[#ccc] font-medium text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 sm:w-auto"
|
||||
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Image
|
||||
className="dark:invert"
|
||||
src="/vercel.svg"
|
||||
alt="Vercel logomark"
|
||||
width={20}
|
||||
height={20}
|
||||
/>
|
||||
Deploy now
|
||||
</a>
|
||||
<a
|
||||
className="rounded-full border border-solid border-black/[.08] dark:border-white/[.145] transition-colors flex items-center justify-center hover:bg-[#f2f2f2] dark:hover:bg-[#1a1a1a] hover:border-transparent font-medium text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 w-full sm:w-auto md:w-[158px]"
|
||||
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Read our docs
|
||||
</a>
|
||||
</div>
|
||||
</main>
|
||||
<footer className="row-start-3 flex gap-[24px] flex-wrap items-center justify-center">
|
||||
<a
|
||||
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
||||
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Image
|
||||
aria-hidden
|
||||
src="/file.svg"
|
||||
alt="File icon"
|
||||
width={16}
|
||||
height={16}
|
||||
/>
|
||||
Learn
|
||||
</a>
|
||||
<a
|
||||
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
||||
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Image
|
||||
aria-hidden
|
||||
src="/window.svg"
|
||||
alt="Window icon"
|
||||
width={16}
|
||||
height={16}
|
||||
/>
|
||||
Examples
|
||||
</a>
|
||||
<a
|
||||
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
||||
href="https://nextjs.org?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Image
|
||||
aria-hidden
|
||||
src="/globe.svg"
|
||||
alt="Globe icon"
|
||||
width={16}
|
||||
height={16}
|
||||
/>
|
||||
Go to nextjs.org →
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2017",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"incremental": true,
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.*
|
||||
.yarn/*
|
||||
!.yarn/patches
|
||||
!.yarn/plugins
|
||||
!.yarn/releases
|
||||
!.yarn/versions
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# env files (can opt-in for committing if needed)
|
||||
.env*
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
FROM node:18-alpine
|
||||
|
||||
WORKDIR /
|
||||
|
||||
# Copy package.json and package-lock.json
|
||||
COPY WebServices/management-frontend/package*.json ./WebServices/management-frontend/
|
||||
|
||||
# Install dependencies
|
||||
RUN cd ./WebServices/management-frontend && npm install
|
||||
|
||||
# Copy the rest of the application
|
||||
COPY WebServices/management-frontend ./WebServices/management-frontend
|
||||
|
||||
## Build the Next.js app
|
||||
#RUN cd ./WebServices/management-frontend && npm run build
|
||||
|
||||
# Expose the port the app runs on
|
||||
EXPOSE 3000
|
||||
|
||||
# Command to run the app
|
||||
CMD ["sh", "-c", "cd /WebServices/management-frontend && npm run dev"]
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
|
||||
|
||||
## Getting Started
|
||||
|
||||
First, run the development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
# or
|
||||
yarn dev
|
||||
# or
|
||||
pnpm dev
|
||||
# or
|
||||
bun dev
|
||||
```
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
|
||||
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
||||
|
||||
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
|
||||
|
||||
## Learn More
|
||||
|
||||
To learn more about Next.js, take a look at the following resources:
|
||||
|
||||
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
||||
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
||||
|
||||
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
|
||||
|
||||
## Deploy on Vercel
|
||||
|
||||
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
||||
|
||||
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
import type { NextConfig } from "next";
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
/* config options here */
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"name": "management-frontend",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"next": "15.2.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
"@tailwindcss/postcss": "^4",
|
||||
"tailwindcss": "^4"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
const config = {
|
||||
plugins: ["@tailwindcss/postcss"],
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
|
@ -0,0 +1 @@
|
|||
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>
|
||||
|
After Width: | Height: | Size: 391 B |
|
|
@ -0,0 +1 @@
|
|||
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
|
|
@ -0,0 +1 @@
|
|||
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>
|
||||
|
After Width: | Height: | Size: 128 B |
|
|
@ -0,0 +1 @@
|
|||
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>
|
||||
|
After Width: | Height: | Size: 385 B |
|
After Width: | Height: | Size: 25 KiB |
|
|
@ -0,0 +1,26 @@
|
|||
@import "tailwindcss";
|
||||
|
||||
:root {
|
||||
--background: #ffffff;
|
||||
--foreground: #171717;
|
||||
}
|
||||
|
||||
@theme inline {
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
--font-sans: var(--font-geist-sans);
|
||||
--font-mono: var(--font-geist-mono);
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--background: #0a0a0a;
|
||||
--foreground: #ededed;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
background: var(--background);
|
||||
color: var(--foreground);
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
import type { Metadata } from "next";
|
||||
import { Geist, Geist_Mono } from "next/font/google";
|
||||
import "./globals.css";
|
||||
|
||||
const geistSans = Geist({
|
||||
variable: "--font-geist-sans",
|
||||
subsets: ["latin"],
|
||||
});
|
||||
|
||||
const geistMono = Geist_Mono({
|
||||
variable: "--font-geist-mono",
|
||||
subsets: ["latin"],
|
||||
});
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Create Next App",
|
||||
description: "Generated by create next app",
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body
|
||||
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
|
||||
>
|
||||
{children}
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
import Image from "next/image";
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-geist-sans)]">
|
||||
<main className="flex flex-col gap-[32px] row-start-2 items-center sm:items-start">
|
||||
<Image
|
||||
className="dark:invert"
|
||||
src="/next.svg"
|
||||
alt="Next.js logo"
|
||||
width={180}
|
||||
height={38}
|
||||
priority
|
||||
/>
|
||||
<ol className="list-inside list-decimal text-sm/6 text-center sm:text-left font-[family-name:var(--font-geist-mono)]">
|
||||
<li className="mb-2 tracking-[-.01em]">
|
||||
Get started by editing{" "}
|
||||
<code className="bg-black/[.05] dark:bg-white/[.06] px-1 py-0.5 rounded font-[family-name:var(--font-geist-mono)] font-semibold">
|
||||
src/app/page.tsx
|
||||
</code>
|
||||
.
|
||||
</li>
|
||||
<li className="tracking-[-.01em]">
|
||||
Save and see your changes instantly.
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<div className="flex gap-4 items-center flex-col sm:flex-row">
|
||||
<a
|
||||
className="rounded-full border border-solid border-transparent transition-colors flex items-center justify-center bg-foreground text-background gap-2 hover:bg-[#383838] dark:hover:bg-[#ccc] font-medium text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 sm:w-auto"
|
||||
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Image
|
||||
className="dark:invert"
|
||||
src="/vercel.svg"
|
||||
alt="Vercel logomark"
|
||||
width={20}
|
||||
height={20}
|
||||
/>
|
||||
Deploy now
|
||||
</a>
|
||||
<a
|
||||
className="rounded-full border border-solid border-black/[.08] dark:border-white/[.145] transition-colors flex items-center justify-center hover:bg-[#f2f2f2] dark:hover:bg-[#1a1a1a] hover:border-transparent font-medium text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 w-full sm:w-auto md:w-[158px]"
|
||||
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Read our docs
|
||||
</a>
|
||||
</div>
|
||||
</main>
|
||||
<footer className="row-start-3 flex gap-[24px] flex-wrap items-center justify-center">
|
||||
<a
|
||||
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
||||
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Image
|
||||
aria-hidden
|
||||
src="/file.svg"
|
||||
alt="File icon"
|
||||
width={16}
|
||||
height={16}
|
||||
/>
|
||||
Learn
|
||||
</a>
|
||||
<a
|
||||
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
||||
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Image
|
||||
aria-hidden
|
||||
src="/window.svg"
|
||||
alt="Window icon"
|
||||
width={16}
|
||||
height={16}
|
||||
/>
|
||||
Examples
|
||||
</a>
|
||||
<a
|
||||
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
||||
href="https://nextjs.org?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Image
|
||||
aria-hidden
|
||||
src="/globe.svg"
|
||||
alt="Globe icon"
|
||||
width={16}
|
||||
height={16}
|
||||
/>
|
||||
Go to nextjs.org →
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2017",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"incremental": true,
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
|
@ -20,7 +20,6 @@ REDIS_HOST=redis_service
|
|||
REDIS_PASSWORD=commercial_redis_password
|
||||
REDIS_PORT=6379
|
||||
REDIS_DB=0
|
||||
API_ACCESS_TOKEN_TAG=evyos-session-key
|
||||
API_ACCESS_EMAIL_EXT=evyos.com.tr
|
||||
API_ALGORITHM=HS256
|
||||
API_ACCESS_TOKEN_LENGTH=90
|
||||
|
|
@ -29,3 +28,9 @@ API_EMAIL_HOST=10.10.2.36
|
|||
API_DATETIME_FORMAT=YYYY-MM-DD HH:mm:ss Z
|
||||
API_FORGOT_LINK=https://www.evyos.com.tr/password/create?tokenUrl=
|
||||
API_VERSION=0.1.001
|
||||
API_ACCESS_TOKEN_TAG=eys-acs-tkn
|
||||
EMAIL_HOST=10.10.2.34
|
||||
EMAIL_USERNAME=karatay@mehmetkaratay.com.tr
|
||||
EMAIL_PASSWORD=system
|
||||
EMAIL_PORT=587
|
||||
EMAIL_SEND=0
|
||||
|
|
|
|||
|
|
@ -50,6 +50,52 @@ services:
|
|||
ports:
|
||||
- "11222:6379"
|
||||
|
||||
client_frontend:
|
||||
container_name: client_frontend
|
||||
build:
|
||||
context: .
|
||||
dockerfile: WebServices/client-frontend/Dockerfile
|
||||
networks:
|
||||
- wag-services
|
||||
ports:
|
||||
- "3000:3000"
|
||||
volumes:
|
||||
- .WebServices/client-frontend:WebServices/client-frontend
|
||||
- WebServices/client-frontend/node_modules
|
||||
- WebServices/client-frontend/.next
|
||||
environment:
|
||||
- NODE_ENV=development
|
||||
|
||||
management_frontend:
|
||||
container_name: management_frontend
|
||||
build:
|
||||
context: .
|
||||
dockerfile: WebServices/management-frontend/Dockerfile
|
||||
networks:
|
||||
- wag-services
|
||||
ports:
|
||||
- "3001:3000" # Using different host port to avoid conflicts
|
||||
volumes:
|
||||
- .WebServices/management-frontend:WebServices/management-frontend
|
||||
- WebServices/management-frontend/node_modules
|
||||
- WebServices/management-frontend/.next
|
||||
environment:
|
||||
- NODE_ENV=development
|
||||
|
||||
# initializer_service:
|
||||
# container_name: initializer_service
|
||||
# build:
|
||||
# context: .
|
||||
# dockerfile: ApiServices/InitialService/Dockerfile
|
||||
# networks:
|
||||
# - wag-services
|
||||
# env_file:
|
||||
# - api_env.env
|
||||
# depends_on:
|
||||
# - postgres-service
|
||||
# - mongo_service
|
||||
# - redis_service
|
||||
|
||||
# template_service:
|
||||
# container_name: template_service
|
||||
# build:
|
||||
|
|
@ -93,7 +139,6 @@ services:
|
|||
- API_PORT=8001
|
||||
- API_LOG_LEVEL=info
|
||||
- API_RELOAD=1
|
||||
- API_ACCESS_TOKEN_TAG=eys-acs-tkn
|
||||
- API_APP_NAME=evyos-auth-api-gateway
|
||||
- API_TITLE=WAG API Auth Api Gateway
|
||||
- API_FORGOT_LINK=https://auth_service/forgot-password
|
||||
|
|
@ -116,6 +161,7 @@ services:
|
|||
# networks:
|
||||
# - wag-services
|
||||
|
||||
|
||||
networks:
|
||||
wag-services:
|
||||
|
||||
|
|
|
|||