Skip to content

Commit 032364e

Browse files
authored
Refactor the data rule to scope rule (#596)
* WIP * update codes * update codes * update filter_data_permission * Fix schema * Fix issues
1 parent bc5d142 commit 032364e

34 files changed

+682
-180
lines changed

backend/app/admin/api/v1/sys/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from fastapi import APIRouter
44

55
from backend.app.admin.api.v1.sys.data_rule import router as data_rule_router
6+
from backend.app.admin.api.v1.sys.data_scope import router as data_scope_router
67
from backend.app.admin.api.v1.sys.dept import router as dept_router
78
from backend.app.admin.api.v1.sys.menu import router as menu_router
89
from backend.app.admin.api.v1.sys.plugin import router as plugin_router
@@ -18,6 +19,7 @@
1819
router.include_router(role_router, prefix='/roles', tags=['系统角色'])
1920
router.include_router(user_router, prefix='/users', tags=['系统用户'])
2021
router.include_router(data_rule_router, prefix='/data-rules', tags=['系统数据规则'])
22+
router.include_router(data_scope_router, prefix='/data-scopes', tags=['系统数据范围'])
2123
router.include_router(token_router, prefix='/tokens', tags=['系统令牌'])
2224
router.include_router(upload_router, prefix='/upload', tags=['系统上传'])
2325
router.include_router(plugin_router, prefix='/plugin', tags=['系统插件'])

backend/app/admin/api/v1/sys/data_rule.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,12 @@
44

55
from fastapi import APIRouter, Depends, Path, Query
66

7-
from backend.app.admin.schema.data_rule import CreateDataRuleParam, GetDataRuleDetail, UpdateDataRuleParam
7+
from backend.app.admin.schema.data_rule import (
8+
CreateDataRuleParam,
9+
GetDataRuleColumnDetail,
10+
GetDataRuleDetail,
11+
UpdateDataRuleParam,
12+
)
813
from backend.app.admin.service.data_rule_service import data_rule_service
914
from backend.common.pagination import DependsPagination, PageData, paging_data
1015
from backend.common.response.response_schema import ResponseModel, ResponseSchemaModel, response_base
@@ -25,7 +30,7 @@ async def get_data_rule_models() -> ResponseSchemaModel[list[str]]:
2530
@router.get('/model/{model}/columns', summary='获取数据规则可用模型列', dependencies=[DependsJwtAuth])
2631
async def get_data_rule_model_columns(
2732
model: Annotated[str, Path(description='模型名称')],
28-
) -> ResponseSchemaModel[list[str]]:
33+
) -> ResponseSchemaModel[list[GetDataRuleColumnDetail]]:
2934
models = await data_rule_service.get_columns(model=model)
3035
return response_base.success(data=models)
3136

+118
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
from typing import Annotated
4+
5+
from fastapi import APIRouter, Depends, Path, Query
6+
7+
from backend.app.admin.schema.data_scope import (
8+
CreateDataScopeParam,
9+
GetDataScopeDetail,
10+
GetDataScopeWithRelationDetail,
11+
UpdateDataScopeParam,
12+
UpdateDataScopeRuleParam,
13+
)
14+
from backend.app.admin.service.data_scope_service import data_scope_service
15+
from backend.common.pagination import DependsPagination, PageData, paging_data
16+
from backend.common.response.response_schema import ResponseModel, ResponseSchemaModel, response_base
17+
from backend.common.security.jwt import DependsJwtAuth
18+
from backend.common.security.permission import RequestPermission
19+
from backend.common.security.rbac import DependsRBAC
20+
from backend.database.db import CurrentSession
21+
22+
router = APIRouter()
23+
24+
25+
@router.get('/{pk}', summary='获取数据范围详情', dependencies=[DependsJwtAuth])
26+
async def get_data_scope(
27+
pk: Annotated[int, Path(description='数据范围 ID')],
28+
) -> ResponseSchemaModel[GetDataScopeDetail]:
29+
data = await data_scope_service.get(pk=pk)
30+
return response_base.success(data=data)
31+
32+
33+
@router.get('/{pk}/rules', summary='获取数据范围所有规则', dependencies=[DependsJwtAuth])
34+
async def get_data_scope_rules(
35+
pk: Annotated[int, Path(description='数据范围 ID')],
36+
) -> ResponseSchemaModel[GetDataScopeWithRelationDetail]:
37+
data = await data_scope_service.get_rules(pk=pk)
38+
return response_base.success(data=data)
39+
40+
41+
@router.get(
42+
'',
43+
summary='分页获取所有数据范围',
44+
dependencies=[
45+
DependsJwtAuth,
46+
DependsPagination,
47+
],
48+
)
49+
async def get_pagination_data_scopes(
50+
db: CurrentSession,
51+
name: Annotated[str | None, Query(description='范围名称')] = None,
52+
status: Annotated[int | None, Query(description='状态')] = None,
53+
) -> ResponseSchemaModel[PageData[GetDataScopeDetail]]:
54+
data_scope_select = await data_scope_service.get_select(name=name, status=status)
55+
page_data = await paging_data(db, data_scope_select)
56+
return response_base.success(data=page_data)
57+
58+
59+
@router.post(
60+
'',
61+
summary='创建数据范围',
62+
dependencies=[
63+
Depends(RequestPermission('data:scope:add')),
64+
DependsRBAC,
65+
],
66+
)
67+
async def create_data_scope(obj: CreateDataScopeParam) -> ResponseModel:
68+
await data_scope_service.create(obj=obj)
69+
return response_base.success()
70+
71+
72+
@router.put(
73+
'/{pk}',
74+
summary='更新数据范围',
75+
dependencies=[
76+
Depends(RequestPermission('data:scope:edit')),
77+
DependsRBAC,
78+
],
79+
)
80+
async def update_data_scope(
81+
pk: Annotated[int, Path(description='数据范围 ID')], obj: UpdateDataScopeParam
82+
) -> ResponseModel:
83+
count = await data_scope_service.update(pk=pk, obj=obj)
84+
if count > 0:
85+
return response_base.success()
86+
return response_base.fail()
87+
88+
89+
@router.put(
90+
'/{pk}/rules',
91+
summary='更新数据范围规则',
92+
dependencies=[
93+
Depends(RequestPermission('data:scope:rule:edit')),
94+
DependsRBAC,
95+
],
96+
)
97+
async def update_data_scope_rules(
98+
pk: Annotated[int, Path(description='数据范围 ID')], rule_ids: UpdateDataScopeRuleParam
99+
):
100+
count = await data_scope_service.update_data_scope_rule(pk=pk, rule_ids=rule_ids)
101+
if count > 0:
102+
return response_base.success()
103+
return response_base.fail()
104+
105+
106+
@router.delete(
107+
'',
108+
summary='批量删除数据范围',
109+
dependencies=[
110+
Depends(RequestPermission('data:scope:del')),
111+
DependsRBAC,
112+
],
113+
)
114+
async def delete_data_scope(pk: Annotated[list[int], Query(description='数据范围 ID 列表')]) -> ResponseModel:
115+
count = await data_scope_service.delete(pk=pk)
116+
if count > 0:
117+
return response_base.success()
118+
return response_base.fail()

backend/app/admin/api/v1/sys/dept.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# -*- coding: utf-8 -*-
33
from typing import Annotated, Any
44

5-
from fastapi import APIRouter, Depends, Path, Query
5+
from fastapi import APIRouter, Depends, Path, Query, Request
66

77
from backend.app.admin.schema.dept import CreateDeptParam, GetDeptDetail, UpdateDeptParam
88
from backend.app.admin.service.dept_service import dept_service
@@ -22,12 +22,13 @@ async def get_dept(pk: Annotated[int, Path(description='部门 ID')]) -> Respons
2222

2323
@router.get('', summary='获取所有部门展示树', dependencies=[DependsJwtAuth])
2424
async def get_all_depts(
25+
request: Request,
2526
name: Annotated[str | None, Query(description='部门名称')] = None,
2627
leader: Annotated[str | None, Query(description='部门负责人')] = None,
2728
phone: Annotated[str | None, Query(description='联系电话')] = None,
2829
status: Annotated[int | None, Query(description='状态')] = None,
2930
) -> ResponseSchemaModel[list[dict[str, Any]]]:
30-
dept = await dept_service.get_dept_tree(name=name, leader=leader, phone=phone, status=status)
31+
dept = await dept_service.get_dept_tree(request=request, name=name, leader=leader, phone=phone, status=status)
3132
return response_base.success(data=dept)
3233

3334

backend/app/admin/api/v1/sys/role.py

+12-14
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,8 @@
1010
GetRoleWithRelationDetail,
1111
UpdateRoleMenuParam,
1212
UpdateRoleParam,
13-
UpdateRoleRuleParam,
13+
UpdateRoleScopeParam,
1414
)
15-
from backend.app.admin.service.data_rule_service import data_rule_service
16-
from backend.app.admin.service.menu_service import menu_service
1715
from backend.app.admin.service.role_service import role_service
1816
from backend.common.pagination import DependsPagination, PageData, paging_data
1917
from backend.common.response.response_schema import ResponseModel, ResponseSchemaModel, response_base
@@ -35,21 +33,21 @@ async def get_all_roles() -> ResponseSchemaModel[list[GetRoleDetail]]:
3533
async def get_user_all_roles(
3634
pk: Annotated[int, Path(description='用户 ID')],
3735
) -> ResponseSchemaModel[list[GetRoleDetail]]:
38-
data = await role_service.get_by_user(pk=pk)
36+
data = await role_service.get_users(pk=pk)
3937
return response_base.success(data=data)
4038

4139

4240
@router.get('/{pk}/menus', summary='获取角色所有菜单', dependencies=[DependsJwtAuth])
4341
async def get_role_all_menus(
4442
pk: Annotated[int, Path(description='角色 ID')],
4543
) -> ResponseSchemaModel[list[dict[str, Any]]]:
46-
menu = await menu_service.get_role_menu_tree(pk=pk)
44+
menu = await role_service.get_menu_tree(pk=pk)
4745
return response_base.success(data=menu)
4846

4947

50-
@router.get('/{pk}/rules', summary='获取角色所有数据规则', dependencies=[DependsJwtAuth])
51-
async def get_role_all_rules(pk: Annotated[int, Path(description='角色 ID')]) -> ResponseSchemaModel[list[int]]:
52-
rule = await data_rule_service.get_role_rules(pk=pk)
48+
@router.get('/{pk}/scopes', summary='获取角色所有数据范围', dependencies=[DependsJwtAuth])
49+
async def get_role_all_scopes(pk: Annotated[int, Path(description='角色 ID')]) -> ResponseSchemaModel[list[int]]:
50+
rule = await role_service.get_scopes(pk=pk)
5351
return response_base.success(data=rule)
5452

5553

@@ -125,17 +123,17 @@ async def update_role_menus(
125123

126124

127125
@router.put(
128-
'/{pk}/rule',
129-
summary='更新角色数据规则',
126+
'/{pk}/scope',
127+
summary='更新角色数据范围',
130128
dependencies=[
131-
Depends(RequestPermission('sys:role:rule:edit')),
129+
Depends(RequestPermission('sys:role:scope:edit')),
132130
DependsRBAC,
133131
],
134132
)
135-
async def update_role_rules(
136-
pk: Annotated[int, Path(description='角色 ID')], rule_ids: UpdateRoleRuleParam
133+
async def update_role_scopes(
134+
pk: Annotated[int, Path(description='角色 ID')], scope_ids: UpdateRoleScopeParam
137135
) -> ResponseModel:
138-
count = await role_service.update_role_rule(pk=pk, rule_ids=rule_ids)
136+
count = await role_service.update_role_scope(pk=pk, scope_ids=scope_ids)
139137
if count > 0:
140138
return response_base.success()
141139
return response_base.fail()

backend/app/admin/api/v1/sys/upload.py

-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#!/usr/bin/env python3
22
# -*- coding: utf-8 -*-
3-
43
from typing import Annotated
54

65
from fastapi import APIRouter, File, UploadFile

backend/app/admin/crud/crud_data_rule.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ async def get_list(self, name: str | None) -> Select:
3131
:param name: 规则名称
3232
:return:
3333
"""
34-
stmt = select(self.model).options(noload(self.model.roles)).order_by(desc(self.model.created_time))
34+
stmt = select(self.model).options(noload(self.model.scope)).order_by(desc(self.model.created_time))
3535

3636
filters = []
3737
if name is not None:
+119
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
from sqlalchemy import Select, and_, desc, select
4+
from sqlalchemy.ext.asyncio import AsyncSession
5+
from sqlalchemy.orm import noload, selectinload
6+
from sqlalchemy_crud_plus import CRUDPlus
7+
8+
from backend.app.admin.model import DataRule, DataScope
9+
from backend.app.admin.schema.data_scope import CreateDataScopeParam, UpdateDataScopeParam, UpdateDataScopeRuleParam
10+
11+
12+
class CRUDDataScope(CRUDPlus[DataScope]):
13+
"""数据范围数据库操作类"""
14+
15+
async def get(self, db: AsyncSession, pk: int) -> DataScope | None:
16+
"""
17+
获取数据范围详情
18+
19+
:param db: 数据库会话
20+
:param pk: 范围 ID
21+
:return:
22+
"""
23+
return await self.select_model(db, pk)
24+
25+
async def get_by_name(self, db: AsyncSession, name: str) -> DataScope | None:
26+
"""
27+
通过名称获取数据范围
28+
29+
:param db: 数据库会话
30+
:param name: 范围名称
31+
:return:
32+
"""
33+
return await self.select_model_by_column(db, name=name)
34+
35+
async def get_with_relation(self, db: AsyncSession, pk: int) -> DataScope:
36+
"""
37+
获取数据范围关联数据
38+
39+
:param db: 数据库会话
40+
:param pk: 范围 ID
41+
:return:
42+
"""
43+
stmt = select(self.model).options(selectinload(self.model.rules)).where(self.model.id == pk)
44+
data_scope = await db.execute(stmt)
45+
return data_scope.scalars().first()
46+
47+
async def get_list(self, name: str | None, status: int | None) -> Select:
48+
"""
49+
获取数据范围列表
50+
51+
:param name: 范围名称
52+
:param status: 范围状态
53+
:return:
54+
"""
55+
stmt = (
56+
select(self.model)
57+
.options(noload(self.model.rules), noload(self.model.roles))
58+
.order_by(desc(self.model.created_time))
59+
)
60+
61+
filters = []
62+
if name is not None:
63+
filters.append(self.model.name.like(f'%{name}%'))
64+
if status is not None:
65+
filters.append(self.model.status == status)
66+
67+
if filters:
68+
stmt = stmt.where(and_(*filters))
69+
70+
return stmt
71+
72+
async def create(self, db: AsyncSession, obj: CreateDataScopeParam) -> None:
73+
"""
74+
创建数据范围
75+
76+
:param db: 数据库会话
77+
:param obj: 创建数据范围参数
78+
:return:
79+
"""
80+
await self.create_model(db, obj)
81+
82+
async def update(self, db: AsyncSession, pk: int, obj: UpdateDataScopeParam) -> int:
83+
"""
84+
更新数据范围
85+
86+
:param db: 数据库会话
87+
:param pk: 范围 ID
88+
:param obj: 更新数据范围参数
89+
:return:
90+
"""
91+
return await self.update_model(db, pk, obj)
92+
93+
async def update_rules(self, db: AsyncSession, pk: int, rule_ids: UpdateDataScopeRuleParam) -> int:
94+
"""
95+
更新数据范围规则
96+
97+
:param db: 数据库会话
98+
:param pk: 范围 ID
99+
:param rule_ids: 数据规则 ID 列表
100+
:return:
101+
"""
102+
current_data_scope = await self.get_with_relation(db, pk)
103+
stmt = select(DataRule).where(DataRule.id.in_(rule_ids.rules))
104+
rules = await db.execute(stmt)
105+
current_data_scope.rules = rules.scalars().all()
106+
return len(current_data_scope.rules)
107+
108+
async def delete(self, db: AsyncSession, pk: list[int]) -> int:
109+
"""
110+
删除数据范围
111+
112+
:param db: 数据库会话
113+
:param pk: 范围 ID 列表
114+
:return:
115+
"""
116+
return await self.delete_model_by_column(db, allow_multiple=True, id__in=pk)
117+
118+
119+
data_scope_dao: CRUDDataScope = CRUDDataScope(DataScope)

0 commit comments

Comments
 (0)