Pārlūkot izejas kodu

Merge branch 'dev'

# Conflicts:
#	Controller/SerialNumberController.py
lang 3 gadi atpakaļ
vecāks
revīzija
9101a79459

+ 40 - 1
AdminController/TestServeController.py

@@ -22,17 +22,20 @@ from time import strftime
 from Ansjer.config import BASE_DIR
 from Object import MergePic
 import os
+import base64
 
 
 class TestServeView(View):
     def get(self, request, *args, **kwargs):
         request.encoding = 'utf-8'
         operation = kwargs.get('operation')
+        print("--------------------get")
         return self.validation(request.GET, request, operation)
 
     def post(self, request, *args, **kwargs):
         request.encoding = 'utf-8'
         operation = kwargs.get('operation')
+        print("--------------------post")
         return self.validation(request.POST, request, operation)
 
     def validation(self, request_dict, request, operation):
@@ -58,11 +61,47 @@ class TestServeView(View):
                 return response.json(404)
 
     def AItest(self, userID, request, request_dict, response):
-        file = request.FILES.get('file', None)
+        # print("--------------request_dict")
+        # print(request_dict)
+
+        file_post_one = request_dict.get('file_one', None)
+        file_post = file_post_one.replace(' ','+')
+        # file_decode = base64.b64decode(file_post)
+
+        file_post_two = request_dict.get('file_two', None)
+        file_post_two = file_post_two.replace(' ', '+')
+        # file_decode_two = base64.b64decode(file_post_two)
+
+        now_time = int(time.time())
+        dir_path = os.path.join(BASE_DIR, 'static/ai/')
+        if not os.path.exists(dir_path):
+            os.makedirs(dir_path)
+
+        file_path_one = dir_path + 'one'+ str(now_time) + '.jpeg'
+        file_path_two = dir_path + 'two'+ str(now_time) + '.jpeg'
+
+        file_list = ['one','two']
+
+        for index in file_list:
+            file_path = dir_path + index + str(now_time) + '.jpeg'
+            with open(file_path, 'wb') as f:
+                # file_byte = file_post.encode('utf-8')
+                f.write(file_decode)
+
+
+
+
+        return HttpResponse("seccess")
         file2 = request.FILES.get('file_one', None)
         file3 = request.FILES.get('file_two', None)
         file4 = request.FILES.get('file_three', None)
 
+        print('--------------------------file')
+        print(file)
+
+        print('===========================post_file')
+        print(file_post)
+
         post_file_list = [file, file2, file3, file4]
         file_list = []
         for index in range(len(post_file_list)):

+ 1 - 0
Ansjer/cn_config/config_formal.py

@@ -29,6 +29,7 @@ PAYPAL_CRD = {
     "client_id": "AVLoQVq3xHZ6FrF4mxHwlCPgVBAw4Fw5RtMkuxmYd23SkUTIY643n2g3KdK-Al8wV05I28lza5uoQbAA",
     "client_secret": "EO8kRc8yioDk0i2Qq-QMcVFfwkmyMJorTvBSLDTnxDJJ_wb9VoM_0jkUY9iEng2Flp1ze8wQOGpH5nB2"
 }
+PAYPAL_WEB_HOOK_ID = '6TS30758D98835230'
 
 DETECT_PUSH_DOMAIN = 'http://push.zositechc.cn/'
 DETECT_PUSH_DOMAINS = 'https://push.zositechc.cn/'

+ 1 - 0
Ansjer/cn_config/config_test.py

@@ -36,6 +36,7 @@ PAYPAL_CRD = {
     "client_id": "AVLoQVq3xHZ6FrF4mxHwlCPgVBAw4Fw5RtMkuxmYd23SkUTIY643n2g3KdK-Al8wV05I28lza5uoQbAA",
     "client_secret": "EO8kRc8yioDk0i2Qq-QMcVFfwkmyMJorTvBSLDTnxDJJ_wb9VoM_0jkUY9iEng2Flp1ze8wQOGpH5nB2"
 }
+PAYPAL_WEB_HOOK_ID = '6TS30758D98835230'
 # PAYPAL_CRD = {
 #     "mode": "sandbox",  # sandbox or live
 #     "client_id": "ATXTpWs8sajNYeU46jNs1yzpy4H_o3RRrGVIJ8Tscc312BjMx12cpRgCucfWX07a4G6GbK8hzElB04Pd",

+ 2 - 1
Ansjer/cn_config/formal_settings.py

@@ -16,6 +16,7 @@ INSTALLED_APPS = [
     'corsheaders',
     'imagekit',
     'Model',
+    'PushModel',
 ]
 
 MIDDLEWARE = [
@@ -110,7 +111,7 @@ DATABASES = {
 DATABASE_ROUTERS = ['Ansjer.database_router.DatabaseAppsRouter']
 DATABASE_APPS_MAPPING = {
     'Model': 'default',
-    'db2': 'mysql02',
+    'PushModel': 'mysql02',
 }
 
 

+ 1 - 1
Ansjer/cn_config/test_settings.py

@@ -115,7 +115,7 @@ DATABASES = {
 DATABASE_ROUTERS = ['Ansjer.database_router.DatabaseAppsRouter']
 DATABASE_APPS_MAPPING = {
     'Model': 'default',
-    'db2': 'mysql02',
+    'PushModel': 'mysql02',
 }
 
 AUTH_PASSWORD_VALIDATORS = [

+ 1 - 1
Ansjer/config.py

@@ -386,7 +386,7 @@ APNS_CONFIG = {
         'pem_path': 'AnsjerPush/file/apns_pem/customizeda-dev.pem',
     },
     'com.ansjer.zccloud': {
-        'pem_path': 'AnsjerPush/file/apns_pem/zccloud-dev.pem',
+        'pem_path': 'Ansjer/file/apns_pem/zccloud-dev.pem',
     },
     'com.ansjer.accloud': {
         'pem_path': 'AnsjerPush/file/apns_pem/accloud-dev.pem',

+ 1 - 0
Ansjer/eur_config/config_formal.py

@@ -29,6 +29,7 @@ PAYPAL_CRD = {
     "client_id": "AVLoQVq3xHZ6FrF4mxHwlCPgVBAw4Fw5RtMkuxmYd23SkUTIY643n2g3KdK-Al8wV05I28lza5uoQbAA",
     "client_secret": "EO8kRc8yioDk0i2Qq-QMcVFfwkmyMJorTvBSLDTnxDJJ_wb9VoM_0jkUY9iEng2Flp1ze8wQOGpH5nB2"
 }
+PAYPAL_WEB_HOOK_ID = '6TS30758D98835230'
 
 DETECT_PUSH_DOMAIN = 'http://push.dvema.com/'
 DETECT_PUSH_DOMAINS = 'https://push.dvema.com/'

+ 1 - 0
Ansjer/eur_config/config_test.py

@@ -35,6 +35,7 @@ PAYPAL_CRD = {
     "client_id": "AVLoQVq3xHZ6FrF4mxHwlCPgVBAw4Fw5RtMkuxmYd23SkUTIY643n2g3KdK-Al8wV05I28lza5uoQbAA",
     "client_secret": "EO8kRc8yioDk0i2Qq-QMcVFfwkmyMJorTvBSLDTnxDJJ_wb9VoM_0jkUY9iEng2Flp1ze8wQOGpH5nB2"
 }
+PAYPAL_WEB_HOOK_ID = '6TS30758D98835230'
 # PAYPAL_CRD = {
 #     "mode": "sandbox",  # sandbox or live
 #     "client_id": "ATXTpWs8sajNYeU46jNs1yzpy4H_o3RRrGVIJ8Tscc312BjMx12cpRgCucfWX07a4G6GbK8hzElB04Pd",

+ 2 - 1
Ansjer/eur_config/formal_settings.py

@@ -16,6 +16,7 @@ INSTALLED_APPS = [
     'corsheaders',
     'imagekit',
     'Model',
+    'PushModel',
 ]
 
 MIDDLEWARE = [
@@ -108,7 +109,7 @@ DATABASES = {
 DATABASE_ROUTERS = ['Ansjer.database_router.DatabaseAppsRouter']
 DATABASE_APPS_MAPPING = {
     'Model': 'default',
-    'db2': 'mysql02',
+    'PushModel': 'mysql02',
 }
 
 

+ 1 - 1
Ansjer/eur_config/test_settings.py

@@ -114,7 +114,7 @@ DATABASES = {
 DATABASE_ROUTERS = ['Ansjer.database_router.DatabaseAppsRouter']
 DATABASE_APPS_MAPPING = {
     'Model': 'default',
-    'db2': 'mysql02',
+    'PushModel': 'mysql02',
 }
 
 AUTH_PASSWORD_VALIDATORS = [

+ 6 - 5
Ansjer/local_config/config_local.py

@@ -6,9 +6,9 @@ import os
 OAUTH_ACCESS_TOKEN_SECRET = 'local_a+jbgnw%@1%zy^=@dn62%'
 OAUTH_REFRESH_TOKEN_SECRET = 'local_r+jbgnw%@1%zy^=@dn62%'
 
-NGINX_RTMP_STAT = 'http://127.0.0.1:8077/stat'
-SERVER_DOMAIN = 'http://127.0.0.1:8077/'
-SERVER_DOMAIN_SSL = 'http://127.0.0.1:8077/'
+NGINX_RTMP_STAT = 'http://127.0.0.1:8000/stat'
+SERVER_DOMAIN = 'http://127.0.0.1:8000/'
+SERVER_DOMAIN_SSL = 'http://127.0.0.1:8000/'
 SERVER_HOST = '127.0.0.1'
 DOMAIN_HOST = '127.0.0.1'
 PUSH_REDIS_ADDRESS = '127.0.0.1'
@@ -17,9 +17,10 @@ PUSH_REDIS_ADDRESS = '127.0.0.1'
 RTMP_PUSH_URL = 'rtmp://127.0.0.1:1935/hls'
 PAYPAL_CRD = {
     "mode": "sandbox",  # sandbox or live
-    "client_id": "AeuhR7FHisO-lOd2OwtzyDu7PSLMmDZoDLgmzuEQ12WCtTu_8Z1AzcD4gG5SnymnuvJs-n5KBB8H9Z_G",
-    "client_secret": "EGkMCB3RWTcUGJGDYahJ9mCO0AQzEn2AvFfx1GAFjfyyn7-8a0NObcZks89QorlFpvNWTsDXVa2INRNM"
+    "client_id": "AVLoQVq3xHZ6FrF4mxHwlCPgVBAw4Fw5RtMkuxmYd23SkUTIY643n2g3KdK-Al8wV05I28lza5uoQbAA",
+    "client_secret": "EO8kRc8yioDk0i2Qq-QMcVFfwkmyMJorTvBSLDTnxDJJ_wb9VoM_0jkUY9iEng2Flp1ze8wQOGpH5nB2"
 }
+PAYPAL_WEB_HOOK_ID = '6TS30758D98835230'
 DETECT_PUSH_DOMAIN = 'http://test.push.dvema.com/'
 DETECT_PUSH_DOMAINS = 'https://test.push.dvema.com/'
 DETECT_PUSH_DOMAIN_JIUAN = 'http://jiuan.push.dvema.com/'

+ 18 - 19
Ansjer/local_config/local_settings.py

@@ -96,23 +96,22 @@ WSGI_APPLICATION = 'Ansjer.local_config.local_wsgi.application'
 # DATABASES_PASS = 'UKv78ezQhiGMmSef5U5s'
 
 # 本地数据库
-DATABASE_DATA = 'ansjer'
+DATABASE_DATA = 'ansjer_test'
 SERVER_HOST = '127.0.0.1'
 DATABASES_USER = 'root'
-DATABASES_PASS = '123456'
+DATABASES_PASS = 'root'
 
 # 推送数据库
-DATABASE_DATA2 = 'push'
+DATABASE_DATA2 = 'ansjerpush'
 SERVER_HOST2 = '127.0.0.1'
 DATABASES_USER2 = 'root'
-DATABASES_PASS2 = '123456'
+DATABASES_PASS2 = 'root'
 
 # 序列号公共数据库
-DATABASE_DATA3 = 'serial'
-SERVER_HOST3 = '127.0.0.1'
-DATABASES_USER3 = 'root'
-DATABASES_PASS3 = '123456'
-
+# DATABASE_DATA3 = 'ansjer_test'
+# SERVER_HOST3 = '127.0.0.1'
+# DATABASES_USER3 = 'root'
+# DATABASES_PASS3 = '123456'
 DATABASES = {
     'default': {
         'ENGINE': 'django.db.backends.mysql',
@@ -134,16 +133,16 @@ DATABASES = {
         'OPTIONS': {'charset': 'utf8mb4', 'use_unicode': True, 'init_command': "SET sql_mode='STRICT_TRANS_TABLES'"},
         'AUTOCOMMIT': True
     },
-    'mysql03': {
-        'ENGINE': 'django.db.backends.mysql',
-        'NAME': DATABASE_DATA3,
-        'USER': DATABASES_USER3,
-        'PASSWORD': DATABASES_PASS3,
-        'HOST': SERVER_HOST3,
-        'PORT': '3306',
-        'OPTIONS': {'charset': 'utf8mb4', 'use_unicode': True, 'init_command': "SET sql_mode='STRICT_TRANS_TABLES'"},
-        'AUTOCOMMIT': True
-    },
+    # 'mysql03': {
+    #     'ENGINE': 'django.db.backends.mysql',
+    #     'NAME': DATABASE_DATA3,
+    #     'USER': DATABASES_USER3,
+    #     'PASSWORD': DATABASES_PASS3,
+    #     'HOST': SERVER_HOST3,
+    #     'PORT': '3306',
+    #     'OPTIONS': {'charset': 'utf8mb4', 'use_unicode': True, 'init_command': "SET sql_mode='STRICT_TRANS_TABLES'"},
+    #     'AUTOCOMMIT': True
+    # },
 }
 DATABASE_ROUTERS = ['Ansjer.database_router.DatabaseAppsRouter']
 DATABASE_APPS_MAPPING = {

+ 7 - 1
Ansjer/urls.py

@@ -19,7 +19,7 @@ from Controller import FeedBack, EquipmentOTA, EquipmentInfo, AdminManage, AppIn
     OrderTaskController, HistoryUIDController, UIDManageUserController, SerialNumberController, CompanyController, \
     RegionController, VPGController, LanguageController, TestController, DeviceConfirmRegion, S3GetStsController, \
     DetectControllerV2, ShadowController, TestDetectController, PcInfo, PctestController, DeviceDebug, PaymentCycle, \
-    DeviceLogController, CouponController
+    DeviceLogController, CouponController, AiController
 from AdminController import UserManageController, RoleController, MenuController, TestServeController, \
     ServeManagementController, LogManagementController, DeviceManagementController, VersionManagementController
 
@@ -137,6 +137,8 @@ urlpatterns = [
     url(r'^v2/account/logout$', UserController.V2LogoutView.as_view()),
     url(r'^v2/account/login$', UserController.v3LoginView.as_view()),
     url(r'^v3/account/login$', UserController.v3LoginView.as_view()),
+    url(r'^account/oneClickLogin$', UserController.oneClickLoginView.as_view()),
+    url(r'^account/createPwd$', UserController.createPwd.as_view()),
 
     #用户删除/注销
     url(r'^account/delete$', UserController.deleteAccount),
@@ -238,6 +240,10 @@ urlpatterns = [
 	url(r'^cloudstorage/(?P<operation>.*)$', CloudStorage.CloudStorageView.as_view()),
     url(r'^payCycle/(?P<operation>.*)$', PaymentCycle.PaypalCycleNotify.as_view()), #周期扣款
 	url(r'^paypalCycleNotify/(?P<operation>.*)$', PaymentCycle.PaypalCycleNotify.as_view()), #paypal周期扣款订阅通知
+	url(r'^paymentCycle/(?P<operation>.*)$', PaymentCycle.payCycle.as_view()), #paypal周期扣款
+
+    #AI服务
+    url(r'^AiService/(?P<operation>.*)$', AiController.AiView.as_view()),
 
     #新增解密的接口
     url(r'^v3/account/changePwd$', UserController.v3ChangePwdView.as_view()),

+ 1 - 0
Ansjer/us_config/config_formal.py

@@ -24,6 +24,7 @@ PAYPAL_CRD = {
     "client_id": "AdSRd6WBn-qLl9OiQHQuNYTDFSx0ZX0RUttqa58au8bPzoGYQUrt8bc6591RmH8_pEAIPijdvVYSVXyI",
     "client_secret": "ENT-J08N3Fw0B0uAokg4RukljAwO9hFHPf8whE6-Dwd8oBWJO8AWMgpdTKpfB1pOy89t4bsFEzMWDowm"
 }
+PAYPAL_WEB_HOOK_ID = '3YH86681TH784461T'
 # PAYPAL_CRD = {
 #     "mode": "sandbox",  # sandbox or live
 #     "client_id": "AVLoQVq3xHZ6FrF4mxHwlCPgVBAw4Fw5RtMkuxmYd23SkUTIY643n2g3KdK-Al8wV05I28lza5uoQbAA",

+ 1 - 0
Ansjer/us_config/config_test.py

@@ -36,6 +36,7 @@ PAYPAL_CRD = {
     "client_id": "AVLoQVq3xHZ6FrF4mxHwlCPgVBAw4Fw5RtMkuxmYd23SkUTIY643n2g3KdK-Al8wV05I28lza5uoQbAA",
     "client_secret": "EO8kRc8yioDk0i2Qq-QMcVFfwkmyMJorTvBSLDTnxDJJ_wb9VoM_0jkUY9iEng2Flp1ze8wQOGpH5nB2"
 }
+PAYPAL_WEB_HOOK_ID = '6TS30758D98835230'
 # PAYPAL_CRD = {
 #     "mode": "sandbox",  # sandbox or live
 #     "client_id": "ATXTpWs8sajNYeU46jNs1yzpy4H_o3RRrGVIJ8Tscc312BjMx12cpRgCucfWX07a4G6GbK8hzElB04Pd",

+ 2 - 1
Ansjer/us_config/formal_settings.py

@@ -16,6 +16,7 @@ INSTALLED_APPS = [
     'corsheaders',
     'imagekit',
     'Model',
+    'PushModel',
 ]
 
 MIDDLEWARE = [
@@ -109,7 +110,7 @@ DATABASES = {
 DATABASE_ROUTERS = ['Ansjer.database_router.DatabaseAppsRouter']
 DATABASE_APPS_MAPPING = {
     'Model': 'default',
-    'db2': 'mysql02',
+    'PushModel': 'mysql02',
 }
 
 

+ 1 - 1
Ansjer/us_config/test_settings.py

@@ -114,7 +114,7 @@ DATABASES = {
 DATABASE_ROUTERS = ['Ansjer.database_router.DatabaseAppsRouter']
 DATABASE_APPS_MAPPING = {
     'Model': 'default',
-    'db2': 'mysql02',
+    'PushModel': 'mysql02',
 }
 
 AUTH_PASSWORD_VALIDATORS = [

+ 991 - 0
Controller/AiController.py

@@ -0,0 +1,991 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+@Copyright (C) ansjer cop Video Technology Co.,Ltd.All rights reserved.
+@AUTHOR: ASJRD018
+@NAME: AnsjerFormal
+@software: PyCharm
+@DATE: 2018/12/5 9:30
+@Version: python3.6
+@MODIFY DECORD:ansjer dev
+@file: cloudstorage.py
+@Contact: chanjunkai@163.com
+"""
+import base64
+import json
+import os
+import time
+import glob
+import urllib
+from urllib.parse import quote, parse_qs, unquote
+
+import apns2
+import boto3
+import jpush
+import oss2
+import paypalrestsdk
+import threading
+import calendar
+import datetime
+import logging
+import sys
+
+import requests
+from aliyunsdkcore import client
+from aliyunsdksts.request.v20150401 import AssumeRoleRequest
+from boto3.session import Session
+from django.http import JsonResponse, HttpResponseRedirect, HttpResponse
+from django.db import transaction
+from django.views.generic.base import View
+import jwt
+from Object.ETkObject import ETkObject
+from pyfcm import FCMNotification
+from Ansjer.config import OSS_STS_ACCESS_KEY, OSS_STS_ACCESS_SECRET, OSS_ROLE_ARN, SERVER_DOMAIN, PAYPAL_CRD, \
+    SERVER_DOMAIN_SSL, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_ARN, APNS_MODE, APNS_CONFIG, BASE_DIR, \
+    JPUSH_CONFIG, FCM_CONFIG, OAUTH_ACCESS_TOKEN_SECRET
+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, PromotionRuleModel, VideoPlaybackTimeModel, CloudLogModel, CouponModel, \
+    AiStoreMeal, AiService, UidSetModel, Ai_Push_Info, iotdeviceInfoModel, AiProcessTime
+from Object.AWS.S3Email import S3Email
+from Object.AliPayObject import AliPayObject
+from Object.AliSmsObject import AliSmsObject
+from Object.RedisObject import RedisObject
+from Object.ResponseObject import ResponseObject
+from Object.TokenObject import TokenObject
+from Object.UidTokenObject import UidTokenObject
+from Service.CommonService import CommonService
+from Object.m3u8generate import PlaylistGenerator
+from Object.WechatPayObject import WechatPayObject
+from django.db.models import Q, F, Count
+from Controller.PaymentCycle import Paypal
+from decimal import Decimal
+from Ansjer.config import SERVER_TYPE
+from Service.ModelService import ModelService
+from Object import MergePic
+import boto3
+import botocore
+from botocore import client
+
+
+
+# AI服务
+class AiView(View):
+    def get(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        return self.validation(request.GET, request, operation)
+
+    def post(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        return self.validation(request.POST, request, operation)
+
+    def validation(self, request_dict, request, operation):
+        response = ResponseObject()
+        if operation is None:
+            return response.json(444, 'error path')
+        elif operation == 'identification':  # ai识别
+            return self.do_ai_identification(request.POST, response)
+        else:
+            token = request_dict.get('token', None)
+            # 设备主键uid
+            tko = TokenObject(token)
+            response.lang = tko.lang
+            if tko.code != 0:
+                return response.json(tko.code)
+            userID = tko.userID
+            if operation == 'createpayorder':  # 创建支付订单
+                ip = CommonService.get_ip_address(request)
+                return self.do_create_pay_order(request_dict, userID, ip, response)
+            elif operation == 'changeaistatus':  # 修改AI开关状态
+                return self.do_change_ai_status(userID, request_dict, response)
+            elif operation == 'getAiStatus':  # 获取AI开关状态
+                return self.getAiStatus(userID, request_dict, response)
+            elif operation == 'commoditylist':  # 修改云存状态,传送两个url,即getsignsts接口和storeplaylist接口
+                return self.do_commodity_list(userID, request_dict, response)
+            elif operation == 'identification':  # ai识别
+                return self.do_ai_identification(request_dict, response)
+            elif operation == 'queryInfo':  # 查询消息列表
+                return self.queryInfo(userID, request_dict, response)
+            elif operation == 'readInfo':  # 消息已读
+                return self.readInfo(userID, request_dict, response)
+            elif operation == 'deleteInfo':  # 删除消息
+                return self.deleteInfo(userID, request_dict, response)
+            elif operation == 'queryorderlist':  # 查询订单
+                return self.do_querylist(userID, request_dict, response)
+            elif operation == 'updateJpushTime':  # 查询订单
+                return self.update_jpush_time(userID, request_dict, response)
+            else:
+                return response.json(414)
+
+    def do_change_ai_status(self, userID, request_dict, response):
+        token_val = request_dict.get('token_val', None)
+        appBundleId = request_dict.get('appBundleId', None)
+        app_type = request_dict.get('app_type', None)
+        push_type = request_dict.get('push_type', None)
+        status = request_dict.get('status', None)
+        m_code = request_dict.get('m_code', None)
+        uid = request_dict.get('uid', None)
+        # 设备语言
+        lang = request_dict.get('lang', 'en')
+        tz = request_dict.get('tz', '0')
+        # 消息提醒功能新增
+
+        # 如果传空上来,就默认为0
+        if tz == '':
+            tz = 0
+        else:
+            tz = tz.replace("GMT", "")
+        detect_group = request_dict.get('detect_group', None)
+        interval = request_dict.get('interval', None)
+        if not status:
+            return response.json(444, 'status')
+        # 关闭推送
+        if not all([appBundleId, app_type, token_val, uid, m_code]):
+            return response.json(444, 'appBundleId,app_type,token_val,uid,m_code')
+        # 判断推送类型对应key是否存在
+        print('push_type:', push_type)
+
+        if push_type == '0':
+            if appBundleId not in APNS_CONFIG.keys():
+                return response.json(904)
+        elif push_type == '1':
+            if appBundleId not in FCM_CONFIG.keys():
+                return response.json(904)
+        elif push_type == '2':
+            if appBundleId not in JPUSH_CONFIG.keys():
+                return response.json(904)
+        else:
+            return response.json(173)
+        hasAiService = AiService.objects.filter(uid=uid,use_status=1)
+        if not hasAiService.exists():
+            return response.json(10053)
+        nowTime = int(time.time())
+        endTime = hasAiService.values('endTime')[0]['endTime']
+        if nowTime >endTime:
+            return response.json(10054)
+        dvqs = Device_Info.objects.filter(userID_id=userID, UID=uid)
+        status = int(status)
+        nowTime = int(time.time())
+        if dvqs.exists():
+            # 修改状态
+            # dvqs.update(NotificationMode=status)
+            uid_set_qs = UidSetModel.objects.filter(uid=uid)
+            # uid配置信息是否存在
+
+            if uid_set_qs.exists():
+                uid_set_id = uid_set_qs[0].id
+                qs_data = {
+                    'updTime': nowTime,
+
+                }
+                if interval:
+                    qs_data['detect_interval'] = int(interval)
+                if detect_group:
+                    qs_data['detect_group'] = detect_group
+                uid_set_qs.update(**qs_data)
+            else:
+                qs_data = {
+                    'uid': uid,
+                    'addTime': nowTime,
+                    'updTime': nowTime,
+                }
+                if interval:
+                    qs_data['detect_interval'] = int(interval)
+                if detect_group:
+                    qs_data['detect_group'] = detect_group
+                # 添加设备配置
+                uid_set_qs = UidSetModel.objects.create(**qs_data)
+                uid_set_id = uid_set_qs.id
+
+            topic_name = 'AiServer/{}'.format(uid)
+            if status == 0:
+                hasAiService.update(**qs_data)
+                # UidPushModel.objects.filter(uid_set__uid=uid).delete()
+                # 状态为0的时候删除redis缓存数据
+                # self.do_delete_redis(uid)
+
+                # mqtt通知设备关闭AI识别功能
+                msg = {'AiStatus': 'inactive'},
+                req_success = self.requestPublishMqtt(uid, topic_name, msg)
+                if not req_success:
+                    return response.json(10044)
+                return response.json(0)
+            elif status == 1:
+                hasAiService.update(**qs_data)
+                uid_push_qs = UidPushModel.objects.filter(userID_id=userID, m_code=m_code, uid_set__uid=uid)
+
+                if uid_push_qs.exists():
+                    uid_push_update_dict = {
+                        'appBundleId': appBundleId,
+                        'app_type': app_type,
+                        'push_type': push_type,
+                        'token_val': token_val,
+                        'updTime': nowTime,
+                        'lang': lang,
+                        'tz': tz
+                    }
+                    uid_push_qs.update(**uid_push_update_dict)
+                else:
+                    # uid_set_id = uid_set_qs[0].id
+                    uid_push_create_dict = {
+                        'uid_set_id': uid_set_id,
+                        'userID_id': userID,
+                        'appBundleId': appBundleId,
+                        'app_type': app_type,
+                        'push_type': push_type,
+                        'token_val': token_val,
+                        'm_code': m_code,
+                        'addTime': nowTime,
+                        'updTime': nowTime,
+                        'lang': lang,
+                        'tz': tz
+                    }
+                    # 绑定设备推送
+                    UidPushModel.objects.create(**uid_push_create_dict)
+
+                # if interval:
+                #     self.do_delete_redis(uid, int(interval))
+                # else:
+                #     self.do_delete_redis(uid)
+                # utko = UidTokenObject()
+                # # right
+                # utko.generate(data={'uid': uid})
+                etkObj = ETkObject(etk='')
+                etk = etkObj.encrypt(uid)
+
+                #只返回一个接口就行
+                # detectUrl = "{DETECT_PUSH_DOMAIN}AiService/push?etk={etk}&endTime={endTime}". \
+                #     format(etk=etk, DETECT_PUSH_DOMAIN=SERVER_DOMAIN_SSL, endTime=endTime)
+                aiIdentificationUrl = "{DETECT_PUSH_DOMAIN}AiService/identification".format(DETECT_PUSH_DOMAIN=SERVER_DOMAIN_SSL)
+
+                # mqtt通知设备开启AI识别功能
+                msg = {
+                          'AiStatus': 'active',
+                          'etk': etk,
+                          'endTime': endTime,
+                          'aiIdentificationUrl': aiIdentificationUrl,
+                      },
+                req_success = self.requestPublishMqtt(uid, topic_name, msg)
+                if not req_success:
+                    return response.json(10044)
+                return response.json(0, {'aiIdentificationUrl': aiIdentificationUrl, 'endTime': endTime, 'etk': etk})
+        else:
+            return response.json(14)
+
+    def getAiStatus(self, userID, request_dict, response):
+        uid = request_dict.get('uid', None)
+
+        if not uid:
+            return response.json(444)
+        try:
+            ai_server_qs = AiService.objects.filter(uid=uid).values('detect_status', 'detect_group')
+            if not ai_server_qs.exists():
+                return response,json(173)
+            res = {
+                'detect_status': ai_server_qs[0]['detect_status'],
+                'detect_group': ai_server_qs[0]['detect_group'],
+            }
+            return response.json(0, {'data': res})
+        except Exception as e:
+            return response.json(500, repr(e))
+
+    def requestPublishMqtt(self, thing_name, topic_name, msg):
+        # 通用发布MQTT主题通知
+        if not all([msg, thing_name, topic_name]):
+            return False
+
+        try:
+            # 获取数据组织将要请求的url
+            iot = iotdeviceInfoModel.objects.filter(
+                thing_name__icontains=thing_name).values(
+                'endpoint', 'token_iot_number')
+            if not iot.exists():
+                return False
+            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}
+            r = requests.post(url=url, headers=headers, json=msg, timeout=2)
+            if r.status_code == 200:
+                res = r.json()
+                if res['message'] == 'OK':
+                    return True
+                return False
+            else:
+                return False
+        except Exception as e:
+            return False
+
+    def do_commodity_list(self, userID, request_dict, response):  # 查询套餐列表
+        uid = request_dict.get('uid', None)
+        lang = request_dict.get('lang', 'en')
+        nowTime = int(time.time())
+        # DVR/NVR设备暂不返回云存套餐列表
+        device_info_qs = Device_Info.objects.filter(Q(UID=uid), Q(Type__lte=4) | Q(Type=10001))
+        if device_info_qs.exists():
+            return response.json(0)
+
+        qs = AiStoreMeal.objects
+
+        qs = qs.filter(is_show=1)  #过滤隐藏套餐
+        qs = qs.annotate(ai_meal_id=F('id'))
+        qs = qs.values("ai_meal_id", "title", "content", "price", "effective_day", "currency",
+                       "virtual_price", "symbol", "pay_type")
+
+        if qs.exists():
+            res = list(qs)
+            for key, val in enumerate(res):
+                pay_types = Pay_Type.objects.filter(aistoremeal=res[key]['ai_meal_id']).values("id", "payment")
+                res[key]['pay_type'] = list(pay_types)
+            result = {
+                'meals': res,
+            }
+            return response.json(0, result)
+        else:
+            return response.json(0)
+
+    def do_querylist(self, userID, request_dict, response):
+        page = request_dict.get('page', None)
+        line = request_dict.get('line', None)
+        uid = request_dict.get('uid', None)
+        lang = request_dict.get('lang', 'en')
+        if not page or not line:
+            return response.json(444, 'page,line')
+        page = int(page)
+        line = int(line)
+        omqs = Order_Model.objects.filter(userID_id=userID, status=1, order_type=1)
+        # 筛选指定设备id的订单
+        if uid:
+            omqs.filter(UID=uid)
+        if not omqs.exists():
+            return response.json(173)
+            # return response.json(10, '订单不存在')
+        count = omqs.count()
+        omqs = omqs.annotate(rank__title=F('ai_rank__title'), rank__content=F('ai_rank__content'),
+                             rank__day=F('ai_rank__effective_day'), rank__price=F('ai_rank__price'),
+                             rank__expire=F('ai_rank__effective_day'), rank__id=F('ai_rank_id'), rank__currency=F('ai_rank__currency'))
+        order_ql = omqs[(page - 1) * line:page * line].values("orderID", "UID", "channel", "desc", "price", "currency",
+                                                              "addTime",
+                                                              "updTime", "paypal", "rank__day", "payType",
+                                                              "rank__price", "status",
+                                                              "rank__content", "rank__title", "rank__currency",
+                                                              "rank__expire", "ai_rank_id")
+        order_list = list(order_ql)
+        data = []
+        nowTime = int(time.time())
+        # 这里需要进行优化
+        uid_list = []
+        for od in order_list:
+            uid_list.append(od['UID'])
+        didqs = Device_Info.objects.filter(userID_id=userID, UID__in=uid_list).values('id', 'UID', 'Type')
+        for d in order_list:
+            if d['status'] == 0:
+                if d['addTime'] + 3600 < nowTime:
+                    d['status'] = 3
+            for did in didqs:
+                if d['UID'] == did['UID']:
+                    d['did'] = did['id']
+                    d['Type'] = did['Type']
+                    data.append(d)
+            # d['rank__lang__content'] = '月' if lang == 'cn' else 'month'
+        return response.json(0, {'data': data, 'count': count})
+
+    def do_create_pay_order(self, request_dict, userID, ip, response):
+        uid = request_dict.get('uid', None)
+        channel = request_dict.get('channel', None)
+        pay_type = int(request_dict.get('pay_type', 1))
+        ai_meal_id = request_dict.get('ai_meal_id', None)
+        lang = request_dict.get('lang', 'en')
+        if not uid or not channel or not pay_type or not ai_meal_id:
+            return response.json(444)
+        # dv_qs = Device_Info.objects.filter(userID_id=userID, UID=uid, isShare=False, isExist=1).values(
+        #     'vodPrimaryUserID',
+        #     'vodPrimaryMaster')
+        # if not dv_qs.exists():
+        #     return response.json(12)
+
+        # dvq = Device_Info.objects.filter(UID=uid)
+        # dvq = dvq.filter(~Q(vodPrimaryUserID='')).values('vodPrimaryUserID')
+        # if dvq.exists():
+        #     if dvq[0]['vodPrimaryUserID'] != userID:
+        #         return response.json(10033)
+
+        nowTime = int(time.time())
+        smqs = AiStoreMeal.objects.filter(id=ai_meal_id, pay_type=pay_type, is_show=1). \
+            values('currency', 'price', 'content', 'effective_day', 'title')
+        if not smqs.exists():
+            return response.json(173)
+        currency = smqs[0]['currency']
+        price = smqs[0]['price']
+        content = smqs[0]['content']
+        day = smqs[0]['effective_day']
+
+        orderID = CommonService.createOrderID()
+        price = float(price)
+        price = round(price, 2)
+        if pay_type == 1:
+            #正常扣款
+            cal_url = "{SERVER_DOMAIN_SSL}web/paid2/fail.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
+            if lang != 'cn':
+                cal_url = "{SERVER_DOMAIN_SSL}web/paid2/en_fail.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
+            call_sub_url = "{SERVER_DOMAIN_SSL}cloudstorage/dopaypalcallback?orderID={orderID}&lang={lang}". \
+                format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL, orderID=orderID, lang=lang)
+            # call_sub_url = "http://binbin.uicp.vip/cloudstorage/dopaypalcallback?orderID={orderID}".format(
+            # SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL, orderID=orderID)
+            Order_Model.objects.create(orderID=orderID, UID=uid, channel=channel, userID_id=userID,
+                                       desc=content, payType=pay_type, payTime=nowTime,
+                                       price=price, currency=currency, addTime=nowTime, updTime=nowTime,
+                                       pay_url='', commodity_code='', commodity_type=1,
+                                       ai_rank_id=ai_meal_id, rank_id=1, order_type=1, status=1)
+            has = AiService.objects.filter(uid=uid, channel=channel, use_status=1)
+            if has.exists():
+                use_status = 0
+            else:
+                use_status = 1
+            # return response.json(0)
+            AiService.objects.create(orders_id=orderID, uid=uid, channel=channel, detect_status=1,
+                                       endTime=nowTime+(day*86400), addTime=nowTime, updTime=nowTime,
+                                     use_status=use_status, detect_group='1')
+            return response.json(0, {"orderID": orderID})
+        return response.json(10, 'generate_order_false')
+
+    def update_jpush_time(self,userID, request_dict, response):
+        logger = logging.getLogger('info')
+        msg_id = request_dict.get('msg_id', None)
+        apns_push_time = request_dict.get('apns_push_time', None)
+        logger.info("----init--apns----push_time={apns_push_time}".format(apns_push_time=apns_push_time))
+        apns_push_time = int(apns_push_time)
+        logger.info("---msg--id={msg_id}".format(msg_id=msg_id))
+        logger.info("---apns----push_time={apns_push_time}".format(apns_push_time=apns_push_time))
+        try:
+            aiRes = AiProcessTime.objects.filter(msg_id=msg_id).update(appPushTime=apns_push_time)
+        except Exception as e:
+            logger.info(repr(e))
+            return response.json(902,repr(e))
+        return response.json(0,aiRes)
+
+    def do_ai_identification(self, request_dict,response):
+        msg_id = CommonService.createOrderID()
+        AiProcessTime.objects.create(detectTime=0, receiveTime=0, aiTime=0,
+                                     aiEndTime=0, pushTime=0,
+                                     pushEndTime=0, serverCountTime=0, msg_id=msg_id)
+        etk = request_dict.get('etk', None)
+        n_time = request_dict.get('n_time', None)
+        receiveTime = int(time.time())
+        logger = logging.getLogger('info')
+        logger.info('-----------into----ai--api')
+        logger.info("etk={etk}".format(etk=etk))
+        if not etk:
+            return response.json(444)
+
+        try:
+            # 解密uid及判断长度
+            eto = ETkObject(etk)
+            uid = eto.uid
+            logger.info("uid={uid}".format(uid=uid))
+            if len(uid) != 20 and len(uid) != 14:
+                return response.json(444)
+
+            ##通过uid查出endTime是否过期,并且ai开关是否打开
+            AiServiceQuery = AiService.objects.filter(uid=uid, detect_status=1, use_status=1, endTime__gt=receiveTime).\
+                values('detect_group')
+            if not AiServiceQuery.exists():
+                logger.info('none-----aiService')
+                return response.json(173)
+            detect_group = AiServiceQuery[0]['detect_group']
+            #{}??
+            #
+            file_post_one = request_dict.get('fileOne', None)
+            file_post_two = request_dict.get('fileTwo', None)
+            file_post_three = request_dict.get('fileThree', None)
+
+            file_post_one = file_post_one.replace(' ', '+')
+            file_post_two = file_post_two.replace(' ', '+')
+            file_post_three = file_post_three.replace(' ', '+')
+
+            file_post_one = base64.b64decode(file_post_one)
+            file_post_two = base64.b64decode(file_post_two)
+            file_post_three = base64.b64decode(file_post_three)
+
+            file_list = [file_post_one, file_post_two, file_post_three]
+            del file_post_one, file_post_two, file_post_three
+
+            dir_path = os.path.join(BASE_DIR, 'static/ai/' + uid + '/' + str(receiveTime))
+            if not os.path.exists(dir_path):
+                os.makedirs(dir_path)
+            file_path_list = []
+            i = 1
+            for index in file_list:
+                file_path = dir_path + '/' + str(i) + '.jpg'
+                file_path_list.append(file_path)
+                with open(file_path, 'wb') as f:
+                    f.write(index)
+                    f.close()
+                i += 1
+
+            image_size = 500  # 每张小图片的大小
+            image_colnum = 1  # 合并成一张图后,一行有几个小图
+            MergePic.merge_images(dir_path, image_size, image_colnum)
+            photo = open(dir_path + '.jpg', 'rb')  #打开合成图
+
+            cover = dir_path + '/' + str(i-1) + '.jpg'
+            desc = dir_path + '.jpg'
+            logger.info('----------------cover')
+            logger.info(cover)
+            logger.info(desc)
+            # photo = open(r'E:\test---------------\test\snipaste20220121_215952.jpg', 'rb')
+            #识别合成图片
+            maxLabels = 50
+            minConfidence = 96
+
+            ai_start_time = int(time.time())
+            client = boto3.client(
+                'rekognition',
+                aws_access_key_id='AKIA2E67UIMD6JD6TN3J',
+                aws_secret_access_key='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',
+                region_name='us-east-1')
+            # doc:
+            rekognition_res = client.detect_labels(
+                Image={'Bytes': photo.read()},
+                MaxLabels=maxLabels,
+                MinConfidence=minConfidence)
+            if rekognition_res['ResponseMetadata']['HTTPStatusCode'] != 200:
+                return response.json(173)
+            ai_end_time = int(time.time())
+            labels =rekognition_res['Labels']
+            label_name = []
+            logger.info('--------识别到的标签-------')
+            logger.info(labels)
+            for label in labels:
+                label_name.append(label['Name'])
+                for Parents in label['Parents']:
+                    label_name.append(Parents['Name'])
+            labels = self.checkLabels(detect_group, label_name)    #检查标签是否符合用户选择的识别类型
+            if len(labels['label_list']) == 0:
+                logger.info('没有识别到任何标签-----------------')
+                return response.json(10055)
+            event_type = ','.join(labels['label_type'])
+            label_list = ','.join(labels['label_list'])
+            logger.info(event_type)
+            logger.info(label_list)
+            #存储消息以及推送
+            channel = request_dict.get('channel', '1')
+            is_st = 1  #单图
+
+            # 查询推送数据
+            uid_push_qs = UidPushModel.objects.filter(uid_set__uid=uid). \
+                values('token_val', 'app_type', 'appBundleId', 'm_code', 'push_type', 'userID_id',
+                       'userID__NickName',
+                       'lang', 'm_code', 'tz', 'uid_set__nickname', 'uid_set__detect_interval',
+                       'uid_set__detect_group',
+                       'uid_set__channel')
+            if not uid_push_qs.exists():
+                return response.json(173)
+            uid_push_list = []
+            for qs in uid_push_qs:
+                uid_push_list.append(qs)
+
+            nickname = uid_push_list[0]['uid_set__nickname']
+            if not nickname:
+                nickname = uid
+
+            eq_list = []
+            userID_ids = []
+            apns_start_time = 0
+            apns_end_time = 0
+            for up in uid_push_list:
+                push_type = up['push_type']
+                appBundleId = up['appBundleId']
+                token_val = up['token_val']
+                lang = up['lang']
+                tz = up['tz']
+                if tz is None or tz == '':
+                    tz = 0
+
+                # 推送标题
+                msg_title = self.get_msg_title(appBundleId=appBundleId, nickname=nickname)
+                # 推送内容
+                msg_text = self.get_msg_text(channel=channel, n_time=n_time, lang=lang, tz=tz, label_list=label_list)
+                kwargs = {
+                    'uid': uid,
+                    'channel': channel,
+                    'event_type': event_type,
+                    'n_time': n_time,
+                    'appBundleId': appBundleId,
+                    'token_val': token_val,
+                    'msg_title': msg_title,
+                    'msg_text': msg_text,
+                     'msg_id' : msg_id,
+                }
+                # 推送消息
+                # if push_type == 0:  # ios apns
+                #     logger.info('into-------apns')
+                #     apns_start_time = int(time.time())
+                #     res = self.do_apns(**kwargs)
+                #     apns_end_time = int(time.time())
+                #     logger.info(res)
+                # # elif push_type == 1:  # android gcm
+                # #     self.do_fcm(**kwargs)
+                # elif push_type == 2:  # android jpush
+                #     logger.info('into-------jpush')
+                #     jpush_start_time = int(time.time())
+                #     res = self.do_jpush(**kwargs)
+                #     jpush_end_time = int(time.time())
+                #     logger.info(res)
+                if push_type == 1:  # android gcm
+                    logger.info('into-------gcm')
+                    apns_start_time = int(time.time())
+                    res = self.do_fcm(**kwargs)
+                    apns_end_time = int(time.time())
+
+                # 以下是存库
+                userID_id = up["userID_id"]
+                if userID_id not in userID_ids:
+                    now_time = int(time.time())
+                    eq_list.append(Ai_Push_Info(
+                        userID_id=userID_id,
+                        eventTime=n_time,
+                        eventType=event_type,
+                        devUid=uid,
+                        devNickName=nickname,
+                        Channel=channel,
+                        alarm='检查到{labels} \tChannel:{channel}'.format(labels=','.join(labels['label_list']), channel=channel),
+                        is_st=is_st,
+                        receiveTime=receiveTime,
+                        addTime=now_time,
+                        storage_location=2
+                    ))
+                    userID_ids.append(userID_id)
+            Ai_Push_Info.objects.bulk_create(eq_list)
+
+            #上传缩略图到s3
+            cover_start_time = int(time.time())
+            upload_cover_path = "{uid}/{channel}/cover{n_time}.jpg".format(uid=uid, channel=channel, n_time=n_time)  #封面图
+            upload_desc_path = "{uid}/{channel}/desc{n_time}.jpg".format(uid=uid, channel=channel, n_time=n_time)   #详情内容图
+            c_res = self.upload_s3(cover, upload_cover_path)
+            d_res = self.upload_s3(desc, upload_desc_path)
+            if c_res and d_res:
+                logger.info('upload-----S3----success')
+                endTime = int(time.time())
+                count_time = endTime - receiveTime
+                AiProcessTime.objects.filter(msg_id=msg_id).update(detectTime=n_time, receiveTime=receiveTime, aiTime=ai_start_time,
+                                             aiEndTime=ai_end_time, pushTime=apns_start_time,
+                                             pushEndTime=apns_end_time, serverCountTime=count_time,picUploadTime=cover_start_time,
+                                                                   picUploadEndTime = endTime, endTime=endTime)
+                #删除临时文件
+                delf = os.path.join(BASE_DIR, 'static/ai')
+                self.delfile(path=delf)
+                return JsonResponse(status=200, data='success', safe=False)
+            return JsonResponse(status=500, data='fail', safe=False)
+
+        except Exception as e:
+            print(e)
+            return response.json(500, repr(e))
+
+    def delfile(self, path):
+
+        #   read all the files under the folder
+        fileNames = glob.glob(path + r'\*')
+
+        for fileName in fileNames:
+            try:
+                #           delete file
+                os.remove(fileName)
+            except:
+                try:
+                    #               delete empty folders
+                    os.rmdir(fileName)
+                except:
+                    #               Not empty, delete files under folders
+                    delfile(fileName)
+                    #               now, folders are empty, delete it
+                    os.rmdir(fileName)
+
+
+    ## 检查是否有符合条件的标签
+    def checkLabels(self, user_detect_group, labels):
+        labels_type = {
+            '1': ['Person', 'Human'],    #人
+            '2': ['Dog', 'Pet', 'Canine', 'Animal'],   #动物
+            '3': ['Car', '', 'Vehicle', 'Transportation', 'Automobile']   #车
+        }
+        user_detect_list = user_detect_group.split(',')
+        user_labels_type = {}
+        for user_detect in user_detect_list:
+            if user_detect in labels_type.keys():
+                user_labels_type[user_detect] = labels_type[user_detect]
+        label_list = []
+        for k, labels_type in user_labels_type.items():
+            for label in labels_type:
+                if label in labels:
+                    label_list.append(label)
+        user_labels_list = list(user_labels_type.keys())
+        user_labels_list.sort()
+        return {'label_type': user_labels_list, 'label_list': label_list}
+
+
+    def upload_s3(self, file_path, upload_path):
+        try:
+            aws_key = "AKIA2MMWBR4DSFG67DTG" #【你的 aws_access_key】
+            aws_secret = "aI9gxcAKPmiGgPy9axrtFKzjYGbvpuytEX4xWweL" # 【你的 aws_secret_key】
+            session = Session(aws_access_key_id=aws_key,
+                              aws_secret_access_key=aws_secret,
+                              region_name="cn-northwest-1")
+            s3 = session.resource("s3")
+            # client = session.client("s3")
+            bucket = "aipush" # 【你 bucket 的名字】 # 首先需要保.证 s3 上已经存在该存储桶,否则报错
+            upload_data = open(file_path, "rb")
+            # upload_key = "test"
+            s3.Bucket(bucket).put_object(Key=upload_path, Body=upload_data)
+            return True
+        except Exception as e:
+            print(repr(e))
+            return False
+
+    def get_msg_title(self, appBundleId, nickname):
+        package_title_config = {
+            'com.ansjer.customizedd_a': 'DVS',
+            'com.ansjer.zccloud_a': 'ZosiSmart',
+            'com.ansjer.zccloud_ab': '周视',
+            'com.ansjer.adcloud_a': 'ADCloud',
+            'com.ansjer.adcloud_ab': 'ADCloud',
+            'com.ansjer.accloud_a': 'ACCloud',
+            'com.ansjer.loocamccloud_a': 'Loocam',
+            'com.ansjer.loocamdcloud_a': 'Anlapus',
+            'com.ansjer.customizedb_a': 'COCOONHD',
+            'com.ansjer.customizeda_a': 'Guardian365',
+            'com.ansjer.customizedc_a': 'PatrolSecure',
+        }
+        if appBundleId in package_title_config.keys():
+            return package_title_config[appBundleId] + '(' + nickname + ')'
+        else:
+            return nickname
+
+    def get_msg_text(self, channel, n_time, lang, tz, label_list):
+        n_date = CommonService.get_now_time_str(n_time=n_time, tz=tz,lang=lang)
+        if lang == 'cn':
+            msg = '摄像头AI识别到了{}'.format(label_list)
+            send_text = '{msg} 通道:{channel} 日期:{date}'.format(msg=msg, channel=channel, date=n_date)
+        else:
+            msg = 'Camera AI recognizes{}'.format(label_list)
+            send_text = '{msg} channel:{channel} date:{date}'.format(msg=msg, channel=channel, date=n_date)
+        return send_text
+
+    def do_jpush(self, uid, channel, appBundleId, token_val, event_type, n_time, msg_title, msg_text, msg_id=0):
+        app_key = JPUSH_CONFIG[appBundleId]['Key']
+        master_secret = JPUSH_CONFIG[appBundleId]['Secret']
+        # 此处换成各自的app_key和master_secre
+        _jpush = jpush.JPush(app_key, master_secret)
+        push = _jpush.create_push()
+        push.audience = jpush.registration_id(token_val)
+        push_data = {"alert": "Motion ", "event_time": n_time, "event_type": event_type, "msg": "",
+                     "received_at": n_time, "sound": "sound.aif", "uid": uid, "zpush": "1", "channel": channel}
+        android = jpush.android(alert=msg_text, priority=1, style=1, alert_type=7,
+                                big_text=msg_text, title=msg_title,
+                                extras=push_data)
+        push.notification = jpush.notification(android=android)
+        push.platform = jpush.all_
+        res = push.send()
+        print(res)
+        return res.status_code
+
+    def do_fcm(self, uid, channel, appBundleId, token_val, event_type, n_time, msg_title, msg_text, msg_id=0):
+        try:
+            serverKey = FCM_CONFIG[appBundleId]
+            push_service = FCMNotification(api_key=serverKey)
+            data = {"alert": "Motion ", "event_time": n_time, "event_type": event_type, "msg": "",
+                    "received_at": n_time, "sound": "sound.aif", "uid": uid, "zpush": "1", "channel": channel,
+                    "msg_id": msg_id}
+            result = push_service.notify_single_device(registration_id=token_val, message_title=msg_title,
+                                                       message_body=msg_text, data_message=data,
+                                                       extra_kwargs={
+                                                           'default_vibrate_timings': True,
+                                                           'default_sound': True,
+                                                           'default_light_settings': True
+                                                       })
+            print('fcm push ing')
+            print(result)
+            return result
+        except Exception as e:
+            return 'serverKey abnormal'
+
+
+    def do_apns(self, uid, channel, appBundleId, token_val, event_type, n_time, msg_title, msg_text, msg_id=0):
+        logger = logging.getLogger('info')
+        logger.info("进来do_apns函数了")
+        logger.info(token_val)
+        logger.info(APNS_MODE)
+        logger.info(os.path.join(BASE_DIR, APNS_CONFIG[appBundleId]['pem_path']))
+        try:
+            cli = apns2.APNSClient(mode=APNS_MODE, client_cert=os.path.join(BASE_DIR, APNS_CONFIG[appBundleId]['pem_path']))
+            push_data = {"alert": "Motion ", "event_time": n_time, "event_type": event_type, "msg": "",
+                         "received_at": n_time, "sound": "", "uid": uid, "zpush": "1", "channel": channel, "msg_id": msg_id}
+            alert = apns2.PayloadAlert(body=msg_text, title=msg_title)
+            payload = apns2.Payload(alert=alert, custom=push_data, sound="default")
+            n = apns2.Notification(payload=payload, priority=apns2.PRIORITY_LOW)
+            res = cli.push(n=n, device_token=token_val, topic=appBundleId)
+
+            if res.status_code == 200:
+                return res.status_code
+            else:
+                logger.info('apns push fail')
+                logger.info(res.reason)
+                return res.status_code
+        except (ValueError, ArithmeticError):
+            return 'The program has a numeric format exception, one of the arithmetic exceptions'
+        except Exception as e:
+            print(repr(e))
+            logger.info(repr(e))
+            return repr(e)
+
+    def queryInfo(self, userID, request_dict, response):
+        page = int(request_dict.get('page', None))
+        line = int(request_dict.get('line', None))
+        if not page or not line:
+            return response.json(444, 'page,line')
+        startTime = request_dict.get('startTime', None)
+        endTime = request_dict.get('endTime', None)
+        eventType = request_dict.get('eventType', None)
+
+        now_time = int(time.time())
+        seven_days_ago = now_time - 7 * 24 * 3600   # 查询7天内的数据
+        qs = Ai_Push_Info.objects.filter(userID_id=userID, eventTime__gt=seven_days_ago).order_by('-eventTime')
+
+        if startTime and endTime:
+            qs = qs.filter(eventTime__range=(startTime, endTime))
+        # if eventType:
+        #     qs = qs.filter(eventType__contains=eventType)
+        uids = request_dict.get('uids', None)
+        if uids:
+            uid_list = uids.split(',')
+            qs = qs.filter(devUid__in=uid_list)
+            dvqs = Device_Info.objects.filter(UID__in=uid_list, userID_id=userID).values('UID', 'Type', 'NickName')
+            uid_type_dict = {}
+            for dv in dvqs:
+                uid_type_dict[dv['UID']] = {'type': dv['Type'], 'NickName': dv['NickName']}
+        else:
+            dvqs = Device_Info.objects.filter(userID_id=userID).values('UID', 'Type', 'NickName')
+            uid_type_dict = {}
+            for dv in dvqs:
+                uid_type_dict[dv['UID']] = {'type': dv['Type'], 'NickName': dv['NickName']}
+
+        if not qs.exists():
+            return response.json(0, {'datas': [], 'count': 0})
+
+        count = qs.count()
+        qs = qs.values('id', 'devUid', 'devNickName', 'Channel', 'eventType', 'status', 'alarm', 'eventTime',
+                       'receiveTime', 'is_st', 'addTime', 'storage_location')
+
+        qs = qs[(page - 1) * line:page * line]
+        res = []
+
+        aws_s3_client = boto3.client(
+            's3',
+            aws_access_key_id=AWS_ACCESS_KEY_ID[0],
+            aws_secret_access_key=AWS_SECRET_ACCESS_KEY[0],
+            config=botocore.client.Config(signature_version='s3v4'),
+            region_name='cn-northwest-1'
+        )
+
+        for p in qs:
+            p['eventType'] = int(p['eventType'][0])
+            devUid = p['devUid']
+            eventTime = p['eventTime']
+            channel = p['Channel']
+            storage_location = p['storage_location']
+            if p['is_st'] == 1:
+                s3_img_cover = '{uid}/{channel}/cover{time}.jpg'.format(uid=devUid, channel=channel, time=eventTime)
+                s3_img_desc = '{uid}/{channel}/desc{time}.jpg'.format(uid=devUid, channel=channel, time=eventTime)
+                response_url_cover = aws_s3_client.generate_presigned_url('get_object',
+                                                                    ExpiresIn=300,
+                                                                    Params={
+                                                                        'Bucket': 'aipush', 'Key': s3_img_cover
+                                                                    },
+                                                                    )
+                response_url_desc = aws_s3_client.generate_presigned_url('get_object',
+                                                                          ExpiresIn=300,
+                                                                          Params={
+                                                                              'Bucket': 'aipush', 'Key': s3_img_desc
+                                                                          },
+                                                                          )
+                p['img'] = response_url_cover
+                p['img_list'] = [response_url_desc]
+
+            elif p['is_st'] == 2:
+                pass
+
+            if devUid in uid_type_dict.keys():
+                p['uid_type'] = uid_type_dict[devUid]['type']
+                p['devNickName'] = uid_type_dict[devUid]['NickName']
+            else:
+                p['uid_type'] = ''
+            res.append(p)
+        return response.json(0, {'datas': res, 'count': count})
+
+    def readInfo(self, userID, request_dict, response):
+        is_update_all = request_dict.get('is_update_all', 0)
+
+        try:
+            if int(is_update_all) == 1:     # 全部已读
+                is_update = Ai_Push_Info.objects.filter(userID_id=userID).update(status=1)
+                return response.json(0, {'update_count': is_update})
+            else:
+                id_list = request_dict.get('id_list', None)
+                if not id_list:
+                    request_dict.getlist('id_list[]', None)     # 获取IOS数组传参
+                logger = logging.getLogger('info')
+                logger.info('已读ai消息id_list:{}'.format(id_list))
+                if not id_list:
+                    return response.json(444)
+                id_list = eval(id_list)     # 字符串转列表
+                param_flag = CommonService.get_param_flag(data=id_list)
+                if not param_flag:
+                    return response.json(444)
+                count = 0
+                for id in id_list:
+                    ai_push_qs = Ai_Push_Info.objects.filter(id=int(id))
+                    if ai_push_qs.exists():
+                        own_dev = ModelService.check_own_device(userID, ai_push_qs[0].devUid)
+                        if own_dev:
+                            count += 1
+                            ai_push_qs.update(status=1)
+                return response.json(0, {'update_success': count})
+        except Exception as e:
+            print(e)
+            return response.json(500, repr(e))
+
+    def deleteInfo(self, userID, request_dict, response):
+        id_list = request_dict.get('id_list', None)
+        if not id_list:
+            request_dict.getlist('id_list[]', None)  # 获取IOS数组传参
+        logger = logging.getLogger('info')
+        logger.info('删除ai消息id_list:{}'.format(id_list))
+        if not id_list:
+            return response.json(444)
+        try:
+            id_list = eval(id_list)  # 字符串转列表
+            param_flag = CommonService.get_param_flag(data=id_list)
+            if not param_flag:
+                return response.json(444)
+            for id in id_list:
+                ai_push_qs = Ai_Push_Info.objects.filter(id=id)
+                if ai_push_qs.exists():
+                    own_dev = ModelService.check_own_device(userID, ai_push_qs[0].devUid)
+                    if own_dev:
+                        ai_push_qs.delete()
+            return response.json(0)
+        except Exception as e:
+            print(e)
+            return response.json(500, repr(e))

+ 38 - 28
Controller/CloudStorage.py

@@ -27,6 +27,7 @@ import threading
 import calendar
 import datetime
 import logging
+import sys
 from aliyunsdkcore import client
 from aliyunsdksts.request.v20150401 import AssumeRoleRequest
 from boto3.session import Session
@@ -742,7 +743,6 @@ class CloudStorageView(View):
     def do_pay_by_ali_callback(self, request):  # 阿里支付回调
         response = ResponseObject()
         data = request.POST.dict()
-        # logger = logging.getLogger('log')
         try:
             passback_params = data["passback_params"]
             parmap = dict([(k, v[0]) for k, v in parse_qs(unquote(passback_params)).items()])
@@ -767,7 +767,7 @@ class CloudStorageView(View):
 
                 nowTime = int(time.time())
                 order_list = order_qs.values("UID", "channel", "commodity_code", "rank", "isSelectDiscounts",
-                                             "userID__userID", "userID__username")
+                                             "userID__userID", "userID__username","coupon_id")
                 userid = order_list[0]['userID__userID']
                 username = order_list[0]['userID__username']
                 UID = order_list[0]['UID']
@@ -837,7 +837,7 @@ class CloudStorageView(View):
 
                     # 核销coupon
                     if order_list[0]['coupon_id']:
-                        CouponModel.objects.filter(id=order_list[0]['coupon_id']).update(use_status=1)
+                        CouponModel.objects.filter(id=order_list[0]['coupon_id']).update(use_status=2)
 
                     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())
@@ -850,6 +850,10 @@ class CloudStorageView(View):
                     return HttpResponseRedirect(red_url)
             return response.json(0, signature)
         except Exception as e:
+            logger = logging.getLogger('info')
+            logger.info('alipay----notify---------')
+            logger.info(repr(e))
+            logger.info(sys.exc_info())
             if order_qs:
                 order_qs.update(status=10, promotion_rule_id=promotion_rule_id)
             redisObj.del_data(key=orderID + 'do_notify')
@@ -967,7 +971,7 @@ class CloudStorageView(View):
 
                 # 核销coupon
                 if order_list[0]['coupon_id']:
-                    CouponModel.objects.filter(id=order_list[0]['coupon_id']).update(use_status=1)
+                    CouponModel.objects.filter(id=order_list[0]['coupon_id']).update(use_status=2)
 
                 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())
@@ -985,6 +989,7 @@ class CloudStorageView(View):
                 return HttpResponseRedirect(red_url)
         except Exception as e:
             print(repr(e))
+
             if order_qs:
                 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)
@@ -1008,6 +1013,8 @@ class CloudStorageView(View):
             promotion_rule_id = ''
             if trade_status == "SUCCESS":
                 check_sign = pay.get_notifypay(data)
+                order_list = order_qs.values("UID", "channel", "commodity_code", "rank", "isSelectDiscounts",
+                                             "userID__userID", "userID__username", "status", "coupon_id")
                 if not check_sign:
                     return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL', 'return_msg': '签名失败'}))
                 orderID = out_trade_no
@@ -1020,9 +1027,6 @@ class CloudStorageView(View):
                     return response.json(5)
 
                 nowTime = int(time.time())
-                order_list = order_qs.values("UID", "channel", "commodity_code", "rank", "isSelectDiscounts",
-                                             "userID__userID", "userID__username","status")
-
                 logger.info(order_list[0]['UID'])
                 logger.info(orderID)
 
@@ -1093,7 +1097,7 @@ class CloudStorageView(View):
 
                     # 核销coupon
                     if order_list[0]['coupon_id']:
-                        CouponModel.objects.filter(id=order_list[0]['coupon_id']).update(use_status=1)
+                        CouponModel.objects.filter(id=order_list[0]['coupon_id']).update(use_status=2)
 
                     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())
@@ -1128,17 +1132,16 @@ class CloudStorageView(View):
         dv_qs = Device_Info.objects.filter(userID_id=userID, UID=uid, isShare=False, isExist=1).values(
             'vodPrimaryUserID',
             'vodPrimaryMaster')
-        # if not dv_qs.exists():
-        #     return response.json(12)
+        if not dv_qs.exists():
+            return response.json(12)
 
         dvq = Device_Info.objects.filter(UID=uid)
         dvq = dvq.filter(~Q(vodPrimaryUserID='')).values('vodPrimaryUserID')
-        # if dvq.exists():
-        #     if dvq[0]['vodPrimaryUserID'] != userID:
-        #         return response.json(10033)
+        if dvq.exists():
+            if dvq[0]['vodPrimaryUserID'] != userID:
+                return response.json(10033)
 
         nowTime = int(time.time())
-
         # uq = UID_Bucket.objects.filter(uid=uid,endTime__gt=str(nowTime)).values('endTime')
         # if uq.exists():
         #     return response.json(10033)
@@ -1183,20 +1186,23 @@ class CloudStorageView(View):
                 return response.json(10049)
             price = Decimal(price)
             coupon_discount = Decimal(couponQuery[0]['coupon_discount'])
-            if couponQuery[0]['type'] == 1:  #折
+            if couponQuery[0]['type'] == 1:  #
                 price = coupon_discount/10 * price
             elif couponQuery[0]['type'] == 2:  #抵扣
                 price = price - coupon_discount
-            if price < 0:
-                return response.json(10049)
-            price = float(price)
-            couponObj.update(use_status=1)
-
+        price = float(price)
+        if price < 0 or price == 0 or price < 0.01:
+            price = 0.01
+        price = round(price, 2)
         if pay_type == 1:
-            # return HttpResponse(price)
             # 订阅周期扣款
             if(smqs[0]['cycle_config_id']):
-                subInfo = Paypal.subscriptions(store_info=smqs[0],lang=lang,orderID=orderID)
+                #查询是否有订阅过,活跃状态
+                # return HttpResponse(price)
+                checkHasSubscribe = Paypal.checkSubscriptions(userID,uid,rank)
+                if checkHasSubscribe is False:
+                    return response.json(10050)
+                subInfo = Paypal.subscriptions(store_info=smqs[0],lang=lang,orderID=orderID,price=price)
                 if not subInfo:
                     return response.json(10048)
                 Order_Model.objects.create(orderID=orderID, UID=uid, channel=channel, userID_id=userID,
@@ -1204,9 +1210,13 @@ class CloudStorageView(View):
                                            price=price, currency=currency, addTime=nowTime, updTime=nowTime,
                                            pay_url=subInfo['url'], isSelectDiscounts=is_select_discount,
                                            commodity_code=commodity_code, commodity_type=commodity_type,
-                                           rank_id=rank, plan_id=subInfo['plan_id'],coupon_id=coupon_id)
-                return response.json(0, {"redirectUrl": subInfo['url'], "orderID": orderID})
+                                           rank_id=rank, plan_id=subInfo['plan_id'],coupon_id=coupon_id,ai_rank_id=1)
+                # if coupon_id:
+                #     #冻结优惠券
+                #     CouponModel.objects.filter(id=coupon_id, use_status=0, distributeTime__lte=nowTime,
+                #                                            valid_time__gt=nowTime).update(use_status=1)
 
+                return response.json(0, {"redirectUrl": subInfo['url'], "orderID": orderID})
             #正常扣款
             cal_url = "{SERVER_DOMAIN_SSL}web/paid2/fail.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
             if lang != 'cn':
@@ -1242,7 +1252,7 @@ class CloudStorageView(View):
                                                price=price, currency=currency, addTime=nowTime, updTime=nowTime,
                                                pay_url=approval_url, isSelectDiscounts=is_select_discount,
                                                commodity_code=commodity_code, commodity_type=commodity_type,
-                                               rank_id=rank, paymentID=paymentID,coupon_id=coupon_id)
+                                               rank_id=rank, paymentID=paymentID,coupon_id=coupon_id,ai_rank_id=1)
                     return response.json(0, {"redirectUrl": approval_url, "orderID": orderID})
             return response.json(10, 'generate_order_false')
         elif pay_type == 2:
@@ -1285,7 +1295,7 @@ class CloudStorageView(View):
                                                price=price, currency=currency, addTime=nowTime, updTime=nowTime,
                                                pay_url=redirectUrl, isSelectDiscounts=is_select_discount,
                                                commodity_code=commodity_code, commodity_type=commodity_type,
-                                               rank_id=rank,coupon_id=coupon_id)
+                                               rank_id=rank,coupon_id=coupon_id,ai_rank_id=1)
 
                     return JsonResponse(status=200, data={'result_code': 0, 'reason': 'success',
                                                           'result': {"redirectUrl": redirectUrl, "orderID": orderID},
@@ -1312,7 +1322,7 @@ class CloudStorageView(View):
                                        desc=content, payType=pay_type, payTime=nowTime,
                                        price=price, currency=currency, addTime=nowTime, updTime=nowTime,
                                        pay_url=notify_url, isSelectDiscounts=is_select_discount,
-                                       commodity_code=commodity_code, commodity_type=commodity_type, rank_id=rank)
+                                       commodity_code=commodity_code, commodity_type=commodity_type, rank_id=rank, ai_rank_id=1)
             return JsonResponse(status=200, data={'result_code': 0, 'reason': 'success',
                                                   'result': response,
                                                   'orderId': orderID,
@@ -1408,7 +1418,7 @@ class CloudStorageView(View):
                                            updTime=nowTime,
                                            pay_url="体验版",
                                            commodity_code=commodity_code, commodity_type=smqs[0]['commodity_type'],
-                                           rank_id=rank, status=1, uid_bucket_id=uid_bucket_id)
+                                           rank_id=rank, status=1, uid_bucket_id=uid_bucket_id, ai_rank_id=1)
 
                 duq = Device_User.objects.filter(userID=userID).values('username')
                 dvq = Device_Info.objects.filter(UID=uid, vodPrimaryUserID='', vodPrimaryMaster='')

+ 8 - 0
Controller/CloudTransfer.py

@@ -13,6 +13,7 @@ from Object.TokenObject import TokenObject
 from Service.CommonService import CommonService
 from Service.ModelService import ModelService
 from Object.ResponseObject import ResponseObject
+from django.db.models import Q
 from Model.models import Device_User, Device_Info, Order_Model, UID_Bucket, StsCrdModel, VodHlsModel, Unused_Uid_Meal, \
     VodBucketModel, UIDMainUser
 
@@ -87,6 +88,13 @@ class cloudTestView(View):
             if new_deviceInfo_qs:
                 return response.json(10009)
 
+            # 旧用户如果开启云存自动续费,不可转移
+            hasCycle = Order_Model.objects.filter(userID=oldUserID,UID=uid)
+            hasCycle = hasCycle.filter(~Q(agreement_id=''))
+            if hasCycle.exists():
+                return response.json(10056)
+
+
             # 获取新设备的username
             newUserName = Device_User.objects.get(userID=newUserID).username
             vodPrimaryUserID = newUserID

+ 43 - 1
Controller/CouponController.py

@@ -4,8 +4,9 @@ import base64
 import json
 import os
 import time
+import math
 from django.views.generic.base import View
-from Model.models import CouponModel
+from Model.models import CouponModel,Device_User
 from Object.ResponseObject import ResponseObject
 from Object.TokenObject import TokenObject
 from django.db.models import Q, F, Count
@@ -30,6 +31,8 @@ class CouponView(View):
         response = ResponseObject()
         if operation is None:
             return response.json(444, 'error path')
+        if operation == 'generateCoupon':  # 用户优惠券
+            return self.generate_coupon(request_dict, response)
 
         else:
             token = request_dict.get('token', None)
@@ -43,6 +46,45 @@ class CouponView(View):
             else:
                 return response.json(414)
 
+    def generate_coupon(self,request_dict,response):
+        username = request_dict.get('username', None)
+        num = request_dict.get('num', None)
+        userID = Device_User.objects.filter(username=username).values('userID')[0]['userID']
+
+        try:
+            data = []
+            for i in range(int(num)):
+                if i % 2 == 0:
+                    data.append(CouponModel(
+                        userID_id=userID,
+                        use_status=0,
+                        type=1,
+                        coupon_discount=7,
+                        distributeTime=int(time.time()),
+                        valid_time=int(time.time()) + 8640000,
+                        addTime=int(time.time())
+                    ))
+                else:
+                    data.append(CouponModel(
+                        userID_id=userID,
+                        use_status=0,
+                        type=2,
+                        coupon_discount=0.01,
+                        distributeTime=int(time.time()),
+                        valid_time=int(time.time()) + 8640000,
+                        addTime=int(time.time())
+                    ))
+            CouponModel.objects.bulk_create(data)
+            return HttpResponse('success')
+        except Exception as e:
+            return HttpResponse(repr(e))
+
+
+
+
+
+
+
     def query_user_coupon(self, request_dict, userID, response):  #用户优惠券列表
         nowTime = int(time.time())
         couponObj = CouponModel.objects.filter(userID_id=userID,use_status=0,distributeTime__lte=nowTime,

+ 3 - 0
Controller/EquipmentManager.py

@@ -1251,6 +1251,7 @@ def update_device_shadow(request):
         resetTime = request_dict.get('resetTime', None)
         is_ptz = request_dict.get('is_ptz', None)
         is_alexa = request_dict.get('is_alexa', None)
+        is_ai = request_dict.get('is_ai', None)
 
         us_qs = UidSetModel.objects.filter(uid=uid)
         # 更新
@@ -1285,6 +1286,8 @@ def update_device_shadow(request):
             qs_dict['is_ptz'] = is_ptz
         if is_alexa:
             qs_dict['is_alexa'] = is_alexa
+        if is_ai:
+            qs_dict['is_ai'] = is_ai
         if us_qs.exists():
             us_qs.update(**qs_dict)
             # 如果推送状态开启,返回推送url

+ 4 - 2
Controller/EquipmentManagerV3.py

@@ -599,7 +599,7 @@ class EquipmentManagerV3(View):
                                                                     'TimeZone', 'TimeStatus', 'SpaceUsable',
                                                                     'SpaceSum', 'MirrorType', 'RecordType',
                                                                     'OutdoorModel', 'WIFIName', 'isDetector',
-                                                                    'DetectorRank', 'is_human', 'is_custom_voice', 'is_ptz', 'double_wifi')
+                                                                    'DetectorRank', 'is_human', 'is_custom_voice', 'is_ptz', 'double_wifi', 'is_ai')
         uv_dict = {}
         for us in us_qs:
             uv_dict[us['uid']] = {
@@ -625,7 +625,8 @@ class EquipmentManagerV3(View):
                 'is_human': us['is_human'],
                 'is_custom_voice': us['is_custom_voice'],
                 'is_ptz': us['is_ptz'],
-                'double_wifi': us['double_wifi']
+                'double_wifi': us['double_wifi'],
+                'is_ai': us['is_ai']
             }
             # 从uid_channel里面取出通道配置信息
             ucs_qs = UidChannelSetModel.objects.filter(uid__id=us['id']).values('channel', 'channel_name',
@@ -723,6 +724,7 @@ class EquipmentManagerV3(View):
                 p['is_ptz'] = uv_dict[p_uid]['is_ptz']
                 p['channels'] = uv_dict[p_uid]['channels']
                 p['double_wifi'] = uv_dict[p_uid]['double_wifi']
+                p['is_ai'] = uv_dict[p_uid]['is_ai']
                 # 设备昵称 调用影子信息昵称,先阶段不可
                 if uv_dict[p_uid]['nickname']:
                     p['NickName'] = uv_dict[p_uid]['nickname']

+ 337 - 87
Controller/PaymentCycle.py

@@ -1,9 +1,12 @@
-from Ansjer.config import PAYPAL_CRD,SERVER_DOMAIN,SERVER_DOMAIN_SSL
-from Model.models import PayCycleConfigModel,Order_Model, Store_Meal, UID_Bucket, PromotionRuleModel, Unused_Uid_Meal,Device_Info, CouponModel
+from Ansjer.config import PAYPAL_CRD,SERVER_DOMAIN,SERVER_DOMAIN_SSL,PAYPAL_WEB_HOOK_ID
+from Model.models import PayCycleConfigModel,Order_Model, Store_Meal, UID_Bucket, PromotionRuleModel, Unused_Uid_Meal,Device_Info, CouponModel, Order_Model
 from Service.CommonService import CommonService
 from django.http import JsonResponse, HttpResponseRedirect, HttpResponse
 import requests
 import time
+import sys
+from Object.TokenObject import TokenObject
+from Object.UidTokenObject import UidTokenObject
 from Object.ResponseObject import ResponseObject
 import paypalrestsdk
 from paypalrestsdk import BillingAgreement
@@ -14,11 +17,24 @@ from django.db.models import Q, F, Count
 from paypalrestsdk.notifications import WebhookEvent
 import logging
 import json
+from paypalrestsdk import BillingPlan
 
 
 #周期扣款相关
 class Paypal:
-    def subscriptions(store_info,lang,orderID):
+    #检查是否有重复订阅
+    def checkSubscriptions(userID,uid,rank):
+        hasOrder = Order_Model.objects.filter(UID=uid,rank=rank)
+        hasOrder = hasOrder.filter(~Q(agreement_id='')).values('agreement_id','orderID').order_by('-addTime')[0:1]
+        if not hasOrder.exists():
+            return True
+        paypalrestsdk.configure(PAYPAL_CRD)
+        billing_agreement = paypalrestsdk.BillingAgreement.find(hasOrder[0]['agreement_id'])
+        if billing_agreement.state == 'Active':
+            return False
+        return True
+
+    def subscriptions(store_info,lang,orderID,price):
         cycle_config = PayCycleConfigModel.objects.filter(id=store_info['cycle_config_id']).values()
         if not cycle_config:
             return False
@@ -29,6 +45,7 @@ class Paypal:
             format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL, lang=lang)
         # call_sub_url = "http://binbin.uicp.vip/cloudstorage/dopaypalcallback?orderID={orderID}".format(
         # SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL, orderID=orderID)
+        # exit(price)
         BillingPlan = {
             "description": orderID,
             "merchant_preferences": {
@@ -40,7 +57,7 @@ class Paypal:
                 # "notify_url": "http://www.notify.com",  #通知客户协议已创建的 URL。只读并保留供将来使用。
                 "setup_fee": {
                     "currency": store_info['currency'],
-                    "value": store_info['price'],
+                    "value": price,
                 }
             },
             "name": store_info['lang__content'],
@@ -143,9 +160,11 @@ class PaypalCycleNotify(View):
         orderID = billing_agreement_response.description
         agreement_id = billing_agreement_response.id
         promotion_rule_id = ''
+        order_qs = Order_Model.objects.filter(orderID=orderID, status=0)
+        order_list = order_qs.values("UID", "channel", "commodity_code", "rank", "isSelectDiscounts",
+                                     "userID__userID",
+                                     "userID__username", 'coupon_id')
         try:
-            order_qs = Order_Model.objects.filter(orderID=orderID, status=0)
-
             if not orderID:
                 print("not orderID")
                 red_url = "{SERVER_DOMAIN_SSL}web/paid2/fail.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
@@ -153,9 +172,6 @@ class PaypalCycleNotify(View):
                     red_url = "{SERVER_DOMAIN_SSL}web/paid2/en_fail.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
                 return HttpResponseRedirect(red_url)
 
-            order_list = order_qs.values("UID", "channel", "commodity_code", "rank", "isSelectDiscounts",
-                                         "userID__userID",
-                                         "userID__username",'coupon_id')
             userid = order_list[0]['userID__userID']
             username = order_list[0]['userID__username']
             UID = order_list[0]['UID']
@@ -229,7 +245,7 @@ class PaypalCycleNotify(View):
 
                 # 核销coupon
                 if order_list[0]['coupon_id']:
-                    CouponModel.objects.filter(id=order_list[0]['coupon_id']).update(use_status=1)
+                    CouponModel.objects.filter(id=order_list[0]['coupon_id']).update(use_status=2)
 
                 order_qs.update(status=1, updTime=nowTime, uid_bucket_id=uid_bucket_id,
                                 promotion_rule_id=promotion_rule_id,agreement_id=agreement_id)
@@ -257,76 +273,216 @@ class PaypalCycleNotify(View):
 
     def do_paypal_webhook_notify(self, request_dict, request, response):
         logger = logging.getLogger('info')
-        json_str = request.body.decode("utf-8")
-        logger.info('json_str----------------')
-        logger.info(json_str)
-
+        json_agreement_str = request.body.decode("utf-8")
+        json_obj = json.loads(json_agreement_str)
         header = request.META
-        logger.info('json_str----------------')
-        logger.info(header)
-        # json_str = '{"id":"WH-9K090101YP819052B-3LD205733F387905X","event_version":"1.0","create_time":"2022-01-05T08:17:36.937Z","resource_type":"plan","event_type":"BILLING.PLAN.CREATED","summary":"A billing plan was created","resource":{"merchant_preferences":{"setup_fee":{"currency":"USD","value":"0.02"},"return_url":"http://127.0.0.1:8000/payCycle/paypalCycleReturn?lang=en","cancel_url":"http://127.0.0.1:8000/web/paid2/en_fail.html","auto_bill_amount":"YES","initial_fail_amount_action":"CANCEL","max_fail_attempts":"1"},"update_time":"2022-01-05T08:17:15.829Z","create_time":"2022-01-05T08:17:15.129Z","name":"One year package","description":"20220105161712830917","links":[{"href":"https://api.sandbox.paypal.com/v1/payments/billing-plans/P-4RE38399B6473962EFFIEW6I","rel":"self","method":"GET"}],"payment_definitions":[{"id":"PD-8DC78035HJ0448121FFIEW6I","name":"Video save for 7 day","type":"REGULAR","frequency":"Day","amount":{"currency":"USD","value":"0.02"},"cycles":"0","frequency_interval":"1"}],"id":"P-4RE38399B6473962EFFIEW6I","state":"ACTIVE","type":"INFINITE"},"links":[{"href":"https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-9K090101YP819052B-3LD205733F387905X","rel":"self","method":"GET"},{"href":"https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-9K090101YP819052B-3LD205733F387905X/resend","rel":"resend","method":"POST"}]}'
-        json_obj = json.loads(json_str)
-        transmission_id = header.get('paypal-transmission-id',None)
-        transmission_time = header.get('paypal-transmission-id',None)
-        webhook_id = '9RW011891A1707801'
-        cert_url = header.get('paypal-cert-url',None)
-        transmission_sig = header.get('paypal-transmission-sig',None)
-        auth_algo = header.get('paypal-auth-algo',None)
+        paypal_body = json_obj.get('resource')
+
+        billing_agreement_id = paypal_body.get('billing_agreement_id')
+        amount = paypal_body.get('amount')
+        if not billing_agreement_id:
+            return HttpResponse('success')
+
+        transmission_id = header.get('HTTP_PAYPAL_TRANSMISSION_ID',None)
+        transmission_time = header.get('HTTP_PAYPAL_TRANSMISSION_TIME',None)
+        cert_url = header.get('HTTP_PAYPAL_CERT_URL',None)
+        transmission_sig = header.get('HTTP_PAYPAL_TRANSMISSION_SIG',None)
+        auth_algo = header.get('HTTP_PAYPAL_AUTH_ALGO',None)
         resource_type = json_obj.get('resource_type')
 
-        json_str = '{"id":"WH-22P96595RY482870W-2B701244WV459014K","event_version":"1.0","create_time":"2022-01-06T05:56:33.126Z","resource_type":"sale","event_type":"PAYMENT.SALE.COMPLETED","summary":"Payment completed for $ 0.02 USD","resource":{"billing_agreement_id":"I-CR65R6YXS3VA","amount":{"total":"0.02","currency":"USD","details":{"subtotal":"0.02"}},"payment_mode":"INSTANT_TRANSFER","update_time":"2022-01-06T05:56:18Z","create_time":"2022-01-06T05:56:18Z","protection_eligibility_type":"ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE","transaction_fee":{"currency":"USD","value":"0.02"},"protection_eligibility":"ELIGIBLE","links":[{"method":"GET","rel":"self","href":"https://api.sandbox.paypal.com/v1/payments/sale/2FE30648Y2273061H"},{"method":"POST","rel":"refund","href":"https://api.sandbox.paypal.com/v1/payments/sale/2FE30648Y2273061H/refund"}],"id":"2FE30648Y2273061H","state":"completed","invoice_number":""},"links":[{"href":"https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-22P96595RY482870W-2B701244WV459014K","rel":"self","method":"GET"},{"href":"https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-22P96595RY482870W-2B701244WV459014K/resend","rel":"resend","method":"POST"}]}'
-        header = "{'PATH_INFO': '/payCycle/paypalCycleNotify', 'wsgi.file_wrapper': <class 'gunicorn.http.wsgi.FileWrapper'>, 'CONTENT_LENGTH': '1226', 'wsgi.multiprocess': True, 'HTTP_PAYPAL_TRANSMISSION_TIME': '2022-01-06T05:56:36Z', 'wsgi.version': (1, 0), 'SERVER_NAME': '0.0.0.0', 'SCRIPT_NAME': '', 'SERVER_PROTOCOL': 'HTTP/1.0', 'REMOTE_PORT': '42322', 'HTTP_HTTP_X_FORWARDED_FOR': '173.0.80.116', 'RAW_URI': '/payCycle/paypalCycleNotify', 'HTTP_X_REAL_IP': '173.0.80.116', 'HTTP_X_B3_SPANID': 'f37d2832010b10f2', 'REMOTE_ADDR': '127.0.0.1', 'wsgi.input': <gunicorn.http.body.Body object at 0x7ff31a5b92b0>, 'HTTP_PAYPAL_TRANSMISSION_SIG': 'JI+rFKqe9YqufExp/aJxkyRWG3II+4t6CSCWLHqNrjcd/FP729G0s8lFMPixnGpUemj4+WsJTbu29G4ZR3zxl+CwrlKhPQxe0fE0mUw+/AaBa6THpnoXEVwz9spI/kbH3dNmSXePfW0D5+HyVmWgkac23icxi4G92ZmmszPBzBdcNIc3BumXGSfJwX19cchta0VY7GnD5ePvW1FstPp9eC7NyhDH11xDpvM2qZZqhxH6hahIywVNA0gyNydkYbkbjnD+hGC+HrKKMx0Tpw8eGxUHReWJIEsiw7YCPLBwZIab5PV/+L4A/LscK/JicOeDealP+SKPJICZvinLHDzK0Q==', 'HTTP_PAYPAL_TRANSMISSION_ID': '688538e0-6eb5-11ec-a473-05e6d85b61e7', 'gunicorn.socket': <socket.socket fd=24, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8082), raddr=('127.0.0.1', 42322)>, 'HTTP_PAYPAL_AUTH_ALGO': 'SHA256withRSA', 'HTTP_PAYPAL_AUTH_VERSION': 'v2', 'wsgi.url_scheme': 'http', 'wsgi.errors': <gunicorn.http.wsgi.WSGIErrorsWrapper object at 0x7ff31a5b9a58>, 'QUERY_STRING': '', 'wsgi.multithread': False, 'HTTP_CORRELATION_ID': 'b696eaa58ea49', 'HTTP_ACCEPT': '*/*', 'HTTP_USER_AGENT': 'PayPal/AUHD-214.0-56138150', 'CONTENT_TYPE': 'application/json', 'HTTP_PAYPAL_CERT_URL': 'https://api.sandbox.paypal.com/v1/notifications/certs/CERT-360caa42-fca2a594-7a8abba8', 'HTTP_CONNECTION': 'close', 'SERVER_PORT': '8082', 'HTTP_HOST': 'test.zositechc.cn:443', 'HTTP_X_FORWARDED_FOR': '173.0.80.116', 'SERVER_SOFTWARE': 'gunicorn/19.7.1', 'wsgi.run_once': False, 'REQUEST_METHOD': 'POST'}"
-
-        if resource_type == 'plan':
+        # self.get_plan_desc('P-4CG284532S612303METMEINY')
+        if resource_type == 'sale' and paypal_body.get('state') == 'completed':
             paypalrestsdk.configure(PAYPAL_CRD)
             response = paypalrestsdk.WebhookEvent.verify(
-                transmission_id, transmission_time, webhook_id, json_str, cert_url, transmission_sig, auth_algo)
-
+                transmission_id, transmission_time, PAYPAL_WEB_HOOK_ID, json_agreement_str, cert_url, transmission_sig, auth_algo)
+            logger.info('-----------------------verify')
+            logger.info(response)
+            if response:
+                try:
+                    agreement_id = paypal_body.get('billing_agreement_id')
+                    billing_agreement = paypalrestsdk.BillingAgreement.find(agreement_id)
+
+                    # 订阅续费订单(如果完成周期数`不是0, 则说明是续费订单,)
+                    if billing_agreement.agreement_details.cycles_completed == '0':
+                        return HttpResponse('success')
+                    oldOrderID = billing_agreement.description
+                    order_qs = Order_Model.objects.filter(orderID=oldOrderID, status=1)
+                    if not order_qs:
+                        return HttpResponse('fail')
+                    order_list = order_qs.values("UID", "channel", "commodity_code", "rank", "isSelectDiscounts",
+                                                 "userID__userID","uid_bucket_id",
+                                                 "userID__username",'plan_id','addTime','desc','payType','currency','commodity_type','updTime')
+                    nowTime = int(time.time())
+                    if order_list[0]['userID__userID'] + 9200 > nowTime:  #避免续费订单重复支付
+                        return HttpResponse('success')
 
+                    userid = order_list[0]['userID__userID']
+                    username = order_list[0]['userID__username']
+                    UID = order_list[0]['UID']
+                    channel = order_list[0]['channel']
+                    rank = order_list[0]['rank']
+                    smqs = Store_Meal.objects.filter(id=rank). \
+                        values("day", "bucket_id", "bucket__storeDay", "expire")
+                    bucketId = smqs[0]['bucket_id']
+                    if not smqs.exists():
+                        return HttpResponse('fail')
+                    # ##
+                    ubqs = UID_Bucket.objects.filter(uid=UID).values("id", "bucket_id", "bucket__storeDay",
+                                                                     "bucket__region",
+                                                                     "endTime", "use_status")
+                    expire = smqs[0]['expire']
 
-            logger.info('response----------------')
-            logger.info(response)
-            return HttpResponse(json_obj.get('id'))
+                    # 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')
+                    # if promotion.exists():
+                    #     promotion_rule_id = promotion[0]['id']
+                    #     expire = expire * 2
+                    with transaction.atomic():
+                        if ubqs.exists():
+                            ubq = ubqs[0]
+                            if ubq['use_status'] == 1 and ubq['bucket_id'] == bucketId:  # 套餐使用中并且相同套餐叠加过期时间
+                                endTime = CommonService.calcMonthLater(expire, ubq['endTime'])
+                                UID_Bucket.objects.filter(id=ubq['id']).update \
+                                    (uid=UID, channel=channel, bucket_id=bucketId,
+                                     endTime=endTime, updateTime=nowTime)
+                            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 = 1
+                                if has_unused.exists():
+                                    Unused_Uid_Meal.objects.filter(id=has_unused[0]['id']).update(num=F('num') + nums)
+                                else:
+                                    Unused_Uid_Meal.objects.create(uid=UID, channel=channel, addTime=nowTime, num=nums,
+                                                                   expire=smqs[0]['expire'], bucket_id=bucketId)
+                                UID_Bucket.objects.filter(id=ubq['id']).update(has_unused=1)
+                            uid_bucket_id = ubq['id']
+                        else:
+                            endTime = CommonService.calcMonthLater(expire)
+                            ub_cqs = UID_Bucket.objects.create \
+                                (uid=UID, channel=channel, bucket_id=bucketId, endTime=endTime, addTime=nowTime,
+                                 updateTime=nowTime, use_status=1)
+                            uid_bucket_id = ub_cqs.id
 
+                        dvq = Device_Info.objects.filter(UID=UID, vodPrimaryUserID='', vodPrimaryMaster='')
+                        if dvq.exists():
+                            dvq_set_update_dict = {
+                                'vodPrimaryUserID': userid,
+                                'vodPrimaryMaster': username
+                            }
+                            dvq.update(**dvq_set_update_dict)
 
-    def do_test(self, request_dict, request, response):
+                        # uid_main_exist = UIDMainUser.objects.filter(UID=UID)
+                        # if not uid_main_exist.exists():
+                        #     uid_main_dict = {
+                        #         'UID': UID,
+                        #         'user_id': userid
+                        #     }
+                        #     UIDMainUser.objects.create(**uid_main_dict)
+                        orderID = CommonService.createOrderID()
+                        Order_Model.objects.create(orderID=orderID, UID=UID, channel=channel, userID_id=userid,
+                                                   desc=order_list[0]['desc'], payType=order_list[0]['payType'], payTime=nowTime,
+                                                   price=amount.get('total'), currency=order_list[0]['currency'], addTime=nowTime, updTime=nowTime,
+                                                   pay_url='', isSelectDiscounts=0,
+                                                   commodity_code=order_list[0]['commodity_code'], commodity_type=order_list[0]['commodity_type'],
+                                                   rank_id=rank, paymentID='', coupon_id='',uid_bucket_id=uid_bucket_id,status=1,
+                                                   agreement_id=agreement_id,plan_id=order_list[0]['plan_id'], ai_rank_id=1)
+                        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())]
 
-        json_str = '{"id":"WH-22P96595RY482870W-2B701244WV459014K","event_version":"1.0","create_time":"2022-01-06T05:56:33.126Z","resource_type":"sale","event_type":"PAYMENT.SALE.COMPLETED","summary":"Payment completed for $ 0.02 USD","resource":{"billing_agreement_id":"I-CR65R6YXS3VA","amount":{"total":"0.02","currency":"USD","details":{"subtotal":"0.02"}},"payment_mode":"INSTANT_TRANSFER","update_time":"2022-01-06T05:56:18Z","create_time":"2022-01-06T05:56:18Z","protection_eligibility_type":"ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE","transaction_fee":{"currency":"USD","value":"0.02"},"protection_eligibility":"ELIGIBLE","links":[{"method":"GET","rel":"self","href":"https://api.sandbox.paypal.com/v1/payments/sale/2FE30648Y2273061H"},{"method":"POST","rel":"refund","href":"https://api.sandbox.paypal.com/v1/payments/sale/2FE30648Y2273061H/refund"}],"id":"2FE30648Y2273061H","state":"completed","invoice_number":""},"links":[{"href":"https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-22P96595RY482870W-2B701244WV459014K","rel":"self","method":"GET"},{"href":"https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-22P96595RY482870W-2B701244WV459014K/resend","rel":"resend","method":"POST"}]}'
-        header = "{'PATH_INFO': '/payCycle/paypalCycleNotify', 'wsgi.file_wrapper': <class 'gunicorn.http.wsgi.FileWrapper'>, 'CONTENT_LENGTH': '1226', 'wsgi.multiprocess': True, 'HTTP_PAYPAL_TRANSMISSION_TIME': '2022-01-06T05:56:36Z', 'wsgi.version': (1, 0), 'SERVER_NAME': '0.0.0.0', 'SCRIPT_NAME': '', 'SERVER_PROTOCOL': 'HTTP/1.0', 'REMOTE_PORT': '42322', 'HTTP_HTTP_X_FORWARDED_FOR': '173.0.80.116', 'RAW_URI': '/payCycle/paypalCycleNotify', 'HTTP_X_REAL_IP': '173.0.80.116', 'HTTP_X_B3_SPANID': 'f37d2832010b10f2', 'REMOTE_ADDR': '127.0.0.1', 'wsgi.input': <gunicorn.http.body.Body object at 0x7ff31a5b92b0>, 'HTTP_PAYPAL_TRANSMISSION_SIG': 'JI+rFKqe9YqufExp/aJxkyRWG3II+4t6CSCWLHqNrjcd/FP729G0s8lFMPixnGpUemj4+WsJTbu29G4ZR3zxl+CwrlKhPQxe0fE0mUw+/AaBa6THpnoXEVwz9spI/kbH3dNmSXePfW0D5+HyVmWgkac23icxi4G92ZmmszPBzBdcNIc3BumXGSfJwX19cchta0VY7GnD5ePvW1FstPp9eC7NyhDH11xDpvM2qZZqhxH6hahIywVNA0gyNydkYbkbjnD+hGC+HrKKMx0Tpw8eGxUHReWJIEsiw7YCPLBwZIab5PV/+L4A/LscK/JicOeDealP+SKPJICZvinLHDzK0Q==', 'HTTP_PAYPAL_TRANSMISSION_ID': '688538e0-6eb5-11ec-a473-05e6d85b61e7', 'gunicorn.socket': <socket.socket fd=24, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8082), raddr=('127.0.0.1', 42322)>, 'HTTP_PAYPAL_AUTH_ALGO': 'SHA256withRSA', 'HTTP_PAYPAL_AUTH_VERSION': 'v2', 'wsgi.url_scheme': 'http', 'wsgi.errors': <gunicorn.http.wsgi.WSGIErrorsWrapper object at 0x7ff31a5b9a58>, 'QUERY_STRING': '', 'wsgi.multithread': False, 'HTTP_CORRELATION_ID': 'b696eaa58ea49', 'HTTP_ACCEPT': '*/*', 'HTTP_USER_AGENT': 'PayPal/AUHD-214.0-56138150', 'CONTENT_TYPE': 'application/json', 'HTTP_PAYPAL_CERT_URL': 'https://api.sandbox.paypal.com/v1/notifications/certs/CERT-360caa42-fca2a594-7a8abba8', 'HTTP_CONNECTION': 'close', 'SERVER_PORT': '8082', 'HTTP_HOST': 'test.zositechc.cn:443', 'HTTP_X_FORWARDED_FOR': '173.0.80.116', 'SERVER_SOFTWARE': 'gunicorn/19.7.1', 'wsgi.run_once': False, 'REQUEST_METHOD': 'POST'}"
+                        if order_list[0]['payType'] == 1:
+                            lang = 'en'
+                        else:
+                            lang = 'cn'
+                        CloudStorage.CloudStorageView.do_vod_msg_Notice(self, UID, channel, userid, lang,
+                                                                        sys_msg_text_list, 'SMS_219738485')
+                        logger.info('-----------------------result')
+                        logger.info('success')
+
+                        #更新agreement
+                        billing_agreement_update_attributes = [
+                            {
+                                "op": "replace",
+                                "path": "/",
+                                "value": {
+                                    "description": orderID,
+                                }
+                            }
+                        ]
+                        billing_agreement.replace(billing_agreement_update_attributes)
 
-        json_obj = json.loads(json_str)
+                        return HttpResponse('success')
+                except Exception as e:
+                    print(e)
+                    return HttpResponse('fail')
+        return HttpResponse('fail')
 
-        # transmission_id = header.get('HTTP_PAYPAL_TRANSMISSION_ID',None)
-        # transmission_time = header.get('HTTP_PAYPAL_TRANSMISSION_TIME',None)
-        # webhook_id = '6TS30758D98835230'
-        # cert_url = header.get('HTTP_PAYPAL_CERT_URL',None)
-        # transmission_sig = header.get('HTTP_PAYPAL_TRANSMISSION_SIG',None)
-        # auth_algo = header.get('HTTP_PAYPAL_AUTH_ALGO',None)
-        # resource_type = json_obj.get('resource_type')
 
-        transmission_id = '688538e0-6eb5-11ec-a473-05e6d85b61e7'
-        transmission_time = '2022-01-06T05:56:36Z'
+    def do_test(self, request_dict, request, response):
+        paypalrestsdk.configure(PAYPAL_CRD)
+        billing_agreement = paypalrestsdk.BillingAgreement
+        billing_agreement = billing_agreement.find("I-HT38K76XPMGJ")
+        print("Got Billing Agreement Details for Billing Agreement[%s]" % (
+            billing_agreement.id))
+        exit()
+        #normal_pay
+        # json_str = '{"id":"WH-8SU832847J141682K-0FF265943E8692615","event_version":"1.0","create_time":"2022-01-10T06:31:49.863Z","resource_type":"sale","event_type":"PAYMENT.SALE.COMPLETED","summary":"Payment completed for $ 0.02 USD","resource":{"amount":{"total":"0.02","currency":"USD","details":{"subtotal":"0.02"}},"payment_mode":"INSTANT_TRANSFER","create_time":"2022-01-10T06:31:45Z","transaction_fee":{"currency":"USD","value":"0.02"},"parent_payment":"PAYID-MHN5E5Y1RH70069CT417990V","update_time":"2022-01-10T06:31:45Z","protection_eligibility_type":"ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE","application_context":{"related_qualifiers":[{"id":"0FJ93448LU7282046","type":"CART"}]},"protection_eligibility":"ELIGIBLE","links":[{"method":"GET","rel":"self","href":"https://api.sandbox.paypal.com/v1/payments/sale/6N498138TH641260G"},{"method":"POST","rel":"refund","href":"https://api.sandbox.paypal.com/v1/payments/sale/6N498138TH641260G/refund"},{"method":"GET","rel":"parent_payment","href":"https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MHN5E5Y1RH70069CT417990V"}],"id":"6N498138TH641260G","state":"completed","invoice_number":""},"links":[{"href":"https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-8SU832847J141682K-0FF265943E8692615","rel":"self","method":"GET"},{"href":"https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-8SU832847J141682K-0FF265943E8692615/resend","rel":"resend","method":"POST"}]}'
+        json_agreement_str = '{"id":"WH-9BE23393R5338163R-48P08088YL173821A","event_version":"1.0","create_time":"2022-01-10T10:27:42.925Z","resource_type":"sale","event_type":"PAYMENT.SALE.COMPLETED","summary":"Payment completed for $ 0.02 USD","resource":{"billing_agreement_id":"I-K8PCK2NJC6N6","amount":{"total":"0.02","currency":"USD","details":{"subtotal":"0.02"}},"payment_mode":"INSTANT_TRANSFER","update_time":"2022-01-10T10:27:19Z","create_time":"2022-01-10T10:27:19Z","protection_eligibility_type":"ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE","transaction_fee":{"currency":"USD","value":"0.02"},"protection_eligibility":"ELIGIBLE","links":[{"method":"GET","rel":"self","href":"https://api.sandbox.paypal.com/v1/payments/sale/4H259512Y67055105"},{"method":"POST","rel":"refund","href":"https://api.sandbox.paypal.com/v1/payments/sale/4H259512Y67055105/refund"}],"id":"4H259512Y67055105","state":"completed","invoice_number":""},"links":[{"href":"https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-9BE23393R5338163R-48P08088YL173821A","rel":"self","method":"GET"},{"href":"https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-9BE23393R5338163R-48P08088YL173821A/resend","rel":"resend","method":"POST"}]}'
+        header = {'wsgi.file_wrapper': '<class gunicorn.http.wsgi.FileWrapper>', 'wsgi.version': '(1, 0)', 'HTTP_CONNECTION': 'close', 'wsgi.url_scheme': 'http', 'HTTP_PAYPAL_CERT_URL': 'https://api.sandbox.paypal.com/v1/notifications/certs/CERT-360caa42-fca2a594-7a8abba8', 'HTTP_PAYPAL_TRANSMISSION_ID': '022fbbc0-7139-11ec-afa1-0114a54fc1fc', 'SERVER_NAME': '0.0.0.0', 'HTTP_CORRELATION_ID': 'be4c80f0a6c05', 'REMOTE_ADDR': '127.0.0.1', 'HTTP_PAYPAL_TRANSMISSION_SIG': 'IM3Xwyjw5YUgBKPsgyjPdMAh6DSFTtqdwy8zbJBXBhFyB77B6mEqnRfhtEgwwBhag6HsStmKBGIScFhs5Nuraru7DbT4+7Tu5fNx3oQIHeHtR/FYZoQcv86bjZ9cq+Xo04HmhUfgBAsSetS+CuY5TsN60d1m8Hld1MTDjk1UuSbk8HA3dBLiMzWT7wUw3/SUau/C7TtLnWGmdJlkFne+b/5s0+HsuXn3wQQCDIHO0sBMBo72NdlyMlLIunSdoEJ61pKi2U1jQ6qqe/59IrY2q4ufx9D6JZ4bUB6z3NQZ+Gm7zrlKabT6HkVovLJbuBgRgRWWUoY02CuVXZ9w4AzVNQ==', 'REMOTE_PORT': '58060', 'HTTP_ACCEPT': '*/*', 'CONTENT_TYPE': 'application/json', 'HTTP_USER_AGENT': 'PayPal/AUHR-214.0-56015767', 'SCRIPT_NAME': '', 'HTTP_X_FORWARDED_FOR': '173.0.80.117', 'HTTP_HOST': 'test.zositechc.cn:443', 'wsgi.multiprocess': True, 'SERVER_PROTOCOL': 'HTTP/1.0', 'PATH_INFO': '/payCycle/paypalCycleNotify', 'SERVER_SOFTWARE': 'gunicorn/19.7.1', 'wsgi.input': '<gunicorn.http.body.Body object at 0x7fb966cddfd0>', 'REQUEST_METHOD': 'POST', 'wsgi.errors': '<gunicorn.http.wsgi.WSGIErrorsWrapper object at 0x7fb966cdda90>', 'CONTENT_LENGTH': '1226', 'wsgi.run_once': False, 'HTTP_X_B3_SPANID': 'e8ede80526720f95', 'HTTP_PAYPAL_AUTH_ALGO': 'SHA256withRSA', 'QUERY_STRING': '', 'HTTP_PAYPAL_TRANSMISSION_TIME': '2022-01-09T10:43:40Z', 'wsgi.multithread': False, 'HTTP_HTTP_X_FORWARDED_FOR': '173.0.80.117', 'HTTP_X_REAL_IP': '173.0.80.117', 'RAW_URI': '/payCycle/paypalCycleNotify', 'HTTP_PAYPAL_AUTH_VERSION': 'v2', 'gunicorn.socket': '<socket.socket fd=51, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=(127.0.0.1, 8082), raddr=(127.0.0.1, 58060)>', 'SERVER_PORT': '8082'}
+
+
+        json_obj = json.loads(json_agreement_str)
+        paypal_body = json_obj.get('resource')
+        billing_agreement_id = paypal_body.get('billing_agreement_id')
+        amount = paypal_body.get('amount')
+        if not billing_agreement_id:
+            return HttpResponse('success')
+
+        nowTime = int(time.time())
+        transmission_id = header.get('HTTP_PAYPAL_TRANSMISSION_ID',None)
+        transmission_time = header.get('HTTP_PAYPAL_TRANSMISSION_TIME',None)
         webhook_id = '6TS30758D98835230'
-        cert_url = 'https://api.sandbox.paypal.com/v1/notifications/certs/CERT-360caa42-fca2a594-7a8abba8'
-        transmission_sig = 'JI+rFKqe9YqufExp/aJxkyRWG3II+4t6CSCWLHqNrjcd/FP729G0s8lFMPixnGpUemj4+WsJTbu29G4ZR3zxl+CwrlKhPQxe0fE0mUw+/AaBa6THpnoXEVwz9spI/kbH3dNmSXePfW0D5+HyVmWgkac23icxi4G92ZmmszPBzBdcNIc3BumXGSfJwX19cchta0VY7GnD5ePvW1FstPp9eC7NyhDH11xDpvM2qZZqhxH6hahIywVNA0gyNydkYbkbjnD+hGC+HrKKMx0Tpw8eGxUHReWJIEsiw7YCPLBwZIab5PV/+L4A/LscK/JicOeDealP+SKPJICZvinLHDzK0Q=='
-        auth_algo = 'SHA256withRSA'
+        cert_url = header.get('HTTP_PAYPAL_CERT_URL',None)
+        transmission_sig = header.get('HTTP_PAYPAL_TRANSMISSION_SIG',None)
+        auth_algo = header.get('HTTP_PAYPAL_AUTH_ALGO',None)
         resource_type = json_obj.get('resource_type')
+        # return HttpResponse(resource_type)
 
-        if resource_type == 'sale':
-            paypalrestsdk.configure(PAYPAL_CRD)
-            response = paypalrestsdk.WebhookEvent.verify(
-                transmission_id, transmission_time, webhook_id, json_str, cert_url, transmission_sig, auth_algo)
+
+        transmission_id = 'f42509f0-71ff-11ec-a473-05e6d85b61e7'
+        transmission_time = '2022-01-10T10:27:46Z'
+        webhook_id = '3J888119TD851704M'
+        cert_url = 'https://api.sandbox.paypal.com/v1/notifications/certs/CERT-360caa42-fca2a594-7a8abba8'
+        transmission_sig = 'R6sBDhsoq5+FRQHWe+8tSeKJMlRDnt9F2SlWlWVVEfDu9mvQ0zKl74bwcN1zMbvH4o7fWVNbwkcPW70/t4O0YBsj9BcMwL8hDxcuWuHp20RBzaI2dlBpdPEke19wr/fhJKGZCDYuvptV2RJGCSePBn3gKs7hkY5ribELPDqHuajlgVxMmoXm/+CHrMmPo6gSGgTuEMzEn4/ENuj3uJoCkcYqsFx3tUHg6eakUvQ+vYAyflRx9hX7QXEQHp15PWLgGzHkm9zGmnX6YoG5keo5MbJEYh9LfHJjmHmHVErvOtHebJxfTEDZwGoqw+WHr3KqnP4L1gaUj7XIXsQzbiFTBg=='
+        auth_algo = 'SHA256withRSA'
+        resource_type = 'sale'
+        self.get_plan_desc('P-4CG284532S612303METMEINY')
+        if resource_type == 'sale' and paypal_body.get('state') == 'completed':
+            # paypalrestsdk.configure(PAYPAL_CRD)
+            # response = paypalrestsdk.WebhookEvent.verify(
+            #     transmission_id, transmission_time, webhook_id, json_agreement_str, cert_url, transmission_sig, auth_algo)
+            response = True
             if response:
                 try:
-                    agreement_id = json_obj.get('resource')['billing_agreement_id']
-                    order_qs = Order_Model.objects.filter(agreement_id=agreement_id, status=0)
-
+                    agreement_id = paypal_body.get('billing_agreement_id')
+                    order_qs = Order_Model.objects.filter(agreement_id=agreement_id, status=1)
                     if not order_qs:
-                        return False
+                        return HttpResponse('failss')
                     order_list = order_qs.values("UID", "channel", "commodity_code", "rank", "isSelectDiscounts",
-                                                 "userID__userID",
-                                                 "userID__username")
-                    return HttpResponse(order_list)
+                                                 "userID__userID","uid_bucket_id",
+                                                 "userID__username",'plan_id','addTime','desc','payType','currency','commodity_type')
+                    plan_id = order_list[0]['plan_id']
+                    # plan_cycle = self.get_plan_desc(plan_id)
+                    # 订阅续费订单(如果查到的本地订单已经付过了且包中的完成周期数`不是0, 则说明是续费订单, 本地可以新建一个订单标记是续费的)
+                    nowTime = int(time.time())
+                    if(order_list[0]['addTime']+600 > nowTime):
+                        return HttpResponse('success')
 
                     userid = order_list[0]['userID__userID']
                     username = order_list[0]['userID__username']
@@ -337,27 +493,22 @@ class PaypalCycleNotify(View):
                         values("day", "bucket_id", "bucket__storeDay", "expire")
                     bucketId = smqs[0]['bucket_id']
                     if not smqs.exists():
-                        print("not smqs")
-                        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)
-                        return HttpResponseRedirect(red_url)
+                        return HttpResponse('fail')
                     # ##
                     ubqs = UID_Bucket.objects.filter(uid=UID).values("id", "bucket_id", "bucket__storeDay",
                                                                      "bucket__region",
                                                                      "endTime", "use_status")
                     expire = smqs[0]['expire']
 
-                    if order_list[0]['isSelectDiscounts'] == 1:
-                        expire = smqs[0]['expire'] * 2
+                    # 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')
-                    if promotion.exists():
-                        promotion_rule_id = promotion[0]['id']
-                        expire = expire * 2
+                    # nowTime = int(time.time())
+                    # promotion = PromotionRuleModel.objects.filter(status=1, startTime__lte=nowTime,
+                    #                                               endTime__gte=nowTime).values('id', 'ruleConfig')
+                    # if promotion.exists():
+                    #     promotion_rule_id = promotion[0]['id']
+                    #     expire = expire * 2
                     with transaction.atomic():
                         if ubqs.exists():
                             ubq = ubqs[0]
@@ -368,9 +519,9 @@ class PaypalCycleNotify(View):
                                      endTime=endTime, updateTime=nowTime)
                             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
+                                # nums = 2 if order_list[0]['isSelectDiscounts'] == 1 else 1
+                                # if promotion.exists():
+                                nums = 1
                                 if has_unused.exists():
                                     Unused_Uid_Meal.objects.filter(id=has_unused[0]['id']).update(num=F('num') + nums)
                                 else:
@@ -400,20 +551,119 @@ class PaypalCycleNotify(View):
                         #         'user_id': userid
                         #     }
                         #     UIDMainUser.objects.create(**uid_main_dict)
-
-                        order_qs.update(status=1, updTime=nowTime, uid_bucket_id=uid_bucket_id,
-                                        promotion_rule_id=promotion_rule_id, agreement_id=agreement_id)
+                        orderID = CommonService.createOrderID()
+                        Order_Model.objects.create(orderID=orderID, UID=UID, channel=channel, userID_id=userid,
+                                                   desc=order_list[0]['desc'], payType=order_list[0]['payType'], payTime=nowTime,
+                                                   price=amount.get('total'), currency=order_list[0]['currency'], addTime=nowTime, updTime=nowTime,
+                                                   pay_url='', isSelectDiscounts=0,
+                                                   commodity_code=order_list[0]['commodity_code'], commodity_type=order_list[0]['commodity_type'],
+                                                   rank_id=rank, paymentID='', coupon_id='',uid_bucket_id=uid_bucket_id,status=1,agreement_id=agreement_id,plan_id=order_list[0]['plan_id'])
                         datetime = time.strftime("%Y-%m-%d", time.localtime())
-                        sys_msg_text_list = ['温馨提示:尊敬的客户,您的' + UID + '设备在' + datetime + '已成功订阅云存套餐',
+                        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())]
 
+                        if order_list[0]['payType'] == 1:
+                            lang = 'en'
+                        else:
+                            lang = 'cn'
                         CloudStorage.CloudStorageView.do_vod_msg_Notice(self, UID, channel, userid, lang,
                                                                         sys_msg_text_list, 'SMS_219738485')
-                        return True
+                        return HttpResponse('success')
                 except Exception as e:
-                    print(repr(e))
-                    if order_qs:
-                        order_qs.update(status=10, promotion_rule_id=promotion_rule_id)
-                    return False
-        return False
+                    print(e)
+                    return HttpResponse('fail')
+        return HttpResponse('fail')
+
+
+    def get_plan_desc(self,plan_id):
+        paypalrestsdk.configure(PAYPAL_CRD)
+        billing_plan = paypalrestsdk.BillingPlan.find(plan_id)
+        print("Got Billing Plan Details for Billing Plan[%s]" % (billing_plan.id))
+        exit()
+
+
+class payCycle(View):
+    def get(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        return self.validation(request.GET, request, operation)
+
+    def post(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        return self.validation(request.POST, request, operation)
+
+    def validation(self, request_dict, request, operation):
+        response = ResponseObject()
+        token = request_dict.get('token', None)
+        # 设备主键uid
+        tko = TokenObject(token)
+        response.lang = tko.lang
+        if tko.code != 0:
+            return response.json(tko.code)
+        userID = tko.userID
+        if operation is None:
+            return response.json(444, 'error path')
+        elif operation == 'queryPayCycle':  # paypal成功订阅回调
+            return self.do_query_pay_cycle(request_dict,userID, response)
+        elif operation == 'cancelPayCycle':  # 取消自动续费
+            return self.do_cancel_pay_cycle(request_dict,userID, response)
+    def do_query_pay_cycle(self, request_dict, userID, response):
+        lang = request_dict.get('lang', 'en')
+        uid = request_dict.get('uid',None)
+        orderObject = Order_Model.objects.filter(userID=userID,status=1,rank__lang__lang=lang).annotate(rank__title=F('rank__lang__title'), rank__content=F('rank__lang__content'))
+        if uid:
+            orderObject = orderObject.filter(UID=uid)
+        orderObject = orderObject.filter(~Q(agreement_id = ''))
+        if not orderObject.exists():
+            return response.json(0, {'data':[], 'count': 0})
+        orderQuery = orderObject.values("orderID", "UID", "channel", "desc", "price", "currency",
+                "addTime",
+                "updTime", "paypal", "rank__day", "payType",
+                "rank__price", "status",
+                "rank__lang__content", "rank__lang__title", "rank__currency",
+                "rank_id", "rank__expire","agreement_id").order_by('addTime')
+        new_data = []
+        values = []
+        for d in orderQuery:
+            if d['agreement_id'] not in values:
+                new_data.append(d)
+                values.append(d['agreement_id'])
+        count = len(new_data)
+        return response.json(0, {'data': new_data, 'count': count})
+
+    def do_cancel_pay_cycle(self, request_dict, userID, response):
+        orderID = request_dict.get('orderID', 'None')
+        orderObject = Order_Model.objects.filter(orderID=orderID)
+        orderObject = orderObject.filter(~Q(agreement_id = '')).values("agreement_id")
+        if not orderObject.exists():
+            return response.json(800)
+
+        paypalrestsdk.configure(PAYPAL_CRD)
+        BILLING_AGREEMENT_ID = orderObject[0]['agreement_id']
+        try:
+            billing_agreement = paypalrestsdk.BillingAgreement.find(BILLING_AGREEMENT_ID)
+            if billing_agreement.state != 'Active':
+                Order_Model.objects.filter(agreement_id=BILLING_AGREEMENT_ID).update(agreement_id='')
+                return response.json(0)
+            cancel_note = {"note": "Canceling the agreement"}
+            if billing_agreement.cancel(cancel_note):
+                Order_Model.objects.filter(agreement_id=BILLING_AGREEMENT_ID).update(agreement_id='')
+                return response.json(0)
+            else:
+                return response.json(10052)
+        except Exception as e:
+            return response.json(10052)
+
+
+
+
+
+
+
+
+
+
+
+

+ 10 - 22
Controller/SerialNumberController.py

@@ -228,18 +228,13 @@ class SerialNumberView(View):
                         }
                         LogModel.objects.create(**log)
                         # 修改其他数据库的序列号使用状态为已占用
-                        data = {'serial': serial, 'status': 3}
+                        company_serial_id = company_serial.id
+                        data = {'company_serial_id': company_serial_id, 'status': 3}
                         if SERVER_TYPE == 'Ansjer.us_config.formal_settings':
                             url = '{}serialNumber/changeSerialNumberStatus'.format(SERVER_DOMAIN_CN)
                         elif SERVER_TYPE == 'Ansjer.cn_config.formal_settings':
                             url = '{}serialNumber/changeSerialNumberStatus'.format(SERVER_DOMAIN_US)
-                        req_res = requests.post(url=url, data=data, timeout=2)
-                        if req_res.status_code != 200:
-                            raise RuntimeError('请求修改序列号状态发生异常')
-                        req_res = req_res.json()
-                        if req_res['result_code'] != 0:
-                            raise RuntimeError('请求修改序列号状态发生异常')
-
+                        requests.post(url=url, data=data, timeout=2)
                         return response.json(0, res)
 
                     return response.json(5)
@@ -342,17 +337,13 @@ class SerialNumberView(View):
                             up_qs.delete()
 
                     # 修改其他数据库的序列号使用状态为已使用
-                    data = {'serial': serial, 'status': 1}
+                    company_serial_id = company_serial_qs.id
+                    data = {'company_serial_id': company_serial_id, 'status': 1}
                     if SERVER_TYPE == 'Ansjer.us_config.formal_settings':
                         url = '{}serialNumber/changeSerialNumberStatus'.format(SERVER_DOMAIN_CN)
                     elif SERVER_TYPE == 'Ansjer.cn_config.formal_settings':
                         url = '{}serialNumber/changeSerialNumberStatus'.format(SERVER_DOMAIN_US)
-                    req_res = requests.post(url=url, data=data, timeout=2)
-                    if req_res.status_code != 200:
-                        raise RuntimeError('请求修改序列号状态发生异常')
-                    req_res = req_res.json()
-                    if req_res['result_code'] != 0:
-                        raise RuntimeError('请求修改序列号状态发生异常')
+                    requests.post(url=url, data=data, timeout=2)
 
                 UIDModel.objects.filter(uid=uid).update(status=0, mac='')    # 重置uid的使用状态为未分配
                 uid_serial.delete()
@@ -396,18 +387,15 @@ class SerialNumberView(View):
 
     # 序列号绑定和解绑uid时修改其他数据库序列号的使用状态
     def changeSerialNumberStatus(self, request_dict, response):
-        serial = request_dict.get('serial', None)
+        company_serial_id = request_dict.get('company_serial_id', None)
         status = request_dict.get('status', None)
-        if not all([serial, status]):
+        if not all([company_serial_id, status]):
             return response(444)
 
         try:
             # 更新CompanySerialModel表的序列号使用状态
-            update = CompanySerialModel.objects.filter(serial_number=serial).update(status=int(status))
-            if update:
-                return response.json(0)
-            else:
-                return response.json(176)
+            CompanySerialModel.objects.filter(id=company_serial_id).update(status=int(status))
+            return response.json(0)
         except Exception as e:
             djangoLogger = logging.getLogger('django')
             djangoLogger.exception(repr(e))

+ 3 - 0
Controller/ShadowController.py

@@ -104,6 +104,7 @@ def update_device_shadow(request):
         double_wifi = request_dict.get('double_wifi', None)
         is_ptz = request_dict.get('is_ptz', None)
         us_qs = UidSetModel.objects.filter(uid=uid)
+        is_ai = request_dict.get('is_ai', None)
         # 更新
         nowTime = int(time.time())
 
@@ -140,6 +141,8 @@ def update_device_shadow(request):
             qs_dict['double_wifi'] = double_wifi
         if is_ptz:
             qs_dict['is_ptz'] = is_ptz
+        if is_ai:
+            qs_dict['is_ai'] = is_ai
         if us_qs.exists():
             if is_alexa and us_qs[0].is_alexa == 0:
                 qs_dict['is_alexa'] = is_alexa

+ 4 - 2
Controller/SysManage.py

@@ -22,7 +22,7 @@ from Ansjer.config import BASE_DIR
 from Object.ResponseObject import ResponseObject
 from Object.TokenObject import TokenObject
 from Service.ModelService import ModelService
-from Model.models import SysMsgModel, Equipment_Info, Device_Info
+from Model.models import SysMsgModel, Equipment_Info, Device_Info, Ai_Push_Info
 
 
 @csrf_exempt
@@ -107,12 +107,14 @@ def initMsgFunc(request):
         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, 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()
+        rq_count = Equipment_Info.objects.filter(userID_id=userID, eventTime__gt=seven_days_ago, eventType=57, status=False).count()
+        ai_count = Ai_Push_Info.objects.filter(userID_id=userID, eventTime__gt=seven_days_ago, status=False).count()
         uid_reset_count = Device_Info.objects.filter(userID_id=userID, isExist=2).count()
         res = {
             'sm_count': sm_count,  # 系统消息未读数量
             'eq_count': eq_count,  # 未读消息总数
             'rq_count': rq_count,  # 人形检测总数
+            'ai_count': ai_count,  # AI消息总数
             'uid_reset_count': uid_reset_count,# 复位的设备数量
         }
         return response.json(0, res)

+ 1 - 1
Controller/TestApi.py

@@ -722,7 +722,7 @@ class testView(View):
         # UserIdToken
         tko = TokenObject()
         res = tko.generate(
-            data={'userID': 160879593527813800138000, 'lang': 'cn', 'user': '597471180@qq.com', 'm_code': '123413243214'})
+            data={'userID': 162156677434713800138000, 'lang': 'cn', 'user': '3076898361@qq.com', 'm_code': '12341324321'})
         #uidToken
         # utko = UidTokenObject()
         # res = utko.generate(data={'uid': '4UZSEDP93MJ3X7YB111A','channel': 1})

+ 143 - 0
Controller/UserController.py

@@ -48,6 +48,8 @@ from io import BytesIO
 from PIL import Image, ImageDraw, ImageFont
 from django.shortcuts import HttpResponse
 from Ansjer.config import BASE_DIR
+from Object.UVerifyObject import UVerifyObject
+
 
 # 获取验证码
 class authCodeView(TemplateView):
@@ -446,6 +448,49 @@ class v3ChangePwdView(TemplateView):
             return response.json(177)
 
 
+# 创建密码接口
+class createPwd(TemplateView):
+    def get(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        return self.validation(request.GET)
+
+    def post(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        return self.validation(request.POST)
+
+    def validation(self, request_dict):
+        token = request_dict.get('token', None)
+        password = request_dict.get('password', None)
+        response = ResponseObject()
+
+        if not all([token, password]):
+            return response.json(444)
+
+        try:
+            # 解密token获取userID
+            tko = TokenObject(token)
+            response.lang = tko.lang
+            if tko.code != 0:
+                return response.json(tko.code)
+            userID = tko.userID
+
+            # 解密
+            for i in range(1, 4):
+                password = base64.b64decode(password)
+                password = password.decode('utf-8')
+                password = password[i:-i]
+            update = Device_User.objects.filter(userID=userID).update(password=make_password(password))
+            if update:
+                return response.json(0)
+            else:
+                return response.json(177)
+        except Exception as e:
+            djangoLogger = logging.getLogger('django')
+            djangoLogger.exception(e)
+            print(e)
+            return response.json(500, repr(e))
+
+
 class ForgetPwdView(TemplateView):
     '''
     忘记密码
@@ -2004,6 +2049,104 @@ class v3LoginView(TemplateView):
             return response.json(tko.code)
 
 
+# 一键登录接口
+class oneClickLoginView(TemplateView):
+    def get(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        return self.validation(request.GET)
+
+    def post(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        return self.validation(request.POST)
+
+    def validation(self, request_dict):
+        token = request_dict.get('token', None)
+        language = request_dict.get('language', 'en')
+        response = ResponseObject(language)
+
+        if not token:
+            return response.json(444)
+
+        try:
+            # 友盟一键登录验证
+            UVerify = UVerifyObject(token)
+            verify = UVerify.verify_request()
+            if not verify:
+                return response.json(309)
+            phone = UVerify.phone
+
+            if not phone:
+                return response.json(102)
+
+            user_qs = Device_User.objects.filter(phone=phone).values('userID', 'username', 'NickName', 'phone', 'password')
+            # 用户已存在的响应
+            if user_qs.exists():
+                tokenObj = TokenObject()
+                res = tokenObj.generate(
+                    data={
+                        'userID': user_qs[0]['userID'],
+                        'lang': response.lang,
+                        'user': user_qs[0]['username'],
+                        'm_code': '123413243214'
+                    }
+                )
+                if tokenObj.code != 0:
+                    return response.json(tokenObj.code)
+
+                res['userID'] = user_qs[0]['userID']
+                res['username'] = user_qs[0]['username']
+                res['NickName'] = user_qs[0]['NickName']
+                res['phone'] = user_qs[0]['phone']
+                res['userEmail'] = ''
+                res['userIconUrl'] = ''
+                res['subscribe_email'] = ''
+                if user_qs[0]['password']:  # 设置密码,返回已设置标识
+                    res['password'] = '1'
+                else:
+                    res['password'] = ''
+                return response.json(0, res)
+
+            # 新用户
+            userID = CommonService.getUserID(μs=False, setOTAID=True)
+            create_data = {
+                "userID": userID,
+                "username": phone,
+                "NickName": phone,
+                "phone": phone,
+                "is_active": True,
+                "user_isValid": True,
+            }
+            users = Device_User.objects.create(**create_data)
+
+            tokenObj = TokenObject()
+            res = tokenObj.generate(
+                data={
+                    'userID': userID,
+                    'lang': response.lang,
+                    'user': users.username,
+                    'm_code': '123413243214'
+                }
+            )
+            if tokenObj.code != 0:
+                return response.json(tokenObj.code)
+
+            # 组织响应数据
+            res['userID'] = userID
+            res['username'] = users.username
+            res['NickName'] = users.NickName
+            res['phone'] = users.phone
+            res['password'] = ''
+            res['userEmail'] = ''
+            res['userIconUrl'] = ''
+            res['subscribe_email'] = ''
+            return response.json(0, res)
+        except Exception as e:
+            djangoLogger = logging.getLogger('django')
+            djangoLogger.exception(e)
+            print(e)
+            return response.json(500, repr(e))
+
+
 # 用户登录后初始化接口
 class InitInfoView(View):
 

+ 110 - 5
Model/models.py

@@ -322,6 +322,35 @@ class Equipment_Info(models.Model):
     eventType = models.IntegerField(default=0, blank=True, verbose_name=u'事件类型')
     status = models.BooleanField(blank=True, default=False, verbose_name=u'事件状态')
     alarm = models.CharField(blank=True, max_length=256, verbose_name=u'报警信息')
+    eventTime = models.CharField(blank=True, db_index=True, default='', max_length=16, verbose_name=u'设备报警时间')
+    receiveTime = models.CharField(blank=True, default='', max_length=16, verbose_name=u'接收到报警时间')
+    userID_id = models.CharField(default='',  db_index=True, blank=True, max_length=32, verbose_name=u'用户ID')
+    is_st = models.SmallIntegerField(default=0, verbose_name='是否截图')  # 0 否,1 是图,2,视频
+    storage_location = models.SmallIntegerField(default=1, verbose_name='数据信息存储位置。1:阿里云oss,2:aws')
+    # message_id = models.CharField(blank=True, max_length=32, default='', verbose_name='第三方推送服务器返回的id')
+    # push_type = models.SmallIntegerField(blank=True, default=0, verbose_name='第三方推送服务器标志。0:APNS推送,1:谷歌推送,2:极光推送')
+    # push_server_status = models.IntegerField(blank=True, default=200, verbose_name='是否成功推送到第三方服务器。200:成功,other:失败')
+    # push_device_status = models.SmallIntegerField(blank=True, default=-1, verbose_name='是否成功推送到目标设备。0:失败,1:成功')
+    addTime = models.IntegerField(verbose_name='添加时间', db_index=True, default=0)
+
+    def __str__(self):
+        return self.id
+
+    class Meta:
+        db_table = 'equipment_info'
+        verbose_name = u'设备信息推送表'
+        verbose_name_plural = verbose_name
+        ordering = ('-id',)
+        app_label = "PushModel"
+
+class Ai_Push_Info(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name=u'自增标记ID')
+    devUid = models.CharField(default='', db_index=True, blank=True, max_length=32, verbose_name=u'设备ID')
+    devNickName = models.CharField(blank=True, max_length=32, default='', verbose_name=u'设备昵称')
+    Channel = models.IntegerField(default=1, blank=True, verbose_name=u'设备通道')
+    eventType = models.CharField(blank=True, max_length=100, default='', verbose_name=u'事件类型')
+    status = models.BooleanField(blank=True, default=False, verbose_name=u'事件状态')
+    alarm = models.CharField(blank=True, max_length=256, verbose_name=u'报警信息')
     eventTime = models.CharField(blank=True, default='', max_length=16, verbose_name=u'设备报警时间')
     receiveTime = models.CharField(blank=True, default='', max_length=16, verbose_name=u'接收到报警时间')
     userID_id = models.CharField(default='',  db_index=True, blank=True, max_length=32, verbose_name=u'用户ID')
@@ -337,11 +366,11 @@ class Equipment_Info(models.Model):
         return self.id
 
     class Meta:
-        db_table = 'equipment_info'
-        verbose_name = u'设备信息推送表'
+        db_table = 'ai_push_info'
+        verbose_name = u'ai信息推送表'
         verbose_name_plural = verbose_name
         ordering = ('-id',)
-        app_label = "db2"
+
 
 class StatResModel(models.Model):
     id = models.AutoField(primary_key=True, verbose_name='自动ID')
@@ -487,6 +516,37 @@ class Store_Meal(models.Model):
         verbose_name_plural = verbose_name
         ordering = ('id',)
 
+class AiStoreMeal(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name=u'自增ID')
+    title = models.CharField(blank=True, max_length=32, verbose_name=u'标题')
+    currency = models.CharField(blank=True, default='$', max_length=32, verbose_name=u'货币符号')
+    symbol = models.CharField(blank=True, default='$', max_length=32, verbose_name=u'符号')
+    price = models.CharField(blank=True, max_length=32, verbose_name=u'价格')
+    virtual_price = models.CharField(blank=True, max_length=32, verbose_name=u'虚拟价格')
+    is_discounts = models.SmallIntegerField(default=0, verbose_name=u'该套餐是否有优惠 [0=否,1是]')   # 0没有;1有
+    discount_price = models.CharField(blank=True, max_length=32, verbose_name=u'第二年优惠价格')
+    effective_day = models.IntegerField(default=0, blank=True, verbose_name=u'有效天数')   # 7,30,180,360
+    content = models.TextField(blank=True, null=True, verbose_name=u'描述')
+    add_time = models.DateTimeField(blank=True, null=True, verbose_name=u'加入时间', auto_now_add=True)
+    # type = models.SmallIntegerField(default=0, verbose_name='付款类型')  # 0是paypal,1为支付宝
+    pay_type = models.ManyToManyField(to='Pay_Type', verbose_name='付款类型', db_table='ai_store_meal_pay')
+    update_time = models.DateTimeField(blank=True, verbose_name=u'更新时间', auto_now=True)
+    # bucket = models.ForeignKey(VodBucketModel, blank=True, to_field='id', on_delete=models.CASCADE,
+    #                            default=1, verbose_name='存储空间')
+    # commodity_type = models.SmallIntegerField(default=0, verbose_name='套餐类型')  # 1:人形 2:动物 3:汽车
+    is_show = models.SmallIntegerField(default=0, verbose_name=u'该套餐是否隐藏 [0=否,1是]')
+    lang = models.CharField(default='', max_length=20, verbose_name='语言/国家')
+    # cycle_config_id = models.IntegerField(null=True, verbose_name='周期付款配置表id')
+
+    def __str__(self):
+        return self.id
+
+    class Meta:
+        db_table = 'ai_store_meal'
+        verbose_name = u'AI套餐'
+        verbose_name_plural = verbose_name
+        ordering = ('id',)
+
 
 class Pay_Type(models.Model):
     id = models.AutoField(primary_key=True, verbose_name=u'自增ID')
@@ -614,7 +674,9 @@ class Order_Model(models.Model):
     # 1: PayPal, 2: 支付宝, 3: 微信, 10: 免费体验, 11: 激活码
     payType = models.SmallIntegerField(default=0, verbose_name='支付方式')
     payTime = models.IntegerField(verbose_name='支付成功时间', default=0)
-    rank = models.ForeignKey(Store_Meal, to_field='id', default='', on_delete=models.CASCADE, verbose_name='套餐类型')
+    rank = models.ForeignKey(Store_Meal, to_field='id', default='', on_delete=models.CASCADE, verbose_name='关联云存套餐表')
+    ai_rank = models.ForeignKey(AiStoreMeal, to_field='id', default='', on_delete=models.CASCADE, verbose_name='关联ai套餐表')
+    order_type = models.SmallIntegerField(default=0, verbose_name='订单类型:0:云存:1:ai')
     nickname = models.CharField(default='', max_length=64, verbose_name='设备昵称')
     uid_bucket_id = models.IntegerField(default=0, verbose_name='关联uid_bucket的字段')
     commodity_type = models.SmallIntegerField(default=0, verbose_name='云存储套餐类型')
@@ -824,7 +886,7 @@ class SysMsgModel(models.Model):
         verbose_name = '系统消息'
         verbose_name_plural = verbose_name
         ordering = ('-id',)
-        app_label = "db2"
+        app_label = "PushModel"
 
 
 # 设备推送重构
@@ -866,6 +928,7 @@ class UidSetModel(models.Model):
     is_custom_voice = models.IntegerField(default=0, verbose_name='是否支持自定义语音。0:不支持,1:支持')
     double_wifi = models.IntegerField(default=0, verbose_name='是否支持双频wifi。0:不支持,1:支持')
     is_ptz = models.IntegerField(default=0, verbose_name='是否支持云台。0:不支持,1:支持')
+    is_ai = models.IntegerField(default=2, verbose_name='是否支持ai')  # 0,关闭,1开启,2,不支持
     class Meta:
         db_table = 'uid_set'
         verbose_name = u'设备配置表'
@@ -1849,3 +1912,45 @@ class RequestRecordModel(models.Model):
         verbose_name = u'请求记录表'
         verbose_name_plural = verbose_name
         ordering = ('-add_time',)
+
+
+class AiService(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name=u'自增标记ID')
+    uid = models.CharField(max_length=20, verbose_name='设备UID', db_index=True)
+    channel = models.SmallIntegerField(default=0, verbose_name='通道')
+    orders = models.ForeignKey(Order_Model, to_field='orderID', default='', on_delete=models.CASCADE, verbose_name='关联订单表')
+    detect_status = models.SmallIntegerField(default=0, verbose_name='状态[0:开启,1:关闭]')
+    endTime = models.BigIntegerField(verbose_name='套餐结束时间', db_index=True, default=0)
+    addTime = models.IntegerField(verbose_name='添加时间', default=0)
+    updTime = models.BigIntegerField(verbose_name='更新时间', default=0)
+    use_status = models.IntegerField(verbose_name='使用状态[0:未使用,1:使用中,2已过期]', default=0)
+    detect_group = models.CharField(blank=True, default='1', max_length=100, verbose_name='侦测类型[1=人;2=动物;3=车]')
+    detect_interval = models.IntegerField(verbose_name='推送间隔', default=60)  # 秒
+
+
+    class Meta:
+        db_table = 'ai_service'
+        verbose_name = 'ai设备服务表'
+        verbose_name_plural = verbose_name
+        ordering = ('id',)
+
+class AiProcessTime(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name=u'自增标记ID')
+    msg_id = models.CharField(max_length=50, verbose_name='消息id', default=0)
+    detectTime  = models.BigIntegerField(verbose_name='设备侦测时间', default=0)
+    receiveTime  = models.BigIntegerField(verbose_name='接口调用时间', default=0)
+    aiTime = models.BigIntegerField(verbose_name='ai识别上传开始时间', default=0)
+    aiEndTime = models.BigIntegerField(verbose_name='ai识别结束时间', default=0)
+    pushTime  = models.BigIntegerField(verbose_name='推送开始时间', default=0)
+    pushEndTime  = models.BigIntegerField(verbose_name='推送结束时间', default=0)
+    picUploadTime = models.BigIntegerField(verbose_name='图片上传开始时间', default=0)
+    picUploadEndTime = models.BigIntegerField(verbose_name='图片上传结束结束时间', default=0)
+    serverCountTime  = models.BigIntegerField(verbose_name='服务器总花时间', default=0)
+    appPushTime = models.IntegerField(verbose_name='添加时间', default=0)
+    endTime = models.IntegerField(verbose_name='接口结束时间', default=0)
+
+    class Meta:
+        db_table = 'ai_process_time'
+        verbose_name = 'ai设备服务表'
+        verbose_name_plural = verbose_name
+        ordering = ('id',)

+ 14 - 0
Object/ResponseObject.py

@@ -106,6 +106,13 @@ class ResponseObject(object):
             10047: 'Please delete all devices under your account first',
             10048: 'Subscribe to the failure',
             10049: 'The coupon is not available',
+            10050: 'You have subscribed to this package, please do not subscribe again',
+            10051: 'Unsubscribe successfully',
+            10052: 'Unsubscribe failed',
+            10053: 'The AI service is not purchased',
+            10054: 'The AI service has expired',
+            10055: 'The AI does not recognize any labels',
+            10056: 'The device has enabled automatic renewal of cloud storage package and cannot be transferred for the time being',
         }
         data_cn = {
             0: '成功',
@@ -205,6 +212,13 @@ class ResponseObject(object):
             10047: '请先删除您当前帐户下的所有设备',
             10048: '订阅失败',
             10049: '该优惠券不可用',
+            10050: '您已订阅过此套餐,请不要重复订阅',
+            10051: '已取消订阅',
+            10052: '订阅取消失败',
+            10053: '未购买AI服务',
+            10054: 'AI服务已过期',
+            10055: 'AI没有识别到任何标签',
+            10056: '该设备已开通云存套餐自动续费,暂时无法转移',
         }
         if self.lang == 'cn':
             msg = data_cn

+ 126 - 0
Object/UVerifyObject.py

@@ -0,0 +1,126 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+import base64
+import hashlib
+import hmac
+import json
+import logging
+import random
+import string
+import time
+import requests
+from collections import OrderedDict
+from datetime import datetime, timedelta
+
+
+class UVerifyObject:
+
+    '''
+    【友盟+】智能认证 U-Verify(一键登录)
+    开发文档:
+    https://developer.umeng.com/docs/143070/detail/144785
+    https://developer.umeng.com/docs/143070/detail/144783
+    '''
+
+    def __init__(self, token):
+        # aliyun config
+        self.ali_appkey = '204024884'
+        self.ali_app_secret = 'lD7AXxc0ji0HzrNXZmfJaz3AecAboItD'
+
+        # umeng config
+        self.host_url = 'https://verify5.market.alicloudapi.com'
+        self.path_url = '/api/v1/mobile/info'
+        self.umeng_app_key = '5d8da0670cafb2a6b5000bc3'
+
+        self.token = token
+        self.phone = ''
+
+        self.body_data_str = json.dumps({'token': self.token})
+        content_md5_str = base64.b64encode(hashlib.md5(self.body_data_str.encode("UTF-8")).digest()).decode("UTF-8")
+
+        now_date_time = datetime.utcnow() + timedelta(hours=8)
+        timestamp = str(int(time.mktime(now_date_time.timetuple()) * 1000))
+
+        sign_headers_dict = {
+            'X-Ca-Key': self.ali_appkey,
+            'X-Ca-Stage': 'RELEASE',
+            'X-Ca-Timestamp': timestamp,
+            'X-Ca-Version': '1'
+        }
+
+        sign_headers_str = ''
+        for key in sorted(sign_headers_dict.keys()):
+            value = sign_headers_dict[key]
+            sign_headers_str = sign_headers_str + key + ':' + value + '\n'
+
+        # 需要使用有序字典,否则StringToSign错误
+        sign_dict = OrderedDict(
+            [('HTTPMethod', 'POST'),
+            ('Accept', 'application/json'),
+            ('Content-MD5', content_md5_str),
+            ('Content-Type', 'application/json; charset=UTF-8'),
+            ('Date', None,),
+            ('Headers', sign_headers_str),
+            ('Url', self.path_url + '?' + 'appkey=' + self.umeng_app_key)]
+        )
+
+        string_to_sign = ""
+        for key in sign_dict.keys():
+            value = sign_dict[key]
+            if key not in ['Headers', 'Url']:
+                if value:
+                    string_to_sign = string_to_sign + value + "\n"
+                else:
+                    string_to_sign = string_to_sign + "\n"
+            else:
+                string_to_sign = string_to_sign + value
+
+        logger = logging.getLogger('info')
+        logger.info('string_to_sign: {}'.format(string_to_sign))
+
+        key_bytes = self.ali_app_secret.encode('utf-8')
+        text_bytes = string_to_sign.encode('utf-8')
+        hash_bytes = hmac.new(key_bytes, text_bytes, hashlib.sha256).digest()
+        signature_str = base64.b64encode(hash_bytes).decode('utf-8')
+
+        nonce_str = self.generate_code(8) + '-' + self.generate_code(4) + '-' + self.generate_code(4) + '-' + \
+                    self.generate_code(4) + '-' + self.generate_code(12)
+
+        self.headers_dict = {
+            'Content-Type': 'application/json; charset=UTF-8',
+            'Accept': 'application/json',
+            'X-Ca-Version': '1',
+            'X-Ca-Signature-Headers': 'X-Ca-Version,X-Ca-Stage,X-Ca-Key,X-Ca-Timestamp',
+            'X-Ca-Stage': 'RELEASE',
+            'X-Ca-Key': self.ali_appkey,
+            'X-Ca-Timestamp': timestamp,
+            'X-Ca-Nonce': nonce_str,
+            'Content-MD5': content_md5_str,
+            'X-Ca-Signature': signature_str
+        }
+
+        self.request_url = self.host_url + self.path_url + '?' + 'appkey=' + self.umeng_app_key
+
+
+    def generate_code(self, length):
+        key = string.digits + 'abcdef'
+        str_list = random.sample(key + key, length)  # length >= len(key+key)
+        result_str = ''.join(str_list)
+        return result_str
+
+    def verify_request(self):
+        logger = logging.getLogger('info')
+        logger.info('request_url: {}, data: {}, headers: {}'.format(self.request_url, self.body_data_str, self.headers_dict))
+        response = requests.post(url=self.request_url, data=self.body_data_str.encode("UTF-8"), headers=self.headers_dict)
+        logger.info('response: {}, headers: {}, text: {}'.format(response, response.headers, response.text))
+        if response.status_code != 200:
+            return False
+        # 替换字符串,防止将字符串转为字典时报错
+        res_text = response.text.replace('true', '"true"').replace('false', '"false"').replace('null', '"null"')
+        logger.info('res_text: {}'.format(res_text))
+        res = eval(res_text)
+        print(res['success'])
+        if res['success'] == 'false':
+            return False
+        self.phone = res['data']['mobile']  # 获取手机号
+        return True