Files
cdtestplant_v1/apps/project/signals.py
2026-04-20 18:00:55 +08:00

132 lines
5.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import jwt
from django.conf import settings
from threading import local
from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver
from django.utils.functional import SimpleLazyObject
from django.contrib.auth import get_user_model
# 导入用例和影响域分析Model-设计信号当删除用例对应影响域分析删除关联用例
from apps.project.models import Case, InfluenceItem
# 导入日志的模型
from apps.user.models import TableOperationLog, Users
# 导入其他模型用于排除
from apps.project.models import CaseStep, TestDemandContent
# 导入异常处理
from jwt.exceptions import ExpiredSignatureError
from utils.chen_response import ChenResponse
# 导入中间件记录日志模型
from apps.system.models import LoginLog
from apps.system.models import OperationLog
log_manager = TableOperationLog.objects
_thread_local = local()
def get_current_user():
"""
获取当前用户对象调用则从local对象里面获取user
:return: Users实例
"""
return getattr(_thread_local, 'user', None)
def clear_request_locals(sender, **kwargs):
"""
被request_finished连接的信号处理函数请求结束后清除local里面的user信息
"""
_thread_local.user = None
def set_request_locals(sender, **kwargs):
"""
被request_started连接的信号处理函数_thread_local.user属性设置为当前登录用户
"""
bearer_token = kwargs['environ'].get('HTTP_AUTHORIZATION', None)
if not bearer_token or bearer_token == 'Bearer null':
return
bearer_token = bearer_token.replace('Bearer ', '')
# 逻辑先获取NINJA_JWT配置中秘钥、和加密算法信息
jwt_settings = settings.NINJA_JWT
jwt_secret = jwt_settings.get('SIGNING_KEY', None)
jwt_algo = jwt_settings.get('ALGORITHM', None)
# 如果为None则使用settings中的秘钥和['HS256']算法
secret_key = jwt_secret or settings.SECRET_KEY
algorithms_str = jwt_algo or 'HS256'
# 解决bug:因为过期前面不跳转首页处理方式
try:
jwt_dict = jwt.decode(bearer_token, secret_key, algorithms=[algorithms_str])
except ExpiredSignatureError as exc:
return ChenResponse(status=403, code=500, message='您的token已过期请重新登录')
user_id = jwt_dict.get('user_id', None)
if user_id:
_thread_local.user = SimpleLazyObject(lambda: get_user_model().objects.get(id=user_id))
# 1.注意可以不传sender为监听所有模型这里来记录日志
# 2.使用get_current_user()获取当前请求用户
@receiver(post_save)
def post_save_handler(sender, instance, created, **kwargs):
"""模型新增-操作日志填写"""
# 注意排除日志模块、用例步骤表、测试项步骤表
if (sender == TableOperationLog or sender == CaseStep or sender == TestDemandContent or sender == LoginLog or sender == OperationLog or sender
== Users):
return
user = get_current_user()
ope_dict = {
'operate_obj': str(instance),
}
if created:
ope_dict['operate_des'] = '新增'
else:
ope_dict['operate_des'] = '修改'
log_manager.create(user=user, **ope_dict)
@receiver(post_delete)
def post_delete_handler(sender, instance, **kwargs):
"""模型删除-操作日志填写"""
# 注意排除日志模块、用例步骤表、测试项步骤表
if (sender == TableOperationLog or sender == CaseStep or sender == TestDemandContent or sender == LoginLog or sender == OperationLog or sender
== Users):
return
user = get_current_user()
ope_dict = {
'operate_obj': str(instance),
'operate_des': '删除'
}
log_manager.create(user=user, **ope_dict)
# 信号:删除影响域分析关联的用例,将影响域分析管理用例删除
@receiver(post_delete, sender=Case)
def clean_up_deleted_case_reference_from_influence(sender, instance, **kwargs):
"""
监听 Case 的删除信号。
仅在同一个 Project 范围内,从 InfluenceItem 的 effect_cases 中移除被删用例的 key。
"""
deleted_key = instance.key
project_id = instance.project_id
if not deleted_key or not project_id:
return
# 查询当前项目的影响域分析并且包含该用例
items = InfluenceItem.objects.filter(
influence__round__project_id=project_id, # 外键链锁定项目
effect_cases__contains=[deleted_key] # JSON 字段包含该 key
)
# 未发现有关联的影响域分析则不处理
if not items.exists():
return
# 更新影响域分析的关联用例
updated_items = []
for item in items:
original_keys = item.effect_cases
# 过滤掉被删除的 key保留其他
new_keys = [k for k in original_keys if k != deleted_key]
if len(new_keys) != len(original_keys):
item.effect_cases = new_keys
updated_items.append(item)
if updated_items:
InfluenceItem.objects.bulk_update(updated_items, ['effect_cases'])
else:
print("⚠️ 查询到记录但未发生变更,可能数据有误")