Initializing multitenant

This commit is contained in:
2025-03-30 17:10:42 +02:00
parent 1a247f14ce
commit 50fdf22afc
14 changed files with 272 additions and 135 deletions

View File

@@ -3,10 +3,12 @@ from beanie.odm.operators.find.comparison import In
from beanie.operators import And, RegEx, Eq
from fastapi import APIRouter, HTTPException, Depends
from fastapi_pagination import Page, Params, add_pagination
from fastapi_pagination.ext.beanie import paginate
from fastapi_filter import FilterDepends
from fastapi_pagination import Page, add_pagination
from fastapi_pagination.ext.motor import paginate
from ..user.manager import get_current_user, get_current_superuser, get_current_user_and_firm
from ..db import get_db_client
from ..user.manager import get_current_user
def parse_sort(sort_by):
@@ -15,8 +17,8 @@ def parse_sort(sort_by):
fields = []
for field in sort_by.split(','):
dir, col = field.split('(')
fields.append((col[:-1], 1 if dir == 'asc' else -1))
direction, column = field.split('(')
fields.append((column[:-1], 1 if direction == 'asc' else -1))
return fields
@@ -33,6 +35,7 @@ def parse_query(query: str, model):
for criterion in query.split(' AND '):
[column, operator, value] = criterion.split(' ', 2)
column = column.lower()
operand = None
if column == 'fulltext':
if not model.Settings.fulltext_search:
continue
@@ -50,68 +53,67 @@ def parse_query(query: str, model):
elif operator == 'in':
operand = In(column, value.split(','))
and_array.append(operand)
if operand:
and_array.append(operand)
if and_array:
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):
return db_client[f"tenant_{instance}_{firm}"]
def get_crud_router(model, model_create, model_read, model_update):
def get_crud_router(model, model_create, model_read, model_update, model_filter):
model_name = model.__name__
router = APIRouter()
@router.post("/", response_description="{} added to the database".format(model.__name__))
async def create(instance: str, firm: str, item: model_create, user=Depends(get_current_user)) -> dict:
await item.validate_foreign_key()
o = await model(**item.dict()).create()
return {"message": "{} added successfully".format(model.__name__), "id": o.id}
@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:
await schema.validate_foreign_key(db)
record = await model.create(db, schema)
return model_read.from_model(record)
@router.get("/{id}", response_description="{} record retrieved".format(model.__name__))
async def read_id(instance: str, firm: str, id: PydanticObjectId, user=Depends(get_current_user)) -> model_read:
item = await model.get(id)
return model_read(**item.dict())
@router.get("/", response_model=Page[model_read], response_description="{} records retrieved".format(model.__name__))
async def read_list(instance: str, firm: str, size: int = 50, page: int = 1, sort_by: str = None, query: str = None,
user=Depends(get_current_user_and_firm)) -> Page[model_read]:
sort = parse_sort(sort_by)
query = parse_query(query, model_read)
items = paginate(model.find(query), Params(**{'size': size, 'page': page}))
return await items
@router.put("/{id}", response_description="{} record updated".format(model.__name__))
async def update(instance: str, firm: str, id: PydanticObjectId, req: model_update, user=Depends(get_current_user)) -> model_read:
req = {k: v for k, v in req.dict().items() if v is not None}
update_query = {"$set": {
field: value for field, value in req.items()
}}
item = await model.get(id)
if not item:
@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:
record = await model.get(db, record_id)
if not record:
raise HTTPException(
status_code=404,
detail="{} record not found!".format(model.__name__)
detail=f"{model_name} record not found!"
)
await item.update(update_query)
return model_read(**item.dict())
return model_read.from_model(record)
@router.delete("/{id}", response_description="{} record deleted from the database".format(model.__name__))
async def delete(instance: str, firm: str, id: PydanticObjectId, user=Depends(get_current_superuser)) -> dict:
item = await model.get(id)
@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))
if not item:
@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:
record = await model.get(db, record_id)
if not record:
raise HTTPException(
status_code=404,
detail="{} record not found!".format(model.__name__)
detail=f"{model_name} record not found!"
)
await item.delete()
record = await model.update(db, record, schema)
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:
record = await model.get(db, record_id)
if not record:
raise HTTPException(
status_code=404,
detail=f"{model_name} record not found!"
)
await model.delete(db, record)
return {
"message": "{} deleted successfully".format(model.__name__)
"message": f"{model_name} deleted successfully"
}
add_pagination(router)