日常修复内容
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -257,7 +257,7 @@ class CaseController(ControllerBase):
|
||||
single_qs.key = case_key
|
||||
index = index + 1
|
||||
single_qs.save()
|
||||
return ChenResponse(message="测试用例删除成功!")
|
||||
return ChenResponse(message="测试用例删除成功!影响域分析中如果有该关联用例则被删除。")
|
||||
|
||||
# 右键测试项,根据测试子项生成用例
|
||||
@route.post("/case/create_by_demand", url_name='case-create-by-demand')
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
# Generated by Django 6.0.4 on 2026-04-17 13:57
|
||||
|
||||
import apps.project.models
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('project', '0029_influenceitem_change_influ'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='project',
|
||||
name='devplant',
|
||||
field=models.JSONField(blank=True, default=apps.project.models.create_list, help_text='开发环境', null=True, verbose_name='开发环境'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='project',
|
||||
name='runtime',
|
||||
field=models.JSONField(blank=True, default=apps.project.models.create_list, help_text='运行环境', null=True, verbose_name='运行环境'),
|
||||
),
|
||||
]
|
||||
18
apps/project/migrations/0031_alter_testdemand_adequacy.py
Normal file
18
apps/project/migrations/0031_alter_testdemand_adequacy.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 6.0.4 on 2026-04-17 16:20
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('project', '0030_alter_project_devplant_alter_project_runtime'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='testdemand',
|
||||
name='adequacy',
|
||||
field=models.CharField(blank=True, help_text='充分条件', max_length=2048, null=True, verbose_name='充分条件'),
|
||||
),
|
||||
]
|
||||
18
apps/project/migrations/0032_alter_design_protocal.py
Normal file
18
apps/project/migrations/0032_alter_design_protocal.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 6.0.4 on 2026-04-20 10:36
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('project', '0031_alter_testdemand_adequacy'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='design',
|
||||
name='protocal',
|
||||
field=models.CharField(blank=True, default='', help_text='接口数据', max_length=1024, null=True, verbose_name='接口数据'),
|
||||
),
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -27,50 +27,29 @@ class Project(CoreModel):
|
||||
vise_person = models.CharField(max_length=64, verbose_name="质量监督员", help_text="质量监督员")
|
||||
config_person = models.CharField(max_length=64, verbose_name="配置管理员", help_text="配置管理员")
|
||||
# ~~~~~~~~~~~
|
||||
security_level = models.CharField(max_length=8, blank=True, null=True, verbose_name="安全等级",
|
||||
help_text="安全等级")
|
||||
test_level = models.JSONField(null=True, blank=True, help_text="测试级别", verbose_name="测试级别",
|
||||
default=create_list)
|
||||
plant_type = models.JSONField(null=True, blank=True, help_text="平台类型", verbose_name="平台类型",
|
||||
default=create_list)
|
||||
report_type = models.CharField(max_length=64, blank=True, null=True, verbose_name="报告类型",
|
||||
help_text="报告类型")
|
||||
language = models.JSONField(null=True, blank=True, help_text="被测语言", verbose_name="被测语言",
|
||||
default=create_list)
|
||||
standard = models.JSONField(null=True, blank=True, help_text="依据标准", verbose_name="依据标准",
|
||||
default=create_list)
|
||||
security_level = models.CharField(max_length=8, blank=True, null=True, verbose_name="安全等级", help_text="安全等级")
|
||||
test_level = models.JSONField(null=True, blank=True, help_text="测试级别", verbose_name="测试级别", default=create_list)
|
||||
plant_type = models.JSONField(null=True, blank=True, help_text="平台类型", verbose_name="平台类型", default=create_list)
|
||||
report_type = models.CharField(max_length=64, blank=True, null=True, verbose_name="报告类型", help_text="报告类型")
|
||||
language = models.JSONField(null=True, blank=True, help_text="被测语言", verbose_name="被测语言", default=create_list)
|
||||
standard = models.JSONField(null=True, blank=True, help_text="依据标准", verbose_name="依据标准", default=create_list)
|
||||
entrust_unit = models.CharField(max_length=64, verbose_name="委托方单位", help_text="委托方单位")
|
||||
entrust_contact = models.CharField(max_length=64, blank=True, null=True, verbose_name="委托方联系人",
|
||||
help_text="委托方联系人")
|
||||
entrust_contact_phone = models.CharField(max_length=64, blank=True, null=True, verbose_name="委托方电话",
|
||||
help_text="委托方电话")
|
||||
entrust_email = models.CharField(max_length=64, blank=True, null=True, verbose_name="委托方邮箱",
|
||||
help_text="委托方邮箱")
|
||||
entrust_contact = models.CharField(max_length=64, blank=True, null=True, verbose_name="委托方联系人", help_text="委托方联系人")
|
||||
entrust_contact_phone = models.CharField(max_length=64, blank=True, null=True, verbose_name="委托方电话", help_text="委托方电话")
|
||||
entrust_email = models.CharField(max_length=64, blank=True, null=True, verbose_name="委托方邮箱", help_text="委托方邮箱")
|
||||
dev_unit = models.CharField(max_length=64, verbose_name="开发方单位", help_text="开发方单位")
|
||||
dev_contact = models.CharField(max_length=64, blank=True, null=True, verbose_name="研制方联系人",
|
||||
help_text="研制方联系人")
|
||||
dev_contact_phone = models.CharField(max_length=64, blank=True, null=True, verbose_name="研制方电话",
|
||||
help_text="研制方电话")
|
||||
dev_email = models.CharField(max_length=64, blank=True, null=True, verbose_name="研制方邮箱",
|
||||
help_text="研制方邮箱")
|
||||
dev_contact = models.CharField(max_length=64, blank=True, null=True, verbose_name="研制方联系人", help_text="研制方联系人")
|
||||
dev_contact_phone = models.CharField(max_length=64, blank=True, null=True, verbose_name="研制方电话", help_text="研制方电话")
|
||||
dev_email = models.CharField(max_length=64, blank=True, null=True, verbose_name="研制方邮箱", help_text="研制方邮箱")
|
||||
test_unit = models.CharField(max_length=64, verbose_name="测试方单位", help_text="测试方单位")
|
||||
test_contact = models.CharField(max_length=64, blank=True, null=True, verbose_name="测评中心联系人",
|
||||
help_text="测评中心联系人")
|
||||
test_contact_phone = models.CharField(max_length=64, blank=True, null=True, verbose_name="测评中心电话",
|
||||
help_text="测评中心电话")
|
||||
test_email = models.CharField(max_length=64, blank=True, null=True, verbose_name="测评中心邮箱",
|
||||
help_text="测评中心邮箱")
|
||||
step = models.CharField(max_length=8, blank=True, null=True, verbose_name="项目阶段",
|
||||
help_text="项目阶段")
|
||||
abbreviation = models.JSONField(null=True, blank=True, help_text="缩略语", verbose_name="缩略语",
|
||||
default=create_list)
|
||||
soft_type = models.SmallIntegerField(verbose_name='软件类型',
|
||||
choices=((1, '新研'), (2, '改造'), (3, '沿用')),
|
||||
default=1)
|
||||
runtime = models.CharField(max_length=8, blank=True, null=True, verbose_name="运行环境",
|
||||
help_text="运行环境")
|
||||
devplant = models.CharField(max_length=8, blank=True, null=True, verbose_name="开发环境",
|
||||
help_text="开发环境")
|
||||
test_contact = models.CharField(max_length=64, blank=True, null=True, verbose_name="测评中心联系人", help_text="测评中心联系人")
|
||||
test_contact_phone = models.CharField(max_length=64, blank=True, null=True, verbose_name="测评中心电话", help_text="测评中心电话")
|
||||
test_email = models.CharField(max_length=64, blank=True, null=True, verbose_name="测评中心邮箱", help_text="测评中心邮箱")
|
||||
step = models.CharField(max_length=8, blank=True, null=True, verbose_name="项目阶段", help_text="项目阶段")
|
||||
abbreviation = models.JSONField(null=True, blank=True, help_text="缩略语", verbose_name="缩略语", default=create_list)
|
||||
soft_type = models.SmallIntegerField(verbose_name='软件类型', choices=((1, '新研'), (2, '改造'), (3, '沿用')), default=1)
|
||||
runtime = models.JSONField(null=True, blank=True, help_text="运行环境", verbose_name="运行环境", default=create_list)
|
||||
devplant = models.JSONField(null=True, blank=True, help_text="开发环境", verbose_name="开发环境", default=create_list)
|
||||
# 9月2日新增字段:密级
|
||||
secret = models.CharField(max_length=30, default='1', verbose_name='密级', help_text='密级')
|
||||
|
||||
@@ -226,7 +205,7 @@ class Design(CoreModel):
|
||||
type = models.CharField(max_length=64, blank=True, null=True, default='', verbose_name='接口类型',
|
||||
help_text='接口类型')
|
||||
# 注意:该字段改为接口数据
|
||||
protocal = models.CharField(max_length=64, blank=True, null=True, default='', verbose_name='接口数据',
|
||||
protocal = models.CharField(max_length=1024, blank=True, null=True, default='', verbose_name='接口数据',
|
||||
help_text='接口数据')
|
||||
|
||||
def __str__(self):
|
||||
@@ -239,23 +218,15 @@ class Design(CoreModel):
|
||||
ordering = ('key',)
|
||||
|
||||
class TestDemand(CoreModel):
|
||||
objects = models.Manager()
|
||||
"""测试项"""
|
||||
ident = models.CharField(max_length=64, blank=True, null=True, verbose_name="测试需求标识",
|
||||
help_text="测试需求标识")
|
||||
name = models.CharField(max_length=64, blank=True, null=True, verbose_name="测试需求名称",
|
||||
help_text="测试需求名称")
|
||||
adequacy = models.CharField(max_length=256, blank=True, null=True, verbose_name="充分条件",
|
||||
help_text="充分条件")
|
||||
priority = models.CharField(max_length=8, blank=True, null=True, verbose_name="优先级",
|
||||
help_text="优先级")
|
||||
testType = models.CharField(max_length=8, null=True, blank=True, help_text="测试类型",
|
||||
verbose_name="测试类型",
|
||||
default="1")
|
||||
testMethod = models.JSONField(blank=True, help_text="测试方法", verbose_name="测试方法",
|
||||
default=create_list)
|
||||
title = models.CharField(max_length=64, blank=True, null=True, verbose_name="树-名称",
|
||||
help_text="树-名称")
|
||||
objects = models.Manager()
|
||||
ident = models.CharField(max_length=64, blank=True, null=True, verbose_name="测试需求标识", help_text="测试需求标识")
|
||||
name = models.CharField(max_length=64, blank=True, null=True, verbose_name="测试需求名称", help_text="测试需求名称")
|
||||
adequacy = models.CharField(max_length=2048, blank=True, null=True, verbose_name="充分条件", help_text="充分条件")
|
||||
priority = models.CharField(max_length=8, blank=True, null=True, verbose_name="优先级", help_text="优先级")
|
||||
testType = models.CharField(max_length=8, null=True, blank=True, help_text="测试类型", verbose_name="测试类型", default="1")
|
||||
testMethod = models.JSONField(blank=True, help_text="测试方法", verbose_name="测试方法", default=create_list)
|
||||
title = models.CharField(max_length=64, blank=True, null=True, verbose_name="树-名称", help_text="树-名称")
|
||||
key = models.CharField(max_length=64, blank=True, null=True,
|
||||
verbose_name="round-dut-designkey-testdemand",
|
||||
help_text="round-dut-designkey-testdemand")
|
||||
|
||||
@@ -1,91 +1,132 @@
|
||||
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
|
||||
# 导入日志的模型
|
||||
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)
|
||||
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("⚠️ 查询到记录但未发生变更,可能数据有误")
|
||||
Reference in New Issue
Block a user