diff --git a/backend/controller/role.py b/backend/controller/role.py index 5084400..0dea596 100644 --- a/backend/controller/role.py +++ b/backend/controller/role.py @@ -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( diff --git a/backend/controller/user.py b/backend/controller/user.py index 7283737..5f0ca22 100644 --- a/backend/controller/user.py +++ b/backend/controller/user.py @@ -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 diff --git a/backend/core/security.py b/backend/core/security.py index 8492817..a8cd394 100644 --- a/backend/core/security.py +++ b/backend/core/security.py @@ -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}" diff --git a/backend/dbhelper/menu.py b/backend/dbhelper/menu.py index 5369052..952d8cd 100644 --- a/backend/dbhelper/menu.py +++ b/backend/dbhelper/menu.py @@ -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") diff --git a/backend/mini.db b/backend/mini.db new file mode 100644 index 0000000..0ce5d52 Binary files /dev/null and b/backend/mini.db differ diff --git a/backend/router/url.py b/backend/router/url.py index c168e7c..9f6b037 100644 --- a/backend/router/url.py +++ b/backend/router/url.py @@ -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 diff --git a/backend/schemas/menu.py b/backend/schemas/menu.py index f8dcb58..0f43829 100644 --- a/backend/schemas/menu.py +++ b/backend/schemas/menu.py @@ -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="权限标识符 -> 按钮显示") diff --git a/backend/tests/test_case.py b/backend/tests/test_case.py index d73701a..359fb31 100644 --- a/backend/tests/test_case.py +++ b/backend/tests/test_case.py @@ -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