Skip to content

Commit

Permalink
自动审核通过后自动发邮件功能给审核人
Browse files Browse the repository at this point in the history
  • Loading branch information
jly8866 committed Mar 17, 2017
1 parent c6d9987 commit ba3bdd0
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 29 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@
*.log
.idea/
.DS_Store
archer/settings.py.github
archer/settings.py.dev
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ django:1.8<br/>
mysql : 5.6及以上<br/>
linux : 64位linux操作系统均可

### 主要功能
### 主要功能
* 自动审核:<br/>
发起SQL上线,工单提交,由inception自动审核,审核通过后需要由审核人进行人工审核
* 人工审核:<br/>
Expand All @@ -22,6 +22,10 @@ linux : 64位linux操作系统均可
工程师角色(engineer)与审核角色(review_man):工程师可以发起SQL上线,在通过了inception自动审核之后,需要由人工审核点击确认才能执行SQL
* 历史工单管理
* 可通过django admin进行匹配SQL关键字的工单搜索
* 发起SQL上线,可配置的邮件提醒审核人进行审核

### 主要配置文件:
* archer/archer/settings.py

### 安装步骤:
1. 环境准备:<br/>
Expand Down
50 changes: 30 additions & 20 deletions archer/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,23 +77,6 @@

WSGI_APPLICATION = 'archer.wsgi.application'


# Database
# https://docs.djangoproject.com/en/1.8/ref/settings/#databases

#该项目本身的mysql数据库地址
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'archer',
'USER': 'archer_rw',
'PASSWORD': 'archer_rw',
'HOST': '172.21.139.1',
'PORT': '5000'
}
}


# Internationalization
# https://docs.djangoproject.com/en/1.8/topics/i18n/

Expand All @@ -114,14 +97,41 @@
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')

#扩展django admin里users字段用到,指定了sql/models.py里的class users
AUTH_USER_MODEL="sql.users"

###############以下部分需要用户根据自己环境自行修改###################

# Database
# https://docs.djangoproject.com/en/1.8/ref/settings/#databases

#该项目本身的mysql数据库地址
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'archer',
'USER': 'archer_rw',
'PASSWORD': 'archer_rw',
'HOST': '127.0.0.1',
'PORT': '5000'
}
}

#inception组件所在的地址
INCEPTION_HOST = '172.16.5.7'
INCEPTION_HOST = '192.168.1.11'
INCEPTION_PORT = '6100'

#inception要备份数据到该远端mysql地址
INCEPTION_REMOTE_BACKUP_HOST='172.16.5.10'
INCEPTION_REMOTE_BACKUP_HOST='192.168.1.12'
INCEPTION_REMOTE_BACKUP_PORT=5621
INCEPTION_REMOTE_BACKUP_USER='inception'
INCEPTION_REMOTE_BACKUP_PASSWORD='inception'

AUTH_USER_MODEL="sql.users"
#是否开启邮件提醒功能:发起SQL上线后会发送邮件提醒审核人审核,执行完毕会发送给DBA. on是开,off是关,配置为其他值均会被archer认为不开启邮件功能
MAIL_ON_OFF='on'

MAIL_REVIEW_SMTP_SERVER='mail.xxx.com'
MAIL_REVIEW_SMTP_PORT=25
MAIL_REVIEW_FROM_ADDR='[email protected]' #发件人,也是登录SMTP server需要提供的用户名
MAIL_REVIEW_FROM_PASSWORD='' #发件人邮箱密码,如果为空则不需要login SMTP server
MAIL_REVIEW_DBA_ADDR=['[email protected]', '[email protected]'] #DBA地址,执行完毕会发邮件给DBA,以list形式保存
10 changes: 6 additions & 4 deletions sql/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,23 @@ class workflowAdmin(admin.ModelAdmin):
class usersCreationForm(UserCreationForm):
def __init__(self, *args, **kwargs):
super(usersCreationForm, self).__init__(*args, **kwargs)
self.fields['email'].required = True
self.fields['display'].required = True
self.fields['role'].required = True

#编辑用户表单重新定义,继承自UserChangeForm
class usersChangeForm(UserChangeForm):
def __init__(self, *args, **kwargs):
super(usersChangeForm, self).__init__(*args, **kwargs)
self.fields['email'].required = True
self.fields['display'].required = True
self.fields['role'].required = True

class usersAdmin(UserAdmin):
def __init__(self, *args, **kwargs):
super(usersAdmin, self).__init__(*args, **kwargs)
self.list_display = ('id', 'username', 'display', 'role', 'password', 'is_superuser', 'is_staff')
self.search_fields = ('id', 'username', 'display', 'role')
self.list_display = ('id', 'username', 'display', 'role', 'email', 'password', 'is_superuser', 'is_staff')
self.search_fields = ('id', 'username', 'display', 'role', 'email')
self.form = usersChangeForm
self.add_form = usersCreationForm
#以上的属性都可以在django源码的UserAdmin类中找到,我们做以覆盖
Expand All @@ -44,13 +46,13 @@ def changelist_view(self, request, extra_context=None):
#此字段定义UserChangeForm表单中的具体显示内容,并可以分类显示
self.fieldsets = (
(('认证信息'), {'fields': ('username', 'password')}),
(('个人信息'), {'fields': ('display', 'role')}),
(('个人信息'), {'fields': ('display', 'role', 'email')}),
(('权限信息'), {'fields': ('is_active', 'is_staff')}),
#(('Important dates'), {'fields': ('last_login', 'date_joined')}),
)
#此字段定义UserCreationForm表单中的具体显示内容
self.add_fieldsets = ((None, {'classes': ('wide',),
'fields': ('username', 'display', 'role', 'password1', 'password2'),
'fields': ('username', 'display', 'role', 'email', 'password1', 'password2'),
}),
)
return super(usersAdmin, self).changelist_view(request, extra_context)
Expand Down
54 changes: 54 additions & 0 deletions sql/sendmail.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/usr/bin/env python
# -*- coding: UTF-8 -*-


import time
from multiprocessing import Process
import email
from email import encoders
from email.header import Header
from email.mime.text import MIMEText
from email.utils import parseaddr, formataddr
import smtplib

from django.conf import settings

class MailSender(object):
def __init__(self):
try:
self.MAIL_REVIEW_SMTP_SERVER = getattr(settings, 'MAIL_REVIEW_SMTP_SERVER')
self.MAIL_REVIEW_SMTP_PORT = int(getattr(settings, 'MAIL_REVIEW_SMTP_PORT'))
self.MAIL_REVIEW_FROM_ADDR = getattr(settings, 'MAIL_REVIEW_FROM_ADDR')
self.MAIL_REVIEW_FROM_PASSWORD = getattr(settings, 'MAIL_REVIEW_FROM_PASSWORD')
self.MAIL_REVIEW_DBA_ADDR = getattr(settings, 'MAIL_REVIEW_DBA_ADDR')

except AttributeError as a:
print("Error: %s" % a)
except ValueError as v:
print("Error: %s" % v)

def _format_addr(self, s):
name, addr = parseaddr(s)
return formataddr((Header(name, 'utf-8').encode(), addr))

def _send(self, strTitle, strContent, listToAddr):
msg = MIMEText(strContent, 'plain', 'utf-8')
# 收件人地址:

msg['From'] = self._format_addr(self.MAIL_REVIEW_FROM_ADDR)
msg['To'] = self._format_addr(listToAddr)
msg['Subject'] = Header(strTitle, "utf-8").encode()

server = smtplib.SMTP(self.MAIL_REVIEW_SMTP_SERVER, self.MAIL_REVIEW_SMTP_PORT) # SMTP协议默认端口是25
#server.set_debuglevel(1)

#如果提供的密码为空,则不需要登录SMTP server
if self.MAIL_REVIEW_FROM_PASSWORD != '':
server.login(self.MAIL_REVIEW_FROM_ADDR, self.MAIL_REVIEW_FROM_PASSWORD)
sendResult = server.sendmail(self.MAIL_REVIEW_FROM_ADDR, listToAddr, msg.as_string())
server.quit()

#调用方应该调用此方法,采用子进程方式异步阻塞地发送邮件,避免邮件服务挂掉影响archer主服务
def sendEmail(self, strTitle, strContent, listToAddr):
p = Process(target=self._send, args=(strTitle, strContent, listToAddr))
p.start()
50 changes: 46 additions & 4 deletions sql/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,24 @@
import re
import json
import time
import multiprocessing

from django.shortcuts import render, get_object_or_404
from django.http import HttpResponse, HttpResponseRedirect
from django.views.decorators.csrf import csrf_exempt
from django.contrib.auth.decorators import login_required
from django.contrib.auth.hashers import check_password
from django.conf import settings

from .models import users, master_config, workflow
from .dao import Dao
from .inception import InceptionDao
from .const import Const
from .sendmail import MailSender
from .inception import InceptionDao
from .models import users, master_config, workflow

dao = Dao()
inceptionDao = InceptionDao()
mailSender = MailSender()

# Create your views here.
def login(request):
Expand Down Expand Up @@ -179,9 +183,10 @@ def autoreview(request):
break

#存进数据库里
engineer = request.session.get('login_username', False)
newWorkflow = workflow()
newWorkflow.workflow_name = workflowName
newWorkflow.engineer = request.session.get('login_username', False)
newWorkflow.engineer = engineer
newWorkflow.review_man = reviewMan
newWorkflow.create_time = getNow()
newWorkflow.status = workflowStatus
Expand All @@ -191,6 +196,21 @@ def autoreview(request):
newWorkflow.sql_content = sqlContent
newWorkflow.save()
workflowId = newWorkflow.id

#如果进入等待人工审核状态了,则根据settings.py里的配置决定是否给审核人和发起人发一封邮件提醒.
if hasattr(settings, 'MAIL_ON_OFF') == True:
if getattr(settings, 'MAIL_ON_OFF') == "on":
url = _getDetailUrl(request) + str(workflowId) + '/'

#发一封邮件
strTitle = "新的SQL上线工单提醒"
strContent = "发起人:" + engineer + "\n审核人:" + reviewMan + "\n工单地址:" + url
objEngineer = users.objects.get(username=engineer)
objReviewMan = users.objects.get(username=reviewMan)
mailSender.sendEmail(strTitle, strContent, [objEngineer.email, objReviewMan.email])
else:
#不发邮件
pass

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

Expand Down Expand Up @@ -242,7 +262,23 @@ def execute(request):
workflowDetail.execute_result = strJsonResult
workflowDetail.finish_time = getNow()
workflowDetail.status = finalStatus
workflowDetail.save()
workflowDetail.save()

#如果执行完毕了,则根据settings.py里的配置决定是否给DBA一封邮件提醒.
if hasattr(settings, 'MAIL_ON_OFF') == True:
if getattr(settings, 'MAIL_ON_OFF') == "on":
url = _getDetailUrl(request) + str(workflowId) + '/'

#发一封邮件
engineer = workflowDetail.engineer
reviewMan = workflowDetail.review_man
strTitle = "SQL上线工单执行完毕"
strContent = "发起人:" + engineer + "\n审核人:" + reviewMan + "\n工单地址:" + url

mailSender.sendEmail(strTitle, strContent, getattr(settings, 'MAIL_REVIEW_DBA_ADDR'))
else:
#不发邮件
pass

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

Expand Down Expand Up @@ -297,3 +333,9 @@ def getMasterConnStr(clusterName):
#获取当前时间
def getNow():
return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())

#获取当前请求url
def _getDetailUrl(request):
scheme = request.scheme
host = request.META['HTTP_HOST']
return "%s://%s/detail/" % (scheme, host)

0 comments on commit ba3bdd0

Please sign in to comment.