Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions backend/app/admin/api/v1/sys/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
from backend.app.admin.api.v1.sys.api import router as api_router
from backend.app.admin.api.v1.sys.casbin import router as casbin_router
from backend.app.admin.api.v1.sys.config import router as config_router
from backend.app.admin.api.v1.sys.data_rule import router as data_rule_router
from backend.app.admin.api.v1.sys.data_rule_type import router as data_rule_type_router
from backend.app.admin.api.v1.sys.dept import router as dept_router
from backend.app.admin.api.v1.sys.dict_data import router as dict_data_router
from backend.app.admin.api.v1.sys.dict_type import router as dict_type_router
Expand All @@ -23,3 +25,5 @@
router.include_router(menu_router, prefix='/menus', tags=['系统目录'])
router.include_router(role_router, prefix='/roles', tags=['系统角色'])
router.include_router(user_router, prefix='/users', tags=['系统用户'])
router.include_router(data_rule_router, prefix='/data-rules', tags=['系统数据权限规则'])
router.include_router(data_rule_type_router, prefix='/data-rule-types', tags=['系统数据权限类型'])
5 changes: 3 additions & 2 deletions backend/app/admin/api/v1/sys/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
from typing import Annotated

from fastapi import APIRouter, Depends, Path, Query
from fastapi import APIRouter, Depends, Path, Query, Request

from backend.app.admin.schema.api import CreateApiParam, GetApiListDetails, UpdateApiParam
from backend.app.admin.service.api_service import api_service
Expand Down Expand Up @@ -37,12 +37,13 @@ async def get_api(pk: Annotated[int, Path(...)]) -> ResponseModel:
],
)
async def get_pagination_apis(
request: Request,
db: CurrentSession,
name: Annotated[str | None, Query()] = None,
method: Annotated[str | None, Query()] = None,
path: Annotated[str | None, Query()] = None,
) -> ResponseModel:
api_select = await api_service.get_select(name=name, method=method, path=path)
api_select = await api_service.get_select(request=request, name=name, method=method, path=path)
page_data = await paging_data(db, api_select, GetApiListDetails)
return response_base.success(data=page_data)

Expand Down
93 changes: 93 additions & 0 deletions backend/app/admin/api/v1/sys/data_rule.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Annotated

from fastapi import APIRouter, Depends, Path, Query

from backend.app.admin.schema.data_rule import CreateDataRuleParam, GetDataRuleListDetails, UpdateDataRuleParam
from backend.app.admin.service.data_rule_service import data_rule_service
from backend.common.pagination import DependsPagination, paging_data
from backend.common.response.response_schema import ResponseModel, response_base
from backend.common.security.jwt import DependsJwtAuth
from backend.common.security.permission import RequestPermission
from backend.common.security.rbac import DependsRBAC
from backend.database.db_mysql import CurrentSession
from backend.utils.serializers import select_as_dict

router = APIRouter()


@router.get('/models', summary='获取支持过滤的数据库模型', dependencies=[DependsJwtAuth])
async def get_data_rule_models() -> ResponseModel:
models = await data_rule_service.get_models()
return response_base.success(data=models)


@router.get('/model/{model}/columns', summary='获取支持过滤的数据库模型列', dependencies=[DependsJwtAuth])
async def get_data_rule_model_columns(model: Annotated[str, Path()]) -> ResponseModel:
models = await data_rule_service.get_columns(model=model)
return response_base.success(data=models)


@router.get('/{pk}', summary='获取数据权限规则详情', dependencies=[DependsJwtAuth])
async def get_data_rule(pk: Annotated[int, Path(...)]) -> ResponseModel:
data_rule = await data_rule_service.get(pk=pk)
data = GetDataRuleListDetails(**select_as_dict(data_rule))
return response_base.success(data=data)


@router.get(
'',
summary='(模糊条件)分页获取所有数据权限规则',
dependencies=[
DependsJwtAuth,
DependsPagination,
],
)
async def get_pagination_data_rule(db: CurrentSession, name: Annotated[str | None, Query()] = None) -> ResponseModel:
data_rule_select = await data_rule_service.get_select(name=name)
page_data = await paging_data(db, data_rule_select, GetDataRuleListDetails)
return response_base.success(data=page_data)


@router.post(
'',
summary='创建数据权限规则',
dependencies=[
Depends(RequestPermission('data:rule:add')),
DependsRBAC,
],
)
async def create_data_rule(obj: CreateDataRuleParam) -> ResponseModel:
await data_rule_service.create(obj=obj)
return response_base.success()


@router.put(
'/{pk}',
summary='更新数据权限规则',
dependencies=[
Depends(RequestPermission('data:rule:edit')),
DependsRBAC,
],
)
async def update_data_rule(pk: Annotated[int, Path(...)], obj: UpdateDataRuleParam) -> ResponseModel:
count = await data_rule_service.update(pk=pk, obj=obj)
if count > 0:
return response_base.success()
return response_base.fail()


@router.delete(
'',
summary='(批量)删除数据权限规则',
dependencies=[
Depends(RequestPermission('data:rule:del')),
DependsRBAC,
],
)
async def delete_data_rule(pk: Annotated[list[int], Query(...)]) -> ResponseModel:
count = await data_rule_service.delete(pk=pk)
if count > 0:
return response_base.success()
return response_base.fail()
85 changes: 85 additions & 0 deletions backend/app/admin/api/v1/sys/data_rule_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Annotated

from fastapi import APIRouter, Depends, Path, Query

from backend.app.admin.schema.data_rule_type import (
CreateDataRuleTypeParam,
GetDataRuleTypeListDetails,
UpdateDataRuleTypeParam,
)
from backend.app.admin.service.data_rule_type_service import data_rule_type_service
from backend.common.pagination import DependsPagination, paging_data
from backend.common.response.response_schema import ResponseModel, response_base
from backend.common.security.jwt import DependsJwtAuth
from backend.common.security.permission import RequestPermission
from backend.common.security.rbac import DependsRBAC
from backend.database.db_mysql import CurrentSession
from backend.utils.serializers import select_as_dict

router = APIRouter()


@router.get('/{pk}', summary='获取数据权限规则类型详情', dependencies=[DependsJwtAuth])
async def get_data_rule_type(pk: Annotated[int, Path(...)]) -> ResponseModel:
data_rule_type = await data_rule_type_service.get(pk=pk)
data = GetDataRuleTypeListDetails(**select_as_dict(data_rule_type))
return response_base.success(data=data)


@router.get(
'',
summary='(模糊条件)分页获取所有数据权限规则类型',
dependencies=[
DependsJwtAuth,
DependsPagination,
],
)
async def get_pagination_data_rule_type(db: CurrentSession) -> ResponseModel:
data_rule_type_select = await data_rule_type_service.get_select()
page_data = await paging_data(db, data_rule_type_select, GetDataRuleTypeListDetails)
return response_base.success(data=page_data)


@router.post(
'',
summary='创建数据权限规则类型',
dependencies=[
Depends(RequestPermission('data:rule:type:add')),
DependsRBAC,
],
)
async def create_data_rule_type(obj: CreateDataRuleTypeParam) -> ResponseModel:
await data_rule_type_service.create(obj=obj)
return response_base.success()


@router.put(
'/{pk}',
summary='更新数据权限规则类型',
dependencies=[
Depends(RequestPermission('data:rule:type:edit')),
DependsRBAC,
],
)
async def update_data_rule_type(pk: Annotated[int, Path(...)], obj: UpdateDataRuleTypeParam) -> ResponseModel:
count = await data_rule_type_service.update(pk=pk, obj=obj)
if count > 0:
return response_base.success()
return response_base.fail()


@router.delete(
'',
summary='(批量)删除数据权限规则类型',
dependencies=[
Depends(RequestPermission('data:rule:type:del')),
DependsRBAC,
],
)
async def delete_data_rule_type(pk: Annotated[list[int], Query(...)]) -> ResponseModel:
count = await data_rule_type_service.delete(pk=pk)
if count > 0:
return response_base.success()
return response_base.fail()
27 changes: 25 additions & 2 deletions backend/app/admin/api/v1/sys/role.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@

from fastapi import APIRouter, Depends, Path, Query, Request

from backend.app.admin.schema.role import CreateRoleParam, GetRoleListDetails, UpdateRoleMenuParam, UpdateRoleParam
from backend.app.admin.schema.role import (
CreateRoleParam,
GetRoleListDetails,
UpdateRoleMenuParam,
UpdateRoleParam,
UpdateRoleRuleParam,
)
from backend.app.admin.service.menu_service import menu_service
from backend.app.admin.service.role_service import role_service
from backend.common.pagination import DependsPagination, paging_data
Expand All @@ -27,7 +33,7 @@ async def get_all_roles() -> ResponseModel:

@router.get('/{pk}/all', summary='获取用户所有角色', dependencies=[DependsJwtAuth])
async def get_user_all_roles(pk: Annotated[int, Path(...)]) -> ResponseModel:
roles = await role_service.get_user_roles(pk=pk)
roles = await role_service.get_by_user(pk=pk)
data = select_list_serialize(roles)
return response_base.success(data=data)

Expand Down Expand Up @@ -109,6 +115,23 @@ async def update_role_menus(
return response_base.fail()


@router.put(
'/{pk}/rule',
summary='更新角色数据权限规则',
dependencies=[
Depends(RequestPermission('sys:role:rule:edit')),
DependsRBAC,
],
)
async def update_role_rules(
request: Request, pk: Annotated[int, Path(...)], rule_ids: UpdateRoleRuleParam
) -> ResponseModel:
count = await role_service.update_role_rule(request=request, pk=pk, rule_ids=rule_ids)
if count > 0:
return response_base.success()
return response_base.fail()


@router.delete(
'',
summary='(批量)删除角色',
Expand Down
8 changes: 6 additions & 2 deletions backend/app/admin/crud/crud_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@
# -*- coding: utf-8 -*-
from typing import Sequence

from fastapi import Request
from sqlalchemy import Select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy_crud_plus import CRUDPlus

from backend.app.admin.model import Api
from backend.app.admin.schema.api import CreateApiParam, UpdateApiParam
from backend.common.security.permission import filter_data_permission


class CRUDApi(CRUDPlus[Api]):
Expand All @@ -21,10 +23,11 @@ async def get(self, db: AsyncSession, pk: int) -> Api | None:
"""
return await self.select_model(db, pk)

async def get_list(self, name: str = None, method: str = None, path: str = None) -> Select:
async def get_list(self, request: Request, name: str = None, method: str = None, path: str = None) -> Select:
"""
获取 API 列表

:param request:
:param name:
:param method:
:param path:
Expand All @@ -37,7 +40,8 @@ async def get_list(self, name: str = None, method: str = None, path: str = None)
filters.update(method=method)
if path is not None:
filters.update(path__like=f'%{path}%')
return await self.select_order('created_time', 'desc', **filters)
stmt = await self.select_order('created_time', 'desc', **filters)
return stmt.where(filter_data_permission(request))

async def get_all(self, db: AsyncSession) -> Sequence[Api]:
"""
Expand Down
89 changes: 89 additions & 0 deletions backend/app/admin/crud/crud_data_rule.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Sequence

from sqlalchemy import Select, desc, select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy_crud_plus import CRUDPlus

from backend.app.admin.model import DataRule
from backend.app.admin.schema.data_rule import CreateDataRuleParam, UpdateDataRuleParam


class CRUDDataRule(CRUDPlus[DataRule]):
async def get(self, db: AsyncSession, pk: int) -> DataRule | None:
"""
获取数据权限规则

:param db:
:param pk:
:return:
"""
return await self.select_model(db, pk)

async def get_list(self, name: str = None) -> Select:
"""
获取数据权限规则列表

:return:
"""
stmt = select(self.model).order_by(desc(self.model.created_time))
where_list = []
if name is not None:
where_list.append(self.model.name.like(f'%{name}%'))
if where_list:
stmt = stmt.where(*where_list)
return stmt

async def get_by_name(self, db: AsyncSession, name: str):
"""
通过 name 获取数据权限规则

:param db:
:param name:
:return:
"""
return await self.select_model_by_column(db, name=name)

async def get_all(self, db: AsyncSession) -> Sequence[DataRule]:
"""
获取所有数据权限规则

:param db:
:return:
"""
return await self.select_models(db)

async def create(self, db: AsyncSession, obj_in: CreateDataRuleParam) -> None:
"""
创建数据权限规则

:param db:
:param obj_in:
:return:
"""
await self.create_model(db, obj_in)

async def update(self, db: AsyncSession, pk: int, obj_in: UpdateDataRuleParam) -> int:
"""
更新数据权限规则

:param db:
:param pk:
:param obj_in:
:return:
"""
return await self.update_model(db, pk, obj_in)

async def delete(self, db: AsyncSession, pk: list[int]) -> int:
"""
删除数据权限规则

:param db:
:param pk:
:return:
"""
return await self.delete_model_by_column(db, allow_multiple=True, id__in=pk)


data_rule_dao: CRUDDataRule = CRUDDataRule(DataRule)
Loading