Skip to content

Commit

Permalink
审核和查询分离,支持审核通过后由审核人或者发起人自由选择执行
Browse files Browse the repository at this point in the history
  • Loading branch information
hhyo authored and lihuanhuan committed Mar 28, 2018
1 parent b171ed8 commit 19d7db3
Show file tree
Hide file tree
Showing 9 changed files with 190 additions and 80 deletions.
17 changes: 9 additions & 8 deletions sql/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@

class Const(object):
workflowStatus = {
'finish': '已正常结束',
'abort': '人工终止流程',
'autoreviewing': '自动审核中',
'manreviewing': '等待审核人审核',
'executing': '执行中',
'autoreviewwrong': '自动审核不通过',
'exception': '执行有异常',
}
'finish': '已正常结束',
'abort': '人工终止流程',
'autoreviewing': '自动审核中',
'manreviewing': '等待审核人审核',
'pass': '审核通过',
'executing': '执行中',
'autoreviewwrong': '自动审核不通过',
'exception': '执行有异常',
}


class WorkflowDict:
Expand Down
2 changes: 1 addition & 1 deletion sql/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class workflow(models.Model):
review_man = models.CharField('审核人', max_length=50)
create_time = models.DateTimeField('创建时间', auto_now_add=True)
finish_time = models.DateTimeField('结束时间', null=True, blank=True)
status = models.CharField(max_length=50, choices=(('已正常结束','已正常结束'),('人工终止流程','人工终止流程'),('自动审核中','自动审核中'),('等待审核人审核','等待审核人审核'),('执行中','执行中'),('自动审核不通过','自动审核不通过'),('执行有异常','执行有异常')))
status = models.CharField(max_length=50, choices=(('已正常结束','已正常结束'),('人工终止流程','人工终止流程'),('自动审核中','自动审核中'),('等待审核人审核','等待审核人审核'),('审核通过','审核通过'),('执行中','执行中'),('自动审核不通过','自动审核不通过'),('执行有异常','执行有异常')))
#is_backup = models.IntegerField('是否备份,0为否,1为是', choices=((0,0),(1,1)))
is_backup = models.CharField('是否备份', choices=(('否','否'),('是','是')), max_length=20)
review_content = models.TextField('自动审核内容的JSON格式')
Expand Down
78 changes: 18 additions & 60 deletions sql/static/allWorkflow.html
Original file line number Diff line number Diff line change
@@ -1,64 +1,25 @@
{% extends "base.html" %}

{% block content %}
<!-- tab-->
<ul class="nav nav-tabs">
{% if navStatus == 'all' %}
<li class="active">
{% else %}
<li>
{% endif %}
<a href="/allworkflow/?pageNo=0&navStatus=all">全部工单</a>
</li>

{% if navStatus == 'manreviewing' %}
<li class="active">
{% else %}
<li>
{% endif %}
<a href="/allworkflow/?navStatus=manreviewing">等待审核人审核</a>
</li>

{% if navStatus == 'finish' %}
<li class="active">
{% else %}
<li>
{% endif %}
<a href="/allworkflow/?navStatus=finish">已执行完毕</a>
</li>

{% if navStatus == 'executing' %}
<li class="active">
{% else %}
<li>
{% endif %}
<a href="/allworkflow/?navStatus=executing">执行中</a>
</li>

{% if navStatus == 'abort' %}
<li class="active">
{% else %}
<li>
{% endif %}
<a href="/allworkflow/?navStatus=abort">人工终止流程</a>
</li>

{% if navStatus == 'autoreviewwrong' %}
<li class="active">
{% else %}
<li>
{% endif %}
<a href="/allworkflow/?navStatus=autoreviewwrong">自动审核不通过的</a>
</li>

</ul>
<!-- 自定义操作按钮-->
<div id="toolbar" class="bootstrap-select">
<select id="navStatus" class="form-control dropdown-menu-right selectpicker ">
<option value="all" selected="selected">全部工单</option>
<option value="manreviewing">待审核</option>
<option value="pass">审核通过</option>
<option value="finish">已执行完毕</option>
<option value="executing">执行中</option>
<option value="abort">人工终止流程</option>
<option value="autoreviewwrong">自动审核不通过</option>
</select>
</div>
<!-- 审核列表的表格-->
<div class="table-responsive">
<table id="sqlaudit-list" data-toggle="table" class="table table-striped table-hover"
style="table-layout:inherit;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;">
</table>
</div>
{% endblock content%}
{% endblock content %}
{% block js %}
{% load staticfiles %}
<script src="{% static 'bootstrap-table/js/bootstrap-table-export.min.js' %}"></script>
Expand Down Expand Up @@ -105,7 +66,7 @@
return {
limit: params.limit,
offset: params.offset,
navStatus: "{{ navStatus }}",
navStatus: $("#navStatus").val(),
search: params.search
}
},
Expand Down Expand Up @@ -150,17 +111,14 @@
});

}
//激活标签页时保存当前标签页的id
$(function () {
$("#nav-tabs").on('shown.bs.tab', "li", function (e) {
var active_tab = $(e.target).parents().attr('id');
get_sqlauditlist();
});

//状态筛选变动自动刷新
$("#navStatus").change(function () {
get_sqlauditlist();
});

//初始化数据
$(document).ready(function () {
var active_tab = 'all';
get_sqlauditlist();
});
</script>
Expand Down
21 changes: 20 additions & 1 deletion sql/static/detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -151,16 +151,35 @@ <h4>单子名称:<span id="editWorkflowNname">{{workflowDetail.workflow_name}}
<br>
{% if workflowDetail.status == '等待审核人审核' %}
{% if loginUser in listAllReviewMen %}
<form action="/passonly/" method="post" style="display:inline-block;">
{% csrf_token %}
<input type="hidden" name="workflowid" value="{{workflowDetail.id}}">
<input type="submit" id="btnPass" type="button" onclick="execute()" class="btn btn-primary btn-success" data-loading-text="Loading..." value="审核通过" />
</form>

<form action="/execute/" method="post" style="display:inline-block;">
{% csrf_token %}
<input type="hidden" name="workflowid" value="{{workflowDetail.id}}">
<input type="submit" id="btnExecute" type="button" onclick="execute()" class="btn btn-primary btn-default" data-loading-text="Loading..." value="审核通过,执行" />
<input type="submit" id="btnExecute" type="button" onclick="execute()" class="btn btn-danger" data-loading-text="Loading..." value="审核通过并执行" />
</form>

{% elif workflowDetail.engineer == loginUser %}
<!--只允许发起人提交其他集群-->
<a type='button' id="btnSubmitOtherCluster" class='btn btn-warning' href="/submitothercluster/">上线其他集群</a>
{% endif %}

<form action="/cancel/" method="post" style="display:inline-block;">
{% csrf_token %}
<input type="hidden" name="workflowid" value="{{workflowDetail.id}}">
<input type="submit" id="btnCancel" type="button" onclick="execute()" class="btn btn-default" data-loading-text="Loading..." value="终止流程" />
</form>

{% elif workflowDetail.status == '审核通过' %}
<form action="/executeonly/" method="post" style="display:inline-block;">
{% csrf_token %}
<input type="hidden" name="workflowid" value="{{workflowDetail.id}}">
<input type="submit" id="btnExecuteonly" type="button" onclick="execute()" class="btn btn-danger" data-loading-text="Loading..." value="执行SQL" />
</form>
<form action="/cancel/" method="post" style="display:inline-block;">
{% csrf_token %}
<input type="hidden" name="workflowid" value="{{workflowDetail.id}}">
Expand Down
7 changes: 7 additions & 0 deletions sql/static/user/js/detail.js
Original file line number Diff line number Diff line change
Expand Up @@ -235,4 +235,11 @@ $(document).ready(function () {
$(this).dequeue();
});
});

$("#btnExecuteonly").click(function(){
$(this).button('loading').delay(2500).queue(function() {
$(this).button('reset');
$(this).dequeue();
});
});
});
4 changes: 4 additions & 0 deletions sql/static/user/js/formatter.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ sqlworkflowStatus = {
'abort': '人工终止流程',
'autoreviewing': '自动审核中',
'manreviewing': '等待审核人审核',
'pass': '审核通过',
'executing': '执行中',
'autoreviewwrong': '自动审核不通过',
'exception': '执行有异常'
Expand All @@ -39,6 +40,9 @@ function sqlworkflowStatus_formatter(value) {
else if (value === sqlworkflowStatus.manreviewing) {
return "<span class=\"label label-info\">" + sqlworkflowStatus.manreviewing + "</span>"
}
else if (value === sqlworkflowStatus.pass) {
return "<span class=\"label label-warning\">" + sqlworkflowStatus.pass + "</span>"
}
else if (value === sqlworkflowStatus.executing) {
return "<span class=\"label label-primary\">" + sqlworkflowStatus.executing + "</span>"
}
Expand Down
2 changes: 2 additions & 0 deletions sql/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

url(r'^autoreview/$', views.autoreview, name='autoreview'),
url(r'^detail/(?P<workflowId>[0-9]+)/$', views.detail, name='detail'),
url(r'^passonly/$', views.passonly, name='passonly'),
url(r'^executeonly/$', views.executeonly, name='executeonly'),
url(r'^execute/$', views.execute, name='execute'),
url(r'^cancel/$', views.cancel, name='cancel'),
url(r'^rollback/$', views.rollback, name='rollback'),
Expand Down
137 changes: 128 additions & 9 deletions sql/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,7 @@ def logout(request):

#首页,也是查看所有SQL工单页面,具备翻页功能
def allworkflow(request):
#参数检查
if 'navStatus' in request.GET:
navStatus = request.GET['navStatus']
else:
navStatus = 'all'
if not isinstance(navStatus, str):
raise TypeError('pageNo或navStatus页面传入参数不对')

context = {'currentMenu':'allworkflow','navStatus':navStatus}
context = {'currentMenu':'allworkflow'}
return render(request, 'allWorkflow.html', context)

#提交SQL的页面
Expand Down Expand Up @@ -186,6 +178,133 @@ def detail(request, workflowId):
context = {'currentMenu':'allworkflow', 'workflowDetail':workflowDetail, 'listContent':listContent,'listAllReviewMen':listAllReviewMen}
return render(request, 'detail.html', context)

#审核通过,不执行
def passonly(request):
workflowId = request.POST['workflowid']
if workflowId == '' or workflowId is None:
context = {'errMsg': 'workflowId参数为空.'}
return render(request, 'error.html', context)
workflowId = int(workflowId)
workflowDetail = workflow.objects.get(id=workflowId)
clusterName = workflowDetail.cluster_name
try:
listAllReviewMen = json.loads(workflowDetail.review_man)
except ValueError:
listAllReviewMen = (workflowDetail.review_man, )

#服务器端二次验证,正在执行人工审核动作的当前登录用户必须为审核人. 避免攻击或被接口测试工具强行绕过
loginUser = request.session.get('login_username', False)
if loginUser is None or loginUser not in listAllReviewMen:
context = {'errMsg': '当前登录用户不是审核人,请重新登录.'}
return render(request, 'error.html', context)

#服务器端二次验证,当前工单状态必须为等待人工审核
if workflowDetail.status != Const.workflowStatus['manreviewing']:
context = {'errMsg': '当前工单状态不是等待人工审核中,请刷新当前页面!'}
return render(request, 'error.html', context)

#将流程状态修改为审核通过,并更新reviewok_time字段
workflowDetail.status = Const.workflowStatus['pass']
workflowDetail.reviewok_time = getNow()
workflowDetail.save()

#如果执行完毕了,则根据settings.py里的配置决定是否给提交者和DBA一封邮件提醒.DBA需要知晓审核并执行过的单子
if getattr(settings, 'MAIL_ON_OFF') == "on":
url = _getDetailUrl(request) + str(workflowId) + '/'

#给主、副审核人,申请人,DBA各发一封邮件
engineer = workflowDetail.engineer
reviewMen = workflowDetail.review_man
workflowStatus = workflowDetail.status
workflowName = workflowDetail.workflow_name
objEngineer = users.objects.get(username=engineer)
strTitle = "SQL上线工单审核通过 # " + str(workflowId)
strContent = "发起人:" + engineer + "\n审核人:" + reviewMen + "\n工单地址:" + url + "\n工单名称: " + workflowName +"\n审核结果:" + workflowStatus
mailSender.sendEmail(strTitle, strContent, [objEngineer.email])
mailSender.sendEmail(strTitle, strContent, getattr(settings, 'MAIL_REVIEW_DBA_ADDR'))
for reviewMan in listAllReviewMen:
if reviewMan == "":
continue
objReviewMan = users.objects.get(username=reviewMan)
mailSender.sendEmail(strTitle, strContent, [objReviewMan.email])
else:
#不发邮件
pass

return HttpResponseRedirect('/detail/' + str(workflowId) + '/')

#执行SQL
def executeonly(request):
workflowId = request.POST['workflowid']
if workflowId == '' or workflowId is None:
context = {'errMsg': 'workflowId参数为空.'}
return render(request, 'error.html', context)

workflowId = int(workflowId)
workflowDetail = workflow.objects.get(id=workflowId)
clusterName = workflowDetail.cluster_name
try:
listAllReviewMen = json.loads(workflowDetail.review_man)
except ValueError:
listAllReviewMen = (workflowDetail.review_man, )

#服务器端二次验证,正在执行人工审核动作的当前登录用户必须为审核人或者提交人. 避免攻击或被接口测试工具强行绕过
loginUser = request.session.get('login_username', False)
if loginUser is None or (loginUser not in listAllReviewMen and loginUser != workflowDetail.engineer):
context = {'errMsg': '当前登录用户不是审核人或者提交人,请重新登录.'}
return render(request, 'error.html', context)

#服务器端二次验证,当前工单状态必须为审核通过状态
if workflowDetail.status != Const.workflowStatus['pass']:
context = {'errMsg': '当前工单状态不是审核通过,请刷新当前页面!'}
return render(request, 'error.html', context)

dictConn = getMasterConnStr(clusterName)

#将流程状态修改为执行中,并更新reviewok_time字段
workflowDetail.status = Const.workflowStatus['executing']
workflowDetail.reviewok_time = getNow()
#执行之前重新split并check一遍,更新SHA1缓存;因为如果在执行中,其他进程去做这一步操作的话,会导致inception core dump挂掉
splitReviewResult = inceptionDao.sqlautoReview(workflowDetail.sql_content, workflowDetail.cluster_name, isSplit='yes')
workflowDetail.review_content = json.dumps(splitReviewResult)
workflowDetail.save()

#交给inception先split,再执行
(finalStatus, finalList) = inceptionDao.executeFinal(workflowDetail, dictConn)

#封装成JSON格式存进数据库字段里
strJsonResult = json.dumps(finalList)
workflowDetail.execute_result = strJsonResult
workflowDetail.finish_time = getNow()
workflowDetail.status = finalStatus
workflowDetail.save()

#如果执行完毕了,则根据settings.py里的配置决定是否给提交者和DBA一封邮件提醒.DBA需要知晓审核并执行过的单子
if hasattr(settings, 'MAIL_ON_OFF') == True:
if getattr(settings, 'MAIL_ON_OFF') == "on":
url = _getDetailUrl(request) + str(workflowId) + '/'

#给主、副审核人,申请人,DBA各发一封邮件
engineer = workflowDetail.engineer
reviewMen = workflowDetail.review_man
workflowStatus = workflowDetail.status
workflowName = workflowDetail.workflow_name
objEngineer = users.objects.get(username=engineer)
strTitle = "SQL上线工单执行完毕 # " + str(workflowId)
strContent = "发起人:" + engineer + "\n审核人:" + reviewMen + "\n工单地址:" + url + "\n工单名称: " + workflowName +"\n执行结果:" + workflowStatus
mailSender.sendEmail(strTitle, strContent, [objEngineer.email])
mailSender.sendEmail(strTitle, strContent, getattr(settings, 'MAIL_REVIEW_DBA_ADDR'))
for reviewMan in listAllReviewMen:
if reviewMan == "":
continue
objReviewMan = users.objects.get(username=reviewMan)
mailSender.sendEmail(strTitle, strContent, [objReviewMan.email])
else:
#不发邮件
pass

return HttpResponseRedirect('/detail/' + str(workflowId) + '/')

#人工审核也通过,执行SQL
def execute(request):
workflowId = request.POST['workflowid']
Expand Down
2 changes: 1 addition & 1 deletion sql/workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ def auditworkflow(self, audit_id, audit_status, audit_user, audit_remark):
auditresult.audit_id = audit_id
auditresult.current_audit_user = '-1'
auditresult.current_status = DirectionsOb.workflow_status['audit_success']
auditresult.save(update_fields=['current_audit_user', 'current_status', 'current_status'])
auditresult.save(update_fields=['current_audit_user', 'current_status'])
else:
# 更新主表审核下级审核人和当前审核人
auditresult = WorkflowAudit()
Expand Down

0 comments on commit 19d7db3

Please sign in to comment.