1. 项目设置支持邮件通知和钉钉通知开关
2. 设置支持邮件通知收件人配置 3. models.py优化db.Boolean类型字段server_default默认值写法,优化db.Integer类型字段default默认值写法
This commit is contained in:
parent
b8badfc2cf
commit
0d6a554d12
|
@ -13,7 +13,8 @@ from app.extensions import (db, migrate, login_manager, mail, csrf, bootstrap, h
|
|||
socketio, dispatcher_scheduler)
|
||||
from app import models
|
||||
from app.template_global import (render_to_json, sort_by_order_in_module, sort_by_order_in_logic_controller,
|
||||
can_show, is_forbidden, get_latest_reports, get_case_from_id, get_tool_from_id)
|
||||
can_show, is_forbidden, get_latest_reports, get_case_from_id, get_tool_from_id,
|
||||
calc_percent)
|
||||
from app.cores.ws import register_all_user_socket
|
||||
|
||||
|
||||
|
@ -169,6 +170,7 @@ def register_template_global(app: Flask):
|
|||
app.add_template_global(is_forbidden, 'is_forbidden')
|
||||
app.add_template_global(get_case_from_id, 'get_case_from_id')
|
||||
app.add_template_global(get_tool_from_id, 'get_tool_from_id')
|
||||
app.add_template_global(calc_percent, 'calc_percent')
|
||||
|
||||
|
||||
def register_before_first_request_funcs(app: Flask):
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
# coding=utf-8
|
||||
# 邮件通知
|
||||
|
||||
from typing import List, Mapping, Any
|
||||
from flask import current_app, render_template
|
||||
|
||||
from app.email import send_email
|
||||
|
||||
|
||||
def send_email_report(addresses: List, report_data: Mapping[str, Any]):
|
||||
"""
|
||||
邮件发送本次调度结果
|
||||
:param addresses: 收件人地址
|
||||
:param report_data: 案例执行结果
|
||||
:return: None
|
||||
"""
|
||||
send_email(
|
||||
subject="[ApiAutomationTest] 构建结果通知",
|
||||
sender=current_app.config['ADMINS'][0],
|
||||
recipients=addresses,
|
||||
# text_body=render_template("email/email_authentication.txt"),
|
||||
html_body=render_template("email/summary_report.html",
|
||||
report_data=report_data,
|
||||
module_results=report_data.get('module_results'))
|
||||
)
|
|
@ -93,8 +93,8 @@ class EmailSetting(db.Model):
|
|||
receiver_address: 收件地址, 多个收件人以逗号分隔
|
||||
"""
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
whether_send_email = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
|
||||
whether_gen_report = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
|
||||
whether_send_email = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
|
||||
whether_gen_report = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
|
||||
email_title = db.Column(db.String(128), nullable=False, default='', server_default='')
|
||||
email_text = db.Column(db.Text, nullable=False, default='', server_default='')
|
||||
receiver_address = db.Column(db.Text, nullable=False, default='', server_default='')
|
||||
|
@ -211,16 +211,23 @@ class ProjectAdvancedConfiguration(db.Model):
|
|||
"""
|
||||
产品高级设置
|
||||
字段说明
|
||||
stop_on_error 发生错误时终止执行
|
||||
ding_talk_notify 执行完毕后是否发送钉钉通知
|
||||
email_notify 执行完毕后是否发送邮件
|
||||
"""
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
stop_on_error = db.Column(db.Boolean, nullable=False, default=True, server_default='True')
|
||||
stop_on_error = db.Column(db.Boolean, nullable=False, default=True, server_default='1')
|
||||
ding_talk_notify = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
|
||||
email_notify = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
|
||||
|
||||
# relationship
|
||||
project_id = db.Column(db.Integer, db.ForeignKey('project.id'))
|
||||
project = db.relationship('Project', back_populates='project_advanced_configuration')
|
||||
|
||||
def update(self, stop_on_error):
|
||||
def update(self, stop_on_error, ding_talk_notify, email_notify):
|
||||
self.stop_on_error = stop_on_error
|
||||
self.ding_talk_notify = ding_talk_notify
|
||||
self.email_notify = email_notify
|
||||
db.session.commit()
|
||||
|
||||
|
||||
|
@ -1550,7 +1557,7 @@ class HTTPCase(db.Model):
|
|||
content_type = db.Column(db.String(128), nullable=False, default='', server_default='')
|
||||
preprocessor_script = db.Column(db.TEXT, nullable=False, default='', server_default='')
|
||||
postprocessor_script = db.Column(db.TEXT, nullable=False, default='', server_default='')
|
||||
postprocessor_failure = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
|
||||
postprocessor_failure = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
|
||||
postprocessor_failure_message = db.Column(db.Text, nullable=False, default='', server_default='')
|
||||
|
||||
# relationship
|
||||
|
@ -1806,9 +1813,9 @@ class HTTPCaseParameter(db.Model):
|
|||
id = db.Column(db.Integer, primary_key=True)
|
||||
name = db.Column(db.String(128), nullable=False, default='', server_default='')
|
||||
value = db.Column(db.Text, nullable=False, default='', server_default='')
|
||||
url_encode = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
|
||||
url_encode = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
|
||||
content_type = db.Column(db.String(128), nullable=False, default='', server_default='')
|
||||
include_equals = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
|
||||
include_equals = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
|
||||
|
||||
# relationship
|
||||
http_case_id = db.Column(db.Integer, db.ForeignKey('http_case.id'))
|
||||
|
@ -1843,9 +1850,9 @@ class HTTPCaseExpectation(db.Model):
|
|||
test_field = db.Column(db.String(64), nullable=False, default='', server_default='')
|
||||
value = db.Column(db.Text, nullable=False, default='', server_default='')
|
||||
matching_rule = db.Column(db.String(64), nullable=False, default='', server_default='')
|
||||
last_result = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
|
||||
last_result = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
|
||||
last_failure_msg = db.Column(db.Text, nullable=False, default='初次执行前默认失败', server_default='初次执行前默认失败')
|
||||
negater = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
|
||||
negater = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
|
||||
|
||||
# relationship
|
||||
http_case_id = db.Column(db.Integer, db.ForeignKey('http_case.id'))
|
||||
|
@ -1929,7 +1936,7 @@ class SSHCase(db.Model):
|
|||
method = db.Column(db.String(128), nullable=False, default='', server_default='')
|
||||
preprocessor_script = db.Column(db.TEXT, nullable=False, default='', server_default='')
|
||||
postprocessor_script = db.Column(db.TEXT, nullable=False, default='', server_default='')
|
||||
postprocessor_failure = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
|
||||
postprocessor_failure = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
|
||||
postprocessor_failure_message = db.Column(db.Text, nullable=False, default='', server_default='')
|
||||
|
||||
# relationship
|
||||
|
@ -2130,9 +2137,9 @@ class SSHCaseExpectation(db.Model):
|
|||
test_field = db.Column(db.String(64), nullable=False, default='', server_default='')
|
||||
value = db.Column(db.Text, nullable=False, default='', server_default='')
|
||||
matching_rule = db.Column(db.String(64), nullable=False, default='', server_default='')
|
||||
last_result = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
|
||||
last_result = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
|
||||
last_failure_msg = db.Column(db.Text, nullable=False, default='初次执行前默认失败', server_default='初次执行前默认失败')
|
||||
negater = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
|
||||
negater = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
|
||||
|
||||
# relationship
|
||||
ssh_case_id = db.Column(db.Integer, db.ForeignKey('ssh_case.id'))
|
||||
|
@ -2189,7 +2196,7 @@ class SQLCase(db.Model):
|
|||
charset = db.Column(db.String(64), nullable=False, default='', server_default='')
|
||||
preprocessor_script = db.Column(db.TEXT, nullable=False, default='', server_default='')
|
||||
postprocessor_script = db.Column(db.TEXT, nullable=False, default='', server_default='')
|
||||
postprocessor_failure = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
|
||||
postprocessor_failure = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
|
||||
postprocessor_failure_message = db.Column(db.Text, nullable=False, default='', server_default='')
|
||||
|
||||
# relationship
|
||||
|
@ -2401,9 +2408,9 @@ class SQLCaseExpectation(db.Model):
|
|||
test_field = db.Column(db.String(64), nullable=False, default='', server_default='')
|
||||
value = db.Column(db.Text, nullable=False, default='', server_default='')
|
||||
matching_rule = db.Column(db.String(64), nullable=False, default='', server_default='')
|
||||
last_result = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
|
||||
last_result = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
|
||||
last_failure_msg = db.Column(db.Text, nullable=False, default='初次执行前默认失败', server_default='初次执行前默认失败')
|
||||
negater = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
|
||||
negater = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
|
||||
|
||||
# relationship
|
||||
sql_case_id = db.Column(db.Integer, db.ForeignKey('sql_case.id'))
|
||||
|
@ -2442,11 +2449,11 @@ class DebugCase(db.Model):
|
|||
case: 案例组件 Case:DebugCase is 1:1
|
||||
"""
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
project_variable = db.Column(db.Boolean, nullable=False, default=False, server_default='True')
|
||||
project_variable = db.Column(db.Boolean, nullable=False, default=False, server_default='1')
|
||||
expectation_logic = db.Column(db.String(64), nullable=False, default=EXPECTATION_LOGIC.AND, server_default=EXPECTATION_LOGIC.AND)
|
||||
preprocessor_script = db.Column(db.TEXT, nullable=False, default='', server_default='')
|
||||
postprocessor_script = db.Column(db.TEXT, nullable=False, default='', server_default='')
|
||||
postprocessor_failure = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
|
||||
postprocessor_failure = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
|
||||
postprocessor_failure_message = db.Column(db.Text, nullable=False, default='', server_default='')
|
||||
|
||||
# relationship
|
||||
|
@ -2595,9 +2602,9 @@ class DebugCaseExpectation(db.Model):
|
|||
test_field = db.Column(db.String(64), nullable=False, default='', server_default='')
|
||||
value = db.Column(db.Text, nullable=False, default='', server_default='')
|
||||
matching_rule = db.Column(db.String(64), nullable=False, default='', server_default='')
|
||||
last_result = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
|
||||
last_result = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
|
||||
last_failure_msg = db.Column(db.Text, nullable=False, default='初次执行前默认失败', server_default='初次执行前默认失败')
|
||||
negater = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
|
||||
negater = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
|
||||
|
||||
# relationship
|
||||
debug_case_id = db.Column(db.Integer, db.ForeignKey('debug_case.id'))
|
||||
|
@ -2642,13 +2649,13 @@ class Dispatcher(db.Model):
|
|||
# field
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
element_type = db.Column(db.String(64), nullable=False, default='', server_default='')
|
||||
element_id = db.Column(db.Integer, nullable=False, default=text('0'), server_default=text('0'))
|
||||
element_id = db.Column(db.Integer, nullable=False, default=0, server_default=text('0'))
|
||||
status = db.Column(db.String(64), nullable=False, default='', server_default='')
|
||||
progress = db.Column(db.Float(), nullable=False, default=text('0.0'), server_default=text('0.0')) # TODO 控制精度?
|
||||
progress = db.Column(db.Float(), nullable=False, default=0.0, server_default=text('0.0')) # TODO 控制精度?
|
||||
start_time = db.Column(db.DateTime, nullable=False, default=datetime.now, server_default=text('CURRENT_TIMESTAMP'))
|
||||
end_time = db.Column(db.DateTime, nullable=False, default=datetime.now, server_default=text('CURRENT_TIMESTAMP'))
|
||||
log = db.Column(db.Text, nullable=False, default='', server_default='')
|
||||
user_id = db.Column(db.Integer, nullable=False, default=text('0'), server_default=text('0'))
|
||||
user_id = db.Column(db.Integer, nullable=False, default=0, server_default=text('0'))
|
||||
|
||||
# relationship
|
||||
details = db.relationship('DispatcherDetail', back_populates='dispatcher', cascade='all, delete-orphan')
|
||||
|
@ -2692,10 +2699,10 @@ class DispatcherDetail(db.Model):
|
|||
# field
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
element_type = db.Column(db.String(64), nullable=False, default='', server_default='')
|
||||
element_id = db.Column(db.Integer, nullable=False, default=text('0'), server_default=text('0'))
|
||||
element_id = db.Column(db.Integer, nullable=False, default=0, server_default=text('0'))
|
||||
element_name = db.Column(db.String(512), nullable=False, default='', server_default='') # case.name大小为512
|
||||
parent_dispatcher_detail_id = db.Column(db.Integer, nullable=False, default=text('0'), server_default=text('0'))
|
||||
parent_element_id = db.Column(db.Integer, nullable=False, default=text('0'), server_default=text('0'))
|
||||
parent_dispatcher_detail_id = db.Column(db.Integer, nullable=False, default=0, server_default=text('0'))
|
||||
parent_element_id = db.Column(db.Integer, nullable=False, default=0, server_default=text('0'))
|
||||
parent_element_type = db.Column(db.String(64), nullable=False, default='', server_default='')
|
||||
start_time = db.Column(db.DateTime, nullable=False, default=datetime.now, server_default=text('CURRENT_TIMESTAMP'))
|
||||
|
||||
|
@ -2816,6 +2823,8 @@ class ReportCaseData(db.Model):
|
|||
字段说明
|
||||
case_type: 案例类型
|
||||
case_id: 案例编号
|
||||
module_id: 案例所属模块id
|
||||
module_name: 案例所属模块名称
|
||||
request_header: 请求头
|
||||
request_body: 请求体
|
||||
response_header: 应答头
|
||||
|
@ -2835,20 +2844,22 @@ class ReportCaseData(db.Model):
|
|||
"""
|
||||
# field
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
case_id = db.Column(db.Integer, nullable=False, default=text('0'), server_default=text('0'))
|
||||
case_id = db.Column(db.Integer, nullable=False, default=0, server_default=text('0'))
|
||||
case_type = db.Column(db.String(64), nullable=False, default='', server_default='')
|
||||
module_id = db.Column(db.Integer, nullable=False, default=0, server_default=text('0'))
|
||||
module_name = db.Column(db.String(64), nullable=False, default='', server_default='')
|
||||
request_header = db.Column(db.Text, nullable=False, default='', server_default='')
|
||||
request_body = db.Column(db.Text, nullable=False, default='', server_default='')
|
||||
response_header = db.Column(db.Text, nullable=False, default='', server_default='')
|
||||
response_body = db.Column(db.Text, nullable=False, default='', server_default='')
|
||||
preprocessor_script = db.Column(db.TEXT, nullable=False, default='', server_default='')
|
||||
postprocessor_script = db.Column(db.TEXT, nullable=False, default='', server_default='')
|
||||
postprocessor_result = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
|
||||
postprocessor_result = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
|
||||
postprocessor_failure_message = db.Column(db.Text, nullable=False, default='', server_default='')
|
||||
log = db.Column(db.Text, nullable=False, default='', server_default='')
|
||||
expectation_logic = db.Column(db.String(64), nullable=False, default=EXPECTATION_LOGIC.AND,
|
||||
server_default=EXPECTATION_LOGIC.AND)
|
||||
elapsed_time = db.Column(db.Integer, nullable=False, default=text('0'), server_default=text('0'))
|
||||
elapsed_time = db.Column(db.Integer, nullable=False, default=0, server_default=text('0'))
|
||||
result = db.Column(db.String(64), nullable=False, default='', server_default='')
|
||||
|
||||
# relationship
|
||||
|
@ -2860,11 +2871,13 @@ class ReportCaseData(db.Model):
|
|||
dispatcher_detail = db.relationship('DispatcherDetail')
|
||||
|
||||
@classmethod
|
||||
def add(cls, report_id, dispatcher_detail_id, case_type, case_id, request_header, request_body, response_header,
|
||||
response_body, elapsed_time, preprocessor_script, postprocessor_script, postprocessor_result,
|
||||
postprocessor_failure_message, log, expectation_logic, result):
|
||||
def add(cls, report_id, dispatcher_detail_id, case_type, case_id, module_id, module_name, request_header,
|
||||
request_body, response_header, response_body, elapsed_time, preprocessor_script, postprocessor_script,
|
||||
postprocessor_result, postprocessor_failure_message, log, expectation_logic, result):
|
||||
report_case_data = cls(case_type=case_type,
|
||||
case_id=case_id,
|
||||
module_id=module_id,
|
||||
module_name=module_name,
|
||||
request_header=request_header,
|
||||
request_body=request_body,
|
||||
response_header=response_header,
|
||||
|
@ -2904,8 +2917,8 @@ class ReportCaseExpectationData(db.Model):
|
|||
test_field = db.Column(db.String(64), nullable=False, default='', server_default='')
|
||||
value = db.Column(db.Text, nullable=False, default='', server_default='')
|
||||
matching_rule = db.Column(db.String(64), nullable=False, default='', server_default='')
|
||||
negater = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
|
||||
result = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
|
||||
negater = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
|
||||
result = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
|
||||
failure_msg = db.Column(db.Text, nullable=False, default='', server_default='')
|
||||
|
||||
# relationship
|
||||
|
@ -2941,7 +2954,7 @@ class ReportToolData(db.Model):
|
|||
|
||||
# field
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
tool_id = db.Column(db.Integer, nullable=False, default=text('0'), server_default=text('0'))
|
||||
tool_id = db.Column(db.Integer, nullable=False, default=0, server_default=text('0'))
|
||||
tool_type = db.Column(db.String(64), nullable=False, default='', server_default='')
|
||||
|
||||
# relationship
|
||||
|
@ -3066,9 +3079,9 @@ class Scheduler(db.Model):
|
|||
# field
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
element_type = db.Column(db.String(64), nullable=False, default='', server_default='')
|
||||
element_id = db.Column(db.Integer, nullable=False, default=text('0'), server_default=text('0'))
|
||||
element_id = db.Column(db.Integer, nullable=False, default=0, server_default=text('0'))
|
||||
cron = db.Column(db.Text, nullable=False, default='', server_default='')
|
||||
enable = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
|
||||
enable = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
|
||||
|
||||
@classmethod
|
||||
def get_scheduler(cls, element_type, element_id):
|
||||
|
@ -3099,10 +3112,10 @@ class DingTalkRobotSetting(db.Model):
|
|||
"""
|
||||
# field
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
enable = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
|
||||
enable = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
|
||||
access_token = db.Column(db.String(512), nullable=False, default='', server_default='')
|
||||
secret = db.Column(db.String(512), nullable=False, default='', server_default='')
|
||||
at_all = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
|
||||
at_all = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
|
||||
at_mobiles = db.Column(db.Text, nullable=False, default='', server_default='')
|
||||
|
||||
@classmethod
|
||||
|
@ -3155,8 +3168,85 @@ class DingTalkRobotSettingAssociationProject(db.Model):
|
|||
"""钉钉机器人配置与项目关系表"""
|
||||
# field
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
setting_id = db.Column(db.Integer, nullable=False, default=text('0'), server_default=text('0'))
|
||||
project_id = db.Column(db.Integer, nullable=False, default=text('0'), server_default=text('0'))
|
||||
setting_id = db.Column(db.Integer, nullable=False, default=0, server_default=text('0'))
|
||||
project_id = db.Column(db.Integer, nullable=False, default=0, server_default=text('0'))
|
||||
|
||||
@classmethod
|
||||
def add(cls, setting_id, projects):
|
||||
for project_id in projects:
|
||||
db.session.add(cls(setting_id=setting_id, project_id=project_id))
|
||||
db.session.commit()
|
||||
|
||||
@classmethod
|
||||
def delete(cls, setting_id):
|
||||
rows = cls.query.filter_by(setting_id=setting_id).all()
|
||||
for row in rows:
|
||||
db.session.delete(row)
|
||||
db.session.commit()
|
||||
|
||||
|
||||
class EmailReceiverSetting(db.Model):
|
||||
"""
|
||||
邮件收件人配置
|
||||
字段说明
|
||||
enable 是否启用当前收件人地址
|
||||
name 收件人名称
|
||||
address 邮件地址
|
||||
"""
|
||||
# field
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
enable = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
|
||||
name = db.Column(db.String(128), nullable=False, default='', server_default='')
|
||||
address = db.Column(db.String(512), nullable=False, default='', server_default='')
|
||||
|
||||
@classmethod
|
||||
def get_project_email_receiver_setting(cls, project_id):
|
||||
"""获取该项目需要通知的所有收件人"""
|
||||
email_receiver_settings = []
|
||||
rows = EmailReceiverSettingAssociationProject.query.filter_by(project_id=project_id).all()
|
||||
if rows:
|
||||
for row in rows:
|
||||
email_receiver_setting = cls.query.filter_by(id=row.setting_id).first()
|
||||
if email_receiver_setting:
|
||||
email_receiver_settings.append(email_receiver_setting)
|
||||
return email_receiver_settings
|
||||
|
||||
@classmethod
|
||||
def add(cls, enable, name, address, projects=None):
|
||||
email_receiver_setting = cls(enable=enable,
|
||||
name=name,
|
||||
address=address)
|
||||
db.session.add(email_receiver_setting)
|
||||
db.session.commit()
|
||||
EmailReceiverSettingAssociationProject.add(setting_id=email_receiver_setting.id, projects=projects)
|
||||
return email_receiver_setting
|
||||
|
||||
@classmethod
|
||||
def modify(cls, id, enable, name, address, projects=None):
|
||||
email_receiver_setting = cls.query.filter_by(id=id).first()
|
||||
if email_receiver_setting:
|
||||
email_receiver_setting.enable = enable
|
||||
email_receiver_setting.name = name
|
||||
email_receiver_setting.address = address
|
||||
db.session.commit()
|
||||
EmailReceiverSettingAssociationProject.delete(setting_id=id)
|
||||
EmailReceiverSettingAssociationProject.add(setting_id=id, projects=projects)
|
||||
|
||||
@classmethod
|
||||
def delete(cls, id):
|
||||
email_receiver_setting = cls.query.filter_by(id=id).first()
|
||||
if email_receiver_setting:
|
||||
db.session.delete(email_receiver_setting)
|
||||
db.session.commit()
|
||||
EmailReceiverSettingAssociationProject.delete(setting_id=email_receiver_setting.id)
|
||||
|
||||
|
||||
class EmailReceiverSettingAssociationProject(db.Model):
|
||||
"""邮件收件人配置与项目关系表"""
|
||||
# field
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
setting_id = db.Column(db.Integer, nullable=False, default=0, server_default=text('0'))
|
||||
project_id = db.Column(db.Integer, nullable=False, default=0, server_default=text('0'))
|
||||
|
||||
@classmethod
|
||||
def add(cls, setting_id, projects):
|
||||
|
|
|
@ -107,5 +107,18 @@ def get_tool_from_id(tool_id):
|
|||
return Tool.query.filter_by(id=tool_id).first()
|
||||
|
||||
|
||||
def calc_percent(a, b):
|
||||
try:
|
||||
a = float(a)
|
||||
b = float(b)
|
||||
except Exception as e:
|
||||
return None
|
||||
else:
|
||||
if b > 0:
|
||||
return round(a / b * 100, 2)
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print(render_to_json)
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<title>TestCenter-PBOX-NewAutoTest-第348次构建日志</title></head>
|
||||
|
||||
<body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4" offset="0">
|
||||
<table width="95%" cellpadding="0" cellspacing="0" style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<span style="color: #FF0000;">(本邮件是程序自动下发的,请勿回复!)</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<h2 style="color: #0000FF">调度 - {{ report_data.get('dispatcher_end_type') }}</h2></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<br />
|
||||
<b><span style="color: #0B610B">调度信息</span></b>
|
||||
<hr size="2" width="100%" align="center" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<ul>
|
||||
<li>名称: {{ report_data.get('report_name') }}</li>
|
||||
<li>级别: {{ report_data.get('trigger_element_type') }}</li>
|
||||
<li>调度编号: 第{{ report_data.get('dispatcher_id') }}次构建</li>
|
||||
<li>报告编号: 第{{ report_data.get('report_id') }}号报告</li>
|
||||
<li>触发类型: {{ report_data.get('dispatcher_trigger_type') }}</li>
|
||||
<li>详细报告:
|
||||
<a href="{{ request.url_root }}report/detail/{{ report_data.get('report_id') }}">{{ request.url_root }}report/detail/{{ report_data.get('report_id') }}</a></li>
|
||||
<li>开始时间: {{ report_data.get('start_time') }}</li>
|
||||
<li>结束时间: {{ report_data.get('end_time') }}</li>
|
||||
<li>耗时: {{ report_data.get('elapsed_time') }}</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<br />
|
||||
<b><span style="color: #0B610B">模块执行结果统计</span></b>
|
||||
<hr size="2" width="100%" align="center" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">
|
||||
<style type="text/css">* { margin: 0; padding: 0 } html, body { width: 100%; height: 100%; font-size: 12px;} table { border-collapse: collapse; table-layout: fixed ;bgcolor:#F0E68C} td { vertical-align: baseline; font-size: 12px }</style>
|
||||
<table align="center" class="details" border="1" cellpadding="5" cellspacing="2" width="95%" bgcolor="#FAFAD2">
|
||||
<tbody>
|
||||
<tr valign="top" bgcolor="#87CEFA" name="line">
|
||||
<th>模块编号</th>
|
||||
<th>模块名称</th>
|
||||
<th>案例个数</th>
|
||||
<th>成功</th>
|
||||
<th>失败</th>
|
||||
<th>错误</th>
|
||||
<th>跳过</th>
|
||||
<th>成功率</th>
|
||||
</tr>
|
||||
{% for module_result in module_results %}
|
||||
<tr valign="top">
|
||||
<td align="center">{{ module_result.get('module_id') }}</td>
|
||||
<td align="center">{{ module_result.get('module_name') }}</td>
|
||||
<td align="center" style="background-color: rgba(0,132,255,0.7)">{{ module_result.get('case_count') }}</td>
|
||||
<td align="center" style="background-color: rgba(40,167,69,0.7)">{{ module_result.get('success_count') }}</td>
|
||||
<td align="center" style="background-color: rgba(220,53,69,0.7)">{{ module_result.get('failure_count') }}</td>
|
||||
<td align="center" style="background-color: rgba(205,0,204,0.7)">{{ module_result.get('error_count') }}</td>
|
||||
<td align="center" style="background-color: rgba(108,117,125,0.7)">{{ module_result.get('skip_count') }}</td>
|
||||
<td align="center">{{ calc_percent(module_result.get('success_count', 0), module_result.get('case_count', 0)) }}%</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<tr valign="top" bgcolor="#87CEFA">
|
||||
<td align="center" colspan="2">
|
||||
<b>总计</b>
|
||||
</td>
|
||||
<td align="center">
|
||||
<b>{{ report_data.get('case_count', 0) }}</b>
|
||||
</td>
|
||||
<td align="center">
|
||||
<b>{{ report_data.get('success_count', 0) }}</b>
|
||||
</td>
|
||||
<td align="center">
|
||||
<b>{{ report_data.get('failure_count', 0) }}</b>
|
||||
</td>
|
||||
<td align="center">
|
||||
<b>{{ report_data.get('error_count', 0) }}</b>
|
||||
</td>
|
||||
<td align="center">
|
||||
<b>{{ report_data.get('skip_count', 0) }}</b>
|
||||
</td>
|
||||
<td align="center">
|
||||
<b>{{ calc_percent(report_data.get('success_count', 0), report_data.get('case_count', 0)) }}%</b>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<br/></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -90,7 +90,7 @@ class="bg-gradient-grey"
|
|||
<div class="modal-body">
|
||||
<input type="text" class="form-control" id="input-config-project-id" placeholder="" disabled style="display: none"/>
|
||||
<div class="form-group">
|
||||
<label>发生错误终止运行:</label>
|
||||
<label>发生错误终止运行</label>
|
||||
<div class="btn-group btn-group-sm" data-toggle="buttons">
|
||||
<label class="btn btn-outline-secondary btn-sm">
|
||||
<input type="radio" name="stop-on-error" id="radio-stop-on-error-yes" autocomplete="off"> 是
|
||||
|
@ -100,8 +100,30 @@ class="bg-gradient-grey"
|
|||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>钉钉通知</label>
|
||||
<div class="btn-group btn-group-sm" data-toggle="buttons">
|
||||
<label class="btn btn-outline-secondary btn-sm">
|
||||
<input type="radio" name="ding-talk-notify" id="radio-ding-talk-notify-yes" autocomplete="off"> 是
|
||||
</label>
|
||||
<label class="btn btn-outline-secondary btn-sm">
|
||||
<input type="radio" name="ding-talk-notify" id="radio-ding-talk-notify-no" autocomplete="off"> 否
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>邮件通知</label>
|
||||
<div class="btn-group btn-group-sm" data-toggle="buttons">
|
||||
<label class="btn btn-outline-secondary btn-sm">
|
||||
<input type="radio" name="email-notify" id="radio-email-notify-yes" autocomplete="off"> 是
|
||||
</label>
|
||||
<label class="btn btn-outline-secondary btn-sm">
|
||||
<input type="radio" name="email-notify" id="radio-email-notify-no" autocomplete="off"> 否
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group input-group-sm mt-2">
|
||||
<label>定时任务:</label>
|
||||
<label>定时任务</label>
|
||||
<div class="input-group-prepend">
|
||||
<label class="input-group-text" for="checkbox-use-scheduler">是否启用</label>
|
||||
</div>
|
||||
|
|
|
@ -9,16 +9,17 @@
|
|||
{% endblock styles %}
|
||||
|
||||
{% block body_attribs %}
|
||||
data-spy="scroll" data-target="#navbar-example3" style="position: relative"
|
||||
data-spy="scroll" data-target="#navbar-basic-setting" style="position: relative"
|
||||
{% endblock %}
|
||||
|
||||
{% block app_content %}
|
||||
<div class="row">
|
||||
<div class="col-lg-2">
|
||||
<nav id="navbar-example3" class="navbar navbar-light bg-light" style="position: fixed">
|
||||
<nav id="navbar-basic-setting" class="navbar navbar-light bg-light" style="position: fixed">
|
||||
<!--<a class="navbar-brand" href="#">Navbar</a>-->
|
||||
<nav class="nav nav-pills flex-column">
|
||||
{# <a class="nav-link" href="#email">邮件设置</a>#}
|
||||
<a class="nav-link" href="#email-receiver-setting">邮件通知</a>
|
||||
<a class="nav-link" href="#ding-talk-robot-setting">钉钉通知</a>
|
||||
<nav class="nav nav-pills flex-column">
|
||||
<a class="nav-link svg-bi-arrow-up-circle-fill" href="#">
|
||||
|
@ -32,7 +33,7 @@ data-spy="scroll" data-target="#navbar-example3" style="position: relative"
|
|||
</nav>
|
||||
</div>
|
||||
<div class="col-lg-10">
|
||||
<div data-spy="scroll" data-target="#navbar-example3" data-offset="0">
|
||||
<div data-spy="scroll" data-target="#navbar-basic-setting" data-offset="0">
|
||||
{# <h2 id="email">邮件设置</h2>#}
|
||||
{# <form method="post" action="{{ url_for('setting.basic_setting') }}">#}
|
||||
{# {{ form.csrf_token() }}#}
|
||||
|
@ -43,6 +44,13 @@ data-spy="scroll" data-target="#navbar-example3" style="position: relative"
|
|||
{# {{ render_field(form.receiver_address) }}#}
|
||||
{# {{ render_field(form.submit, class="btn btn-primary") }}#}
|
||||
{# </form>#}
|
||||
<h2 class="mt-2" id="email-receiver-setting">邮件通知</h2>
|
||||
<div class="btn-toolbar" role="toolbar" id="table-email-receiver-setting-toolbar">
|
||||
<div class="btn-group mr-2" role="group">
|
||||
<button type="button" class="btn btn-primary" id="btn-add-email-receiver">新增</button>
|
||||
</div>
|
||||
</div>
|
||||
<table id="table-email-receiver-setting"></table>
|
||||
<h2 class="mt-2" id="ding-talk-robot-setting">钉钉通知</h2>
|
||||
<div class="btn-toolbar" role="toolbar" id="table-ding-talk-robot-setting-toolbar">
|
||||
<div class="btn-group mr-2" role="group">
|
||||
|
@ -65,7 +73,7 @@ data-spy="scroll" data-target="#navbar-example3" style="position: relative"
|
|||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<label>是否启用:</label>
|
||||
<label>是否启用</label>
|
||||
<div class="btn-group btn-group-sm" data-toggle="buttons">
|
||||
<label class="btn btn-outline-secondary btn-sm">
|
||||
<input type="radio" name="input-add-ding-talk-robot-enable" id="input-add-ding-talk-robot-enable-yes" autocomplete="off"> 是
|
||||
|
@ -74,7 +82,7 @@ data-spy="scroll" data-target="#navbar-example3" style="position: relative"
|
|||
<input type="radio" name="input-add-ding-talk-robot-enable" id="input-add-ding-talk-robot-enable-no" autocomplete="off" checked> 否
|
||||
</label>
|
||||
</div>
|
||||
<label>@全体成员:</label>
|
||||
<label>@全体成员</label>
|
||||
<div class="btn-group btn-group-sm" data-toggle="buttons">
|
||||
<label class="btn btn-outline-secondary btn-sm">
|
||||
<input type="radio" name="input-add-ding-talk-robot-at-all" id="input-add-ding-talk-robot-at-all-yes" autocomplete="off"> 是
|
||||
|
@ -97,7 +105,7 @@ data-spy="scroll" data-target="#navbar-example3" style="position: relative"
|
|||
<input type="text" class="form-control" id="input-add-ding-talk-robot-at-mobiles" placeholder="请输入需要@成员的手机号,多个成员以,分割">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="select-add-ding-talk-robot-projects">关联项目: </label>
|
||||
<label for="select-add-ding-talk-robot-projects">关联项目</label>
|
||||
<select id="select-add-ding-talk-robot-projects" class="selectpicker" multiple data-width="100%" data-actions-box="true">
|
||||
{% for project in projects %}
|
||||
<option value="{{ project.id }}" data-subtext="(project_id: {{ project.id }})">{{ project.name }}</option>
|
||||
|
@ -125,7 +133,7 @@ data-spy="scroll" data-target="#navbar-example3" style="position: relative"
|
|||
<div class="modal-body">
|
||||
<input type="text" class="form-control" id="input-modify-ding-talk-robot-id" placeholder="" disabled style="display: none"/>
|
||||
<div class="form-group">
|
||||
<label>是否启用:</label>
|
||||
<label>是否启用</label>
|
||||
<div class="btn-group btn-group-sm" data-toggle="buttons">
|
||||
<label class="btn btn-outline-secondary btn-sm">
|
||||
<input type="radio" name="input-modify-ding-talk-robot-enable" id="input-modify-ding-talk-robot-enable-yes" autocomplete="off"> 是
|
||||
|
@ -134,7 +142,7 @@ data-spy="scroll" data-target="#navbar-example3" style="position: relative"
|
|||
<input type="radio" name="input-modify-ding-talk-robot-enable" id="input-modify-ding-talk-robot-enable-no" autocomplete="off" checked> 否
|
||||
</label>
|
||||
</div>
|
||||
<label>@全体成员:</label>
|
||||
<label>@全体成员</label>
|
||||
<div class="btn-group btn-group-sm" data-toggle="buttons">
|
||||
<label class="btn btn-outline-secondary btn-sm">
|
||||
<input type="radio" name="input-modify-ding-talk-robot-at-all" id="input-modify-ding-talk-robot-at-all-yes" autocomplete="off"> 是
|
||||
|
@ -157,7 +165,7 @@ data-spy="scroll" data-target="#navbar-example3" style="position: relative"
|
|||
<input type="text" class="form-control" id="input-modify-ding-talk-robot-at-mobiles" placeholder="请输入需要@成员的手机号,多个成员以,分割">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="select-modify-ding-talk-robot-projects">关联项目: </label>
|
||||
<label for="select-modify-ding-talk-robot-projects">关联项目</label>
|
||||
<select id="select-modify-ding-talk-robot-projects" class="selectpicker" multiple data-width="100%" data-actions-box="true">
|
||||
{% for project in projects %}
|
||||
<option value="{{ project.id }}" data-subtext="(project_id: {{ project.id }})">{{ project.name }}</option>
|
||||
|
@ -172,6 +180,100 @@ data-spy="scroll" data-target="#navbar-example3" style="position: relative"
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="modal-add-email-receiver-setting" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">新增邮件收件人</h5>
|
||||
<button type="button" class="close" data-dismiss="modal">
|
||||
<span>×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<label>是否启用</label>
|
||||
<div class="btn-group btn-group-sm" data-toggle="buttons">
|
||||
<label class="btn btn-outline-secondary btn-sm">
|
||||
<input type="radio" name="input-add-email-receiver-enable" id="input-add-email-receiver-enable-yes" autocomplete="off"> 是
|
||||
</label>
|
||||
<label class="btn btn-outline-secondary btn-sm">
|
||||
<input type="radio" name="input-add-email-receiver-enable" id="input-add-email-receiver-enable-no" autocomplete="off" checked> 否
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="input-add-email-receiver-name">名称</label>
|
||||
<input type="text" class="form-control" id="input-add-email-receiver-name" placeholder="请输入收件人名称">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="input-add-email-receiver-address">邮箱地址</label>
|
||||
<input type="text" class="form-control" id="input-add-email-receiver-address" placeholder="请输入邮箱地址">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="select-add-email-receiver-projects">关联项目</label>
|
||||
<select id="select-add-email-receiver-projects" class="selectpicker" multiple data-width="100%" data-actions-box="true">
|
||||
{% for project in projects %}
|
||||
<option value="{{ project.id }}" data-subtext="(project_id: {{ project.id }})">{{ project.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
|
||||
<button id="btn-save-add-email-receiver-setting" type="button" class="btn btn-primary">确定</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="modal-modify-email-receiver-setting" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">修改邮件收件人</h5>
|
||||
<button type="button" class="close" data-dismiss="modal">
|
||||
<span>×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<input type="text" class="form-control" id="input-modify-email-receiver-id" placeholder="" disabled style="display: none"/>
|
||||
<div class="form-group">
|
||||
<label>是否启用</label>
|
||||
<div class="btn-group btn-group-sm" data-toggle="buttons">
|
||||
<label class="btn btn-outline-secondary btn-sm">
|
||||
<input type="radio" name="input-modify-email-receiver-enable" id="input-modify-email-receiver-enable-yes" autocomplete="off"> 是
|
||||
</label>
|
||||
<label class="btn btn-outline-secondary btn-sm">
|
||||
<input type="radio" name="input-modify-email-receiver-enable" id="input-modify-email-receiver-enable-no" autocomplete="off" checked> 否
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="input-modify-email-receiver-name">名称</label>
|
||||
<input type="text" class="form-control" id="input-modify-email-receiver-name" placeholder="请输入收件人名称">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="input-modify-email-receiver-address">邮箱地址</label>
|
||||
<input type="text" class="form-control" id="input-modify-email-receiver-address" placeholder="请输入邮箱地址">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="select-modify-email-receiver-projects">关联项目</label>
|
||||
<select id="select-modify-email-receiver-projects" class="selectpicker" multiple data-width="100%" data-actions-box="true">
|
||||
{% for project in projects %}
|
||||
<option value="{{ project.id }}" data-subtext="(project_id: {{ project.id }})">{{ project.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
|
||||
<button id="btn-save-modify-email-receiver-setting" type="button" class="btn btn-primary">确定</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock app_content %}
|
||||
|
||||
{% block scripts %}
|
||||
|
|
Loading…
Reference in New Issue