[FWA-5] Home Create and List
This commit is contained in:
@ -1,6 +1,7 @@
|
||||
from collections.abc import AsyncGenerator
|
||||
from contextlib import asynccontextmanager
|
||||
from fastapi import FastAPI, Request, HTTPException
|
||||
from fastapi.exceptions import RequestValidationError
|
||||
from fastapi.responses import JSONResponse
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.middleware.gzip import GZipMiddleware
|
||||
@ -70,6 +71,11 @@ async def unicorn_exception_handler(request: Request, exc: HTTPException):
|
||||
content={"status": exc.status_code, "data": exc.detail},
|
||||
)
|
||||
|
||||
@app.exception_handler(RequestValidationError)
|
||||
async def validation_exception_handler(request: Request, exc: RequestValidationError):
|
||||
print(exc)
|
||||
return JSONResponse(status_code=422, content={"status": 422, "data": str(exc)})
|
||||
|
||||
def api_routers():
|
||||
app.include_router(router)
|
||||
|
||||
|
@ -30,7 +30,7 @@ async def is_logged_in(token: str = Depends(oauth2_scheme_soft_fail)) -> bool:
|
||||
user = user_service.get_by_id(user_id)
|
||||
if not user:
|
||||
raise credentials_exception
|
||||
if user.is_lock is True:
|
||||
if user.is_lock is not None:
|
||||
raise HTTPException(status_code=status.HTTP_423_LOCKED, detail=MessageCode.ACCOUNT_LOCK)
|
||||
except Exception:
|
||||
return credentials_exception
|
||||
|
@ -1,6 +1,9 @@
|
||||
|
||||
class MessageCode():
|
||||
CREATE_USER_SUCCESS: str = 'CREATE_USER_SUCCESS'
|
||||
CREATED_USER: str = 'CREATED_USER'
|
||||
WRONG_INPUT: str = 'LOGIN_WRONG'
|
||||
ACCOUNT_LOCK: str = 'USER_LOCK'
|
||||
REFRESH_TOKEN_EXPIRED: str = 'REFRESH_TOKEN_EXPIRED'
|
||||
CREATE_HOUSE_FAIL: str = 'CREATE_HOUSE_FAIL'
|
||||
CREATE_HOUSE_SUCCESS: str = 'CREATE_HOUSE_SUCCESS'
|
||||
|
@ -18,3 +18,6 @@ class SqlAlchemyBase(Model):
|
||||
@classmethod
|
||||
def normalize(cls, val: str) -> str:
|
||||
return unidecode(val).lower().strip()
|
||||
|
||||
class DeleteMixin:
|
||||
deleted_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
||||
|
@ -4,30 +4,30 @@ from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from backend.db.models.guid import GUID
|
||||
|
||||
from .._model_base import SqlAlchemyBase
|
||||
from .._model_base import SqlAlchemyBase, DeleteMixin
|
||||
|
||||
class Houses(SqlAlchemyBase):
|
||||
class Houses(SqlAlchemyBase, DeleteMixin):
|
||||
__tablename__ = 'houses'
|
||||
|
||||
id: Mapped[GUID] = mapped_column(GUID, primary_key=True, default=GUID.generate, index=True)
|
||||
icon: Mapped[str | None] = mapped_column(String, index=True, nullable=False)
|
||||
icon: Mapped[str | None] = mapped_column(String, nullable=False)
|
||||
name: Mapped[str | None] = mapped_column(String, index=True, nullable=False)
|
||||
address: Mapped[str | None] = mapped_column(String, index=True, nullable=False)
|
||||
address: Mapped[str | None] = mapped_column(String, nullable=False)
|
||||
|
||||
areas: Mapped[List["Areas"]] = relationship()
|
||||
areas: Mapped[List["Areas"]] = relationship("Areas", back_populates="house", cascade="all, delete", passive_deletes=True)
|
||||
|
||||
def __repr__(self):
|
||||
return f"{self.__class__.__name__}, name: {self.name}"
|
||||
|
||||
class Areas(SqlAlchemyBase):
|
||||
class Areas(SqlAlchemyBase, DeleteMixin):
|
||||
__tablename__ = 'areas'
|
||||
|
||||
id: Mapped[GUID] = mapped_column(GUID, primary_key=True, default=GUID.generate, index=True)
|
||||
house_id: Mapped[GUID] = mapped_column(GUID, ForeignKey('houses.id'), index=True, nullable=False)
|
||||
house_id: Mapped[GUID] = mapped_column(GUID, ForeignKey('houses.id', ondelete='CASCADE'), nullable=False)
|
||||
name: Mapped[str | None] = mapped_column(String, index=True, nullable=False)
|
||||
desc: Mapped[str | None] = mapped_column(String, index=True, nullable=False)
|
||||
desc: Mapped[str | None] = mapped_column(String, nullable=False)
|
||||
|
||||
user: Mapped['Houses'] = relationship(back_populates="areas")
|
||||
house: Mapped['Houses'] = relationship(back_populates="areas")
|
||||
|
||||
def __repr__(self):
|
||||
return f"{self.__class__.__name__}, name: {self.name}"
|
||||
|
@ -1,4 +1,6 @@
|
||||
from sqlalchemy import Boolean, String
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import Boolean, String, DateTime
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from backend.db.models.guid import GUID
|
||||
@ -13,7 +15,7 @@ class Users(SqlAlchemyBase):
|
||||
password: Mapped[str | None] = mapped_column(String, index=True, nullable=False)
|
||||
name: Mapped[str | None] = mapped_column(String, index=True, nullable=True)
|
||||
is_admin: Mapped[bool | None] = mapped_column(Boolean, default=False)
|
||||
is_lock: Mapped[bool | None] = mapped_column(Boolean, default=False)
|
||||
is_lock: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
||||
|
||||
def __repr__(self):
|
||||
return f"{self.__class__.__name__}, name: {self.name}, username: {self.username}"
|
||||
|
@ -1,4 +1,4 @@
|
||||
from backend.db.models.houses import Houses
|
||||
from backend.db.models.houses import Houses, Areas
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from backend.schemas.house import HouseCreate
|
||||
@ -6,16 +6,26 @@ from backend.schemas.house import HouseCreate
|
||||
class RepositoryHouses:
|
||||
def __init__(self):
|
||||
self.houses = Houses()
|
||||
self.areas = Areas()
|
||||
|
||||
def get_all(self, skip: int = 0, limit: int = 100):
|
||||
return self.houses.query.offset(skip).limit(limit).all()
|
||||
return self.houses.query.filter_by(deleted_at=None).offset(skip).limit(limit).all()
|
||||
|
||||
def get_all_areas(self, house_id: str, skip: int = 0, limit: int = 100):
|
||||
return self.areas.query.filter_by(deleted_at=None, house_id=house_id).offset(skip).limit(limit).all()
|
||||
|
||||
def get_count_all(self, skip: int = 0, limit: int = 100):
|
||||
return self.houses.query.filter_by(deleted_at=None).offset(skip).limit(limit).count()
|
||||
|
||||
def get_by_id(self, house_id: str):
|
||||
return self.houses.query.filter_by(id=house_id).one()
|
||||
|
||||
def create(self, db: Session, house: HouseCreate):
|
||||
try:
|
||||
db_house = Houses(**house.dict())
|
||||
areas = getattr(house, "areas")
|
||||
db_house = Houses(**house.dict(exclude={"areas"}))
|
||||
for area in areas:
|
||||
db_house.areas.append(Areas(**area.dict()))
|
||||
db.add(db_house)
|
||||
db.commit()
|
||||
except Exception:
|
||||
|
@ -16,21 +16,18 @@ def dev_users() -> list[dict]:
|
||||
"password": "admin",
|
||||
"name": "Sam",
|
||||
"is_admin": True,
|
||||
"is_lock": False,
|
||||
},
|
||||
{
|
||||
"username": "duy",
|
||||
"password": "admin",
|
||||
"name": "Duy",
|
||||
"is_admin": True,
|
||||
"is_lock": False,
|
||||
},
|
||||
{
|
||||
"username": "sam1",
|
||||
"password": "admin",
|
||||
"name": "Sam1",
|
||||
"is_admin": False,
|
||||
"is_lock": False,
|
||||
},
|
||||
]
|
||||
|
||||
|
@ -1,11 +1,13 @@
|
||||
from typing import Annotated, Any
|
||||
from fastapi import APIRouter, Depends
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy.orm import Session
|
||||
from backend.core.config import get_app_settings
|
||||
from backend.core.dependencies import is_logged_in
|
||||
from backend.core.message_code import MessageCode
|
||||
from backend.db.db_setup import generate_session
|
||||
from backend.schemas.common import ReturnValue
|
||||
from backend.schemas.house import HouseCreate
|
||||
from backend.schemas.house.house import HousesListResponse
|
||||
from backend.schemas.user import ProfileResponse
|
||||
from backend.services.house import HouseService
|
||||
|
||||
@ -16,6 +18,16 @@ settings = get_app_settings()
|
||||
db_dependency = Annotated[Session, Depends(generate_session)]
|
||||
current_user_token = Annotated[ProfileResponse, Depends(is_logged_in)]
|
||||
|
||||
@public_router.get("/create", response_model=ReturnValue[Any])
|
||||
@public_router.post("/create", response_model=ReturnValue[Any])
|
||||
def create_house(house: HouseCreate, db: db_dependency, current_user: current_user_token) -> ReturnValue[Any]:
|
||||
return ReturnValue(status=200, data="created")
|
||||
try:
|
||||
house_service.create(db=db, house=house)
|
||||
except Exception:
|
||||
raise HTTPException(status_code=400, detail=MessageCode.CREATE_HOUSE_FAIL)
|
||||
return ReturnValue(status=200, data=MessageCode.CREATE_HOUSE_SUCCESS)
|
||||
|
||||
@public_router.get("/all", response_model=ReturnValue[HousesListResponse])
|
||||
async def get_all_house(page: int, pageSize: int, current_user: current_user_token) -> ReturnValue[HousesListResponse]:
|
||||
housesCount = house_service.get_all_count(skip=page-1, limit=pageSize)
|
||||
houses = house_service.get_all(skip=page-1, limit=pageSize)
|
||||
return ReturnValue(status=200, data={'total': housesCount, 'list': list(houses)})
|
||||
|
@ -23,7 +23,7 @@ def register_user(user: UserCreate, db: db_dependency) -> ReturnValue[Any]:
|
||||
if db_user:
|
||||
raise HTTPException(status_code=400, detail=MessageCode.CREATED_USER)
|
||||
user_service.create(db=db, user=user)
|
||||
return ReturnValue(status=200, data="created")
|
||||
return ReturnValue(status=200, data=MessageCode.CREATE_USER_SUCCESS)
|
||||
|
||||
@public_router.get("/me", response_model=ReturnValue[ProfileResponse])
|
||||
def get_user(current_user: current_user_token) -> ReturnValue[Any]:
|
||||
|
@ -1,3 +1,7 @@
|
||||
from datetime import datetime
|
||||
from uuid import UUID
|
||||
|
||||
from pydantic import ConfigDict
|
||||
from backend.schemas.main_model import MainModel
|
||||
|
||||
class HouseBase(MainModel):
|
||||
@ -15,3 +19,14 @@ class HouseCreate(HouseBase):
|
||||
name: str
|
||||
address: str
|
||||
areas: list[AreaCreate]
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
class HousesList(HouseCreate):
|
||||
id: UUID
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
deleted_at: datetime | None
|
||||
|
||||
class HousesListResponse(MainModel):
|
||||
total: int
|
||||
list: list[HousesList]
|
||||
|
@ -27,13 +27,12 @@ class UserProfile(MainModel):
|
||||
|
||||
class UserSeeds(UserCreate):
|
||||
is_admin: bool
|
||||
is_lock: bool
|
||||
|
||||
class PrivateUser(UserBase):
|
||||
id: UUID
|
||||
name: str
|
||||
is_admin: bool
|
||||
is_lock: bool
|
||||
is_lock: datetime
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
@ -9,3 +9,9 @@ class HouseService(BaseService):
|
||||
|
||||
def create(self, db: Session, house: HouseCreate):
|
||||
return self.repos.create(db=db, house=house)
|
||||
|
||||
def get_all(self, skip: int = 0, limit: int = 100):
|
||||
return self.repos.get_all(skip=skip, limit=limit)
|
||||
|
||||
def get_all_count(self, skip: int = 0, limit: int = 100):
|
||||
return self.repos.get_count_all(skip=skip, limit=limit)
|
||||
|
Reference in New Issue
Block a user