Browse Source

Merge branch 'dev' into cloud_storage_dev

lang 3 years ago
parent
commit
d2ab99b2d4

+ 91 - 1
AdminController/LogManagementController.py

@@ -9,12 +9,14 @@ import uuid
 import boto3
 import threading
 import logging
+
+import requests
 from boto3.session import Session
 from django.http import JsonResponse, HttpResponseRedirect, HttpResponse
 from django.views.generic.base import View
 
 from Controller.CheckUserData import date_handler
-from Model.models import Device_Info, Role, MenuModel, RequestRecordModel
+from Model.models import Device_Info, Role, MenuModel, RequestRecordModel, iotdeviceInfoModel
 from Object.ResponseObject import ResponseObject
 from Object.TokenObject import TokenObject
 from Object.UidTokenObject import UidTokenObject
@@ -49,6 +51,12 @@ class LogManagementView(View):
             userID = tko.userID
             if operation == 'getRequestList':
                 return self.getRequestList(request_dict, response)
+            elif operation == 'getDeviceIotInfoList':
+                return self.getDeviceIotInfoList(request_dict, response)
+            elif operation == 'requestPublishMqtt':
+                return self.requestPublishMqtt(request_dict, response)
+            else:
+                return response.json(404)
 
     def getRequestList(self, request_dict, response):
         pageNo = request_dict.get('pageNo', None)
@@ -96,3 +104,85 @@ class LogManagementView(View):
         except Exception as e:
             print(e)
             return response.json(500, repr(e))
+
+    def getDeviceIotInfoList(self, request_dict, response):
+        serial_number = request_dict.get('serial_number', None)
+        uid = request_dict.get('uid', None)
+        pageNo = request_dict.get('pageNo', None)
+        pageSize = request_dict.get('pageSize', None)
+
+        if not all([pageNo, pageSize]):
+            return response.json(444)
+
+        page = int(pageNo)
+        line = int(pageSize)
+        try:
+            if serial_number or uid:
+                if serial_number:
+                    iot_device_info_qs = iotdeviceInfoModel.objects.filter(serial_number__contains=serial_number)
+                if uid:
+                    iot_device_info_qs = iotdeviceInfoModel.objects.filter(uid__contains=uid)
+                if not iot_device_info_qs.exists():
+                    return response.json(0)
+                total = len(iot_device_info_qs)
+                iot_device_info_qs = iot_device_info_qs.values('serial_number', 'uid', 'thing_name', 'thing_groups',
+                                                               'add_time', 'update_time')[(page - 1) * line:page * line]
+            else:
+                total = iotdeviceInfoModel.objects.filter().count()
+                iot_device_info_qs = iotdeviceInfoModel.objects.filter().values('serial_number', 'uid', 'thing_name',
+                                                                                'thing_groups', 'add_time', 'update_time')[(page - 1) * line:page * line]
+
+            iot_device_info_list = CommonService.qs_to_list(iot_device_info_qs)
+            # 获取序列号的uid
+            for iot_device_info in iot_device_info_list:
+                if not iot_device_info['uid']:
+                    device_info_qs = Device_Info.objects.filter(serial_number__contains=iot_device_info['serial_number']).values('UID')
+                    if device_info_qs.exists():
+                        iot_device_info['uid'] = device_info_qs[0]['UID']
+            return response.json(0, {'list': iot_device_info_list, 'total': total})
+        except Exception as e:
+            print(e)
+            return response.json(500, repr(e))
+
+    def requestPublishMqtt(self, request_dict, response):
+        # 通用发布主题通知
+        uid = request_dict.get('uid', None)
+        msg = request_dict.get('msg', None)
+        thing_name = request_dict.get('thing_name', None)
+        topic_name = request_dict.get('topic_name', None)
+        if not all([uid, msg, thing_name, topic_name]):
+            return response.json(444)
+
+        try:
+            # 设备没被添加不发送
+            device_info_qs = Device_Info.objects.filter(UID=uid).values('UID', 'serial_number')
+            if not device_info_qs.exists():
+                return response.json(10043)
+            # 获取数据组织将要请求的url
+            iot = iotdeviceInfoModel.objects.filter(thing_name=thing_name).values('endpoint', 'token_iot_number')
+            if not iot.exists():
+                return response.json(10043)
+            endpoint = iot[0]['endpoint']
+            Token = iot[0]['token_iot_number']
+
+            # api doc: https://docs.aws.amazon.com/zh_cn/iot/latest/developerguide/http.html
+            # url: https://IoT_data_endpoint/topics/url_encoded_topic_name?qos=1
+            # post请求url发布MQTT消息
+            url = 'https://{}/topics/{}'.format(endpoint, topic_name)
+            authorizer_name = 'Ansjer_Iot_Auth'
+            signature = CommonService.rsa_sign(Token)  # Token签名
+            headers = {'x-amz-customauthorizer-name': authorizer_name, 'Token': Token,
+                       'x-amz-customauthorizer-signature': signature}
+            msg = eval(msg)
+            r = requests.post(url=url, headers=headers, json=msg, timeout=2)
+            if r.status_code == 200:
+                res = r.json()
+                if res['message'] == 'OK':
+                    return response.json(0)
+                return response.json(10044)
+            else:
+                # print('发布失败')
+                return response.json(10044)
+        except Exception as e:
+            # print(e)
+            return response.json(500, repr(e))

+ 17 - 0
AdminController/UserManageController.py

@@ -311,6 +311,8 @@ class UserManagement(View):
             return self.getAppDataList(request_dict, response)
         elif operation == 'replyFeedBack':
             return self.replyFeedBack(request_dict, response)
+        elif operation == 'sendSysMsgToUser':
+            return self.sendSysMsgToUser(request_dict, response)
         else:
             tko = TokenObject(request.META.get('HTTP_AUTHORIZATION'), returntpye='pc')
             if tko.code != 0:
@@ -558,6 +560,21 @@ class UserManagement(View):
             print(e)
             return response.json(500, repr(e))
 
+    def sendSysMsgToUser(self, request_dict, response):
+        userID = request_dict.get('userID', None)
+        msg = request_dict.get('msg', None)
+
+        if not all([userID, msg]):
+            return response.json(444)
+
+        try:
+            nowTime = int(time.time())
+            SysMsgModel.objects.create(userID_id=userID, msg=msg, addTime=nowTime, updTime=nowTime)
+            return response.json(0)
+        except Exception as e:
+            print(e)
+            return response.json(500, repr(e))
+
     def deleteFeedBack(self, request_dict, response):
         feedBackID = request_dict.get('feedBackID', None)
         if not feedBackID:

+ 127 - 1
AdminController/VersionManagementController.py

@@ -2,10 +2,12 @@
 # -*- coding: utf-8 -*-
 import os
 import hashlib
+import time
+
 from django.views.generic.base import View
 
 from Ansjer.config import BASE_DIR
-from Model.models import Equipment_Version
+from Model.models import Equipment_Version, App_Info, AppSetModel
 from Object.TokenObject import TokenObject
 from Object.ResponseObject import ResponseObject
 from Service.CommonService import CommonService
@@ -41,6 +43,16 @@ class VersionManagement(View):
                 return self.editVersionInformation(request_dict, response)
             elif operation == 'deleteEquipmentVersion':
                 return self.deleteEquipmentVersion(request_dict, response)
+            elif operation == 'getAppVersionList':
+                return self.getAppVersionList(request_dict, response)
+            elif operation == 'addOrEditAppInfo':
+                return self.addOrEditAppInfo(request_dict, response)
+            elif operation == 'deleteAppVersion':
+                return self.deleteAppVersion(request_dict, response)
+            elif operation == 'getAppSet':
+                return self.getAppSet(request_dict, response)
+            elif operation == 'editAppSet':
+                return self.editAppSet(request_dict, response)
             else:
                 return response.json(404)
 
@@ -178,3 +190,117 @@ class VersionManagement(View):
             print(e)
             return response.json(500, repr(e))
 
+    def getAppVersionList(self, request_dict, response):
+        app_type = request_dict.get('app_type', None)
+        appName = request_dict.get('appName', None)
+        version = request_dict.get('version', None)
+        pageNo = request_dict.get('pageNo', None)
+        pageSize = request_dict.get('pageSize', None)
+
+        if not all([pageNo, pageSize]):
+            return response.json(444)
+
+        page = int(pageNo)
+        line = int(pageSize)
+
+        try:
+            app_info_qs = App_Info.objects.filter()
+            if app_type:
+                if app_type == 'IOS':
+                    app_type = 1
+                elif app_type == '安卓':
+                    app_type = 2
+                else:
+                    app_type = 3
+                app_info_qs = app_info_qs.filter(app_type=app_type)
+            if appName:
+                app_info_qs = app_info_qs.filter(appName__contains=appName)
+            if version:
+                app_info_qs = app_info_qs.filter(version__contains=version)
+
+            total = app_info_qs.count()
+            app_info_qs = app_info_qs.values()[(page - 1) * line:page * line]
+            app_info_list = CommonService.qs_to_list(app_info_qs)
+            return response.json(0, {'list': app_info_list, 'total': total})
+        except Exception as e:
+            print(e)
+            return response.json(500, repr(e))
+
+    def addOrEditAppInfo(self, request_dict, response):
+        id = request_dict.get('id', None)
+        appName = request_dict.get('appName', '')
+        appBundleId = request_dict.get('appBundleId', '')
+        bundleVersion = request_dict.get('bundleVersion', '')
+        newAppversion = request_dict.get('newAppversion', '')
+        minAppversion = request_dict.get('minAppversion', '')
+        content = request_dict.get('content', '')
+        app_type = request_dict.get('app_type', '')
+        downloadLink = request_dict.get('downloadLink', '')
+
+        try:
+            app_type = int(app_type)
+            data_dict = {'appName': appName, 'appBundleId': appBundleId, 'bundleVersion': bundleVersion,
+                         'newAppversion': newAppversion, 'minAppversion': minAppversion, 'content': content,
+                         'app_type': app_type, 'downloadLink': downloadLink}
+            if not id:      # 添加
+                App_Info.objects.create(**data_dict)
+            else:           # 编辑
+                app_info_qs = App_Info.objects.filter(id=id)
+                if not app_info_qs.exists():
+                    return response.json(173)
+                app_info_qs.update(**data_dict)
+            return response.json(0)
+        except Exception as e:
+            print(e)
+            return response.json(500, repr(e))
+
+    def deleteAppVersion(self, request_dict, response):
+        appBundleId = request_dict.get('appBundleId', None)
+
+        if not appBundleId:
+            return response.json(444)
+
+        try:
+            App_Info.objects.filter(appBundleId=appBundleId).delete()
+            AppSetModel.objects.filter(appBundleId=appBundleId).delete()
+            return response.json(0)
+        except Exception as e:
+            print(e)
+            return response.json(500, repr(e))
+
+    def getAppSet(self, request_dict, response):
+        appBundleId = request_dict.get('appBundleId', None)
+
+        if not appBundleId:
+            return response.json(444)
+
+        try:
+            app_set_qs = AppSetModel.objects.filter(appBundleId=appBundleId).values('content')
+            if app_set_qs.exists():
+                content = app_set_qs[0]['content']
+                return response.json(0, {'content': content})
+            else:
+                nowTime = int(time.time())
+                AppSetModel.objects.create(
+                    appBundleId=appBundleId,
+                    addTime=nowTime,
+                    updTime=nowTime
+                )
+                return response.json(0)
+        except Exception as e:
+            print(e)
+            return response.json(500, repr(e))
+
+    def editAppSet(self, request_dict, response):
+        appBundleId = request_dict.get('appBundleId', None)
+        content = request_dict.get('content', None)
+
+        if not all([appBundleId, content]):
+            return response.json(444)
+
+        try:
+            AppSetModel.objects.filter(appBundleId=appBundleId).update(content=content)
+            return response.json(0)
+        except Exception as e:
+            print(e)
+            return response.json(500, repr(e))

+ 4 - 1
Ansjer/cn_config/config_formal.py

@@ -125,7 +125,10 @@ TUTK_PUSH_DOMAIN = 'http://push.iotcplatform.com/tpns'
 
 # aws api key
 AWS_ARN_S3 = 'arn:aws-cn:s3'
-AVATAR_BUCKET = 'avatar-cn'
 REGION_NAME = 'cn-northwest-1'
 ACCESS_KEY_ID = 'AKIA2MMWBR4DSFG67DTG'
 SECRET_ACCESS_KEY = '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'
+
+# 存储桶名
+AVATAR_BUCKET = 'avatar-cn'         # 头像存储桶
+LOG_BUCKET = 'ansjer-statres'       # 日志存储桶

+ 4 - 1
Ansjer/cn_config/config_test.py

@@ -137,7 +137,10 @@ TUTK_PUSH_DOMAIN = 'http://push.iotcplatform.com/tpns'
 
 # aws api key
 AWS_ARN_S3 = 'arn:aws-cn:s3'
-AVATAR_BUCKET = 'avatar-cn'
 REGION_NAME = 'cn-northwest-1'
 ACCESS_KEY_ID = 'AKIA2MMWBR4DSFG67DTG'
 SECRET_ACCESS_KEY = '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'
+
+# 存储桶名
+AVATAR_BUCKET = 'avatar-cn'         # 头像存储桶
+LOG_BUCKET = 'ansjer-statres'       # 日志存储桶

+ 4 - 1
Ansjer/local_config/config_local.py

@@ -58,7 +58,10 @@ TUTK_PUSH_DOMAIN = 'http://push.iotcplatform.com/tpns'
 
 # aws api key
 AWS_ARN_S3 = 'arn:aws-cn:s3'
-AVATAR_BUCKET = 'avatar-cn'
 REGION_NAME = 'cn-northwest-1'
 ACCESS_KEY_ID = 'AKIA2MMWBR4DSFG67DTG'
 SECRET_ACCESS_KEY = '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'
+
+# 存储桶名
+AVATAR_BUCKET = 'avatar-cn'         # 头像存储桶
+LOG_BUCKET = 'ansjer-statres'       # 日志存储桶

+ 4 - 1
Ansjer/us_config/config_formal.py

@@ -125,7 +125,10 @@ TUTK_PUSH_DOMAIN = 'http://push.iotcplatform.com/tpns'
 
 # aws api key
 AWS_ARN_S3 = 'arn:aws:s3'
-AVATAR_BUCKET = 'avatar-us'
 REGION_NAME = 'us-east-1'
 ACCESS_KEY_ID = 'AKIA2E67UIMD45Y3HL53'
 SECRET_ACCESS_KEY = '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'
+
+# 存储桶名
+AVATAR_BUCKET = 'avatar-us'         # 头像存储桶
+LOG_BUCKET = 'ansjer-statres'       # 日志存储桶

+ 4 - 1
Ansjer/us_config/config_test.py

@@ -136,7 +136,10 @@ TUTK_PUSH_DOMAIN = 'http://push.iotcplatform.com/tpns'
 
 # aws api key
 AWS_ARN_S3 = 'arn:aws:s3'
-AVATAR_BUCKET = 'avatar-us'
 REGION_NAME = 'us-east-1'
 ACCESS_KEY_ID = 'AKIA2E67UIMD45Y3HL53'
 SECRET_ACCESS_KEY = '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'
+
+# 存储桶名
+AVATAR_BUCKET = 'avatar-us'         # 头像存储桶
+LOG_BUCKET = 'ansjer-statres'       # 日志存储桶

+ 3 - 2
Controller/AppLogController.py

@@ -7,7 +7,8 @@ import botocore
 import oss2
 from django.views.generic.base import View
 
-from Ansjer.config import OSS_STS_ACCESS_KEY, OSS_STS_ACCESS_SECRET, REGION_NAME, ACCESS_KEY_ID, SECRET_ACCESS_KEY
+from Ansjer.config import OSS_STS_ACCESS_KEY, OSS_STS_ACCESS_SECRET, REGION_NAME, ACCESS_KEY_ID, SECRET_ACCESS_KEY, \
+    LOG_BUCKET
 from Model.models import AppLogModel
 from Object.ResponseObject import ResponseObject
 from Object.TokenObject import TokenObject
@@ -66,7 +67,7 @@ class AppLogView(View):
         response_url = aws_s3_client.generate_presigned_url(
             ClientMethod='put_object',
             Params={
-                'Bucket': 'ansjer-statres',
+                'Bucket': LOG_BUCKET,
                 'Key': obj
             },
             ExpiresIn=3600

+ 8 - 1
Controller/AppSetController.py

@@ -12,7 +12,7 @@
 @Contact: chanjunkai@163.com
 """
 from Ansjer.config import SERVER_TYPE
-from Model.models import AppSetModel
+from Model.models import AppSetModel,PromotionRuleModel
 from django.views.generic.base import View
 from Object.RedisObject import RedisObject
 from Object.TokenObject import TokenObject
@@ -67,6 +67,13 @@ class AppSetView(View):
             if not app_set_qs[0]['content']:
                 return response.json(0)
             dict_json = json.loads(app_set_qs[0]['content'])
+            #加入促销弹窗
+            promotion = PromotionRuleModel.objects.filter(status=1).values('startTime','endTime','popups')
+            if promotion.exists():
+                dict_json['popupsStartTime'] = promotion[0]['startTime']
+                dict_json['popupsEndTime'] = promotion[0]['endTime']
+                dict_json['popupsContent'] = json.loads(promotion[0]['popups']).get(lang,'')
+                dict_json['nowTime'] = int(time.time())
             if 'editionUpgrading' in dict_json:
                 if dict_json['editionUpgrading'] == 1:
                     if lang == 'cn':

+ 95 - 19
Controller/CloudStorage.py

@@ -40,7 +40,7 @@ from Ansjer.config import OSS_STS_ACCESS_KEY, OSS_STS_ACCESS_SECRET, OSS_ROLE_AR
 from Controller.CheckUserData import DataValid
 from Model.models import Device_Info, Order_Model, Store_Meal, VodHlsModel, OssCrdModel, UID_Bucket, StsCrdModel, \
     ExperienceContextModel, Pay_Type, CDKcontextModel, Device_User, SysMassModel, SysMsgModel, UidPushModel, \
-    Unused_Uid_Meal, UIDMainUser, UserModel
+    Unused_Uid_Meal, UIDMainUser, UserModel, PromotionRuleModel
 from Object.AWS.S3Email import S3Email
 from Object.AliPayObject import AliPayObject
 from Object.AliSmsObject import AliSmsObject
@@ -52,7 +52,7 @@ from Service.CommonService import CommonService
 from Object.m3u8generate import PlaylistGenerator
 from Object.WechatPayObject import WechatPayObject
 from django.db.models import Q, F, Count
-
+from Ansjer.config import SERVER_TYPE
 from Service.ModelService import ModelService
 
 # SERVER_DOMAIN = 'http://test.dvema.com/'
@@ -232,13 +232,32 @@ class CloudStorageView(View):
 
                 res_c = {'area': area, 'items': items_list}
                 res.append(res_c)
+            #是否促销
+            nowTime = int(time.time())
+            promotion = PromotionRuleModel.objects.filter(status=1, startTime__lte=nowTime,
+                                                          endTime__gte=nowTime).values('id','ruleConfig','ruleName',
+                                                                                       'startTime','endTime','ruleDesc')
+            if promotion.exists():
+                promotion = {
+                    'is_promotion': 1,
+                    'promotionStartTime': promotion[0]['startTime'],
+                    'promotionEndTime': promotion[0]['endTime'],
+                    'promotionName': json.loads(promotion[0]['ruleName']).get(lang, ''),
+                    'promotionDesc': json.loads(promotion[0]['ruleDesc']).get(lang, ''),
+                    'nowTime':int(time.time())
+                }
+            else:
+                promotion = {
+                    'is_promotion': 0
+                }
             result = {
                 'meals': res,
                 'extra':
                     {
                         'cloud_banner': SERVER_DOMAIN+'web/images/cloud_cn_banner.png',
                         'cloud_en_baner': SERVER_DOMAIN_SSL+'web/images/cloud_en_banner.png'
-                    }
+                    },
+                'promotion':promotion
             }
             return response.json(0, result)
         else:
@@ -418,6 +437,7 @@ class CloudStorageView(View):
         vh_qs = VodHlsModel.objects.filter \
             (uid=uid, channel=channel, endTime__gte=now_time, time__range=(startTime, endTime)). \
             values("id", "time", "sec", "bucket__bucket", "fg", "bucket__endpoint", "bucket__region", "bucket__mold")
+
         vod_play_list = []
         if not vh_qs.exists():
             return response.json(0, vod_play_list)
@@ -726,12 +746,17 @@ class CloudStorageView(View):
             data.pop('sign')
             orderID = data['out_trade_no']
 
-            order_qs = Order_Model.objects.filter(orderID=orderID, status=0)
+            # redis加锁,防止订单重复
+            redisObj = RedisObject()
+            isLock = redisObj.CONN.setnx(orderID + 'do_notify', 1)
+            redisObj.CONN.expire(orderID + 'do_notify', 60)
+            if not isLock:
+                return response.json(5)
 
+            order_qs = Order_Model.objects.filter(orderID=orderID, status=0)
             aliPayObj = AliPayObject()
             alipay = aliPayObj.conf()
             success = alipay.verify(data, signature)
-
             if success and data["trade_status"] in ("TRADE_SUCCESS", "TRADE_FINISHED"):
                 print("trade succeed")
 
@@ -754,6 +779,14 @@ class CloudStorageView(View):
                 expire = smqs[0]['expire']
                 if order_list[0]['isSelectDiscounts'] == 1:
                     expire = smqs[0]['expire'] * 2
+                # 是否有促销
+                nowTime = int(time.time())
+                promotion = PromotionRuleModel.objects.filter(status=1, startTime__lte=nowTime,
+                                                              endTime__gte=nowTime).values('id','ruleConfig')
+                promotion_rule_id = ''
+                if promotion.exists():
+                    promotion_rule_id = promotion[0]['id']
+                    expire = expire * 2
                 with transaction.atomic():
                     if ubqs.exists():
                         ubq = ubqs[0]
@@ -765,6 +798,8 @@ class CloudStorageView(View):
                         else:     #已过期或者不相同的套餐加入未使用的关联套餐表
                             has_unused = Unused_Uid_Meal.objects.filter(uid=UID, bucket_id=bucketId).values("id")
                             nums = 2 if order_list[0]['isSelectDiscounts'] == 1 else 1
+                            if promotion.exists():
+                                nums = nums + 1
                             if has_unused.exists():
                                 Unused_Uid_Meal.objects.filter(id=has_unused[0]['id']).update(num=F('num') + nums)
                             else:
@@ -795,18 +830,20 @@ class CloudStorageView(View):
                     #     }
                     #     UIDMainUser.objects.create(**uid_main_dict)
 
-                    order_qs.update(status=1, updTime=nowTime, uid_bucket_id=uid_bucket_id)
+                    order_qs.update(status=1, updTime=nowTime, uid_bucket_id=uid_bucket_id, promotion_rule_id=promotion_rule_id)
                     datetime = time.strftime("%Y-%m-%d", time.localtime())
                     sys_msg_text_list = ['温馨提示:尊敬的客户,您的'+UID+'设备在'+datetime+'已成功购买云存套餐', 'Dear customer,you already subscribed the cloud storage package successfully for device ' + UID + ' on '+ time.strftime("%b %dth,%Y", time.localtime())]
                     self.do_vod_msg_Notice(UID, channel, userid, lang, sys_msg_text_list, 'SMS_219738485')
                     red_url = "{SERVER_DOMAIN_SSL}web/paid2/success.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
                     if lang != 'cn':
                         red_url = "{SERVER_DOMAIN_SSL}web/paid2/en_success.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
+                    redisObj.del_data(key=orderID + 'do_notify')
                     return HttpResponseRedirect(red_url)
             return response.json(0, signature)
         except Exception as e:
             if order_qs:
-                order_qs.update(status=10)
+                order_qs.update(status=10, promotion_rule_id=promotion_rule_id)
+            redisObj.del_data(key=orderID + 'do_notify')
             red_url = "{SERVER_DOMAIN_SSL}web/paid2/fail.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
             if lang != 'cn':
                 red_url = "{SERVER_DOMAIN_SSL}web/paid2/en_fail.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
@@ -817,6 +854,12 @@ class CloudStorageView(View):
         PayerID = request_dict.get('PayerID', None)
         orderID = request_dict.get('orderID', None)
         lang = request_dict.get('lang', 'en')
+        # redis加锁,防止订单重复
+        redisObj = RedisObject()
+        isLock = redisObj.CONN.setnx(orderID + 'do_notify', 1)
+        redisObj.CONN.expire(orderID + 'do_notify', 60)
+        if not isLock:
+            return response.json(5)
         try:
             order_qs = Order_Model.objects.filter(orderID=orderID, status=0)
 
@@ -837,6 +880,7 @@ class CloudStorageView(View):
                 red_url = "{SERVER_DOMAIN_SSL}web/paid2/fail.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
                 if lang != 'cn':
                     red_url = "{SERVER_DOMAIN_SSL}web/paid2/en_fail.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
+                redisObj.del_data(key=orderID + 'do_notify')
                 return HttpResponseRedirect(red_url)
             print("Payment execute successfully")
 
@@ -861,6 +905,14 @@ class CloudStorageView(View):
 
             if order_list[0]['isSelectDiscounts'] == 1:
                 expire = smqs[0]['expire'] * 2
+            # 是否有促销
+            nowTime = int(time.time())
+            promotion = PromotionRuleModel.objects.filter(status=1, startTime__lte=nowTime,
+                                                          endTime__gte=nowTime).values('id','ruleConfig')
+            promotion_rule_id = ''
+            if promotion.exists():
+                promotion_rule_id = promotion[0]['id']
+                expire = expire * 2
             with transaction.atomic():
                 if ubqs.exists():
                     ubq = ubqs[0]
@@ -872,6 +924,8 @@ class CloudStorageView(View):
                     else:     #已过期或者不相同的套餐加入未使用的关联套餐表
                         has_unused = Unused_Uid_Meal.objects.filter(uid=UID, bucket_id=bucketId).values("id")
                         nums = 2 if order_list[0]['isSelectDiscounts'] == 1 else 1
+                        if promotion.exists():
+                            nums = nums + 1
                         if has_unused.exists():
                             Unused_Uid_Meal.objects.filter(id=has_unused[0]['id']).update(num=F('num') + nums)
                         else:
@@ -902,7 +956,7 @@ class CloudStorageView(View):
                 #     }
                 #     UIDMainUser.objects.create(**uid_main_dict)
 
-                order_qs.update(status=1, updTime=nowTime, uid_bucket_id=uid_bucket_id)
+                order_qs.update(status=1, updTime=nowTime, uid_bucket_id=uid_bucket_id, promotion_rule_id=promotion_rule_id)
                 datetime = time.strftime("%Y-%m-%d", time.localtime())
                 sys_msg_text_list = ['温馨提示:尊敬的客户,您的' + UID + '设备在' + datetime + '已成功购买云存套餐',
                                      'Dear customer,you already subscribed the cloud storage package successfully for device ' + UID + ' on ' + time.strftime(
@@ -914,15 +968,16 @@ class CloudStorageView(View):
                 red_url = "{SERVER_DOMAIN_SSL}web/paid2/success.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
                 if lang != 'cn':
                     red_url = "{SERVER_DOMAIN_SSL}web/paid2/en_success.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
-
+                redisObj.del_data(key=orderID + 'do_notify')
                 return HttpResponseRedirect(red_url)
         except Exception as e:
             print(repr(e))
             if order_qs:
-                order_qs.update(status=10)
+                order_qs.update(status=10, promotion_rule_id=promotion_rule_id)
             red_url = "{SERVER_DOMAIN_SSL}web/paid2/fail.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
             if lang != 'cn':
                 red_url = "{SERVER_DOMAIN_SSL}web/paid2/en_fail.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
+            redisObj.del_data(key=orderID + 'do_notify')
             return HttpResponseRedirect(red_url)
 
     def do_pay_by_wechat_callback(self, request, response):  # 微信支付回调
@@ -938,17 +993,25 @@ class CloudStorageView(View):
             out_trade_no = data['out_trade_no']  # 商户订单号
             order_qs = Order_Model.objects.filter(orderID=out_trade_no, status=0)
             if trade_status == "SUCCESS":
-                logger.info('微信回调返回值 进来了。')
                 check_sign = pay.get_notifypay(data)
                 if not check_sign:
                     return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL', 'return_msg': '签名失败'}))
-                logger.info('签名成功')
                 orderID = out_trade_no
-                print("进来了,微信支付成功回调")
+
+                #redis加锁,防止订单重复
+                redisObj = RedisObject()
+                isLock = redisObj.CONN.setnx(orderID + 'do_notify', 1)
+                redisObj.CONN.expire(orderID + 'do_notify', 60)
+                if not isLock:
+                    return response.json(5)
 
                 nowTime = int(time.time())
                 order_list = order_qs.values("UID", "channel", "commodity_code", "rank", "isSelectDiscounts",
-                                             "userID__userID", "userID__username")
+                                             "userID__userID", "userID__username","status")
+
+                logger.info(order_list[0]['UID'])
+                logger.info(orderID)
+
                 userid = order_list[0]['userID__userID']
                 username = order_list[0]['userID__username']
                 UID = order_list[0]['UID']
@@ -965,6 +1028,13 @@ class CloudStorageView(View):
                 expire = smqs[0]['expire']
                 if order_list[0]['isSelectDiscounts'] == 1:
                     expire = smqs[0]['expire'] * 2
+                #是否有促销
+                nowTime = int(time.time())
+                promotion = PromotionRuleModel.objects.filter(status=1,startTime__lte=nowTime,endTime__gte=nowTime).values('id','ruleConfig')
+                promotion_rule_id = ''
+                if promotion.exists():
+                    promotion_rule_id = promotion[0]['id']
+                    expire = expire * 2
                 with transaction.atomic():
                     if ubqs.exists():
                         ubq = ubqs[0]
@@ -976,6 +1046,8 @@ class CloudStorageView(View):
                         else:     #已过期或者不相同的套餐加入未使用的关联套餐表
                             has_unused = Unused_Uid_Meal.objects.filter(uid=UID, bucket_id=bucketId).values("id")
                             nums = 2 if order_list[0]['isSelectDiscounts'] == 1 else 1
+                            if promotion.exists():
+                                nums = nums + 1
                             if has_unused.exists():
                                 Unused_Uid_Meal.objects.filter(id=has_unused[0]['id']).update(num=F('num') + nums)
                             else:
@@ -1006,20 +1078,24 @@ class CloudStorageView(View):
                     #     }
                     #     UIDMainUser.objects.create(**uid_main_dict)
 
-                    order_qs.update(status=1, updTime=nowTime, uid_bucket_id=uid_bucket_id)
+                    order_qs.update(status=1, updTime=nowTime, uid_bucket_id=uid_bucket_id, promotion_rule_id=promotion_rule_id)
                     datetime = time.strftime("%Y-%m-%d", time.localtime())
                     sys_msg_text_list = ['温馨提示:尊敬的客户,您的' + UID + '设备在' + datetime + '已成功购买云存套餐',
                                          'Dear customer,you already subscribed the cloud storage package successfully for device ' + UID + ' on ' + time.strftime(
                                              "%b %dth,%Y", time.localtime())]
-
                     self.do_vod_msg_Notice(UID, channel, userid, lang, sys_msg_text_list, 'SMS_219738485')
-                    return HttpResponse(pay.xml_to_dict({'return_code': 'SUCCESS', 'return_msg': 'OK'}))
+                    redisObj.del_data(key=orderID + 'do_notify')
+                    return HttpResponse("<xml>\
+                      <return_code><![CDATA[SUCCESS]]></return_code>\
+                      <return_msg><![CDATA[OK]]></return_msg>\
+                    </xml>")
             else:
-                order_qs.update(status=10)
+                order_qs.update(status=10, promotion_rule_id=promotion_rule_id)
             return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL', 'return_msg': '参数格式校验错误'}))
         except Exception as e:
             if order_qs:
-                order_qs.update(status=10)
+                order_qs.update(status=10, promotion_rule_id=promotion_rule_id)
+            redisObj.del_data(key=orderID + 'do_notify')
             return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL', 'return_msg': repr(e)}))
 
     def do_create_pay_order(self, request_dict, userID, ip, response):  # 创建支付订单

+ 236 - 37
Controller/EquipmentManagerV3.py

@@ -50,6 +50,8 @@ class EquipmentManagerV3(View):
         # 手机端添加设备,查询,修改
         if operation == 'add':
             return self.do_add(userID, request_dict, response, request)
+        if operation == 'batchAdd':
+            return self.do_batch_add(userID, request_dict, response, request)
         elif operation == 'query':
             return self.do_query(userID, request_dict, response)
         elif operation == 'modify':
@@ -257,6 +259,213 @@ class EquipmentManagerV3(View):
                 }
             return response.json(0, res)
 
+    def do_batch_add(self, userID, request_dict, response, request):
+        # 批量添加设备
+        uidContent = request_dict.get('uidContent', None)
+
+        if not uidContent:
+            return response.json(444, {'param': 'uidContent'})
+
+        try:
+            deviceNumber = 0            # 添加成功数量
+            add_success_flag = False    # 添加成功标识
+            exception_flag = False      # 异常标识
+            exists_flag = False         # 已存在标识
+            uid_content_list = eval(uidContent)
+            print('uidContent: ', uid_content_list)
+            re_uid = re.compile(r'^[A-Za-z0-9]{14,20}$')
+            for uid_content in uid_content_list:
+                exception_flag = False  # 重置异常标识
+                exists_flag = False     # 已存在标识
+                UID = uid_content['uid']
+                NickName = uid_content['nickName']
+                Type = uid_content['type']
+                ChannelIndex = uid_content['channelIndex']
+                version = uid_content['version']
+                isCheckMainUser = uid_content['isCheckMainUser']
+                View_Account = uid_content['viewAccount']
+                encryptPassword = uid_content['encryptPassword']
+                View_Password = self.decode_pwd(encryptPassword)
+                if not all([UID, NickName, View_Account]):  # Type和ChannelIndex可能为0
+                    return response.json(444, {'param': 'UID, NickName, View_Account'})
+
+                if not re_uid.match(UID):   # 检查uid长度
+                    return response.json(444, {'error uid length': UID})
+
+                device_info_qs = Device_Info.objects.filter(UID=UID, userID_id=userID)
+                if device_info_qs:
+                    # 判断设备是否已存在
+                    if device_info_qs[0].isExist == 1:
+                        exists_res = {UID: 'device already exists!'}
+                        exists_flag = True
+                        continue
+                    else:
+                        device_info_qs.delete()
+
+                id = CommonService.getUserID(getUser=False)
+                userName = Device_User.objects.get(userID=userID).username
+                main_exist = Device_Info.objects.filter(UID=UID)
+                main_exist = main_exist.filter(~Q(vodPrimaryUserID='')).values('vodPrimaryUserID', 'vodPrimaryMaster')
+
+                vodPrimaryUserID = userID
+                vodPrimaryMaster = userName
+                primaryUserID = ''
+                primaryMaster = ''
+                isShare = False
+
+                is_bind = Device_Info.objects.filter(UID=UID, isShare=False).values('userID__userID', 'primaryUserID', 'primaryMaster')
+
+                if main_exist.exists():
+                    vodPrimaryUserID = main_exist[0]['vodPrimaryUserID']
+                    vodPrimaryMaster = main_exist[0]['vodPrimaryMaster']
+
+                if is_bind.exists():
+                    primaryUserID = is_bind[0]['primaryUserID']
+                    primaryMaster = is_bind[0]['primaryMaster']
+                    isShare = True
+
+                isusermain = False
+                if (vodPrimaryUserID != userID and vodPrimaryUserID != '') or (primaryUserID != userID and primaryUserID != ''):
+                    isusermain = True
+
+                # 判断是否有已绑定用户
+                if isCheckMainUser == 1 and isusermain:
+                    res = {
+                        'id': id,
+                        'userID': userID,
+                        'NickName': NickName,
+                        'UID': UID,
+                        'View_Account': View_Account,
+                        'View_Password': View_Password,
+                        'ChannelIndex': ChannelIndex,
+                        'Type': Type,
+                        'isShare': isShare,
+                        'primaryUserID': primaryUserID,
+                        'primaryMaster': primaryMaster,
+                        'vodPrimaryUserID': vodPrimaryUserID,
+                        'vodPrimaryMaster': vodPrimaryMaster,
+                        'data_joined': '',
+                        'version': version,
+                        'isVod': 0,
+                        'isExist': 1,
+                        'userID__userEmail': ''
+                    }
+                    res['vod'] = [
+                        {
+                            "status": 1,
+                            "channel": ChannelIndex,
+                            "endTime": '',
+                            "bucket__content": '',
+                            "uid": UID
+                        }
+                    ]
+                    res['isMainUserExists'] = 1
+                    continue
+
+                # 判断是否有用户绑定
+                nowTime = int(time.time())
+                us_qs = UidSetModel.objects.filter(uid=UID)
+                if us_qs.exists():
+                    us_qs.update(nickname=NickName)
+                    UidSet_id = us_qs.first().id
+                else:
+                    ip = CommonService.get_ip_address(request)
+                    region_id = Device_Region().get_device_region(ip)
+                    region_alexa = 'CN' if region_id == 1 else 'ALL'
+                    uid_set_create_dict = {
+                        'uid': UID,
+                        'addTime': nowTime,
+                        'updTime': nowTime,
+                        'ip': CommonService.get_ip_address(request_dict),
+                        'channel': ChannelIndex,
+                        'nickname': NickName,
+                        'version': version,
+                        'region_alexa': region_alexa,
+                    }
+                    UidSet = UidSetModel.objects.create(**uid_set_create_dict)
+                    UidSet_id = UidSet.id
+
+                # 查询uid_channel表有无该uid的数据
+                uid_channel_set = UidChannelSetModel.objects.filter(uid_id=UidSet_id)
+                if not uid_channel_set.exists():
+                    # 多通道设备设置通道名
+                    multi_channel_list = [1, 2, 3, 4, 10001]
+                    if Type in multi_channel_list:
+                        UidChannelSet_bulk = []
+                        for i in range(1, ChannelIndex+1):
+                            channel_name = 'channel'+str(i)  # channel1,channel2...
+                            UidChannelSet = UidChannelSetModel(uid_id=UidSet_id, channel=i, channel_name=channel_name)
+                            UidChannelSet_bulk.append(UidChannelSet)
+                        UidChannelSetModel.objects.bulk_create(UidChannelSet_bulk)
+
+                userDevice = Device_Info(id=id, userID_id=userID, UID=UID, NickName=NickName, View_Account=View_Account,
+                                         View_Password=View_Password, Type=Type, ChannelIndex=ChannelIndex, version=version,
+                                         vodPrimaryUserID=vodPrimaryUserID, vodPrimaryMaster=vodPrimaryMaster)
+                userDevice.save()
+                uid_serial_qs = UIDCompanySerialModel.objects.filter(uid__uid=UID)
+                if uid_serial_qs.exists():
+                    uid_serial = uid_serial_qs[0]
+                    Device_Info.objects.filter(UID=UID).update(vodPrimaryUserID=vodPrimaryUserID,
+                                                               vodPrimaryMaster=vodPrimaryMaster,
+                                                               serial_number=uid_serial.company_serial.serial_number + uid_serial.company_serial.company.mark)
+                else:
+                    Device_Info.objects.filter(UID=UID).update(vodPrimaryUserID=vodPrimaryUserID,
+                                                               vodPrimaryMaster=vodPrimaryMaster)
+
+                if not us_qs.exists():
+                    us_qs = UidSetModel.objects.filter(uid=UID)
+
+                if us_qs.exists() and us_qs[0].is_alexa == 1:
+                    if us_qs[0].channel > 1:
+                        data_list = []
+                        uid_channel_set_qs = UidChannelSetModel.objects.filter(uid_id=us_qs[0].id).\
+                            values('channel', 'channel_name')
+                        if uid_channel_set_qs.exists():
+                            # 多通道设备名为 UidChannelSetModel 的 channel_name
+                            for uid_channel_set in uid_channel_set_qs:
+                                data_list.append({'userID': userID, 'UID': UID, 'uid_nick': uid_channel_set['channel_name'],
+                                                  'channel': uid_channel_set['channel'], 'password': encryptPassword})
+                    else:
+                        data_list = [{'userID': userID, 'UID': UID, 'uid_nick': NickName, 'password': encryptPassword}]
+
+                    # 请求Alexa服务器更新事件网关
+                    data_list = json.dumps(data_list)
+                    data = {'data_list': data_list}
+                    url = 'https://www.zositech.xyz/deviceStatus/addOrUpdateV2'
+                    requests.post(url, data=data, timeout=2)
+                dvqs = Device_Info.objects.filter(id=id).values('id', 'userID', 'NickName', 'UID',
+                                                                'View_Account',
+                                                                'View_Password', 'ChannelIndex', 'Type',
+                                                                'isShare',
+                                                                'primaryUserID', 'primaryMaster',
+                                                                'vodPrimaryUserID', 'vodPrimaryMaster',
+                                                                'userID__userEmail',
+                                                                'data_joined', 'version',
+                                                                'isVod', 'isExist', 'isCameraOpenCloud', 'serial_number')
+                dvql = CommonService.qs_to_list(dvqs)
+                ubqs = UID_Bucket.objects.filter(uid=UID). \
+                    values('bucket__content', 'status', 'channel', 'endTime', 'uid')
+                success_res = dvql[0]
+                success_res['vod'] = list(ubqs)
+                iotqs = iotdeviceInfoModel.objects.filter(serial_number=dvql[0]['serial_number'])
+                if iotqs.exists():
+                    success_res['iot'] = {'endpoint': iotqs[0].endpoint, 'token_iot_number': iotqs[0].endpoint}
+                deviceNumber += 1
+                success_res['deviceNumber'] = deviceNumber
+                add_success_flag = True
+        except Exception as e:
+            print(e)
+            error_res = repr(e)
+            exception_flag = True
+            pass
+        finally:
+            if add_success_flag:    # 有一台添加成功则返回成功
+                return response.json(0, success_res)
+            if exists_flag:         # 全部设备已存在
+                return response.json(174, exists_res)
+            if exception_flag:
+                return response.json(500, error_res)
+            return response.json(0, res)
 
     def do_modify(self, userID, request_dict, response, request):
         token = request_dict.get('token', None)
@@ -368,17 +577,12 @@ class EquipmentManagerV3(View):
                            'isCameraOpenCloud', 'serial_number')
         dvls = CommonService.qs_to_list(dvql)
         uid_list = []
-        serial_number_list = []
         for dvl in dvls:
             if dvl['primaryUserID'] and dvl['id'] == dvl['primaryUserID']:
                 dvl['isPrimaryUser'] = 1
             else:
                 dvl['isPrimaryUser'] = 0
             uid_list.append(dvl['UID'])
-            serial_number_list.append(dvl['serial_number'][0:6])
-
-        # 新增获取IOT证书内容
-        iotqs = iotdeviceInfoModel.objects.filter(serial_number__in=serial_number_list)
 
         ubqs = UID_Bucket.objects.filter(uid__in=uid_list). \
             values('bucket__content', 'status', 'channel', 'endTime', 'uid')
@@ -457,16 +661,18 @@ class EquipmentManagerV3(View):
             uv_dict[us['uid']]['channels'] = channels
 
         for p in dvls:
-            # 新增IOT
+            # 获取iot_deviceInfo表的endpoint和token_iot_number
             p['iot'] = []
-            for iot in iotqs:
-                if p['serial_number'][0:6] == iot.serial_number:
-                    p['iot'].append(
-                        {
-                            'endpoint': iot.endpoint,
-                            'token_iot_number': iot.token_iot_number
-                        }
-                    )
+            if p['serial_number']:  # 存在序列号根据序列号查询
+                iotdeviceInfo_qs = iotdeviceInfoModel.objects.filter(serial_number=p['serial_number'][0:6])
+            else:   # 根据uid查询
+                iotdeviceInfo_qs = iotdeviceInfoModel.objects.filter(uid=p['UID'])
+            if iotdeviceInfo_qs.exists():
+                iotdeviceInfo = iotdeviceInfo_qs.values('endpoint', 'token_iot_number')
+                p['iot'].append({
+                    'endpoint': iotdeviceInfo[0]['endpoint'],
+                    'token_iot_number': iotdeviceInfo[0]['token_iot_number']
+                })
 
             p['vod'] = []
             for dm in ubqs:
@@ -545,6 +751,7 @@ class EquipmentManagerV3(View):
                     item['View_Password'] = self.encrypt_pwd(item['View_Password'])
                     data.append(item)
                     return response.json(0, data)
+                return response.json(0, data)
         items = []
         # print('缓存分页')
         for index, item in enumerate(result):
@@ -579,13 +786,8 @@ class EquipmentManagerV3(View):
 
                 dvls = CommonService.qs_to_list(device_qs)
                 uid_list = []
-                serial_number_list = []
                 for dvl in dvls:
                     uid_list.append(dvl['UID'])
-                    serial_number_list.append(dvl['serial_number'][0:6])
-
-                # 新增获取IOT证书内容
-                iotqs = iotdeviceInfoModel.objects.filter(serial_number__in=serial_number_list)
 
                 ubqs = UID_Bucket.objects.filter(uid__in=uid_list). \
                     values('bucket__content', 'status', 'channel', 'endTime', 'uid')
@@ -650,17 +852,19 @@ class EquipmentManagerV3(View):
                     uv_dict[us['uid']]['channels'] = channels
 
                 for p in dvls:
-                    # 新增IOT
+                    # 获取iot_deviceInfo表的endpoint和token_iot_number
                     p['iot'] = []
-                    for iot in iotqs:
-                        if p['serial_number'][0:6] == iot.serial_number:
-                            p['iot'].append(
-                                {
-                                    'endpoint': iot.endpoint,
-                                    'token_iot_number': iot.token_iot_number
-
-                                }
-                            )
+                    if p['serial_number']:  # 存在序列号根据序列号查询
+                        iotdeviceInfo_qs = iotdeviceInfoModel.objects.filter(serial_number=p['serial_number'][0:6])
+                    else:  # 根据uid查询
+                        iotdeviceInfo_qs = iotdeviceInfoModel.objects.filter(uid=p['UID'])
+                    if iotdeviceInfo_qs.exists():
+                        iotdeviceInfo = iotdeviceInfo_qs.values('endpoint', 'token_iot_number')
+                        p['iot'].append({
+                            'endpoint': iotdeviceInfo[0]['endpoint'],
+                            'token_iot_number': iotdeviceInfo[0]['token_iot_number']
+                        })
+
                     p['vod'] = []
                     for dm in ubqs:
                         if p['UID'] == dm['uid']:
@@ -795,14 +999,9 @@ class EquipmentManagerV3(View):
         if not all([token, time_stamp]):
             return response.json(444)
 
-        token = int(CommonService.decode_data(token))
-        time_stamp = int(time_stamp)
-
-        now_time = int(time.time())
-        distance = now_time - time_stamp
-
-        if token != time_stamp or distance > 60000 or distance < -60000:  # 为了全球化时间控制在一天内
-            return response.json(404)
+        # 时间戳token校验
+        if not CommonService.check_time_stamp_token(token, time_stamp):
+            return response.json(13)
 
         dvq = Device_Info.objects.filter(UID=UID)
         dvq = dvq.filter(~Q(vodPrimaryUserID='')).values('vodPrimaryUserID')

+ 9 - 109
Controller/IotCoreController.py

@@ -74,13 +74,9 @@ class IotCoreView(View):
         if not all([token, time_stamp, device_version, language]):
             return response.json(444, {'param': 'token, uid_code, time_stamp, device_version, language'})
 
-        # token时间戳校验
-        token = int(CommonService.decode_data(token))
-        time_stamp = int(time_stamp)
-        now_time = int(time.time())
-        distance = now_time - time_stamp
-        if token != time_stamp or distance > 60000 or distance < -60000:  # 为了全球化时间控制在一天内
-            return response.json(404)
+        # 时间戳token校验
+        if not CommonService.check_time_stamp_token(token, time_stamp):
+            return response.json(13)
 
         if not uid:
             # 使用序列号
@@ -120,7 +116,7 @@ class IotCoreView(View):
 
             iotClient = IOTClient(region_id)
             res = iotClient.create_keys_and_certificate(ThingNameSuffix, thingGroup, response)
-            token_iot_number = hashlib.md5((str(uuid.uuid1()) + str(now_time)).encode('utf-8')).hexdigest()
+            token_iot_number = hashlib.md5((str(uuid.uuid1()) + str(int(time.time()))).encode('utf-8')).hexdigest()
 
             iotdeviceInfoModel.objects.create(uid=uid,
                                               serial_number=serial,
@@ -164,13 +160,9 @@ class IotCoreView(View):
         if not all([token, language, time_stamp, device_version]):
             return response.json(444, {'param: token, language, time_stamp, device_version'})
 
-        # 封装token认证
-        token = int(CommonService.decode_data(token))
-        time_stamp = int(time_stamp)
-        now_time = int(time.time())
-        distance = now_time - time_stamp
-        if token != time_stamp or distance > 60000 or distance < -60000:  # 为了全球化时间控制在一天内
-            return response.json(404)
+        # 时间戳token校验
+        if not CommonService.check_time_stamp_token(token, time_stamp):
+            return response.json(13)
 
         ip = CommonService.get_ip_address(request)
         region_id = Device_Region().get_device_region(ip)
@@ -242,7 +234,7 @@ class IotCoreView(View):
             return response.json(444)
 
         try:
-            # 获取检查uid的序列号,如果没有序列号,不使用MQTT下发消息
+            # 获取设备的物品名后缀
             device_info_qs = Device_Info.objects.filter(UID=UID).values('UID', 'serial_number')
             if not device_info_qs.exists():
                 return response.json(10043)
@@ -268,60 +260,7 @@ class IotCoreView(View):
             # post请求url来发布MQTT消息
             url = 'https://{}/topics/{}'.format(endpoint, topic_name)
             authorizer_name = 'Ansjer_Iot_Auth'
-            signature = self.rsa_sign(Token)  # Token签名
-            headers = {'x-amz-customauthorizer-name': authorizer_name, 'Token': Token,
-                       'x-amz-customauthorizer-signature': signature}
-            params = {'command': MSG}
-            r = requests.post(url=url, headers=headers, json=params, timeout=2)
-            if r.status_code == 200:
-                res = r.json()
-                if res['message'] == 'OK':
-                    return response.json(0)
-                return response.json(10044)
-            else:
-                # print('发布失败')
-                return response.json(10044)
-        except Exception as e:
-            # print(e)
-            return response.json(500, repr(e))
-
-    def request_publish_mqtt(self, request_dict, response, request):
-        # 通用发布主题通知
-        UID = request_dict.get('UID', None)
-        MSG = request_dict.get('MSG', None)
-        return_topic_name = request_dict.get('return_topic_name', None)
-        if not all([UID, MSG]):
-            return response.json(444)
-
-        try:
-            # 获取检查uid的序列号,如果没有序列号,不使用MQTT下发消息
-            device_info_qs = Device_Info.objects.filter(UID=UID).values('UID', 'serial_number')
-            if not device_info_qs.exists():
-                return response.json(10043)
-            uid = device_info_qs[0]['UID']
-            serial_number = device_info_qs[0]['serial_number']
-            # 如果device_info表的serial_number不为空,物品名为'Ansjer_Device_序列号'
-            thing_name_suffix = serial_number if serial_number != '' else uid
-            # 获取数据组织将要请求的url
-            iot = iotdeviceInfoModel.objects.filter(thing_name__contains=thing_name_suffix).values('thing_name',
-                                                                                                   'endpoint',
-                                                                                                   'token_iot_number')
-            if not iot.exists():
-                return response.json(10043)
-            thing_name = iot[0]['thing_name'][14:]  # IoT core上的物品名: Ansjer_Device_ + 序列号+企业编码/uid
-            endpoint = iot[0]['endpoint']
-            Token = iot[0]['token_iot_number']
-            # Token = '297a601b3925e04daab5a60280650e09'
-            topic_name = thing_name + return_topic_name     # MQTT主题
-            if return_topic_name == 'get_s3_key_return':
-                MSG = self.get_s3_key_return_msg(endpoint)
-
-            # api doc: https://docs.aws.amazon.com/zh_cn/iot/latest/developerguide/http.html
-            # url: https://IoT_data_endpoint/topics/url_encoded_topic_name?qos=1
-            # post请求url来发布MQTT消息
-            url = 'https://{}/topics/{}'.format(endpoint, topic_name)
-            authorizer_name = 'Ansjer_Iot_Auth'
-            signature = self.rsa_sign(Token)  # Token签名
+            signature = CommonService.rsa_sign(Token)  # Token签名
             headers = {'x-amz-customauthorizer-name': authorizer_name, 'Token': Token,
                        'x-amz-customauthorizer-signature': signature}
             params = {'command': MSG}
@@ -391,42 +330,3 @@ class IotCoreView(View):
         MSG['arn'] = arn
         MSG['region_name'] = region_name
         return MSG
-
-
-    def rsa_sign(self, Token):
-        # 私钥签名Token
-        private_key_file = '''-----BEGIN RSA PRIVATE KEY-----
-MIIEpQIBAAKCAQEA5iJzEDPqtGmFMggekVro6C0lrjuC2BjunGkrFNJWpDYzxCzE
-X5jf4/Fq7hcIaQd5sqHugDxPVollSLPe9zNilbrd0sZfU+Ed8gRVuKW9KwfE9XFr
-L0pt6bKRQ0IIRfiZ9TuR0tsQysvcO1GZSXcYfPue3tGM1zOnWFThWDqZ06+sOxzt
-RMRl4yNfbpCG4MfxG3itNXOfrjZv2OMLSXrxmzubSvRpUYSvQPs4fm9302SAnySY
-0MKzx6H6528ZQm/IDDSZy6EmNBIyTRDfxC56vnYcXvqedAQh7jJnjdvt6Q4MhASH
-eIYi1FBSdu2NT6wgpnrqXzx5pq9kR/lnsLID0wIDAQABAoIBAQCiF4GT1/1oNSpr
-ouxk1PNXFPWFUsVGD8mAwVJmx//eiY7MjfuCmdqYYmI+cFqsH2fIOeYSzGfVO9Dq
-9EYHN1oovAWhf7eFDPpajFMUSyiCNmazub8VAAeKowtNpCTPo9pMsDh1m3aoYA4u
-ebrN0+Sbo16y8kWRDgDAZoiR7DSMs8lczk16hwfv5mw8XpNDbaL3Coi4Koe2S1Yh
-2SX3vWFlpd7qF1ZYXuZIp+b8JPrV7n9eUKoFgzj0gqgwQK80CoexIjiOrNMPvkQa
-q+8kCvFjAzKxOK7e8gjM8lMRiGodb61kmYZkkJzFwWO4EaGbl34lfVECd1Ixp3tF
-be0OWAGBAoGBAPSteXDzzToD8ovM7LL11x0jWwI6HOiHu89kZtW566rIezjWBuA2
-TxrcYKM3h9jQRXS3CsMdoIv6XGk5lqM8ADtjn23FBWe/THYLh8bm8JOgh5RRWQDg
-SvkLfi9Ih2mM4NJfmuuDOh3Nze2efLM7+kOZWUQwF2Zx9mL5jvRBk351AoGBAPDI
-sYmT2Li+i5+0vykA2m5uPF8ZOW8BGtAfCZv0suW7BNzSgin78g9WapRd/4p0NNiL
-/nVMqPPCpd1akCUpV+GDWQt0hV+HZjxANE0KWhciQRyo2qvo51j8SWILJSgh0tXC
-aTF8qt6oGw3VN3m57vKhbrlDaz0J/NDJFci6msAnAoGBAOuG6bXPGijUj+//DYKf
-n7jOxdZ49kboEePrtAncdHzri6IEdI3z+WXT6bpzw/LzWUimwldb96WHFNm9s8Hi
-Ch8hIODbnP5naUTgiIzw1XhmONyPCewL/F+LrqX5XVA/alNX8JrwsUrrR2WLAGLQ
-Q3I69XDsEjptTU2tCO0bCs3ZAoGBAJ2lCHfm0JHET230zONvp5N9oREyVqQSuRdh
-+syc3TQDyh85w/bw+X6JOaaCFHj1tFPC9Iqf8k4GNspCLPXnp54CfR4+38O3xnvU
-HWoDSRC0YKT++IxtJGriYrlKSr2Hx54kdvLriIPW1D+uRW/xCDza7L9nIKMKEvgv
-b4/IfOEpAoGAeKM9Te7T1VzlAkS0CJOwanzwYV/zrex84WuXxlsGgPQ871lTs5AP
-H1QLfLfFXH+UVrCEC2yv4eml/cqFkpB3gE5i4MQ8GPVIOSs5tsIyl8YUA03vdNdB
-GCqvlyw5dfxNA+EtxNE2wCW/LW7ENJlACgcfgPlBZtpLheWoZB/maw4=
------END RSA PRIVATE KEY-----'''
-        # 使用密钥文件方式
-        # private_key_file_path = os.path.join(BASE_DIR, 'static/iotCore/private.pem')#.replace('\\', '/')
-        # private_key_file = open(private_key_file_path, 'r')
-        private_key = ct.load_privatekey(ct.FILETYPE_PEM, private_key_file)
-        signature = ct.sign(private_key, Token.encode('utf8'), 'sha256')
-        signature = encodebytes(signature).decode('utf8').replace('\n', '')
-        # print('signature:', signature)
-        return signature

+ 20 - 61
Controller/SerialNumberController.py

@@ -132,25 +132,21 @@ class SerialNumberView(View):
         company_id = request_dict.get('company_id', None)
         token = request_dict.get('token', None)
         time_stamp = request_dict.get('time_stamp', None)
-        DeviceSubType = request_dict.get('DeviceSubType', None)
-        p2ptype = request_dict.get('p2ptype', 1)
+        p2p_type = request_dict.get('p2ptype', 1)
+
         if not all([serial_number, company_id, token, time_stamp]):
             return response.json(444)
 
-        token = int(CommonService.decode_data(token))
-        time_stamp = int(time_stamp)
+        # 时间戳token校验
+        if not CommonService.check_time_stamp_token(token, time_stamp):
+            return response.json(13)
 
         now_time = int(time.time())
-        distance = now_time - time_stamp
-
-        if token != time_stamp or distance > 60000 or distance < -60000:  # 为了全球化时间控制在一天内
-            return response.json(404)
-
         serial = serial_number[0:6]
         full_serial = serial_number[0:9]
 
         if serial_number[9:10]:
-            p2ptype = serial_number[9:10]
+            p2p_type = serial_number[9:10]
         try:
             if not country_id:
                 ip = CommonService.get_ip_address(request)
@@ -172,44 +168,18 @@ class SerialNumberView(View):
                     while count < 3:
                         # 查询是否存在未绑定序列号的uid
                         uid_qs = UIDModel.objects.filter(vpg__company_id=company_serial.company.id,
-                                                         vpg__region_id=country_id, status=0, p2p_type=p2ptype). \
+                                                         vpg__region_id=country_id, status=0, p2p_type=p2p_type). \
                                                          order_by('id')
                         if not uid_qs.exists():
                             return response.json(173)
 
                         uid = uid_qs[0]
+                        # 判断uid是否已绑定过序列号
+                        uid_company_serial_qs = UIDCompanySerialModel.objects.filter(uid_id=uid.id)
+                        if uid_company_serial_qs.exists():
+                            return response.json(174)
 
-                        if DeviceSubType:
-                            # 获取最新的mac,判断分配到哪里,且进行绑定
-                            mac = MacModel.objects.filter().values('id', 'value', 'is_active')[0]
-                            current_mac = mac['value']
-                            username = 'cspublic@ansjer.com'
-                            if current_mac[-8:] == '1F:42:40':  # 一组一共1048576个,此mac是第100w个时
-                                sys_msg_text = "当前国外uid管理系统mac地址已分配到" + current_mac + ",此mac地址是当前组的第100w个,还剩下48576个可分配,mac地址即将用完。"
-                                S3Email().faEmail(sys_msg_text, username)
-                            elif current_mac[-8:] == '1F:90:60':  # 此mac是第102w个时
-                                sys_msg_text = "当前国外uid管理系统mac地址已分配到" + current_mac + ",此mac地址是当前组的第102w个,还剩下28576个可分配,mac地址即将用完。"
-                                S3Email().faEmail(sys_msg_text, username)
-                            elif not mac['is_active']:
-                                return response.json(175)
-                            elif current_mac[-8:] == '1F:FF:FF':
-                                MacModel.objects.filter().update(is_active=False)  # 更改mac可使用的状态,当再此调用接口时使用上面条件进行阻止
-                                sys_msg_text = "当前国外uid管理系统mac地址已分配到" + current_mac + ",mac地址已分配使用完,请更换分组。"
-                                S3Email().faEmail(sys_msg_text, username)
-                                return response.json(175)
-                            UIDModel.objects.filter(id=uid.id).update(mac=current_mac)  # 更新绑定uid的mac值
-                            # 绑定mac地址成功后更新mac表
-                            temp_mac = CommonService.updateMac(current_mac)  # mac地址值+1;后3个字节为FF时返回None
-                            if temp_mac:
-                                current_mac = temp_mac  # 更新赋值写入uid表
-                            else:
-                                temp_mac = current_mac  # 赋值为FF写入mac表
-                            MacModel.objects.filter().update(value=temp_mac, add_time=now_time,
-                                                             update_time=now_time)  # 更新mac表的mac地址值
-
-                        result = UIDModel.objects.filter(id=uid.id, status=0).\
-                            update(status=2, update_time=now_time)
-
+                        result = UIDModel.objects.filter(id=uid.id, status=0).update(status=2, update_time=now_time)
                         if int(result) <= 0:    # 更新失败
                             count += 1
                             continue
@@ -232,7 +202,6 @@ class SerialNumberView(View):
                         res = {
                             'full_uid_code': CommonService.encode_data(full_uid_code),
                             'uid': CommonService.encode_data(uid.uid),
-                            'mac': CommonService.encode_data(uid.mac),
                             'extra': uid.uid_extra,
                             'platform': uid.platform,
                             'initString': uid.init_string,
@@ -267,7 +236,6 @@ class SerialNumberView(View):
                 res = {
                     'full_uid_code': CommonService.encode_data(full_uid_code),
                     'uid': CommonService.encode_data(uid['uid__uid']),
-                    'mac': CommonService.encode_data(uid['uid__mac']),
                     'extra': uid['uid__uid_extra'],
                     'platform': uid['uid__platform'],
                     'initString': uid['uid__init_string'],
@@ -284,16 +252,10 @@ class SerialNumberView(View):
         token = request_dict.get('token', None)
         time_stamp = request_dict.get('time_stamp', None)
 
-        if token and time_stamp and serial_number :
-
-            token = int(CommonService.decode_data(token))
-            time_stamp = int(time_stamp)
-
-            now_time = int(time.time())
-            distance = now_time - time_stamp
-
-            if token != time_stamp or distance > 60000 or distance < -60000:  # 为了全球化时间控制在一天内
-                return response.json(404)
+        if token and time_stamp and serial_number:
+            # 时间戳token校验
+            if not CommonService.check_time_stamp_token(token, time_stamp):
+                return response.json(13)
 
             mark = serial_number[6:9]
             serial = serial_number[0:6]
@@ -321,15 +283,12 @@ class SerialNumberView(View):
 
         if not all([token, time_stamp, serial_number]):
             return response.json(444)
-        token = int(CommonService.decode_data(token))
-        time_stamp = int(time_stamp)
 
-        now_time = int(time.time())
-        distance = now_time - time_stamp
-
-        if token != time_stamp or distance > 60000 or distance < -60000:  # 为了全球化时间控制在一天内
-            return response.json(404)
+        # 时间戳token校验
+        if not CommonService.check_time_stamp_token(token, time_stamp):
+            return response.json(13)
 
+        now_time = int(time.time())
         serial = serial_number[0:6]
         uid_serial_qs = UIDCompanySerialModel.objects.filter(company_serial__serial_number=serial)
         if not uid_serial_qs.exists():

+ 4 - 2
Controller/SysManage.py

@@ -12,6 +12,7 @@
 @Contact: chanjunkai@163.com
 """
 import os
+import time
 
 from django.http import HttpResponse
 from django.views.decorators.csrf import csrf_exempt
@@ -103,9 +104,10 @@ def initMsgFunc(request):
     response.lang = tko.lang
     if tko.code == 0:
         userID = tko.userID
+        seven_days_ago = int(time.time()) - 3600 * 24 * 7   # 过滤七天前数据
         sm_count = SysMsgModel.objects.filter(userID_id=userID, status=0).count()
-        eq_count = Equipment_Info.objects.filter(userID_id=userID).filter(status=False).count()
-        rq_count = Equipment_Info.objects.filter(userID_id=userID).filter(eventType=57, status=False,).count()
+        eq_count = Equipment_Info.objects.filter(userID_id=userID, eventTime__gt=seven_days_ago, status=False).count()
+        rq_count = Equipment_Info.objects.filter(userID_id=userID, eventTime__gt=seven_days_ago, eventType=57, status=False,).count()
         uid_reset_count = Device_Info.objects.filter(userID_id=userID, isExist=2).count()
         res = {
             'sm_count': sm_count,  # 系统消息未读数量

+ 17 - 42
Controller/VPGController.py

@@ -196,9 +196,6 @@ class VPGView(View):
 @csrf_exempt
 def do_upload_uid(request):
     # 上传UID,需要request.FILES,单独提取出来
-    # perm = ModelService.check_perm_uid_manage(userID, 0)
-    # if not perm:
-    #     return response.json(309)
 
     request.encoding = 'utf-8'
     response = uidManageResponseObject()
@@ -210,33 +207,24 @@ def do_upload_uid(request):
         return response.json(444)
     file = request.FILES.get('file', None)
     vpg_id = request_dict.get('vpg_id', None)
+    p2p_type = request_dict.get('p2p_type', None)
     platform = request_dict.get('platform', '')
     init_string = request_dict.get('init_string', '')
     init_string_app = request_dict.get('init_string_app', '')
 
-    if not vpg_id:
+    if not all([vpg_id, p2p_type]):
         return response.json(444)
 
-    bulk = []
-    add_time = update_time = int(time.time())
-    # MAC = MacModel.objects.filter().values('id', 'value', 'is_active')[0]   # 获取最新可用的mac
-    # current_mac = MAC['value']
-    # if (not MAC['is_active']) or (current_mac[-8:] == 'FF.FF.FF'):
-    #     return response.json(175)
-
-    area = 1 if vpg_id != '1' else 0
-    # path = '/'.join((BASE_DIR, 'static/uid')).replace('\\', '/') + '/'
-    # if not os.path.exists(path):
-    #     os.makedirs(path)
-    # full_path = path + str(file)
-    # with open(full_path, 'wb+') as uid_file:
     try:
+        bulk = []
+        p2p_type = int(p2p_type)
+        # 尚云必须输入平台和初始化字符
+        if p2p_type == 1 and (not platform or not platform or not init_string_app):
+            return response.json(444)
+        p2p = '尚云' if p2p_type == 1 else 'tutk'
+        area = 1 if vpg_id != '1' else 0    # vpg_id为'1':国内
+        add_time = update_time = int(time.time())
         for chunk in file.chunks():
-            # str_chunk = str(chunk)
-            # print('str(chunk):', str_chunk)
-            # str_chunk = re.findall("b\'(.*)\'", str_chunk)[0]
-            # str_chunk = str_chunk.split('\\r\\n')
-            # print('str(chunk):', str_chunk)
             uid_list = re.findall("b\'(.*)\'", str(chunk))[0].split('\\r\\n')
             for uid in uid_list:
                 UID = UIDModel(
@@ -247,29 +235,17 @@ def do_upload_uid(request):
                     update_time=update_time,
                     area=area,  # 关联vgp表已有区域信息,可以考虑去掉
                     vpg_id=vpg_id,
+                    p2p_type=p2p_type,
                     platform=platform,
                     init_string=init_string,
                     init_string_app=init_string_app
                 )
-                if len(uid) == 14:  # 宸云
-                    UID.p2p_type = 1
-                    UID.uid = uid
-                elif len(uid) == 20:    # tutk
-                    UID.p2p_type = 2
-                    UID.uid = uid
-                elif len(uid) == 23:    # 宸云完整uid
-                    a = uid.split('-')
-                    new_uid = a[0] + a[1] + a[2].split(',')[0]
-                    UID.p2p_type = 1
-                    UID.uid = new_uid
+                if '-' in uid:  # 尚云完整uid,eg.ACN-000005-FHCGR,VRWEDU -> ACN000005FHCGR
                     UID.full_uid_code = uid
+                    uid_split = uid.split('-')
+                    uid = uid_split[0] + uid_split[1] + uid_split[2].split(',')[0]
+                UID.uid = uid
                 bulk.append(UID)
-                # temp_mac = CommonService.updateMac(current_mac)    # mac地址值+1;后3个字节为FF时返回None
-                # if temp_mac:
-                #     current_mac = temp_mac  # 更新赋值写入uid表
-                # else:
-                #     temp_mac = current_mac  # 赋值为FF写入mac表
-                #     break
 
         ip = CommonService.get_ip_address(request)
         content = json.loads(json.dumps(request_dict))
@@ -280,7 +256,7 @@ def do_upload_uid(request):
             'time': add_time,
             'url': 'vpgUid/uid',
             'content': json.dumps(content),
-            'operation': '上传{}个uid到VPG ID {}'.format(len(uid_list), vpg_id),
+            'operation': '上传{}个{}uid到VPG ID {}'.format(len(uid_list), p2p, vpg_id),
         }
         
         with transaction.atomic():
@@ -288,8 +264,7 @@ def do_upload_uid(request):
             UIDModel.objects.bulk_create(bulk)  # 批量写入uid数据
             uid_count = UIDModel.objects.filter(vpg_id=vpg_id).count()  # 获取族群下uid的数量
             VPGModel.objects.filter(id=vpg_id).update(uid_count=uid_count)   # 更新vgp表的uid_count
-            # MacModel.objects.filter().update(value=temp_mac)  # 更新mac表的mac地址值
         return response.json(0)
     except Exception as e:
         print(e)
-        return response.json(500, repr(e))
+        return response.json(500, repr(e))

+ 42 - 3
Model/models.py

@@ -622,6 +622,7 @@ class Order_Model(models.Model):
     commodity_code = models.CharField(default='', max_length=32, verbose_name='套餐规格码')
     pay_url = models.CharField(max_length=2000, default='', verbose_name='支付url')
     paypal = models.CharField(max_length=500, null=True, blank=True, verbose_name='支付批准url')
+    promotion_rule_id = models.CharField(blank=True, max_length=64, default='', verbose_name='促销id')
 
     # 备用字段
     spare_1 = models.CharField(default='', blank=True, max_length=64, verbose_name=u'备用字段1')
@@ -638,6 +639,27 @@ class Order_Model(models.Model):
         verbose_name_plural = verbose_name
         ordering = ('-orderID',)
 
+class PromotionRuleModel(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name='主键')
+    ruleName = models.TextField(default='', verbose_name='规则名字')                     #json格式, 例: {"cn":"黑色星期五","en":"Black Friday"}
+    ruleDesc = models.TextField(default='', verbose_name='规则描述')                     #json格式,   例:  {"cn":"买一送一","en":"buy one get one free"}
+    ruleConfig = models.CharField(max_length=2000, default='', verbose_name='规则配置')  #json格式, 例: {"buy": 1, "get": 1}
+    startTime = models.IntegerField(verbose_name='促销活动开始时间', default=0)
+    endTime = models.IntegerField(verbose_name='促销活动结束时间', default=0)
+    status = models.SmallIntegerField(default=0, verbose_name='活动状态:0未进行;1进行中')
+    remark = models.CharField(max_length=50, default='', verbose_name='备注')
+    popups = models.CharField(max_length=2000, default='', verbose_name='app弹窗消息')   #json格式 ,例: {"cn":"买一送一","en":"buy one get one free"}
+
+    def __str__(self):
+        return self.id
+
+    class Meta:
+        db_table = 'promotion_rule'
+        verbose_name = u'促销规则表'
+        verbose_name_plural = verbose_name
+        ordering = ('-id',)
+
+
 
 class VodHlsModel(models.Model):
     id = models.AutoField(primary_key=True, verbose_name='回放列表主键')
@@ -1116,7 +1138,7 @@ class AppLogModel(models.Model):
     user = models.ForeignKey(Device_User, to_field='userID', on_delete=models.CASCADE, verbose_name='关联设备用户表')
     uid = models.CharField(max_length=20, default='', verbose_name='设备uid')
     average_delay = models.CharField(max_length=32, default='', verbose_name='最高平均延时')
-    status = models.SmallIntegerField(default=0, verbose_name='失败状态')
+    status = models.SmallIntegerField(default=0, verbose_name='失败状态')   # 0: 成功,1: 失败
     filename = models.CharField(max_length=120, default='', verbose_name='文件名')
     add_time = models.IntegerField(default=0, verbose_name='日期')
 
@@ -1126,6 +1148,20 @@ class AppLogModel(models.Model):
         verbose_name_plural = verbose_name
 
 
+class DeviceLogModel(models.Model):
+    id = models.AutoField(primary_key=True)
+    ip = models.CharField(default='', max_length=32, verbose_name='ip')
+    uid = models.CharField(max_length=32, default='', verbose_name='设备uid')
+    status = models.SmallIntegerField(default=0, verbose_name='上传状态')   # 0: 成功,1: 失败
+    filename = models.CharField(max_length=120, default='', verbose_name='文件名')
+    add_time = models.DateTimeField(blank=True, auto_now_add=True, verbose_name=u'添加时间')
+
+    class Meta:
+        db_table = 'device_log'
+        verbose_name = '设备日志表'
+        verbose_name_plural = verbose_name
+
+
 class EquipmentInfoExStatisticsModel(models.Model):
     id = models.AutoField(primary_key=True)
     push_type = models.SmallIntegerField(default=0, verbose_name='第三方推送服务器标志。0:APNS推送,1:谷歌推送,2:极光推送')
@@ -1584,11 +1620,14 @@ class iotdeviceInfoModel(models.Model):
     thing_name = models.CharField(blank=True, max_length=256, default='', verbose_name=u'IoT Thing Name')
     thing_groups = models.CharField(blank=True, max_length=256, default='', verbose_name=u'IoT Thing Groups')
     endpoint = models.CharField(blank=True, max_length=256, db_index=True, default='', verbose_name=u'iot端点')
-    token_iot_number = models.CharField(blank=True,  db_index=True ,default='', max_length=50, verbose_name='连接iot令牌')
+    token_iot_number = models.CharField(blank=True,  db_index=True, default='', max_length=50, verbose_name='连接iot令牌')
+    add_time = models.DateTimeField(blank=True, auto_now_add=True, verbose_name=u'添加时间')
+    update_time = models.DateTimeField(blank=True, auto_now=True, verbose_name=u'更新时间')
     class Meta:
         db_table = 'iot_deviceInfo'
         verbose_name = 'iot设备信息表'
         verbose_name_plural = verbose_name
+        ordering = ('-add_time',)
 
 
 class UIDMainUser(models.Model):
@@ -1630,7 +1669,7 @@ class Pc_Info(models.Model):
 class CloudLogModel(models.Model):
     id = models.AutoField(primary_key=True, verbose_name=u'自增标记ID')
     user = models.CharField(max_length=100, default='', db_index=True, blank=True, verbose_name=u'用户')
-    uid = models.CharField(blank=True, max_length=32, verbose_name=u'uid', default='')
+    uid = models.CharField(blank=True, max_length=32, db_index=True, verbose_name=u'uid', default='')
     operation = models.CharField(max_length=100, db_index=True, default='', blank=True, verbose_name=u'操作')
     ip = models.CharField(max_length=100, default='', db_index=True, blank=True, verbose_name=u'访问ip地址')
     url = models.CharField(max_length=150, default='', blank=True, verbose_name=u'访问路径')

+ 2 - 0
Object/ResponseObject.py

@@ -13,6 +13,7 @@ class ResponseObject(object):
             5: 'Please try again one minute later!',
             10: res,
             12: 'You are not the primary user of the device!',
+            13: 'Timestamp token verification failed',
             14: 'Device is not belong to you',
             15: 'Device has been bound',
             16: 'WeChat has been bound, please log in and unbind using WeChat',
@@ -109,6 +110,7 @@ class ResponseObject(object):
             5: '请一分钟后再尝试',
             10: res,
             12: '非设备主用户',
+            13: '时间戳token校验失败',
             14: '设备不属于您',
             15: '设备已被绑定',
             16: '微信已被绑定,请使用微信登录并解绑',

+ 68 - 3
Service/CommonService.py

@@ -1,4 +1,5 @@
 # -*- coding: utf-8 -*-
+# 高复用性函数封装到CommonService类
 import base64
 import datetime
 import time
@@ -10,9 +11,8 @@ from django.core import serializers
 from django.utils import timezone
 from pyipip import IPIPDatabase
 from Ansjer.config import BASE_DIR, UNICODE_ASCII_CHARACTER_SET
-
-
-# 复用性且公用较高封装代码在这
+import OpenSSL.crypto as ct
+from base64 import encodebytes
 from Controller.CheckUserData import RandomStr
 from Service.ModelService import ModelService
 
@@ -253,6 +253,8 @@ class CommonService:
 
     @staticmethod
     def decode_data(content, start=1, end=4):
+        if not content:
+            return ''
         try:
             for i in range(start, end):
                 if i == 1:
@@ -275,6 +277,8 @@ class CommonService:
 
     @staticmethod
     def encode_data(content, start=1, end=4):
+        if not content:
+            return ''
         for i in range(start, end):
             if i == 1:
                 content = RandomStr(3, False)+content+RandomStr(3, False)
@@ -385,6 +389,8 @@ class CommonService:
 
     @staticmethod
     def decode_data(content, start=1, end=4):
+        if not content:
+            return ''
         try:
             for i in range(start, end):
                 if i == 1:
@@ -408,6 +414,8 @@ class CommonService:
 
     @staticmethod
     def encode_data(content, start=1, end=4):
+        if not content:
+            return ''
         for i in range(start, end):
             if i == 1:
                 content = CommonService.RandomStr(3, False) + content + CommonService.RandomStr(3, False)
@@ -424,4 +432,61 @@ class CommonService:
     def encode_data_without_salt(content):
         return base64.b64encode(str(content).encode("utf-8")).decode('utf8')
 
+    @staticmethod
+    def check_time_stamp_token(token, time_stamp):
+        # 时间戳token校验
+        if not all([token, time_stamp]):
+            return False
+        try:
+            token = int(CommonService.decode_data(token))
+            time_stamp = int(time_stamp)
+            now_time = int(time.time())
+            distance = now_time - time_stamp
+            if token != time_stamp or distance > 60000 or distance < -60000:  # 为了全球化时间控制在一天内
+                return False
+            return True
+        except Exception as e:
+            print(e)
+            return False
+
+    @staticmethod
+    def rsa_sign(Token):
+        # 私钥签名Token
+        if not Token:
+            return ''
+        private_key_file = '''-----BEGIN RSA PRIVATE KEY-----
+MIIEpQIBAAKCAQEA5iJzEDPqtGmFMggekVro6C0lrjuC2BjunGkrFNJWpDYzxCzE
+X5jf4/Fq7hcIaQd5sqHugDxPVollSLPe9zNilbrd0sZfU+Ed8gRVuKW9KwfE9XFr
+L0pt6bKRQ0IIRfiZ9TuR0tsQysvcO1GZSXcYfPue3tGM1zOnWFThWDqZ06+sOxzt
+RMRl4yNfbpCG4MfxG3itNXOfrjZv2OMLSXrxmzubSvRpUYSvQPs4fm9302SAnySY
+0MKzx6H6528ZQm/IDDSZy6EmNBIyTRDfxC56vnYcXvqedAQh7jJnjdvt6Q4MhASH
+eIYi1FBSdu2NT6wgpnrqXzx5pq9kR/lnsLID0wIDAQABAoIBAQCiF4GT1/1oNSpr
+ouxk1PNXFPWFUsVGD8mAwVJmx//eiY7MjfuCmdqYYmI+cFqsH2fIOeYSzGfVO9Dq
+9EYHN1oovAWhf7eFDPpajFMUSyiCNmazub8VAAeKowtNpCTPo9pMsDh1m3aoYA4u
+ebrN0+Sbo16y8kWRDgDAZoiR7DSMs8lczk16hwfv5mw8XpNDbaL3Coi4Koe2S1Yh
+2SX3vWFlpd7qF1ZYXuZIp+b8JPrV7n9eUKoFgzj0gqgwQK80CoexIjiOrNMPvkQa
+q+8kCvFjAzKxOK7e8gjM8lMRiGodb61kmYZkkJzFwWO4EaGbl34lfVECd1Ixp3tF
+be0OWAGBAoGBAPSteXDzzToD8ovM7LL11x0jWwI6HOiHu89kZtW566rIezjWBuA2
+TxrcYKM3h9jQRXS3CsMdoIv6XGk5lqM8ADtjn23FBWe/THYLh8bm8JOgh5RRWQDg
+SvkLfi9Ih2mM4NJfmuuDOh3Nze2efLM7+kOZWUQwF2Zx9mL5jvRBk351AoGBAPDI
+sYmT2Li+i5+0vykA2m5uPF8ZOW8BGtAfCZv0suW7BNzSgin78g9WapRd/4p0NNiL
+/nVMqPPCpd1akCUpV+GDWQt0hV+HZjxANE0KWhciQRyo2qvo51j8SWILJSgh0tXC
+aTF8qt6oGw3VN3m57vKhbrlDaz0J/NDJFci6msAnAoGBAOuG6bXPGijUj+//DYKf
+n7jOxdZ49kboEePrtAncdHzri6IEdI3z+WXT6bpzw/LzWUimwldb96WHFNm9s8Hi
+Ch8hIODbnP5naUTgiIzw1XhmONyPCewL/F+LrqX5XVA/alNX8JrwsUrrR2WLAGLQ
+Q3I69XDsEjptTU2tCO0bCs3ZAoGBAJ2lCHfm0JHET230zONvp5N9oREyVqQSuRdh
++syc3TQDyh85w/bw+X6JOaaCFHj1tFPC9Iqf8k4GNspCLPXnp54CfR4+38O3xnvU
+HWoDSRC0YKT++IxtJGriYrlKSr2Hx54kdvLriIPW1D+uRW/xCDza7L9nIKMKEvgv
+b4/IfOEpAoGAeKM9Te7T1VzlAkS0CJOwanzwYV/zrex84WuXxlsGgPQ871lTs5AP
+H1QLfLfFXH+UVrCEC2yv4eml/cqFkpB3gE5i4MQ8GPVIOSs5tsIyl8YUA03vdNdB
+GCqvlyw5dfxNA+EtxNE2wCW/LW7ENJlACgcfgPlBZtpLheWoZB/maw4=
+-----END RSA PRIVATE KEY-----'''
+        # 使用密钥文件方式
+        # private_key_file_path = os.path.join(BASE_DIR, 'static/iotCore/private.pem')#.replace('\\', '/')
+        # private_key_file = open(private_key_file_path, 'r')
+        private_key = ct.load_privatekey(ct.FILETYPE_PEM, private_key_file)
+        signature = ct.sign(private_key, Token.encode('utf8'), 'sha256')
+        signature = encodebytes(signature).decode('utf8').replace('\n', '')
+        # print('signature:', signature)
+        return signature