You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
iTi-System/iti_system/routes/role.py

177 lines
5.4 KiB
Python

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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()