Skip to content

Commit d640ac3

Browse files
perf: Optimize datasource-related API permission validation
1 parent eb19f75 commit d640ac3

File tree

7 files changed

+51
-12
lines changed

7 files changed

+51
-12
lines changed

backend/apps/data_training/api/data_training.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828

2929
@router.get("/page/{current_page}/{page_size}", summary=f"{PLACEHOLDER_PREFIX}get_dt_page")
30+
@require_permissions(permission=SqlbotPermission(role=['ws_admin']))
3031
async def pager(session: SessionDep, current_user: CurrentUser, current_page: int, page_size: int,
3132
question: Optional[str] = Query(None, description="搜索问题(可选)")):
3233
current_page, page_size, total_count, total_pages, _list = page_data_training(session, current_page, page_size,
@@ -43,6 +44,7 @@ async def pager(session: SessionDep, current_user: CurrentUser, current_page: in
4344

4445

4546
@router.put("", response_model=int, summary=f"{PLACEHOLDER_PREFIX}create_or_update_dt")
47+
@require_permissions(permission=SqlbotPermission(role=['ws_admin'], type='ds', keyExpression="info.datasource"))
4648
@system_log(LogConfig(operation_type=OperationType.CREATE_OR_UPDATE, module=OperationModules.DATA_TRAINING,resource_id_expr='info.id', result_id_expr="result_self"))
4749
async def create_or_update(session: SessionDep, current_user: CurrentUser, trans: Trans, info: DataTrainingInfo):
4850
oid = current_user.oid

backend/apps/datasource/api/datasource.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,21 @@ def inner():
7575
@system_log(LogConfig(operation_type=OperationType.CREATE, module=OperationModules.DATASOURCE, result_id_expr="id"))
7676
@require_permissions(permission=SqlbotPermission(role=['ws_admin']))
7777
async def add(session: SessionDep, trans: Trans, user: CurrentUser, ds: CreateDatasource):
78-
def inner():
78+
""" def inner():
7979
return create_ds(session, trans, user, ds)
8080
81-
return await asyncio.to_thread(inner)
81+
return await asyncio.to_thread(inner) """
82+
loop = asyncio.get_event_loop()
83+
84+
def sync_wrapper():
85+
loop = asyncio.new_event_loop()
86+
asyncio.set_event_loop(loop)
87+
try:
88+
return loop.run_until_complete(create_ds(session, trans, user, ds))
89+
finally:
90+
loop.close()
91+
92+
return await loop.run_in_executor(None, sync_wrapper)
8293

8394

8495
@router.post("/chooseTables/{id}", response_model=None, summary=f"{PLACEHOLDER_PREFIX}ds_choose_tables")
@@ -107,7 +118,7 @@ def inner():
107118
@system_log(LogConfig(operation_type=OperationType.DELETE, module=OperationModules.DATASOURCE, resource_id_expr="id",
108119
))
109120
async def delete(session: SessionDep, id: int = Path(..., description=f"{PLACEHOLDER_PREFIX}ds_id"), name: str = None):
110-
return delete_ds(session, id)
121+
return await delete_ds(session, id)
111122

112123

113124
@router.post("/getTables/{id}", response_model=List[TableSchemaResponse], summary=f"{PLACEHOLDER_PREFIX}ds_get_tables")

backend/apps/datasource/crud/datasource.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@
1313
from apps.db.constant import DB
1414
from apps.db.db import get_tables, get_fields, exec_sql, check_connection
1515
from apps.db.engine import get_engine_config, get_engine_conn
16+
from apps.system.schemas.auth import CacheName, CacheNamespace
1617
from common.core.config import settings
1718
from common.core.deps import SessionDep, CurrentUser, Trans
1819
from common.utils.embedding_threads import run_save_table_embeddings, run_save_ds_embeddings
19-
from common.utils.utils import deepcopy_ignore_extra
20+
from common.utils.utils import SQLBotLogUtil, deepcopy_ignore_extra
21+
from common.core.sqlbot_cache import cache, clear_cache
2022
from .table import get_tables_by_ds_id
2123
from ..crud.field import delete_field_by_ds_id, update_field
2224
from ..crud.table import delete_table_by_ds_id, update_table
@@ -63,8 +65,8 @@ def check_name(session: SessionDep, trans: Trans, user: CurrentUser, ds: CoreDat
6365
if ds_list is not None and len(ds_list) > 0:
6466
raise HTTPException(status_code=500, detail=trans('i18n_ds_name_exist'))
6567

66-
67-
def create_ds(session: SessionDep, trans: Trans, user: CurrentUser, create_ds: CreateDatasource):
68+
@clear_cache(namespace=CacheNamespace.AUTH_INFO, cacheName=CacheName.DS_ID_LIST, keyExpression="user.oid")
69+
async def create_ds(session: SessionDep, trans: Trans, user: CurrentUser, create_ds: CreateDatasource):
6870
ds = CoreDatasource()
6971
deepcopy_ignore_extra(create_ds, ds)
7072
check_name(session, trans, user, ds)
@@ -117,7 +119,7 @@ def update_ds_recommended_config(session: SessionDep, datasource_id: int, recomm
117119
session.commit()
118120

119121

120-
def delete_ds(session: SessionDep, id: int):
122+
async def delete_ds(session: SessionDep, id: int):
121123
term = session.exec(select(CoreDatasource).where(CoreDatasource.id == id)).first()
122124
if term.type == "excel":
123125
# drop all tables for current datasource
@@ -132,6 +134,8 @@ def delete_ds(session: SessionDep, id: int):
132134
session.commit()
133135
delete_table_by_ds_id(session, id)
134136
delete_field_by_ds_id(session, id)
137+
if term:
138+
await clear_ws_resource_cache(term.oid)
135139
return {
136140
"message": f"Datasource with ID {id} deleted successfully."
137141
}
@@ -526,3 +530,12 @@ def get_table_schema(session: SessionDep, current_user: CurrentUser, ds: CoreDat
526530
schema_str += f"{table_dict.get(int(ele.get('source').get('cell')))}.{field_dict.get(int(ele.get('source').get('port')))}={table_dict.get(int(ele.get('target').get('cell')))}.{field_dict.get(int(ele.get('target').get('port')))}\n"
527531

528532
return schema_str
533+
534+
@cache(namespace=CacheNamespace.AUTH_INFO, cacheName=CacheName.DS_ID_LIST, keyExpression="oid")
535+
async def get_ws_ds(session, oid) -> list:
536+
stmt = select(CoreDatasource.id).distinct().where(CoreDatasource.oid == oid)
537+
db_list = session.exec(stmt).all()
538+
return db_list
539+
@clear_cache(namespace=CacheNamespace.AUTH_INFO, cacheName=CacheName.DS_ID_LIST, keyExpression="oid")
540+
async def clear_ws_ds_cache(oid):
541+
SQLBotLogUtil.info(f"ds cache for ws [{oid}] has been cleaned")

backend/apps/system/api/assistant.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from apps.system.crud.assistant_manage import dynamic_upgrade_cors, save
1616
from apps.system.models.system_model import AssistantModel
1717
from apps.system.schemas.auth import CacheName, CacheNamespace
18+
from apps.system.schemas.permission import SqlbotPermission, require_permissions
1819
from apps.system.schemas.system_schema import AssistantBase, AssistantDTO, AssistantUiSchema, AssistantValidator
1920
from common.core.config import settings
2021
from common.core.deps import CurrentAssistant, SessionDep, Trans, CurrentUser
@@ -217,27 +218,31 @@ def get_db_type(type):
217218

218219

219220
@router.get("", response_model=list[AssistantModel], summary=f"{PLACEHOLDER_PREFIX}assistant_grid_api", description=f"{PLACEHOLDER_PREFIX}assistant_grid_api")
221+
@require_permissions(permission=SqlbotPermission(role=['ws_admin']))
220222
async def query(session: SessionDep, current_user: CurrentUser):
221223
list_result = session.exec(select(AssistantModel).where(AssistantModel.oid == current_user.oid, AssistantModel.type != 4).order_by(AssistantModel.name,
222224
AssistantModel.create_time)).all()
223225
return list_result
224226

225227

226228
@router.get("/advanced_application", response_model=list[AssistantModel], include_in_schema=False)
227-
async def query_advanced_application(session: SessionDep):
228-
list_result = session.exec(select(AssistantModel).where(AssistantModel.type == 1).order_by(AssistantModel.name,
229+
@require_permissions(permission=SqlbotPermission(role=['ws_admin']))
230+
async def query_advanced_application(session: SessionDep, current_user: CurrentUser):
231+
list_result = session.exec(select(AssistantModel).where(AssistantModel.type == 1, AssistantModel.oid == current_user.oid).order_by(AssistantModel.name,
229232
AssistantModel.create_time)).all()
230233
return list_result
231234

232235

233236
@router.post("", summary=f"{PLACEHOLDER_PREFIX}assistant_create_api", description=f"{PLACEHOLDER_PREFIX}assistant_create_api")
237+
@require_permissions(permission=SqlbotPermission(role=['ws_admin']))
234238
@system_log(LogConfig(operation_type=OperationType.CREATE, module=OperationModules.APPLICATION, result_id_expr="id"))
235239
async def add(request: Request, session: SessionDep, current_user: CurrentUser, creator: AssistantBase):
236240
oid = current_user.oid if creator.type != 4 else 1
237241
return await save(request, session, creator, oid)
238242

239243

240244
@router.put("", summary=f"{PLACEHOLDER_PREFIX}assistant_update_api", description=f"{PLACEHOLDER_PREFIX}assistant_update_api")
245+
@require_permissions(permission=SqlbotPermission(role=['ws_admin']))
241246
@clear_cache(namespace=CacheNamespace.EMBEDDED_INFO, cacheName=CacheName.ASSISTANT_INFO, keyExpression="editor.id")
242247
@system_log(LogConfig(operation_type=OperationType.UPDATE, module=OperationModules.APPLICATION, resource_id_expr="editor.id"))
243248
async def update(request: Request, session: SessionDep, editor: AssistantDTO):
@@ -262,6 +267,7 @@ async def get_one(session: SessionDep, id: int = Path(description="ID")):
262267

263268

264269
@router.delete("/{id}", summary=f"{PLACEHOLDER_PREFIX}assistant_del_api", description=f"{PLACEHOLDER_PREFIX}assistant_del_api")
270+
@require_permissions(permission=SqlbotPermission(role=['ws_admin']))
265271
@clear_cache(namespace=CacheNamespace.EMBEDDED_INFO, cacheName=CacheName.ASSISTANT_INFO, keyExpression="id")
266272
@system_log(LogConfig(operation_type=OperationType.DELETE, module=OperationModules.APPLICATION, resource_id_expr="id"))
267273
async def delete(request: Request, session: SessionDep, id: int = Path(description="ID")):

backend/apps/system/schemas/auth.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class CacheName(Enum):
1717
ASSISTANT_INFO = "assistant:info"
1818
ASSISTANT_DS = "assistant:ds"
1919
ASK_INFO = "ask:info"
20+
DS_ID_LIST = "ds:id:list"
2021
def __str__(self):
2122
return self.value
2223

backend/apps/system/schemas/permission.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from starlette.middleware.base import BaseHTTPMiddleware
99
from sqlmodel import Session, select
1010
from apps.chat.models.chat_model import Chat
11+
from apps.datasource.crud.datasource import get_ws_ds
1112
from apps.datasource.models.datasource import CoreDatasource
1213
from common.core.db import engine
1314
from apps.system.schemas.system_schema import UserInfoDTO
@@ -22,7 +23,7 @@ async def get_ws_resource(oid, type) -> list:
2223
with Session(engine) as session:
2324
stmt = None
2425
if type == 'ds' or type == 'datasource':
25-
stmt = select(CoreDatasource.id).where(CoreDatasource.oid == oid)
26+
return await get_ws_ds(session, oid)
2627
if type == 'chat':
2728
stmt = select(Chat.id).where(Chat.oid == oid)
2829
if stmt is not None:
@@ -32,6 +33,9 @@ async def get_ws_resource(oid, type) -> list:
3233

3334

3435
async def check_ws_permission(oid, type, resource) -> bool:
36+
if not resource or (isinstance(resource, list) and len(resource) == 0):
37+
return True
38+
3539
resource_id_list = await get_ws_resource(oid, type)
3640
if not resource_id_list:
3741
return False
@@ -53,7 +57,7 @@ async def wrapper(*args, **kwargs):
5357
)
5458
current_oid = current_user.oid
5559

56-
if current_user.isAdmin:
60+
if current_user.isAdmin and not permission.type:
5761
return await func(*args, **kwargs)
5862
role_list = permission.role
5963
keyExpression = permission.keyExpression
@@ -62,7 +66,7 @@ async def wrapper(*args, **kwargs):
6266
if role_list:
6367
if 'admin' in role_list and not current_user.isAdmin:
6468
raise Exception('no permission to execute, only for admin')
65-
if 'ws_admin' in role_list and current_user.weight == 0:
69+
if 'ws_admin' in role_list and current_user.weight == 0 and not current_user.isAdmin:
6670
raise Exception('no permission to execute, only for workspace admin')
6771
if not resource_type:
6872
return await func(*args, **kwargs)

backend/apps/terminology/api/terminology.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727

2828
@router.get("/page/{current_page}/{page_size}", summary=f"{PLACEHOLDER_PREFIX}get_term_page")
29+
@require_permissions(permission=SqlbotPermission(role=['ws_admin']))
2930
async def pager(session: SessionDep, current_user: CurrentUser, current_page: int, page_size: int,
3031
word: Optional[str] = Query(None, description="搜索术语(可选)"),
3132
dslist: Optional[list[int]] = Query(None, description="数据集ID集合(可选)")):
@@ -42,6 +43,7 @@ async def pager(session: SessionDep, current_user: CurrentUser, current_page: in
4243

4344

4445
@router.put("", summary=f"{PLACEHOLDER_PREFIX}create_or_update_term")
46+
@require_permissions(permission=SqlbotPermission(role=['ws_admin'], type='ds', keyExpression="info.datasource_ids"))
4547
@system_log(LogConfig(operation_type=OperationType.CREATE_OR_UPDATE, module=OperationModules.TERMINOLOGY,resource_id_expr='info.id', result_id_expr="result_self"))
4648
async def create_or_update(session: SessionDep, current_user: CurrentUser, trans: Trans, info: TerminologyInfo):
4749
oid = current_user.oid

0 commit comments

Comments
 (0)