Add role-related interfaces (#89)

This commit is contained in:
Wu Clan
2023-06-03 10:07:55 +08:00
committed by GitHub
parent d4f4f3f329
commit 8a18186a7c
9 changed files with 172 additions and 16 deletions
+51 -2
View File
@@ -1,7 +1,56 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from fastapi import APIRouter
from typing import Annotated
from fastapi import APIRouter, Query, Request
from backend.app.common.casbin_rbac import DependsRBAC
from backend.app.common.jwt import DependsJwtAuth
from backend.app.common.pagination import PageDepends, paging_data
from backend.app.common.response.response_schema import response_base
from backend.app.database.db_mysql import CurrentSession
from backend.app.schemas.role import GetAllRole, CreateRole, UpdateRole
from backend.app.services.role_service import RoleService
from backend.app.utils.serializers import select_to_json
router = APIRouter()
# TODO: 添加 role 相关接口
@router.get('/{pk}', summary='获取角色详情', dependencies=[DependsJwtAuth])
async def get_role(pk: int):
role = await RoleService.get(pk=pk)
data = GetAllRole(**select_to_json(role))
return response_base.success(data=data)
@router.get('', summary='(模糊条件)分页获取所有角色', dependencies=[DependsJwtAuth, PageDepends])
async def get_all_roles(
db: CurrentSession,
name: Annotated[str | None, Query()] = None,
data_scope: Annotated[int | None, Query()] = None,
):
role_select = await RoleService.get_select(name=name, data_scope=data_scope)
page_data = await paging_data(db, role_select, GetAllRole)
return response_base.success(data=page_data)
@router.post('', summary='创建角色', dependencies=[DependsRBAC])
async def create_role(request: Request, obj: CreateRole):
await RoleService.create(obj=obj, user_id=request.user.id)
return response_base.success()
@router.put('/{pk}', summary='更新角色', dependencies=[DependsRBAC])
async def update_role(request: Request, pk: int, obj: UpdateRole):
count = await RoleService.update(pk=pk, obj=obj, user_id=request.user.id)
if count > 0:
return response_base.success()
return response_base.fail()
@router.delete('', summary='(批量)删除角色', dependencies=[DependsRBAC])
async def delete_role(pk: Annotated[list[int], Query(...)]):
count = await RoleService.delete(pk=pk)
if count > 0:
return response_base.success()
return response_base.fail()
+2 -2
View File
@@ -6,8 +6,8 @@ from backend.app.schemas.menu import CreateMenu, UpdateMenu
class CRUDMenu(CRUDBase[Menu, CreateMenu, UpdateMenu]):
# TODO: 添加 menu 相关数据库操作
pass
async def get(self, db, menu_id: int) -> Menu | None:
return await self.get_(db, menu_id)
MenuDao: CRUDMenu = CRUDMenu(Menu)
+59 -2
View File
@@ -1,13 +1,70 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import NoReturn
from sqlalchemy import select, update, delete
from sqlalchemy.orm import selectinload
from backend.app.crud.base import CRUDBase
from backend.app.models import Role
from backend.app.models import Role, Menu
from backend.app.schemas.role import CreateRole, UpdateRole
class CRUDRole(CRUDBase[Role, CreateRole, UpdateRole]):
async def get(self, db, role_id: int):
async def get(self, db, role_id: int) -> Role | None:
return await self.get_(db, role_id)
async def get_with_relation(self, db, role_id: int) -> Role | None:
role = await db.execute(
select(self.model)
.options(selectinload(self.model.menus))
.where(self.model.id == role_id)
)
return role.scalars().first()
async def get_all(self, name: str = None, data_scope: int = None):
se = select(self.model).options(selectinload(self.model.menus)).order_by(self.model.created_time.desc())
where_list = []
if name:
where_list.append(self.model.name.like(f'%{name}%'))
if data_scope:
where_list.append(self.model.data_scope == data_scope)
if where_list:
se = se.where(*where_list)
return se
async def get_by_name(self, db, name: str) -> Role | None:
role = await db.execute(select(self.model).where(self.model.name == name))
return role.scalars().first()
async def create(self, db, obj_in: CreateRole, user_id: int) -> NoReturn:
new_role = self.model(**obj_in.dict(exclude={'menus'}), create_user=user_id)
menu_list = []
for menu_id in obj_in.menus:
menu_list.append(await db.get(Menu, menu_id))
new_role.menus.append(*menu_list)
db.add(new_role)
async def update(self, db, role_id: int, obj_in: UpdateRole, user_id: int) -> int:
role = await db.execute(
update(self.model)
.where(self.model.id == role_id)
.values(**obj_in.dict(exclude={'menus'}), update_user=user_id)
)
current_role = await self.get_with_relation(db, role_id)
# 删除角色所有菜单
for i in list(current_role.menus):
current_role.menus.remove(i)
# 添加角色菜单
menu_list = []
for menu_id in obj_in.menus:
menu_list.append(await db.get(Menu, menu_id))
current_role.menus.append(*menu_list)
return role.rowcount
async def delete(self, db, role_id: list[int]) -> int:
roles = await db.execute(delete(self.model).where(self.model.id.in_(role_id)))
return roles.rowcount
RoleDao: CRUDRole = CRUDRole(Role)
+1 -1
View File
@@ -20,6 +20,6 @@ class Dept(Base):
phone: Mapped[str | None] = mapped_column(String(11), default=None, comment='手机')
email: Mapped[str | None] = mapped_column(String(50), default=None, comment='邮箱')
status: Mapped[bool] = mapped_column(default=True, comment='部门状态(0停用 1正常)')
del_flag: Mapped[bool] = mapped_column(default=True, comment='删除标志(0删除 1存在)')
del_flag: Mapped[bool] = mapped_column(default=False, comment='删除标志(0删除 1存在)')
# 用户部门一对多
users: Mapped['User'] = relationship(init=False, back_populates='dept') # noqa: F821
+1 -1
View File
@@ -22,7 +22,7 @@ class Menu(Base):
menu_type: Mapped[int] = mapped_column(default=0, comment='菜单类型(0目录 1菜单 2按钮)')
icon: Mapped[str | None] = mapped_column(String(100), default='#', comment='菜单图标')
remark: Mapped[str | None] = mapped_column(LONGTEXT, default=None, comment='备注')
del_flag: Mapped[bool] = mapped_column(default=True, comment='删除标志(0删除 1存在)')
del_flag: Mapped[bool] = mapped_column(default=False, comment='删除标志(0删除 1存在)')
# 菜单角色多对多
roles: Mapped[list['Role']] = relationship( # noqa: F821
init=False, secondary=sys_role_menu, back_populates='menus'
+1 -2
View File
@@ -15,9 +15,8 @@ class Role(Base):
id: Mapped[id_key] = mapped_column(init=False)
name: Mapped[str] = mapped_column(String(20), unique=True, comment='角色名称')
sort: Mapped[int] = mapped_column(default=0, comment='显示顺序')
data_scope: Mapped[int | None] = mapped_column(default=2, comment='数据范围(1:全部数据权限 2:自定数据权限)')
del_flag: Mapped[bool] = mapped_column(default=True, comment='删除标志(0删除 1存在)')
del_flag: Mapped[bool] = mapped_column(default=False, comment='删除标志(0删除 1存在)')
# 角色用户多对多
users: Mapped[list['User']] = relationship( # noqa: F821
init=False, secondary=sys_user_role, back_populates='roles'
+2 -3
View File
@@ -10,7 +10,6 @@ from backend.app.schemas.menu import GetAllMenu
class RoleBase(BaseModel):
name: str
sort: int = Field(default=0, ge=0, description='排序')
data_scope: int | None = Field(default=RoleDataScope.custom, description='数据范围(1:全部数据权限 2:自定数据权限)') # noqa: E501
del_flag: bool
@@ -22,11 +21,11 @@ class RoleBase(BaseModel):
class CreateRole(RoleBase):
menu_ids: list[int]
menus: list[int]
class UpdateRole(RoleBase):
menu_ids: list[int]
menus: list[int]
class GetAllRole(RoleBase):
+1 -1
View File
@@ -12,7 +12,7 @@ from backend.app.schemas.api import CreateApi, UpdateApi
class ApiService:
@staticmethod
async def get(*, pk: int) -> Api:
async with async_db_session.begin() as db:
async with async_db_session() as db:
api = await ApiDao.get(db, pk)
if not api:
raise errors.NotFoundError(msg='接口不存在')
+54 -2
View File
@@ -1,7 +1,59 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from sqlalchemy import Select
from backend.app.common.exception import errors
from backend.app.crud.crud_menu import MenuDao
from backend.app.crud.crud_role import RoleDao
from backend.app.database.db_mysql import async_db_session
from backend.app.models import Role
from backend.app.schemas.role import CreateRole, UpdateRole
class RoleService:
# TODO: 添加 role 相关服务
pass
@staticmethod
async def get(pk: int) -> Role:
async with async_db_session() as db:
role = await RoleDao.get_with_relation(db, pk)
if not role:
raise errors.NotFoundError(msg='角色不存在')
return role
@staticmethod
async def get_select(*, name: str = None, data_scope: int = None) -> Select:
return await RoleDao.get_all(name=name, data_scope=data_scope)
@staticmethod
async def create(*, obj: CreateRole, user_id: int) -> None:
async with async_db_session.begin() as db:
role = await RoleDao.get_by_name(db, obj.name)
if role:
raise errors.ForbiddenError(msg='角色已存在')
for menu_id in obj.menus:
menu = await MenuDao.get(db, menu_id)
if not menu:
raise errors.ForbiddenError(msg='菜单不存在')
await RoleDao.create(db, obj, user_id)
@staticmethod
async def update(*, pk: int, obj: UpdateRole, user_id: int) -> int:
async with async_db_session.begin() as db:
role = await RoleDao.get(db, pk)
if not role:
raise errors.NotFoundError(msg='角色不存在')
if role.name != obj.name:
role = await RoleDao.get_by_name(db, obj.name)
if role:
raise errors.ForbiddenError(msg='角色已存在')
for menu_id in obj.menus:
menu = await MenuDao.get(db, menu_id)
if not menu:
raise errors.ForbiddenError(msg='菜单不存在')
count = await RoleDao.update(db, pk, obj, user_id)
return count
@staticmethod
async def delete(*, pk: list[int]) -> int:
async with async_db_session.begin() as db:
count = await RoleDao.delete(db, pk)
return count