feat: role & menu api

This commit is contained in:
zy7y 2022-09-12 23:22:18 +08:00
parent f27d2e9f7c
commit 8e154d492a
18 changed files with 701 additions and 270 deletions

3
backend/.gitignore vendored
View File

@ -141,4 +141,5 @@ cython_debug/
.pdm.toml
__pypackages__/
.pytest_cache
.db-*
.db*
*/.pytest_cache

View File

@ -1,17 +1 @@
from fastapi import Depends, FastAPI
from core.security import check_token
def register_routers(app: FastAPI):
from controller.common import common
from controller.menu import menu
from controller.role import role
from controller.user import user
app.include_router(router=common)
app.include_router(
router=user,
)
app.include_router(router=menu)
app.include_router(router=role)

View File

@ -4,7 +4,7 @@ from schemas import LoginForm, LoginResult, Response
async def login(auth_data: LoginForm) -> Response[LoginResult]:
user_obj = await get_user({"username": auth_data.username})
user_obj = await get_user({"username": auth_data.username, "status__not": 9})
if user_obj:
if verify_password(auth_data.password, user_obj.password):
return Response(
@ -12,4 +12,9 @@ async def login(auth_data: LoginForm) -> Response[LoginResult]:
id=user_obj.id, token=generate_token(auth_data.username)
)
)
return Response(msg="账号或密码错误")
return Response(code=400, msg="账号或密码错误")
async def about() -> Response:
"""关于"""
pass

View File

@ -1,6 +1,23 @@
from dbhelper.menu import insert_menu
from schemas import MenuIn, MenuRead, Response
from fastapi import Query
from dbhelper.menu import del_menu, get_menus, insert_menu
from schemas import ListAll, MenuIn, MenuRead, Response
async def menu_add(data: MenuIn) -> Response[MenuRead]:
return Response(data=await insert_menu(data))
async def menu_arr(
offset: int = Query(default=1, description="偏移量"),
limit: int = Query(default=10, description="数量"),
) -> Response[ListAll[list[MenuRead]]]:
skip = (offset - 1) * limit
menus, count = await get_menus(skip, limit)
return Response(data=ListAll(total=count, items=menus))
async def menu_del(pk: int) -> Response:
if await del_menu(pk) == 0:
return Response(code=400, msg="菜单不存在")
return Response()

View File

@ -1,8 +1,18 @@
import json
from fastapi import Query
from core.utils import list_to_tree
from dbhelper.role import get_role_menus, new_role
from schemas import Response, RoleIn, RoleInfo
from dbhelper.relation import role_assigned_menu
from dbhelper.role import (
del_role,
get_role,
get_role_menus,
get_roles,
new_role,
put_role,
)
from schemas import ListAll, Response, RoleIn, RoleInfo, RoleMenuIn, RoleQuery, RoleRead
async def role_add(data: RoleIn) -> Response[RoleInfo]:
@ -17,3 +27,43 @@ async def role_has_menu(rid: int):
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))
async def role_arr(
offset: int = Query(default=1, description="偏移量-页码"),
limit: int = Query(default=10, description="数据量"),
) -> Response[ListAll[list[RoleRead]]]:
skip = (offset - 1) * limit
roles, count = await get_roles(skip, limit)
return Response(data=ListAll(total=count, items=roles))
async def assigned_menu(data: RoleMenuIn) -> Response:
"""分配菜单给角色"""
if await get_role({"id": data.rid, "status__not": 9}) is None:
return Response(code=400, msg="角色不存在")
if isinstance(await role_assigned_menu(data), int):
return Response(code=400, msg=f"菜单不存在")
return Response()
async def role_del(pk: int) -> Response:
if await del_role(pk) == 0:
return Response(code=400, msg="角色不存在")
return Response()
async def role_put(pk: int, data: RoleIn) -> Response:
"""更新角色"""
if await put_role(pk, data) == 0:
return Response(code=400, msg="角色不存在")
return Response()
async def role_query(query: RoleQuery) -> Response[ListAll[list[RoleRead]]]:
"""post条件查询角色表"""
limit = query.size
skip = (query.offset - 1) * limit
del query.offset, query.size
users, count = await get_roles(skip, limit, query.dict())
return Response(data=ListAll(total=count, items=users))

View File

@ -1,48 +1,71 @@
from fastapi import Query
from core.security import get_password_hash
from dbhelper.user import get_user, get_user_info, get_users, insert_user, new_user
from schemas import Response, UserAdd, UserIn, UserInfo, UserList, UserQuery, UserRead
from dbhelper.user import (
del_user,
get_user,
get_user_info,
get_users,
insert_user,
put_user,
)
from schemas import Response, UserAdd, UserInfo, UserPut, UserQuery, UserRead
from schemas.common import ListAll
async def user_add(data: UserAdd) -> Response[UserInfo]:
async def user_add(data: UserAdd) -> Response[UserRead]:
"""新增用户并分配角色 一步到位"""
if await get_user({"username": data.username}) is not None:
return Response(code=400, msg="用户名已存在")
roles = data.rids
del data.rids
data.password = get_password_hash(data.password)
return await insert_user(data, roles)
async def create_user(data: UserIn) -> Response[UserRead]:
"""新增用户"""
result = await get_user({"username": data.username})
if result is None:
data.password = get_password_hash(data.password)
return Response(data=await new_user(data))
return Response(msg="用户名已存在")
result = await insert_user(data, roles)
if isinstance(result, int):
return Response(code=400, msg=f"角色{result}不存在")
return Response(data=result)
async def user_info(pk: int) -> Response[UserInfo]:
try:
return Response(data=await get_user_info(pk))
except Exception as e:
return Response(msg=f"用户不存在 {e}")
"""获取用户信息"""
obj = await get_user({"id": pk})
if obj is None:
return Response(code=400, msg="用户不存在")
return Response(data=await get_user_info(obj))
async def user_arr(
offset: int = Query(default=1, description="偏移量-页码"),
limit: int = Query(default=10, description="数据量"),
) -> Response[ListAll[UserList]]:
) -> Response[ListAll[list[UserRead]]]:
"""分页列表数据"""
skip = (offset - 1) * limit
users, count = await get_users(skip, limit)
return Response(data=ListAll(total=count, items=users))
async def user_list(query: UserQuery) -> Response[ListAll[UserList]]:
async def user_list(query: UserQuery) -> Response[ListAll[list[UserRead]]]:
"""post查询用户列表"""
limit = query.size
skip = (query.offset - 1) * limit
del query.offset, query.size
users, count = await get_users(skip, limit, query.dict())
return Response(data=ListAll(total=count, items=users))
async def user_del(pk: int) -> Response:
"""删除用户"""
if await del_user(pk) == 0:
return Response(code=400, msg="用户不存在")
return Response()
async def user_put(pk: int, data: UserPut) -> Response:
"""更新用户"""
if await get_user({"id": pk}) is None:
return Response(code=400, msg="用户不存在")
result = await put_user(pk, data)
if isinstance(result, int):
return Response(code=400, msg=f"角色不存在{result}")
return Response()

View File

@ -10,6 +10,6 @@ sh.setLevel(logging.DEBUG)
sh.setFormatter(fmt)
# will print debug sql
logger_db_client = logging.getLogger("mini-rbac")
logger_db_client.setLevel(logging.DEBUG)
logger_db_client.addHandler(sh)
logger = logging.getLogger("mini-rbac")
logger.setLevel(logging.DEBUG)
logger.addHandler(sh)

View File

@ -5,3 +5,39 @@ from schemas.menu import MenuIn
async def insert_menu(menu: MenuIn):
"""新增菜单"""
return await MenuModel.create(**menu.dict())
async def get_menus(skip: int, limit: int, kwargs: dict = None):
"""
分页获取用户并且支持字段模糊查询
Args:
skip: 偏移量
limit: 数量
kwargs: 查询字典
Returns:
"""
if kwargs is not None:
kwargs = {f"{k}__contains": v for k, v in kwargs.items()}
else:
kwargs = {}
result = MenuModel.filter(status__not=9, **kwargs).all().order_by("-created")
return await result.offset(skip).limit(limit), await result.count()
async def get_menu(kwargs):
"""
根据条件查询到第一条符合结果的数据
Args:
kwargs:
Returns:
"""
return await MenuModel.filter(**kwargs).first()
async def del_menu(mid: int):
"""删除用户"""
return await MenuModel.filter(id=mid).update(status=9)

View File

@ -0,0 +1,31 @@
from tortoise import connections
from dbhelper.menu import get_menu
from models import RoleMenuModel, UserRoleModel
from schemas import UserRole
async def user_assigned_role(data: UserRole):
"""给用户分配角色"""
return await UserRoleModel.create(**data.dict())
async def role_assigned_menu(data):
"""给角色分配菜单"""
for mid in data.menus:
if await get_menu({"id": mid}) is None:
return mid
# todo 性能优化
db = connections.get("default")
# 1. 先把所有数据做删除
await db.execute_query_dict(
"""
update sys_role_menu set status = 9 where rid = (?)
""",
[data.rid],
)
# 2. 新增数据
await RoleMenuModel.bulk_create(
[RoleMenuModel(rid=data.rid, mid=mid) for mid in data.menus]
)

View File

@ -11,9 +11,9 @@ async def get_role_menus(rid: int):
db = connections.get("default")
return await db.execute_query_dict(
"""
select m.id, m.name, m.meta, m.path, m.type, m.component, m.pid, m.identifier, m.api_regx,m.api, m.method, m.sort
select m.id, m.name, m.meta, m.path, m.type, m.component, m.pid, m.identifier, m.regx,m.api, m.method
FROM sys_menu as m, sys_role_menu WHERE m.id = sys_role_menu.mid
AND sys_role_menu.rid = (%s) AND m.`status` = 1 ORDER BY m.sort""",
AND sys_role_menu.rid = (?) AND m.`status` = 1""",
[rid],
)
@ -21,3 +21,44 @@ async def get_role_menus(rid: int):
async def new_role(role: RoleIn):
"""新增角色"""
return await RoleModel.create(**role.dict())
async def get_roles(skip: int, limit: int, kwargs: dict = None):
"""
分页获取用户并且支持字段模糊查询
Args:
skip: 偏移量
limit: 数量
kwargs: 查询字典
Returns:
"""
if kwargs is not None:
kwargs = {f"{k}__contains": v for k, v in kwargs.items()}
else:
kwargs = {}
result = RoleModel.filter(status__not=9, **kwargs).all().order_by("-created")
return await result.offset(skip).limit(limit), await result.count()
async def get_role(kwargs):
"""
根据条件查询到第一条符合结果的数据
Args:
kwargs:
Returns:
"""
return await RoleModel.filter(**kwargs).first()
async def del_role(rid: int):
"""删除用户"""
return await RoleModel.filter(id=rid).update(status=9)
async def put_role(pk: int, data):
"""更新角色"""
return await RoleModel.filter(id=pk).update(**data.dict())

View File

@ -1,7 +1,9 @@
from tortoise.transactions import atomic
from fastapi.encoders import jsonable_encoder
from tortoise import connections
from models import RoleModel, UserModel, UserRoleModel
from schemas.user import UserIn, UserRole
from dbhelper.role import get_role
from models import UserModel, UserRoleModel
from schemas import UserPut
async def get_user(kwargs):
@ -16,25 +18,21 @@ async def get_user(kwargs):
return await UserModel.filter(**kwargs).first()
async def get_user_info(pk: int):
async def get_user_info(user: UserModel):
"""
根据id查用户角色列表,当前激活角色
根据id查用户角色列表 按激活角色倒序显示
"""
user = await UserModel.get(pk=pk).values(
"id", "username", "nickname", "identity", "created", "modified"
db = connections.get("default")
sql_result = await db.execute_query_dict(
"""
select r.id, r.name, ur.status from sys_role as r
left join sys_user_role as ur on r.id = ur.rid where
ur.uid = (?) and ur.status != 9 and r.status != 9 order by ur.status desc
""",
[user.id],
)
role = (
await UserRoleModel.filter(uid=pk, status__not_in=[9, 5])
.all()
.values("rid", "status")
)
active_rid = role[0].get("rid")
rids = []
for obj in role:
if obj.get("status") == 5:
active_rid = obj.get("rid")
rids.append(obj.get("rid"))
return {**user, "active_rid": active_rid, "rids": rids}
return {**jsonable_encoder(user), "roles": sql_result}
async def get_users(skip: int, limit: int, kwargs: dict = None):
@ -58,22 +56,51 @@ async def get_users(skip: int, limit: int, kwargs: dict = None):
return await result.offset(skip).limit(limit), await result.count()
@atomic()
async def insert_user(user, roles):
for index, rid in enumerate(roles):
# 1. 查角色表是否有该角色
await RoleModel.get(pk=rid)
# 创建用户
obj = await UserModel.create(**user.dict())
"""新增用户,选择角色"""
for role in roles:
if await get_role({"id": role.rid, "status__not": 9}) is None:
return role.rid
user_role = UserRole(rid=rid, uid=obj.id)
if index == 0:
user_role.status = 5
# 第一个角色默认, 添加到关系表
await UserRoleModel.create(**user_role.dict())
return user
# 创建用户
obj = await UserModel.create(**user.dict())
await UserRoleModel.bulk_create(
[UserRoleModel(rid=role.rid, uid=obj.id, status=role.status) for role in roles]
)
return obj
async def new_user(user: UserIn):
"""新增用户"""
return await UserModel.create(**user.dict())
async def del_user(uid: int):
"""删除用户"""
return await UserModel.filter(id=uid).update(status=9)
async def put_user(uid: int, data: UserPut):
"""更新用户"""
from core.security import get_password_hash
roles = data.rids
del data.rids
for role in roles:
if await get_role({"id": role.rid, "status__not": 9}) is None:
return role.rid
# 更新用户
data.password = get_password_hash(data.password)
await UserModel.filter(id=uid).update(**data.dict())
# todo 1. 先前有的角色,这次更新成没有 2. 先前没有的角色 这次更新成有, 3. 只更新了状态
db = connections.get("default")
# 1. 先把所有数据做删除
await db.execute_query_dict(
"""
update sys_user_role set status = 9 where uid = (?)
""",
[uid],
)
# 2. 新增次此更新的数据
await UserRoleModel.bulk_create(
[UserRoleModel(uid=uid, **role.dict()) for role in roles]
)

View File

@ -1,7 +1,7 @@
from fastapi import FastAPI
from core.events import close_orm, init_orm
from core.log import logger_db_client as logger
from core.log import logger
from core.middleware import middlewares
from router.url import routes

Binary file not shown.

View File

@ -1,11 +1,20 @@
from typing import Any, Callable, get_type_hints
from fastapi import routing
from fastapi import Depends, routing
from controller.common import login
from controller.menu import menu_add
from controller.role import role_add, role_has_menu
from controller.user import create_user, user_arr, user_info, user_list
from controller.common import about, login
from controller.menu import menu_add, menu_arr, menu_del
from controller.role import (
assigned_menu,
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
from core.security import check_token
class Route(routing.APIRoute):
@ -106,18 +115,47 @@ class Route(routing.APIRoute):
routes = [
Route.post("/login", endpoint=login, tags=["公共"], summary="登录"),
# 用户管理
Route.post("/user", endpoint=create_user, tags=["用户管理"], summary="用户新增"),
Route.get("/user/{pk}", endpoint=user_info, tags=["用户管理"], summary="用户信息"),
Route.get("/about", endpoint=about, tags=["公共"], summary="关于"),
# 用户管理
Route.get("/user", endpoint=user_arr, tags=["用户管理"], summary="用户列表"),
Route.post("/user", endpoint=user_add, tags=["用户管理"], summary="用户新增"),
Route.delete(
"/user/{pk}",
endpoint=user_del,
tags=["用户管理"],
summary="用户删除",
),
Route.put("/user/{pk}", endpoint=user_put, tags=["用户管理"], summary="用户更新"),
Route.get("/user/{pk}", endpoint=user_info, tags=["用户管理"], summary="用户信息"),
Route.post("/user/query", endpoint=user_list, tags=["用户管理"], summary="用户列表查询"),
# 角色管理
# 角色管理,
Route.get("/role", endpoint=role_arr, tags=["角色管理"], summary="角色列表"),
Route.post("/role", endpoint=role_add, tags=["角色管理"], summary="角色新增"),
Route.delete(
"/role/{pk}",
endpoint=role_del,
tags=["角色管理"],
summary="角色删除",
dependencies=[Depends(check_token)],
),
Route.get(
"role/{rid}/menu", endpoint=role_has_menu, tags=["角色管理"], summary="查询角色拥有权限"
"/role/{rid}/menu", endpoint=role_has_menu, tags=["角色管理"], summary="查询角色拥有权限"
),
Route.put("/role", endpoint=role_put, tags=["角色管理"], summary="角色更新"),
Route.post("/role/query", endpoint=role_query, tags=["角色管理"], summary="角色条件查询"),
Route.post(
"/role/assigned/menu", endpoint=assigned_menu, tags=["角色管理"], summary="角色分配菜单"
),
# 菜单新增
Route.get("/menu", endpoint=menu_arr, tags=["菜单管理"], summary="菜单列表"),
Route.post("/menu", endpoint=menu_add, tags=["菜单管理"], summary="菜单新增"),
Route.delete(
"/menu/{pk}",
endpoint=menu_del,
tags=["菜单管理"],
summary="菜单删除",
dependencies=[Depends(check_token)],
),
]
__all__ = [routes]

View File

@ -1,32 +1,26 @@
from tortoise.contrib.pydantic import pydantic_model_creator
from typing import Optional
from models import MenuModel
from pydantic import BaseModel, Field
MenuRead = pydantic_model_creator(MenuModel, name="MenuOut")
MenuIn = pydantic_model_creator(MenuModel, name="MenuIn", exclude_readonly=True)
from schemas.common import ReadBase
# from pydantic import BaseModel, Field
# from typing import Optional
# from core import ReadBase
#
#
# class MenuBasic(BaseModel):
# name: str
# meta: Optional[str] = Field(default=None, description="元信息")
# path: Optional[str] = Field(default=None, description="前端路由地址")
# type: int = Field(description="0 目录 1 组件 2 按钮")
# component: Optional[str] = Field(default=None, description="前端组件地址")
# pid: int = Field(default=0, description="0 表示没有根节点")
# identifier: Optional[str] = Field(default=None, description="权限标识符 -> 按钮显示")
# api: Optional[str] = Field(default=None, description="后端接口地址")
# method: Optional[str] = Field(default=None, description="接口请求方法")
# regx: Optional[str] = Field(default=None, description="正则匹配")
#
#
# class MenuIn(MenuBasic):
# pass
#
#
# class MenuRead(MenuBasic, ReadBase):
# pass
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 按钮")
component: Optional[str] = Field(default=None, description="前端组件地址")
pid: int = Field(default=0, description="0 表示没有根节点")
identifier: Optional[str] = Field(default=None, description="权限标识符 -> 按钮显示")
api: Optional[str] = Field(default=None, description="后端接口地址")
method: Optional[str] = Field(default=None, description="接口请求方法")
regx: Optional[str] = Field(default=None, description="正则匹配")
class MenuIn(MenuBasic):
pass
class MenuRead(MenuBasic, ReadBase):
pass

View File

@ -1,10 +1,17 @@
from pydantic import BaseModel, Field
from tortoise.contrib.pydantic import pydantic_model_creator
from models import RoleModel
from schemas.common import ReadBase
from schemas.common import QueryData, ReadBase
RoleRed = pydantic_model_creator(RoleModel, name="RoleOut")
class RoleMenuIn(BaseModel):
"""角色 -分配菜单id"""
rid: int = Field(description="角色ID")
menus: list[int] = Field(description="菜单ID 列表")
class RoleMenuRead(RoleMenuIn, ReadBase):
pass
class RoleBasic(BaseModel):
@ -16,9 +23,15 @@ class RoleIn(RoleBasic):
pass
class RoleRed(RoleBasic, ReadBase):
class RoleRead(RoleBasic, ReadBase):
pass
class RoleInfo(RoleRed):
class RoleInfo(RoleRead):
pass
class RoleQuery(QueryData):
"""查询模型"""
name: str = Field("", description="角色名")

View File

@ -1,14 +1,19 @@
from typing import List, Optional
from typing import Optional
from pydantic import BaseModel, Field
from tortoise.contrib.pydantic import pydantic_model_creator
from models import UserRoleModel
from schemas.common import QueryData
from schemas.common import QueryData, ReadBase
UserRole = pydantic_model_creator(UserRoleModel, name="UserRole", exclude_readonly=True)
from schemas.common import ReadBase
class UserRole(BaseModel):
uid: int = Field(description="用户id")
rid: int = Field(description="角色id")
class UserRoleRead(UserRole, ReadBase):
"""用户 角色 读取模型"""
pass
class UserBasic(BaseModel):
@ -24,18 +29,41 @@ class UserRead(UserBasic, ReadBase):
pass
class UserHasRole(BaseModel):
"""用户拥有角色"""
id: int
name: str
status: int = Field(default=1, description="激活角色 5 正常 1 删除 9")
class UserInfo(UserRead):
active_rid: int = Field(..., description="用户当前激活角色")
rids: List[int] = Field(..., description="用户拥有角色")
"""用户信息模型"""
roles: list[UserHasRole] = Field(..., description="用户拥有角色")
class RoleActive(BaseModel):
rid: int = Field(description="角色id")
status: int = Field(default=1, description="激活角色 5 正常 1 删除 9")
class UserAdd(UserIn):
rids: List[int] = Field(..., description="用户角色列表")
"""新增用户模型"""
rids: list[RoleActive] = Field(..., description="选择角色列表")
class UserQuery(QueryData):
"""查询模型"""
username: Optional[str] = Field("", description="用户名")
nickname: Optional[str] = Field("", description="姓名")
UserList = List[UserRead]
class UserPut(BaseModel):
"""用户更新模型"""
nickname: str = Field(..., description="用户昵称")
password: str = Field(..., description="密码")
rids: list[RoleActive] = Field(..., description="选择角色列表")

View File

@ -1,51 +1,49 @@
import json
import pytest
import requests as client
from core.log import logger
from schemas.menu import MenuIn
from schemas.role import RoleIn
from schemas.user import UserIn
from schemas.role import RoleIn, RoleMenuIn
from schemas.user import RoleActive, UserAdd
base = "http://localhost:8000"
def test_user_add():
url = base + "/user"
res = client.request(
method="post",
url=url,
json=UserIn(username="admin", nickname="超级管理员", password="123456").dict(),
)
assert res.status_code == 200
res = client.request(
method="post",
url=url,
json=UserIn(username="tester", nickname="测试员", password="123456").dict(),
)
assert res.status_code == 200
def test_role_add():
url = base + "/role"
res = client.request(
method="post", url=url, json=RoleIn(name="super", remark="全部权限").dict()
)
assert res.status_code == 200
res = client.request(
method="post", url=url, json=RoleIn(name="user", remark="用户权限").dict()
)
assert res.status_code == 200
def test_menu_add():
url = base + "/menu"
# id 1
res = client.request(
method="post",
url=url,
json=MenuIn(
params = [
# 创建角色
("/role", RoleIn(name="super", remark="全部权限").dict()),
("/role", RoleIn(name="user", remark="用户权限").dict()),
# 创建用户
(
"/user",
UserAdd(
username="admin",
nickname="管理员",
password="123456",
rids=[
RoleActive(rid=1, status=5),
RoleActive(rid=2),
],
).dict(),
),
(
"/user",
UserAdd(
username="tester",
nickname="测试员",
password="123456",
rids=[
RoleActive(rid=2, status=5),
],
).dict(),
),
# 创建菜单
# 目录
(
"/menu",
MenuIn( # id 1
name="系统管理",
meta=json.dumps({"icon": "Group"}),
meta={"icon": "Group"},
path="/system",
type=0,
component=None,
@ -55,16 +53,28 @@ def test_menu_add():
method=None,
regx=None,
).dict(),
)
assert res.status_code == 200
# id 2
res = client.request(
method="post",
url=url,
json=MenuIn(
),
(
"/menu",
MenuIn( # id 2
name="系统设置",
meta={"icon": "setting"},
path="/system",
type=0,
component=None,
pid=0,
identifier=None,
api=None,
method=None,
regx=None,
).dict(),
),
# 组件
(
"/menu",
MenuIn( # id 3
name="用户管理",
meta=json.dumps({"icon": "User"}),
meta={"icon": "User"},
path="/system/user",
type=1,
component="/system/user.vue",
@ -74,15 +84,12 @@ def test_menu_add():
method="{'GET'}",
regx="^/user$",
).dict(),
)
assert res.status_code == 200
# id 3
res = client.request(
method="post",
url=url,
json=MenuIn(
),
(
"/menu",
MenuIn( # id 4
name="角色管理",
meta=json.dumps({"icon": "User"}),
meta={"icon": "Role"},
path="/system/role",
type=1,
component="/system/role.vue",
@ -92,15 +99,12 @@ def test_menu_add():
method="{'GET'}",
regx="^/role$",
).dict(),
)
# id 4
res = client.request(
method="post",
url=url,
json=MenuIn(
),
(
"/menu",
MenuIn( # id 5
name="菜单管理",
meta=json.dumps({"icon": "Menu"}),
meta={"icon": "Menu"},
path="/system/menu",
type=1,
component="/system/menu.vue",
@ -110,92 +114,231 @@ def test_menu_add():
method="{'GET'}",
regx="^/menu$",
).dict(),
)
# id 5
res = client.request(
method="post",
url=url,
json=MenuIn(
name="系统设置",
meta=json.dumps({"icon": "Setting"}),
path="/setting",
type=0,
component=None,
pid=0,
),
(
"/menu",
MenuIn( # id 6
name="关于",
meta={"icon": "Menu"},
path="/setting/about",
type=1,
component="/setting/about.vue",
pid=2,
identifier=None,
api=None,
method=None,
regx=None,
api="/about",
method="{'GET'}",
regx="^/about",
).dict(),
)
res = client.request(
method="post",
url=url,
json=MenuIn(
name="系统监控",
meta=json.dumps({"icon": "minitor"}),
path="/setting/minitor",
type=0,
component="/setting/minitor.vue",
pid=5,
identifier=None,
api=None,
method=None,
regx=None,
).dict(),
)
res = client.request(
method="post",
url=url,
json=MenuIn(
name="新增用户",
meta=json.dumps({"icon": "Add"}),
),
# 按钮
(
"/menu",
MenuIn(
name="用户新增",
meta={"icon": "Add"},
path=None,
type=2,
component=None,
pid=2,
identifier="user:add",
pid=3,
identifier="user:create",
api="/user",
method="{'POST'}",
regx="^/user$",
).dict(),
)
assert res.status_code == 200
res = client.request(
method="post",
url=url,
json=MenuIn(
name="查询用户",
meta=json.dumps({"icon": "Select"}),
),
(
"/menu",
MenuIn(
name="用户删除",
meta={"icon": "Delete"},
path=None,
type=2,
component=None,
pid=2,
pid=3,
identifier="user:delete",
api="/user/{pk}",
method="{'DELETE'}",
regx="^/user/(?P<pk>[^/]+)$",
).dict(),
),
(
"/menu",
MenuIn(
name="用户更新",
meta={"icon": "Update"},
path=None,
type=2,
component=None,
pid=3,
identifier="user:update",
api="/user/{pk}",
method="{'PUT'}",
regx="^/user/(?P<pk>[^/]+)$",
).dict(),
),
(
"/menu",
MenuIn(
name="用户详情",
meta={"icon": "Info"},
path=None,
type=2,
component=None,
pid=3,
identifier="user:get",
api="/user/{pk}",
method="{'GET'}",
regx="^/user/(?P<pk>[^/]+)$",
).dict(),
),
(
"/menu",
MenuIn(
name="用户查询",
meta={"icon": "Search"},
path=None,
type=2,
component=None,
pid=3,
identifier="user:query",
api="/user/query",
method="{'POST'}",
regx="^/user/query$",
).dict(),
)
res = client.request(
method="post",
url=url,
json=MenuIn(
name="角色管理",
meta=json.dumps({"icon": "User"}),
path="/system/role",
type=1,
component="/system/role.vue",
pid=1,
identifier=None,
),
# 角色管理
(
"/menu",
MenuIn(
name="角色新增",
meta={"icon": "Add"},
path=None,
type=2,
component=None,
pid=4,
identifier="role:create",
api="/role",
method="{'GET'}",
regx="^/role",
method="{'POST'}",
regx="^/role$",
).dict(),
)
),
(
"/menu",
MenuIn(
name="角色删除",
meta={"icon": "Delete"},
path=None,
type=2,
component=None,
pid=4,
identifier="role:delete",
api="/role/{pk}",
method="{'DELETE'}",
regx="^/role/(?P<pk>[^/]+)$",
).dict(),
),
(
"/menu",
MenuIn(
name="查询角色拥有权限",
meta={"icon": "Delete"},
path=None,
type=2,
component=None,
pid=4,
identifier=None,
api="/role/{rid}/menu",
method="{'GET'}",
regx="^/role/(?P<rid>[^/]+)/menu$",
).dict(),
),
(
"/menu",
MenuIn(
name="查询角色",
meta={"icon": "Search"},
path=None,
type=2,
component=None,
pid=4,
identifier="",
api="/role/query",
method="{'POST'}",
regx="^/role/query$",
).dict(),
),
(
"/menu",
MenuIn(
name="分配权限",
meta={"icon": "Delete"},
path=None,
type=2,
component=None,
pid=4,
identifier="role:assign",
api="/role/assigned/menu",
method="{'POST'}",
regx="^/role/assigned/menu$",
).dict(),
),
(
"/menu",
MenuIn(
name="更新角色",
meta={"icon": "Update"},
path=None,
type=2,
component=None,
pid=4,
identifier="role:update",
api="/role",
method="{'PUT'}",
regx="^/role$",
).dict(),
),
# 菜单管理的权限
(
"/menu",
MenuIn(
name="新增菜单",
meta={"icon": "Update"},
path=None,
type=2,
component=None,
pid=5,
identifier="menu:create",
api="/menu",
method="{'POST'}",
regx="^/menu$",
).dict(),
),
(
"/menu",
MenuIn(
name="删除菜单",
meta={"icon": "Delete"},
path=None,
type=2,
component=None,
pid=5,
identifier="menu:delete",
api="/menu/{pk}",
method="{'DELETE'}",
regx="/menu/(?P<pk>[^/]+)$",
).dict(),
),
# 分配权限
(
"/role/assigned/menu",
RoleMenuIn(rid=1, menus=[num for num in range(1, 20)]).dict(),
),
("/role/assigned/menu", RoleMenuIn(rid=2, menus=[3, 7, 8, 9, 10, 11]).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