updated timezone params header

This commit is contained in:
berkay 2025-04-03 15:20:39 +03:00
parent ee405133be
commit f284d4c61b
7 changed files with 322 additions and 120 deletions

View File

@ -1,7 +1,6 @@
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import RedirectResponse
from fastapi.staticfiles import StaticFiles
from ApiServices.AuthService.create_route import RouteRegisterController
from ApiServices.AuthService.endpoints.routes import get_routes
@ -13,11 +12,6 @@ from ApiServices.AuthService.config import api_config
def create_app():
application = FastAPI(**api_config.api_info)
# application.mount(
# "/application/static",
# StaticFiles(directory="application/static"),
# name="static",
# )
application.add_middleware(
CORSMiddleware,
allow_origins=api_config.ALLOW_ORIGINS,

View File

@ -8,7 +8,10 @@ from ApiServices.AuthService.config import api_config
from ApiServices.AuthService.validations.request.authentication.login_post import (
RequestLogin,
RequestSelectLiving,
RequestSelectOccupant, RequestCreatePassword, RequestChangePassword, RequestForgotPasswordPhone,
RequestSelectOccupant,
RequestCreatePassword,
RequestChangePassword,
RequestForgotPasswordPhone,
RequestForgotPasswordEmail,
)
@ -29,6 +32,7 @@ def authentication_login_post(
data: RequestLogin,
language: str = Header(None, alias="language"),
domain: str = Header(None, alias="domain"),
tz: str = Header(None, alias="timezone"),
):
"""
Authentication Login Route with Post Method
@ -61,6 +65,7 @@ def authentication_select_post(
data: Union[RequestSelectOccupant, RequestSelectLiving],
language: str = Header(None, alias="language"),
domain: str = Header(None, alias="domain"),
tz: str = Header(None, alias="timezone"),
):
"""
Authentication Select Route with Post Method
@ -86,6 +91,109 @@ def authentication_select_post(
)
@auth_route.post(
path="/password/create",
summary="Create password with access token",
description="Create password",
)
def authentication_password_create_post(
request: Request,
data: RequestCreatePassword,
language: str = Header(None, alias="language"),
domain: str = Header(None, alias="domain"),
tz: str = Header(None, alias="timezone"),
):
"""
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,
}
if not domain or not language:
return JSONResponse(
content={"error": "EYS_0001"},
status_code=status.HTTP_406_NOT_ACCEPTABLE,
headers=headers,
)
return JSONResponse(
content={**data.model_dump()},
status_code=status.HTTP_202_ACCEPTED,
headers=headers,
)
@auth_route.post(
path="/password/change",
summary="Change password with access token",
description="Change password",
)
def authentication_password_change_post(
request: Request,
data: RequestChangePassword,
language: str = Header(None, alias="language"),
domain: str = Header(None, alias="domain"),
tz: str = Header(None, alias="timezone"),
):
"""
Authentication change 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,
}
if not domain or not language:
return JSONResponse(
content={"error": "EYS_0001"},
status_code=status.HTTP_406_NOT_ACCEPTABLE,
headers=headers,
)
return JSONResponse(
content={**data.model_dump()},
status_code=status.HTTP_202_ACCEPTED,
headers=headers,
)
@auth_route.post(
path="/password/reset",
summary="Reset password with access token",
description="Reset password",
)
def authentication_password_reset_post(
request: Request,
data: Union[RequestForgotPasswordEmail, RequestForgotPasswordPhone],
language: str = Header(None, alias="language"),
domain: str = Header(None, alias="domain"),
tz: str = Header(None, alias="timezone"),
):
"""
Authentication reset password Route with Post Method
"""
headers = {
"language": language or "",
"domain": domain or "",
"eys-ext": f"{str(uuid.uuid4())}",
}
if not domain or not language:
return JSONResponse(
content={"error": "EYS_0001"},
status_code=status.HTTP_406_NOT_ACCEPTABLE,
headers=headers,
)
return JSONResponse(
content={**data.model_dump()},
status_code=status.HTTP_202_ACCEPTED,
headers=headers,
)
@auth_route.get(
path="/logout",
summary="Logout user",
@ -95,6 +203,7 @@ def authentication_logout_post(
request: Request,
language: str = Header(None, alias="language"),
domain: str = Header(None, alias="domain"),
tz: str = Header(None, alias="timezone"),
):
"""
Logout user from the system
@ -129,6 +238,7 @@ def authentication_disconnect_post(
request: Request,
language: str = Header(None, alias="language"),
domain: str = Header(None, alias="domain"),
tz: str = Header(None, alias="timezone"),
):
"""
Disconnect all sessions of user in access token
@ -164,6 +274,7 @@ def authentication_token_check_post(
request: Request,
language: str = Header(None, alias="language"),
domain: str = Header(None, alias="domain"),
tz: str = Header(None, alias="timezone"),
):
"""
Check if access token is valid for user
@ -199,6 +310,7 @@ def authentication_token_refresh_post(
request: Request,
language: str = Header(None, alias="language"),
domain: str = Header(None, alias="domain"),
tz: str = Header(None, alias="timezone"),
):
"""
Refresh if access token is valid for user
@ -220,103 +332,3 @@ def authentication_token_refresh_post(
status_code=status.HTTP_202_ACCEPTED,
headers=headers,
)
@auth_route.post(
path="/password/create",
summary="Create password with access token",
description="Create password",
)
def authentication_password_create_post(
request: Request,
data: RequestCreatePassword,
language: str = Header(None, alias="language"),
domain: str = Header(None, alias="domain"),
):
"""
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,
}
if not domain or not language:
return JSONResponse(
content={"error": "EYS_0001"},
status_code=status.HTTP_406_NOT_ACCEPTABLE,
headers=headers,
)
return JSONResponse(
content={**data.model_dump()},
status_code=status.HTTP_202_ACCEPTED,
headers=headers,
)
@auth_route.post(
path="/password/change",
summary="Change password with access token",
description="Change password",
)
def authentication_password_change_post(
request: Request,
data: RequestChangePassword,
language: str = Header(None, alias="language"),
domain: str = Header(None, alias="domain"),
):
"""
Authentication change 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,
}
if not domain or not language:
return JSONResponse(
content={"error": "EYS_0001"},
status_code=status.HTTP_406_NOT_ACCEPTABLE,
headers=headers,
)
return JSONResponse(
content={**data.model_dump()},
status_code=status.HTTP_202_ACCEPTED,
headers=headers,
)
@auth_route.post(
path="/password/reset",
summary="Reset password with access token",
description="Reset password",
)
def authentication_password_reset_post(
request: Request,
data: Union[RequestForgotPasswordEmail, RequestForgotPasswordPhone],
language: str = Header(None, alias="language"),
domain: str = Header(None, alias="domain"),
):
"""
Authentication reset password Route with Post Method
"""
headers = {
"language": language or "",
"domain": domain or "",
"eys-ext": f"{str(uuid.uuid4())}",
}
if not domain or not language:
return JSONResponse(
content={"error": "EYS_0001"},
status_code=status.HTTP_406_NOT_ACCEPTABLE,
headers=headers,
)
return JSONResponse(
content={**data.model_dump()},
status_code=status.HTTP_202_ACCEPTED,
headers=headers,
)

View File

@ -0,0 +1,2 @@
class AuthHandlers:
pass

View File

@ -0,0 +1,120 @@
import enum
from typing import Optional, List
from pydantic import BaseModel
# Company / Priority / Department / Duty / Employee / Occupant / Module / Endpoint are changeable dynamics
# domain: Optional[str] = "app.evyos.com.tr"
# lang: Optional[str] = "TR"
# timezone: Optional[str] = "GMT+3"
# full_name: Optional[str] = None
class UserType(enum.Enum):
employee = 1
occupant = 2
class Credentials(BaseModel):
person_id: int
person_name: str
class ApplicationToken(BaseModel):
# Application Token Object -> is the main object for the user
user_type: int = UserType.occupant.value
credential_token: str = ""
user_uu_id: str
user_id: int
person_id: int
person_uu_id: str
request: Optional[dict] = None # Request Info of Client
expires_at: Optional[float] = None # Expiry timestamp
class OccupantToken(BaseModel):
# Selection of the occupant type for a build part is made by the user
living_space_id: int # Internal use
living_space_uu_id: str # Outer use
occupant_type_id: int
occupant_type_uu_id: str
occupant_type: str
build_id: int
build_uuid: str
build_part_id: int
build_part_uuid: str
responsible_company_id: Optional[int] = None
responsible_company_uuid: Optional[str] = None
responsible_employee_id: Optional[int] = None
responsible_employee_uuid: Optional[str] = None
reachable_event_codes: Optional[list[str]] = None # ID list of reachable modules
class CompanyToken(BaseModel):
# Selection of the company for an employee is made by the user
company_id: int
company_uu_id: str
department_id: int # ID list of departments
department_uu_id: str # ID list of departments
duty_id: int
duty_uu_id: str
staff_id: int
staff_uu_id: str
employee_id: int
employee_uu_id: str
bulk_duties_id: int
reachable_event_codes: Optional[list[str]] = None # ID list of reachable modules
class OccupantTokenObject(ApplicationToken):
# Occupant Token Object -> Requires selection of the occupant type for a specific build part
available_occupants: dict = None
selected_occupant: Optional[OccupantToken] = None # Selected Occupant Type
@property
def is_employee(self) -> bool:
return False
@property
def is_occupant(self) -> bool:
return True
class EmployeeTokenObject(ApplicationToken):
# Full hierarchy Employee[staff_id] -> Staff -> Duty -> Department -> Company
companies_id_list: List[int] # List of company objects
companies_uu_id_list: List[str] # List of company objects
duty_id_list: List[int] # List of duty objects
duty_uu_id_list: List[str] # List of duty objects
selected_company: Optional[CompanyToken] = None # Selected Company Object
@property
def is_employee(self) -> bool:
return True
@property
def is_occupant(self) -> bool:
return False

View File

@ -10,24 +10,50 @@ class RequestLogin(BaseModel):
class RequestSelectOccupant(BaseModel):
company_uu_id: str
@property
def is_employee(self):
return True
@property
def is_occupant(self):
return False
class RequestSelectLiving(BaseModel):
build_living_space_uu_id: str
@property
def is_employee(self):
return False
@property
def is_occupant(self):
return True
class RequestCreatePassword(BaseModel):
password_token: str
password: str
re_password: str
@property
def is_valid(self):
return self.password == self.re_password
class RequestChangePassword(BaseModel):
old_password: str
password: str
re_password: str
@property
def is_valid(self):
return self.password == self.re_password
class RequestForgotPasswordEmail(BaseModel):
email: str
@ -35,4 +61,3 @@ class RequestForgotPasswordEmail(BaseModel):
class RequestForgotPasswordPhone(BaseModel):
phone_number: str

View File

@ -114,18 +114,18 @@ class CrudCollection(CrudMixin):
cryp_uu_id: Mapped[str] = mapped_column(
String, nullable=True, index=True, comment="Cryptographic UUID"
)
created_by: Mapped[str] = mapped_column(
String, nullable=True, comment="Creator name"
)
created_by_id: Mapped[int] = mapped_column(
Integer, nullable=True, comment="Creator ID"
)
updated_by: Mapped[str] = mapped_column(
String, nullable=True, comment="Last modifier name"
)
updated_by_id: Mapped[int] = mapped_column(
Integer, nullable=True, comment="Last modifier ID"
)
# created_by: Mapped[str] = mapped_column(
# String, nullable=True, comment="Creator name"
# )
# created_by_id: Mapped[int] = mapped_column(
# Integer, nullable=True, comment="Creator ID"
# )
# updated_by: Mapped[str] = mapped_column(
# String, nullable=True, comment="Last modifier name"
# )
# updated_by_id: Mapped[int] = mapped_column(
# Integer, nullable=True, comment="Last modifier ID"
# )
confirmed_by: Mapped[str] = mapped_column(
String, nullable=True, comment="Confirmer name"
)

View File

@ -35,6 +35,55 @@ class UsersTokens(CrudCollection):
# users = relationship("Users", back_populates="tokens", foreign_keys=[user_id])
class Credentials(CrudCollection):
"""
Credentials class to store user credentials
"""
__tablename__ = "credentials"
__exclude__fields__ = []
credential_token: Mapped[str] = mapped_column(
String, server_default="", comment="Credential token for authentication"
)
user_id: Mapped[int] = mapped_column(
ForeignKey("users.id"), nullable=False, comment="Foreign key to users table"
)
user_uu_id: Mapped[str] = mapped_column(
String, server_default="", comment="User UUID", index=True
)
person_id: Mapped[int] = mapped_column(
ForeignKey("people.id"), nullable=False, comment="Foreign key to person table"
)
person_uu_id: Mapped[str] = mapped_column(
String, server_default="", comment="Person UUID", index=True
)
name: Mapped[str] = mapped_column(
String, server_default="", comment="Name of the user", index=True
)
surname: Mapped[str] = mapped_column(
String, server_default="", comment="Surname of the user", index=True
)
email: Mapped[str] = mapped_column(
String, server_default="", comment="Email address of the user", index=True
)
phone: Mapped[str] = mapped_column(
String, server_default="", comment="Phone number of the user", index=True
)
is_verified: Mapped[bool] = mapped_column(
Boolean, server_default="0", comment="Flag to check if user is verified"
)
def generate_token(self) -> str:
"""
Generate a unique token for the user
"""
name_token, rest_of_token = "", ""
if self.name and self.surname:
name_token = f"{self.name[0].upper()}{self.surname[0].upper()}"
return ""
class Users(CrudCollection):
"""
Application User frame to connect to API with assigned token-based HTTP connection