feat: 菜单树缺少根节点异常处理
This commit is contained in:
parent
80947a608e
commit
aefb93b399
@ -4,8 +4,14 @@ from fastapi import Query
|
||||
|
||||
from core.utils import list_to_tree
|
||||
from dbhelper.menu import get_menu
|
||||
from dbhelper.role import (del_role, get_role, get_role_menus, get_roles,
|
||||
new_role, put_role)
|
||||
from dbhelper.role import (
|
||||
del_role,
|
||||
get_role,
|
||||
get_role_menus,
|
||||
get_roles,
|
||||
new_role,
|
||||
put_role,
|
||||
)
|
||||
from schemas import ListAll, Response, RoleIn, RoleInfo, RoleQuery, RoleRead
|
||||
|
||||
|
||||
@ -22,7 +28,11 @@ async def role_has_menu(rid: int):
|
||||
menus = await get_role_menus(rid)
|
||||
for obj in menus:
|
||||
obj["meta"] = json.loads(obj["meta"]) if obj["meta"] is not None else None
|
||||
return Response(data=list_to_tree(menus))
|
||||
try:
|
||||
result = list_to_tree(menus)
|
||||
except KeyError:
|
||||
return Response(code=400, msg="菜单缺少根节点.")
|
||||
return Response(data=result)
|
||||
|
||||
|
||||
async def role_arr(
|
||||
|
@ -2,8 +2,15 @@ from fastapi import Depends, Query
|
||||
from starlette.requests import Request
|
||||
|
||||
from core.security import check_token, get_password_hash
|
||||
from dbhelper.user import (del_user, get_user, get_user_info, get_users,
|
||||
insert_user, put_user, select_role)
|
||||
from dbhelper.user import (
|
||||
del_user,
|
||||
get_user,
|
||||
get_user_info,
|
||||
get_users,
|
||||
insert_user,
|
||||
put_user,
|
||||
select_role,
|
||||
)
|
||||
from schemas import Response, UserAdd, UserInfo, UserPut, UserQuery, UserRead
|
||||
from schemas.common import ListAll
|
||||
|
||||
|
@ -7,7 +7,7 @@ from jose import JWTError, jwt
|
||||
from passlib.context import CryptContext
|
||||
|
||||
from core.exceptions import PermissionsError, TokenAuthFailure
|
||||
from dbhelper.menu import get_apis, get_has_api
|
||||
from dbhelper.menu import get_apis
|
||||
from dbhelper.user import get_user, get_user_info
|
||||
from models import UserModel
|
||||
|
||||
@ -79,8 +79,6 @@ async def check_permissions(request: Request, user: UserModel = Depends(check_to
|
||||
api = request.url.path
|
||||
for k, v in request.path_params.items():
|
||||
api = api.replace(v, "{%s}" % k)
|
||||
# 方法1. 每一次去查数据库
|
||||
# result = await get_has_api(active_rid, api, request.method)
|
||||
|
||||
# 2. 登录之后查一次 后面去结果查 todo 更新权限时需要更新 , 最好结果放redis
|
||||
cache_key = f"{user.username}_{active_rid}"
|
||||
|
@ -49,18 +49,6 @@ async def del_menu(mid: int):
|
||||
return await MenuModel.filter(id=mid).update(status=9)
|
||||
|
||||
|
||||
async def get_has_api(pk: int, api: str, method: str):
|
||||
"""获取角色接口权限 每次来查数据库"""
|
||||
db = connections.get("default")
|
||||
return await db.execute_query_dict(
|
||||
"""
|
||||
select m.api, m.method
|
||||
FROM sys_menu as m, sys_role_menu as srm WHERE m.id = srm.mid
|
||||
AND srm.rid = (?) and m.api = (?) and m.method = (?) and m.status != 9""",
|
||||
[pk, api, method],
|
||||
)
|
||||
|
||||
|
||||
async def get_apis(pk: int):
|
||||
"""返回当前角色拥有的接口权限列表"""
|
||||
db = connections.get("default")
|
||||
|
BIN
backend/mini.db
Normal file
BIN
backend/mini.db
Normal file
Binary file not shown.
@ -4,10 +4,23 @@ from fastapi import Depends, routing
|
||||
|
||||
from controller.common import login, websocket
|
||||
from controller.menu import menu_add, menu_arr, menu_del, menu_put
|
||||
from controller.role import (role_add, role_arr, role_del, role_has_menu,
|
||||
role_put, role_query)
|
||||
from controller.user import (user_add, user_arr, user_del, user_info,
|
||||
user_list, user_put, user_select_role)
|
||||
from controller.role import (
|
||||
role_add,
|
||||
role_arr,
|
||||
role_del,
|
||||
role_has_menu,
|
||||
role_put,
|
||||
role_query,
|
||||
)
|
||||
from controller.user import (
|
||||
user_add,
|
||||
user_arr,
|
||||
user_del,
|
||||
user_info,
|
||||
user_list,
|
||||
user_put,
|
||||
user_select_role,
|
||||
)
|
||||
from core.security import check_permissions
|
||||
|
||||
|
||||
|
@ -9,7 +9,7 @@ class MenuBasic(BaseModel):
|
||||
name: str
|
||||
meta: dict = Field(default=None, description="元信息")
|
||||
path: Optional[str] = Field(default=None, description="前端路由地址")
|
||||
type: int = Field(description="0 目录 1 组件 2 按钮")
|
||||
type: int = Field(description="0 目录 1 组件 2 按钮 3数据")
|
||||
component: Optional[str] = Field(default=None, description="前端组件地址")
|
||||
pid: int = Field(default=0, description="0 表示没有根节点")
|
||||
identifier: Optional[str] = Field(default=None, description="权限标识符 -> 按钮显示")
|
||||
|
@ -8,8 +8,8 @@ from schemas.user import RoleActive, UserAdd
|
||||
|
||||
base = "http://localhost:8000"
|
||||
|
||||
params = [
|
||||
# 创建菜单
|
||||
|
||||
dirs = [
|
||||
(
|
||||
"/menu",
|
||||
MenuIn( # id 1
|
||||
@ -38,267 +38,256 @@ params = [
|
||||
method=None,
|
||||
).dict(),
|
||||
),
|
||||
# 组件
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("path, data", dirs)
|
||||
def test_add_dir(path, data):
|
||||
"""添加一级目录"""
|
||||
res = client.post(url=base + path, json=data)
|
||||
logger.info(res.json())
|
||||
assert res.status_code == 200
|
||||
|
||||
|
||||
menus = [
|
||||
(
|
||||
"/menu",
|
||||
MenuIn( # id 3
|
||||
name="用户管理",
|
||||
meta={"icon": "TeamOutlined"},
|
||||
meta={"icon": "TeamOutlined", "title": "用户管理"},
|
||||
path="/system/user",
|
||||
type=1,
|
||||
component="/system/user/user.vue",
|
||||
pid=1,
|
||||
identifier=None,
|
||||
api="/user",
|
||||
method="GET",
|
||||
).dict(),
|
||||
),
|
||||
(
|
||||
"/menu",
|
||||
MenuIn( # id 4
|
||||
name="角色管理",
|
||||
meta={"icon": "UserOutlined"},
|
||||
meta={"icon": "UserOutlined", "title": "角色管理"},
|
||||
path="/system/role",
|
||||
type=1,
|
||||
component="/system/role/role.vue",
|
||||
pid=1,
|
||||
identifier=None,
|
||||
api="/role",
|
||||
method="GET",
|
||||
).dict(),
|
||||
),
|
||||
(
|
||||
"/menu",
|
||||
MenuIn( # id 5
|
||||
name="菜单管理",
|
||||
meta={"icon": "MenuOutlined"},
|
||||
meta={"icon": "MenuOutlined", "title": "菜单管理"},
|
||||
path="/system/menu",
|
||||
type=1,
|
||||
component="/system/menu/menu.vue",
|
||||
pid=1,
|
||||
identifier=None,
|
||||
api="/menu",
|
||||
method="GET",
|
||||
).dict(),
|
||||
),
|
||||
(
|
||||
"/menu",
|
||||
MenuIn( # id 6
|
||||
name="关于",
|
||||
meta={"icon": "DashboardOutlined"},
|
||||
meta={"icon": "DashboardOutlined", "title": "关于"},
|
||||
path="/setting/about",
|
||||
type=1,
|
||||
component="/setting/about/about.vue",
|
||||
pid=2,
|
||||
identifier=None,
|
||||
).dict(),
|
||||
),
|
||||
# 按钮
|
||||
(
|
||||
"/menu",
|
||||
MenuIn(
|
||||
name="用户新增",
|
||||
meta={"icon": "Add"},
|
||||
path=None,
|
||||
type=2,
|
||||
component=None,
|
||||
pid=3,
|
||||
identifier="user:create",
|
||||
api="/user",
|
||||
method="POST",
|
||||
).dict(),
|
||||
),
|
||||
(
|
||||
"/menu",
|
||||
MenuIn(
|
||||
name="用户删除",
|
||||
meta={"icon": "Delete"},
|
||||
path=None,
|
||||
type=2,
|
||||
component=None,
|
||||
pid=3,
|
||||
identifier="user:delete",
|
||||
api="/user/{pk}",
|
||||
method="DELETE",
|
||||
).dict(),
|
||||
),
|
||||
(
|
||||
"/menu",
|
||||
MenuIn(
|
||||
name="用户更新",
|
||||
meta={"icon": "Update"},
|
||||
path=None,
|
||||
type=2,
|
||||
component=None,
|
||||
pid=3,
|
||||
identifier="user:update",
|
||||
api="/user/{pk}",
|
||||
method="PUT",
|
||||
).dict(),
|
||||
),
|
||||
(
|
||||
"/menu",
|
||||
MenuIn(
|
||||
name="用户详情",
|
||||
meta={"icon": "Info"},
|
||||
path=None,
|
||||
type=2,
|
||||
component=None,
|
||||
pid=3,
|
||||
identifier="user:get",
|
||||
api="/user/{pk}",
|
||||
method="GET",
|
||||
).dict(),
|
||||
),
|
||||
(
|
||||
"/menu",
|
||||
MenuIn(
|
||||
name="用户查询",
|
||||
meta={"icon": "Search"},
|
||||
path=None,
|
||||
type=2,
|
||||
component=None,
|
||||
pid=3,
|
||||
identifier="user:query",
|
||||
api="/user/query",
|
||||
method="POST",
|
||||
).dict(),
|
||||
),
|
||||
# 角色管理
|
||||
(
|
||||
"/menu",
|
||||
MenuIn(
|
||||
name="角色新增",
|
||||
meta={"icon": "Add"},
|
||||
path=None,
|
||||
type=2,
|
||||
component=None,
|
||||
pid=4,
|
||||
identifier="role:create",
|
||||
api="/role",
|
||||
method="POST",
|
||||
).dict(),
|
||||
),
|
||||
(
|
||||
"/menu",
|
||||
MenuIn(
|
||||
name="角色删除",
|
||||
meta={"icon": "Delete"},
|
||||
path=None,
|
||||
type=2,
|
||||
component=None,
|
||||
pid=4,
|
||||
identifier="role:delete",
|
||||
api="/role/{pk}",
|
||||
method="DELETE",
|
||||
).dict(),
|
||||
),
|
||||
(
|
||||
"/menu",
|
||||
MenuIn(
|
||||
name="查询角色拥有权限",
|
||||
meta={"icon": "Delete"},
|
||||
path=None,
|
||||
type=2,
|
||||
component=None,
|
||||
pid=4,
|
||||
identifier=None,
|
||||
api="/role/{rid}/menu",
|
||||
method="GET",
|
||||
).dict(),
|
||||
),
|
||||
(
|
||||
"/menu",
|
||||
MenuIn(
|
||||
name="查询角色",
|
||||
meta={"icon": "Search"},
|
||||
path=None,
|
||||
type=2,
|
||||
component=None,
|
||||
pid=4,
|
||||
identifier="role:query",
|
||||
api="/role/query",
|
||||
method="POST",
|
||||
).dict(),
|
||||
),
|
||||
(
|
||||
"/menu",
|
||||
MenuIn(
|
||||
name="更新角色",
|
||||
meta={"icon": "Update"},
|
||||
path=None,
|
||||
type=2,
|
||||
component=None,
|
||||
pid=4,
|
||||
identifier="role:update",
|
||||
api="/role/{pk}",
|
||||
method="PUT",
|
||||
).dict(),
|
||||
),
|
||||
# 菜单管理的权限
|
||||
(
|
||||
"/menu",
|
||||
MenuIn(
|
||||
name="新增菜单",
|
||||
meta={"icon": "Update"},
|
||||
path=None,
|
||||
type=2,
|
||||
component=None,
|
||||
pid=5,
|
||||
identifier="menu:create",
|
||||
api="/menu",
|
||||
method="POST",
|
||||
).dict(),
|
||||
),
|
||||
(
|
||||
"/menu",
|
||||
MenuIn(
|
||||
name="删除菜单",
|
||||
meta={"icon": "Delete"},
|
||||
path=None,
|
||||
type=2,
|
||||
component=None,
|
||||
pid=5,
|
||||
identifier="menu:delete",
|
||||
api="/menu/{pk}",
|
||||
method="DELETE",
|
||||
).dict(),
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("path,data", menus)
|
||||
def test_add_menu(path, data):
|
||||
"""添加二级菜单"""
|
||||
res = client.post(url=base + path, json=data)
|
||||
logger.info(res.json())
|
||||
assert res.status_code == 200
|
||||
|
||||
|
||||
user_manager_pre = [
|
||||
MenuIn(
|
||||
name="用户详情",
|
||||
type=3,
|
||||
identifier="user:get",
|
||||
api="/user/{pk}",
|
||||
method="GET",
|
||||
),
|
||||
MenuIn(
|
||||
name="用户列表",
|
||||
type=3, # 数据类
|
||||
api="/user",
|
||||
method="GET",
|
||||
),
|
||||
MenuIn(
|
||||
name="用户查询",
|
||||
type=2,
|
||||
identifier="user:query",
|
||||
api="/user/query",
|
||||
method="POST",
|
||||
),
|
||||
MenuIn(
|
||||
name="用户新增",
|
||||
type=2,
|
||||
identifier="user:create",
|
||||
api="/user",
|
||||
method="POST",
|
||||
),
|
||||
MenuIn(
|
||||
name="用户删除",
|
||||
type=2,
|
||||
identifier="user:delete",
|
||||
api="/user/{pk}",
|
||||
method="DELETE",
|
||||
),
|
||||
MenuIn(
|
||||
name="用户更新",
|
||||
type=2,
|
||||
identifier="user:update",
|
||||
api="/user/{pk}",
|
||||
method="PUT",
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", user_manager_pre)
|
||||
def test_add_user_pre(data):
|
||||
"""用户管理相关权限"""
|
||||
data.pid = 3
|
||||
res = client.post(url=base + "/menu", json=data.dict())
|
||||
logger.info(res.json())
|
||||
assert res.status_code == 200
|
||||
|
||||
|
||||
role_manager_pre = [
|
||||
MenuIn(
|
||||
name="查询角色拥有权限",
|
||||
type=3,
|
||||
api="/role/{rid}/menu",
|
||||
method="GET",
|
||||
),
|
||||
MenuIn(
|
||||
name="角色列表",
|
||||
type=3,
|
||||
api="/role",
|
||||
method="GET",
|
||||
),
|
||||
MenuIn(
|
||||
name="角色查询",
|
||||
meta={"icon": "Search"},
|
||||
type=2,
|
||||
identifier="role:query",
|
||||
api="/role/query",
|
||||
method="POST",
|
||||
),
|
||||
MenuIn(
|
||||
name="角色新增",
|
||||
type=2,
|
||||
identifier="role:create",
|
||||
api="/role",
|
||||
method="POST",
|
||||
),
|
||||
MenuIn(
|
||||
name="角色删除",
|
||||
type=2,
|
||||
identifier="role:delete",
|
||||
api="/role/{pk}",
|
||||
method="DELETE",
|
||||
),
|
||||
MenuIn(
|
||||
name="角色更新",
|
||||
type=2,
|
||||
identifier="role:update",
|
||||
api="/role/{pk}",
|
||||
method="PUT",
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", role_manager_pre)
|
||||
def test_add_role_pre(data):
|
||||
"""角色管理相关权限"""
|
||||
logger.debug(data.dict())
|
||||
data.pid = 4
|
||||
res = client.post(url=base + "/menu", json=data.dict())
|
||||
logger.info(res.json())
|
||||
assert res.status_code == 200
|
||||
|
||||
|
||||
menu_manager_pre = [
|
||||
MenuIn(
|
||||
name="菜单列表",
|
||||
type=3,
|
||||
api="/menu",
|
||||
method="GET",
|
||||
),
|
||||
MenuIn(
|
||||
name="菜单新增",
|
||||
type=2,
|
||||
identifier="menu:create",
|
||||
api="/menu",
|
||||
method="POST",
|
||||
),
|
||||
MenuIn(
|
||||
name="菜单更新",
|
||||
type=2,
|
||||
identifier="menu:update",
|
||||
api="/menu/{pk}",
|
||||
method="PUT",
|
||||
),
|
||||
MenuIn(
|
||||
name="菜单删除",
|
||||
type=2,
|
||||
identifier="menu:delete",
|
||||
api="/menu/{pk}",
|
||||
method="DELETE",
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", menu_manager_pre)
|
||||
def test_add_menu_pre(data):
|
||||
"""菜单管理相关权限"""
|
||||
data.pid = 5
|
||||
res = client.post(url=base + "/menu", json=data.dict())
|
||||
logger.info(res.json())
|
||||
assert res.status_code == 200
|
||||
|
||||
|
||||
menus_len = (
|
||||
len(user_manager_pre)
|
||||
+ len(menus)
|
||||
+ len(dirs)
|
||||
+ len(role_manager_pre)
|
||||
+ len(menu_manager_pre)
|
||||
)
|
||||
|
||||
datas = [
|
||||
(
|
||||
"/role",
|
||||
RoleIn(
|
||||
name="super",
|
||||
name="superStar",
|
||||
remark="全部权限",
|
||||
menus=[num for num in range(1, len(params) + 1)],
|
||||
).dict(),
|
||||
menus=[num for num in range(1, menus_len)],
|
||||
),
|
||||
),
|
||||
# 创建用户
|
||||
(
|
||||
"/user",
|
||||
UserAdd(
|
||||
username="admin",
|
||||
nickname="管理员",
|
||||
nickname="666管理员",
|
||||
password="123456",
|
||||
roles=[RoleActive(rid=1, status=5)],
|
||||
).dict(),
|
||||
),
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("path, data", params)
|
||||
def test_add_data(path, data):
|
||||
"""注册菜单"""
|
||||
res = client.post(url=base + path, json=data)
|
||||
logger.info(res.json())
|
||||
assert res.status_code == 200
|
||||
|
||||
|
||||
@pytest.mark.parametrize("path, data", datas)
|
||||
def test_add_user(path, data):
|
||||
"""添加账号"""
|
||||
res = client.post(url=base + path, json=data)
|
||||
res = client.post(url=base + path, json=data.dict())
|
||||
logger.info(res.json())
|
||||
logger.info(menus_len)
|
||||
assert res.status_code == 200
|
||||
|
Loading…
Reference in New Issue
Block a user