|
|
from dataclasses import asdict
|
|
|
from apiflask import APIBlueprint
|
|
|
from flask_jwt_extended import jwt_required
|
|
|
from iti.applications.common.utils.schema import pagination_fields
|
|
|
from iti.applications.extensions import db
|
|
|
from iti_system.extensions.sys_log import sys_log
|
|
|
from iti_system.models import SysMenu
|
|
|
from .schemas.role import RoleCreateRequest, RoleQuery, RoleUpdateRequest
|
|
|
from iti_system.models import Role, RoleSchema, sys_user_role, sys_role_menu
|
|
|
from iti.applications.common.utils import success, page_schema, page
|
|
|
from iti.applications.common.enums import LogType
|
|
|
from iti.applications.common import ModelFilter
|
|
|
from iti.applications.common.exceptions.biz_exp import BizException
|
|
|
from sqlalchemy import select, delete, exists
|
|
|
from iti_system.events.names import RoleEvents, RoleRelEvents
|
|
|
from iti.applications.extensions import eventbus
|
|
|
from iti_system.permission import permission
|
|
|
|
|
|
bp = APIBlueprint("sys_role", __name__, url_prefix="/role", tag="系统.角色管理")
|
|
|
|
|
|
|
|
|
@bp.get("/list")
|
|
|
@jwt_required()
|
|
|
@bp.doc(security="JWT")
|
|
|
@permission("system:role:list")
|
|
|
@bp.input(RoleQuery.Schema(exclude=pagination_fields), location="query")
|
|
|
@bp.output(RoleSchema(exclude=["users"], many=True))
|
|
|
def list_role(query_data: RoleQuery):
|
|
|
"""
|
|
|
获取角色列表
|
|
|
"""
|
|
|
|
|
|
return success(get_list_or_page(query_data))
|
|
|
|
|
|
|
|
|
def get_list_or_page(query_data: RoleQuery):
|
|
|
"""
|
|
|
获取角色列表或分页
|
|
|
"""
|
|
|
query = select(Role).order_by(Role.sort.asc())
|
|
|
if query_data.name:
|
|
|
query = query.filter_by(name=ModelFilter.escape_like(query_data.name))
|
|
|
if query_data.code:
|
|
|
query = query.filter_by(code=ModelFilter.escape_like(query_data.code))
|
|
|
if query_data.status:
|
|
|
query = query.filter_by(status=query_data.status)
|
|
|
if query_data.createdAt and len(query_data.createdAt) >= 2:
|
|
|
query = query.filter(
|
|
|
Role.created_at.between(query_data.createdAt[0], query_data.createdAt[1])
|
|
|
)
|
|
|
if query_data.updatedAt and len(query_data.updatedAt) >= 2:
|
|
|
query = query.filter(
|
|
|
Role.updated_at.between(query_data.updatedAt[0], query_data.updatedAt[1])
|
|
|
)
|
|
|
if query_data.page and query_data.size:
|
|
|
return db.paginate(query, page=query_data.page, per_page=query_data.size)
|
|
|
else:
|
|
|
return db.session.scalars(query).all()
|
|
|
|
|
|
|
|
|
@bp.get("/page")
|
|
|
@jwt_required()
|
|
|
@bp.doc(security="JWT")
|
|
|
@permission("system:role:list")
|
|
|
@bp.input(RoleQuery.Schema, location="query")
|
|
|
@bp.output(page_schema(RoleSchema(exclude=["users"])))
|
|
|
def page_role(query_data: RoleQuery):
|
|
|
"""
|
|
|
分页获取角色列表
|
|
|
"""
|
|
|
return page(get_list_or_page(query_data))
|
|
|
|
|
|
|
|
|
@bp.post("")
|
|
|
@jwt_required()
|
|
|
@bp.doc(security="JWT")
|
|
|
@permission("system:role:create")
|
|
|
@bp.input(RoleCreateRequest.Schema, location="json")
|
|
|
@bp.output(RoleSchema)
|
|
|
@sys_log(
|
|
|
name="创建角色",
|
|
|
desc="创建角色",
|
|
|
type=LogType.OPERATION,
|
|
|
save_db=True,
|
|
|
execute_time=True,
|
|
|
)
|
|
|
def create_role(json_data: RoleCreateRequest):
|
|
|
"""
|
|
|
创建角色
|
|
|
"""
|
|
|
role = Role(**asdict(json_data))
|
|
|
|
|
|
db.session.add(role)
|
|
|
db.session.commit()
|
|
|
return success(role)
|
|
|
|
|
|
|
|
|
@bp.put("/<string:id>")
|
|
|
@jwt_required()
|
|
|
@bp.doc(security="JWT")
|
|
|
@permission("system:role:edit")
|
|
|
@bp.input(RoleUpdateRequest.Schema(partial=True), location="json")
|
|
|
@sys_log(
|
|
|
name="更新角色",
|
|
|
desc="更新角色",
|
|
|
type=LogType.OPERATION,
|
|
|
save_db=True,
|
|
|
execute_time=True,
|
|
|
)
|
|
|
def update_role(id: str, json_data: RoleUpdateRequest):
|
|
|
"""
|
|
|
更新角色
|
|
|
"""
|
|
|
role = db.session.scalar(select(Role).filter_by(id=id))
|
|
|
if not role:
|
|
|
raise BizException("角色不存在")
|
|
|
# Code不能重复,排除自己
|
|
|
if db.session.scalar(
|
|
|
select(exists().where(Role.code == json_data.code, Role.id != id))
|
|
|
):
|
|
|
raise BizException("角色编码已存在")
|
|
|
# 传入则更新,否则不变
|
|
|
menus_updated = False
|
|
|
old_menus = role.menus
|
|
|
for key, value in asdict(json_data).items():
|
|
|
if key == "permissions" and value is not None:
|
|
|
role.menus = db.session.scalars(
|
|
|
select(SysMenu)
|
|
|
.filter(SysMenu.id.in_(value))
|
|
|
.options(db.noload(SysMenu.children), db.noload(SysMenu.parent))
|
|
|
).all()
|
|
|
menus_updated = True
|
|
|
continue
|
|
|
if value is not None:
|
|
|
setattr(role, key, value)
|
|
|
# 提交事务
|
|
|
db.session.commit()
|
|
|
# 触发角色事件
|
|
|
eventbus.emit(RoleEvents.ROLE_UPDATED.value, role)
|
|
|
if menus_updated:
|
|
|
eventbus.emit(RoleRelEvents.ROLE_MENUS_UPDATED.value, role, old_menus)
|
|
|
return success()
|
|
|
|
|
|
|
|
|
@bp.delete("/<string:id>")
|
|
|
@jwt_required()
|
|
|
@bp.doc(security="JWT")
|
|
|
@permission("system:role:delete")
|
|
|
@sys_log(
|
|
|
name="删除角色",
|
|
|
desc="删除角色",
|
|
|
type=LogType.OPERATION,
|
|
|
save_db=True,
|
|
|
execute_time=True,
|
|
|
)
|
|
|
def delete_role(id: str):
|
|
|
"""
|
|
|
删除角色
|
|
|
"""
|
|
|
role = db.session.scalar(select(Role).filter_by(id=id))
|
|
|
if not role:
|
|
|
raise BizException("角色不存在")
|
|
|
try:
|
|
|
# 删除角色关联关系
|
|
|
db.session.execute(delete(sys_user_role).filter_by(role_id=id))
|
|
|
db.session.execute(delete(sys_role_menu).filter_by(role_id=id))
|
|
|
# 删除角色
|
|
|
db.session.delete(role)
|
|
|
db.session.commit()
|
|
|
|
|
|
# 触发角色删除事件
|
|
|
eventbus.emit(RoleEvents.ROLE_DELETED.value, role)
|
|
|
except Exception as e:
|
|
|
db.session.rollback()
|
|
|
raise BizException(f"删除角色失败: {e}")
|
|
|
return success()
|