Full Working static multi tenant

This commit is contained in:
2025-04-01 00:29:43 +02:00
parent 50fdf22afc
commit 59cc709ed5
24 changed files with 327 additions and 244 deletions

View File

@@ -6,12 +6,16 @@ from pydantic import BaseModel, Field, computed_field
class CrudDocument(BaseModel):
id: Optional[PydanticObjectId] = Field(alias="_id", default=None)
id: Optional[PydanticObjectId] = Field(default=None)
created_at: datetime = Field(default=datetime.now(UTC), nullable=False, title="Créé le")
# created_by: str
updated_at: datetime = Field(default_factory=datetime.utcnow, nullable=False, title="Modifié le")
# updated_by: str
@property
def _id(self):
return self.id
@computed_field
def label(self) -> str:
return self.compute_label()
@@ -45,12 +49,17 @@ class CrudDocument(BaseModel):
@classmethod
async def get(cls, db, model_id):
return cls.model_validate(await cls._get_collection(db).find_one({"_id": model_id}))
value = await cls._get_collection(db).find_one({"_id": model_id})
if not value:
return None
value["id"] = value.pop("_id")
return cls.model_validate(value)
@classmethod
async def update(cls, db, model, update_schema):
update_query = {
"$set": {field: value for field, value in update_schema.model_dump(mode="json").items()}
"$set": {field: value for field, value in update_schema.model_dump(mode="json").items() if field!= "id" }
}
await cls._get_collection(db).update_one({"_id": model.id}, update_query)

View File

@@ -7,8 +7,9 @@ from fastapi_filter import FilterDepends
from fastapi_pagination import Page, add_pagination
from fastapi_pagination.ext.motor import paginate
from .models import CrudDocument
from .schemas import Writer, Reader
from ..db import get_db_client
from ..user.manager import get_current_user
def parse_sort(sort_by):
@@ -60,23 +61,35 @@ def parse_query(query: str, model):
return And(*and_array) if len(and_array) > 1 else and_array[0]
else:
return {}
#user=Depends(get_current_user)
def get_tenant_db_cursor(instance: str="westside", firm: str="cht", db_client=Depends(get_db_client), user=None):
#instance: str="westside", firm: str="cht",
def get_tenant_db_cursor(db_client=Depends(get_db_client)):
instance = "westside"
firm = "cht"
return db_client[f"tenant_{instance}_{firm}"]
def get_crud_router(model, model_create, model_read, model_update, model_filter):
#instance: str="westside", firm: str="cht",
#user=Depends(get_current_user)
def get_logged_tenant_db_cursor(db_client=Depends(get_db_client), user=None):
instance = "westside"
firm = "cht"
return db_client[f"tenant_{instance}_{firm}"]
def get_crud_router(model: CrudDocument, model_create: Writer, model_read: Reader, model_update: Writer, model_filter):
model_name = model.__name__
router = APIRouter()
@router.get("/", response_model=Page[model_read], response_description=f"{model_name} records retrieved")
async def read_list(filters: model_filter=FilterDepends(model_filter), db=Depends(get_logged_tenant_db_cursor)) -> Page[model_read]:
return await paginate(model.list(db, filters))
@router.post("/", response_description=f"{model_name} added to the database")
async def create(schema: model_create, db=Depends(get_tenant_db_cursor)) -> model_read:
async def create(schema: model_create, db=Depends(get_logged_tenant_db_cursor)) -> model_read:
await schema.validate_foreign_key(db)
record = await model.create(db, schema)
return model_read.from_model(record)
return model_read.validate_model(record)
@router.get("/{record_id}", response_description=f"{model_name} record retrieved")
async def read_one(record_id: PydanticObjectId, db=Depends(get_tenant_db_cursor)) -> model_read:
async def read_one(record_id: PydanticObjectId, db=Depends(get_logged_tenant_db_cursor)) -> model_read:
record = await model.get(db, record_id)
if not record:
raise HTTPException(
@@ -86,12 +99,8 @@ def get_crud_router(model, model_create, model_read, model_update, model_filter)
return model_read.from_model(record)
@router.get("/", response_model=Page[model_read], response_description=f"{model_name} records retrieved")
async def read_list(filters: model_filter=FilterDepends(model_filter), db=Depends(get_tenant_db_cursor)) -> Page[model_read]:
return await paginate(model.list(db, filters))
@router.put("/{record_id}", response_description=f"{model_name} record updated")
async def update(record_id: PydanticObjectId, schema: model_update, db=Depends(get_tenant_db_cursor)) -> model_read:
async def update(record_id: PydanticObjectId, schema: model_update, db=Depends(get_logged_tenant_db_cursor)) -> model_read:
record = await model.get(db, record_id)
if not record:
raise HTTPException(
@@ -103,7 +112,7 @@ def get_crud_router(model, model_create, model_read, model_update, model_filter)
return model_read.from_model(record)
@router.delete("/{record_id}", response_description=f"{model_name} record deleted from the database")
async def delete(record_id: PydanticObjectId, db=Depends(get_tenant_db_cursor)) -> dict:
async def delete(record_id: PydanticObjectId, db=Depends(get_logged_tenant_db_cursor)) -> dict:
record = await model.get(db, record_id)
if not record:
raise HTTPException(

View File

@@ -1,13 +1,15 @@
from typing import Optional
from beanie import PydanticObjectId
from pydantic import BaseModel, Field
class Reader(BaseModel):
id: str = Field()
id: Optional[PydanticObjectId] = Field(default=None, validation_alias="_id")
@classmethod
def from_model(cls, model):
schema = cls.model_validate(model.model_dump())
schema.id = model.id
schema = cls.model_validate(model, from_attributes=True)
return schema