# coding=utf-8
import random
from urllib import request, parse
import re
import math
from django.db import models
from django.utils import timezone
from utils.exceptions import CustomError
from apps.wechat.models import Wechat
class XGJSMS:
def __init__(self):
self.SMS_URL = 'http://sms.zzliaoyuan.com:8088'
self.SMS_PRODUCT_NOTIFY = 30 # 通知短信的代码
self.success_result = {'Code': u'OK', 'Message': u'短信提交成功'}
self.false_result = {'Code': u'FALSE', 'Message': u'短信提交失败'}
def _do_request(self, req):
try:
resp = request.urlopen(req)
except Exception as e:
raise CustomError(u"短信平台错误")
if resp.getcode() != 200:
raise CustomError(u'短信平台错误')
return resp.read()
def send(self, sms_token, sms_sign, mobile, content):
content = u"【%s】%s" % (sms_sign, content)
url = '%s/balance/?token=%s' % (self.SMS_URL, sms_token)
req = request.Request(url)
try:
resp = self._do_request(req)
except CustomError as e:
self.false_result['Message'] = e.get_error_msg()
return self.false_result
p = '([\d]+?)' % self.SMS_PRODUCT_NOTIFY
r = re.search(p, resp.decode('utf-8'))
if r == None:
self.false_result['Message'] = u'短信平台账号余额不足'
return self.false_result
else:
balance = int(r.groups()[0])
fee_count = 1
if len(content) > 70:
fee_count = int(math.ceil(len(content) / 65.0))
if balance < 1 or balance < 1 * fee_count:
self.false_result['Message'] = u'短信平台账号余额不足'
return self.false_result
postDict = {'token': sms_token, 'product': self.SMS_PRODUCT_NOTIFY, 'numbers': mobile, 'content': content.encode('utf-8')}
postData = parse.urlencode(postDict).encode('utf-8')
url = self.SMS_URL + "/submit/"
req = request.Request(url, postData)
req.add_header('content-Type', "application/x-www-form-urlencoded; charset=UTF-8")
try:
resp = self._do_request(req)
except CustomError as e:
self.false_result['Message'] = e.get_error_msg()
return self.false_result
r = re.search("([\s\S]+?)", resp.decode('utf-8'))
if r != None:
self.false_result['Message'] = u'短信平台返回错误[%s]' % r.groups()[0]
return self.false_result
return self.success_result
class XGJVCode(models.Model):
SUCCESSED = 0
FAILED = 1
STATUS_CHOICES = (
(SUCCESSED, u'发送成功'),
(FAILED, u'发送失败'),
)
vcode = models.CharField(verbose_name=u'验证码', max_length=4)
mobile = models.CharField(verbose_name=u'手机号', max_length=11)
create_time = models.DateTimeField(verbose_name=u'时间', auto_now_add=True)
status = models.PositiveSmallIntegerField(choices=STATUS_CHOICES, verbose_name=u"状态", editable=False, default=SUCCESSED)
error = models.CharField(verbose_name=u"错误原因", null=True, max_length=500)
class Meta:
db_table = "xgj_vcode"
verbose_name = u"销管佳短信验证码"
ordering = ['-id']
default_permissions = ()
@staticmethod
def send(mobile, appid, type, captcha_key=None, captcha=None):
# 参数说明:
# token:
# numbers: 手机号 以半角逗号分隔多个手机号码
# content: 短信内容,中文使用utf-8编码
# product:产品代码 只够买一个产品时可以省略该参数
# schedule:定时发送时间 非必填
if mobile == '' or not mobile:
raise CustomError(u"无效的手机号!")
app = Wechat.objects.filter(appid=appid).first()
if not app:
raise CustomError(u'参数无效')
vcs = XGJVCode.objects.filter(mobile=mobile, type=type).order_by('-id')
if vcs.count() > 0:
vc = vcs[0]
if (timezone.now() - vc.create_time).seconds < 60:
raise CustomError(u'获取太频繁,请稍后再试!')
code = str(random.randint(1234, 9999))
str_code = u'短信验证码为:' + code + u'。为了保障您的账户安全,请勿泄露给他人,有效期为10分钟。'
sms = XGJSMS()
result = sms.send(app.sms_token, app.sms_sign, mobile, str_code)
if result['Code'] == 'OK':
XGJVCode.objects.create(mobile=mobile, vcode=code, type=type)
else:
XGJVCode.objects.create(mobile=mobile, vcode=code, type=type, status=XGJVCode.FAILED, error=result['Message'])
raise CustomError(u"发送失败,请重试!")
@staticmethod
def verify(mobile, vcode, type):
if mobile is None or vcode is None:
raise CustomError(u'参数错误!')
vc = XGJVCode.objects.filter(mobile=mobile, type=type).order_by('-id').first()
if vc:
if vc.vcode == vcode:
if (timezone.now() - vc.create_time).seconds > 600:
raise CustomError(u'验证码已过期!')
else:
raise CustomError(u'验证码错误!')
else:
raise CustomError(u'该手机号未发送短信验证码!')