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.

143 lines
4.1 KiB
Python

from iti.applications.extensions import eventbus
from iti.applications.common.events import (
UserEvents,
UserRelEvents,
RoleEvents,
MenuEvents,
RoleRelEvents,
)
from iti.applications.models import User, Role, SysMenu, sys_role_menu, sys_user_role
from iti.applications.extensions import cache_simple, db
from sqlalchemy import select, distinct
class UserCacheEventHandler:
"""
用户数据缓存 事件处理器
"""
def __init__(self, app=None):
if app:
self.init_app(app)
def init_app(self, app):
self.app = app
self._register_handlers()
def _register_handlers(self):
"""
注册事件处理器
"""
# 用户
eventbus.register_handler(
UserEvents.USER_UPDATED,
self._handle_user_updated,
order=-1,
async_mode=True,
)
eventbus.register_handler(
UserEvents.USER_DELETED,
self._handle_user_deleted,
order=-1,
async_mode=True,
)
eventbus.register_handler(
UserEvents.USER_AUTH_REFRESHED,
self._handle_user_updated,
order=-1,
async_mode=True,
)
eventbus.register_handler(
UserEvents.USER_LOGOUT,
self._handle_user_updated,
order=-1,
async_mode=True,
)
eventbus.register_handler(
UserEvents.USER_PASSWORD_UPDATED,
self._handle_user_updated,
order=-1,
async_mode=True,
)
# 用户关系
eventbus.register_handler(
UserRelEvents.USER_ROLES_UPDATED,
self._handle_user_updated,
order=-1,
async_mode=True,
)
eventbus.register_handler(
UserRelEvents.USER_DEPTS_UPDATED,
self._handle_user_updated,
order=-1,
async_mode=True,
)
# 角色删除
eventbus.register_handler(
RoleEvents.ROLE_DELETED,
self._handle_role_changed,
order=-1,
async_mode=True,
)
eventbus.register_handler(
RoleRelEvents.ROLE_MENUS_UPDATED.value,
self._handle_role_changed,
order=-1,
async_mode=True,
)
# 菜单
eventbus.register_handler(
MenuEvents.MENU_UPDATED,
self._handle_menu_updated,
order=-1,
async_mode=True,
)
eventbus.register_handler(
MenuEvents.MENU_DELETED,
self._handle_menu_deleted,
order=-1,
async_mode=True,
)
def _invalidate_user_cache(self, user_id):
"""
清理用户缓存
"""
if user_id:
cache_simple.delete(f"user_{user_id}")
def _handle_user_updated(self, user: User):
self._invalidate_user_cache(user.id)
def _handle_user_deleted(self, user_id):
self._invalidate_user_cache(user_id)
def _handle_role_changed(self, role: Role):
# 角色关联的用户缓存都应该被删除
if role.users:
for user in role.users:
self._invalidate_user_cache(user.id)
def _handle_menu_updated(self, menu: SysMenu, old_menu: SysMenu):
# 若菜单更新了权限字段
if old_menu and old_menu.auth_code != menu.auth_code:
# 与该菜单相关的角色的用户缓存都应该被删除
# 查询菜单相关的角色关联的所有用户ID
self._handle_menu_deleted(menu)
def _handle_menu_deleted(self, menu: SysMenu):
# 与该菜单相关的角色的用户缓存都应该被删除
# 查询菜单相关的角色关联的所有用户ID
user_ids = db.session.scalars(
select(distinct(sys_user_role.c.user_id))
.join(sys_user_role, sys_role_menu.c.role_id == sys_user_role.c.role_id)
.where(sys_role_menu.c.menu_id == menu.id)
).all()
for user_id in user_ids:
self._invalidate_user_cache(user_id)