# 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, 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).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) else: XGJVCode.objects.create(mobile=mobile, vcode=code, status=XGJVCode.FAILED, error=result['Message']) raise CustomError(u"发送失败,请重试!") @staticmethod def verify(mobile, vcode): if mobile is None or vcode is None: raise CustomError(u'参数错误!') vc = XGJVCode.objects.filter(mobile=mobile).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'该手机号未发送短信验证码!')