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 import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import RedirectResponse from fastapi.responses import RedirectResponse
from fastapi.staticfiles import StaticFiles
from ApiServices.AuthService.create_route import RouteRegisterController from ApiServices.AuthService.create_route import RouteRegisterController
from ApiServices.AuthService.endpoints.routes import get_routes from ApiServices.AuthService.endpoints.routes import get_routes
@ -13,11 +12,6 @@ from ApiServices.AuthService.config import api_config
def create_app(): def create_app():
application = FastAPI(**api_config.api_info) application = FastAPI(**api_config.api_info)
# application.mount(
# "/application/static",
# StaticFiles(directory="application/static"),
# name="static",
# )
application.add_middleware( application.add_middleware(
CORSMiddleware, CORSMiddleware,
allow_origins=api_config.ALLOW_ORIGINS, 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 ( from ApiServices.AuthService.validations.request.authentication.login_post import (
RequestLogin, RequestLogin,
RequestSelectLiving, RequestSelectLiving,
RequestSelectOccupant, RequestCreatePassword, RequestChangePassword, RequestForgotPasswordPhone, RequestSelectOccupant,
RequestCreatePassword,
RequestChangePassword,
RequestForgotPasswordPhone,
RequestForgotPasswordEmail, RequestForgotPasswordEmail,
) )
@ -29,6 +32,7 @@ def authentication_login_post(
data: RequestLogin, data: RequestLogin,
language: str = Header(None, alias="language"), language: str = Header(None, alias="language"),
domain: str = Header(None, alias="domain"), domain: str = Header(None, alias="domain"),
tz: str = Header(None, alias="timezone"),
): ):
""" """
Authentication Login Route with Post Method Authentication Login Route with Post Method
@ -61,6 +65,7 @@ def authentication_select_post(
data: Union[RequestSelectOccupant, RequestSelectLiving], data: Union[RequestSelectOccupant, RequestSelectLiving],
language: str = Header(None, alias="language"), language: str = Header(None, alias="language"),
domain: str = Header(None, alias="domain"), domain: str = Header(None, alias="domain"),
tz: str = Header(None, alias="timezone"),
): ):
""" """
Authentication Select Route with Post Method 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( @auth_route.get(
path="/logout", path="/logout",
summary="Logout user", summary="Logout user",
@ -95,6 +203,7 @@ def authentication_logout_post(
request: Request, request: Request,
language: str = Header(None, alias="language"), language: str = Header(None, alias="language"),
domain: str = Header(None, alias="domain"), domain: str = Header(None, alias="domain"),
tz: str = Header(None, alias="timezone"),
): ):
""" """
Logout user from the system Logout user from the system
@ -129,6 +238,7 @@ def authentication_disconnect_post(
request: Request, request: Request,
language: str = Header(None, alias="language"), language: str = Header(None, alias="language"),
domain: str = Header(None, alias="domain"), domain: str = Header(None, alias="domain"),
tz: str = Header(None, alias="timezone"),
): ):
""" """
Disconnect all sessions of user in access token Disconnect all sessions of user in access token
@ -164,6 +274,7 @@ def authentication_token_check_post(
request: Request, request: Request,
language: str = Header(None, alias="language"), language: str = Header(None, alias="language"),
domain: str = Header(None, alias="domain"), domain: str = Header(None, alias="domain"),
tz: str = Header(None, alias="timezone"),
): ):
""" """
Check if access token is valid for user Check if access token is valid for user
@ -199,6 +310,7 @@ def authentication_token_refresh_post(
request: Request, request: Request,
language: str = Header(None, alias="language"), language: str = Header(None, alias="language"),
domain: str = Header(None, alias="domain"), domain: str = Header(None, alias="domain"),
tz: str = Header(None, alias="timezone"),
): ):
""" """
Refresh if access token is valid for user Refresh if access token is valid for user
@ -220,103 +332,3 @@ def authentication_token_refresh_post(
status_code=status.HTTP_202_ACCEPTED, status_code=status.HTTP_202_ACCEPTED,
headers=headers, 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): class RequestSelectOccupant(BaseModel):
company_uu_id: str company_uu_id: str
@property
def is_employee(self):
return True
@property
def is_occupant(self):
return False
class RequestSelectLiving(BaseModel): class RequestSelectLiving(BaseModel):
build_living_space_uu_id: str build_living_space_uu_id: str
@property
def is_employee(self):
return False
@property
def is_occupant(self):
return True
class RequestCreatePassword(BaseModel): class RequestCreatePassword(BaseModel):
password_token: str password_token: str
password: str password: str
re_password: str re_password: str
@property
def is_valid(self):
return self.password == self.re_password
class RequestChangePassword(BaseModel): class RequestChangePassword(BaseModel):
old_password: str old_password: str
password: str password: str
re_password: str re_password: str
@property
def is_valid(self):
return self.password == self.re_password
class RequestForgotPasswordEmail(BaseModel): class RequestForgotPasswordEmail(BaseModel):
email: str email: str
@ -35,4 +61,3 @@ class RequestForgotPasswordEmail(BaseModel):
class RequestForgotPasswordPhone(BaseModel): class RequestForgotPasswordPhone(BaseModel):
phone_number: str phone_number: str

View File

@ -114,18 +114,18 @@ class CrudCollection(CrudMixin):
cryp_uu_id: Mapped[str] = mapped_column( cryp_uu_id: Mapped[str] = mapped_column(
String, nullable=True, index=True, comment="Cryptographic UUID" String, nullable=True, index=True, comment="Cryptographic UUID"
) )
created_by: Mapped[str] = mapped_column( # created_by: Mapped[str] = mapped_column(
String, nullable=True, comment="Creator name" # String, nullable=True, comment="Creator name"
) # )
created_by_id: Mapped[int] = mapped_column( # created_by_id: Mapped[int] = mapped_column(
Integer, nullable=True, comment="Creator ID" # Integer, nullable=True, comment="Creator ID"
) # )
updated_by: Mapped[str] = mapped_column( # updated_by: Mapped[str] = mapped_column(
String, nullable=True, comment="Last modifier name" # String, nullable=True, comment="Last modifier name"
) # )
updated_by_id: Mapped[int] = mapped_column( # updated_by_id: Mapped[int] = mapped_column(
Integer, nullable=True, comment="Last modifier ID" # Integer, nullable=True, comment="Last modifier ID"
) # )
confirmed_by: Mapped[str] = mapped_column( confirmed_by: Mapped[str] = mapped_column(
String, nullable=True, comment="Confirmer name" 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]) # 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): class Users(CrudCollection):
""" """
Application User frame to connect to API with assigned token-based HTTP connection Application User frame to connect to API with assigned token-based HTTP connection