Parcourir la source

升级python版本更新代码

peng il y a 2 ans
Parent
commit
820bfc9d63
61 fichiers modifiés avec 2505 ajouts et 973 suppressions
  1. 24 2
      AdminController/ServeManagementController.py
  2. 21 2
      AdminController/UnicomManageController.py
  3. 36 1
      AdminController/UserManageController.py
  4. 1 2
      AdminController/dataSystemManagement/BusinessDataController.py
  5. 1 1
      AdminController/dataSystemManagement/UserDataController.py
  6. 1 0
      Ansjer/cn_config/config_formal.py
  7. 11 6
      Ansjer/cn_config/config_test.py
  8. 5 5
      Ansjer/cn_config/formal_settings.py
  9. 8 20
      Ansjer/cn_config/test_settings.py
  10. 1 0
      Ansjer/eur_config/config_formal.py
  11. 4 4
      Ansjer/eur_config/formal_settings.py
  12. 1 0
      Ansjer/local_config/config_local.py
  13. 5 41
      Ansjer/local_config/local_settings.py
  14. 4 0
      Ansjer/server_urls/algorithm_shop_url.py
  15. 13 0
      Ansjer/server_urls/kvs_url.py
  16. 0 85
      Ansjer/test/coposs_sts.py
  17. 0 65
      Ansjer/test/oss_sts.py
  18. 0 44
      Ansjer/test/osssigput.py
  19. 10 1
      Ansjer/urls.py
  20. 1 0
      Ansjer/us_config/config_formal.py
  21. 2 0
      Ansjer/us_config/formal_settings.py
  22. 472 0
      Controller/AWS/KVSController.py
  23. 2 3
      Controller/AdminManage.py
  24. 173 0
      Controller/AppAccountManagement.py
  25. 7 7
      Controller/AppInfo.py
  26. 12 63
      Controller/CDKController.py
  27. 183 0
      Controller/CloudPhoto/CloudPhotoController.py
  28. 232 0
      Controller/Cron/CronCloudPhotoController.py
  29. 32 6
      Controller/DeviceShare.py
  30. 3 0
      Controller/EquipmentManager.py
  31. 1 1
      Controller/EquipmentManagerV3.py
  32. 25 2
      Controller/PcInfo.py
  33. 154 0
      Controller/ShadowController.py
  34. 7 22
      Controller/StsOssController.py
  35. 1 0
      Controller/SysMsg.py
  36. 76 314
      Controller/TestApi.py
  37. 2 2
      Controller/UserBrandController.py
  38. 23 24
      Controller/UserController.py
  39. 195 0
      Controller/UserDevice/UserDeviceShareController.py
  40. 2 1
      Controller/UserExController.py
  41. 1 1
      Controller/shareUserPermission.py
  42. 227 10
      Model/models.py
  43. 34 0
      Object/AWS/AmazonKVSUtil.py
  44. 187 0
      Object/AWS/AmazonKinesisVideoUtil.py
  45. 15 2
      Object/AWS/AmazonS3Util.py
  46. 8 0
      Object/RedisObject.py
  47. 15 38
      Object/TokenObject.py
  48. 6 27
      Object/UidTokenObject.py
  49. 1 1
      Object/UrlTokenObject.py
  50. 0 58
      README.md
  51. 0 0
      SerialModel/__init__.py
  52. 0 3
      SerialModel/admin.py
  53. 0 5
      SerialModel/apps.py
  54. 0 0
      SerialModel/migrations/__init__.py
  55. 0 3
      SerialModel/models.py
  56. 0 3
      SerialModel/tests.py
  57. 0 3
      SerialModel/views.py
  58. 37 90
      Service/CommonService.py
  59. 86 5
      Service/UserDeviceService.py
  60. 137 0
      Service/VodHlsService.py
  61. BIN
      requirements.txt

+ 24 - 2
AdminController/ServeManagementController.py

@@ -679,6 +679,7 @@ class serveManagement(View):
         status = request_dict.get('status', None)
         timeRange = request_dict.getlist('timeRange[]', None)
         orderType = request_dict.get('orderType', None)
+        serialNumber = request_dict.get('serialNumber', None)
 
         if not all([pageNo, pageSize]):
             return response.json(444)
@@ -704,6 +705,10 @@ class serveManagement(View):
                 omqs = omqs.filter(status=status)
             if orderType:
                 omqs = omqs.filter(order_type=int(orderType))
+            if serialNumber:
+                device_info_qs = Device_Info.objects.filter(serial_number=serialNumber).values('UID')
+                uid = device_info_qs[0]['UID'] if device_info_qs.exists() else 'N/A'
+                omqs = omqs.filter(UID=uid)
             if timeRange:
                 startTime, endTime = int(
                     timeRange[0][:-3]), int(timeRange[1][:-3])
@@ -763,6 +768,12 @@ class serveManagement(View):
                         data['user_status'] = 1
                     else:
                         data['user_status'] = 2
+                #  添加序列号
+                data['serial_number'] = 'N/A'
+                device_info_qs = Device_Info.objects.filter(UID=order['UID']).values('serial_number')
+                if device_info_qs.exists():
+                    data['serial_number'] = device_info_qs[0]['serial_number'] if device_info_qs[0][
+                        'serial_number'] else 'N/A'
                 #  添加PayPal交易号字段
                 data['trade_no'] = 'N/A'
                 if data['payType'] == 1:
@@ -995,6 +1006,9 @@ class serveManagement(View):
         # 日志表查询
         logTimeRange = request_dict.getlist('logTimeRange[]', None)
 
+        # 序列号查询
+        serialNumber = request_dict.get('serialNumber', None)
+
         pageNo = request_dict.get('pageNo', None)
         pageSize = request_dict.get('pageSize', None)
         if not all([pageNo, pageSize]):
@@ -1012,6 +1026,10 @@ class serveManagement(View):
                 uid_bucket_qs = uid_bucket_qs.filter(use_status=use_status)
             if has_unused:
                 uid_bucket_qs = uid_bucket_qs.filter(has_unused=has_unused)
+            if serialNumber:
+                device_info_qs = Device_Info.objects.filter(serial_number=serialNumber).values('UID')
+                uid = device_info_qs[0]['UID'] if device_info_qs.exists() else 'N/A'
+                uid_bucket_qs = uid_bucket_qs.filter(uid__icontains=uid)
             if addTimeRange:
                 addStartTime, addEndTime = int(
                     addTimeRange[0][:-3]), int(addTimeRange[1][:-3])
@@ -1114,9 +1132,13 @@ class serveManagement(View):
                         'phone': order['userID__phone'],
                         'userEmail': order['userID__userEmail'],
                         'data_joined': order['userID__data_joined'].strftime("%Y-%m-%d %H:%M:%S"),
-                        'playcount': cg_qs.filter(operation='cloudstorage/queryvodlist', uid=order['UID']).count()
+                        'playcount': cg_qs.filter(operation='cloudstorage/queryvodlist', uid=order['UID']).count(),
+                        'serial_number': 'N/A'
                     }
-
+                    device_info_qs = Device_Info.objects.filter(UID=uid).values('serial_number')
+                    if device_info_qs.exists():
+                        data['serial_number'] = device_info_qs[0]['serial_number'] if device_info_qs[0][
+                            'serial_number'] else 'N/A'
                     if uid in uid_set_dict:
                         data['ucode'] = uid_set_dict[uid]['ucode']
                         data['version'] = uid_set_dict[uid]['version']

+ 21 - 2
AdminController/UnicomManageController.py

@@ -10,8 +10,7 @@ from django.db import transaction, connection
 from django.views.generic.base import View
 
 from Controller.UnicomCombo.UnicomComboController import UnicomComboView
-from Model.models import UnicomDeviceInfo, UnicomCombo, Pay_Type, UnicomComboOrderInfo, Device_User, Device_Info, \
-    Order_Model
+from Model.models import UnicomDeviceInfo, UnicomCombo, Pay_Type, UnicomComboOrderInfo, Device_User, Order_Model
 from Object.ResponseObject import ResponseObject
 from Object.UnicomObject import UnicomObjeect
 from Service.CommonService import CommonService
@@ -56,6 +55,8 @@ class UnicomManageControllerView(View):
         #  获取 / 筛选4G流量卡订单信息
         elif operation == 'query-order':
             return self.query_4G_user_order(request_dict, response)
+        elif operation == 'sim-info':
+            return self.get_iccid_info(request_dict, response)
         else:
             return response.json(0)
 
@@ -496,3 +497,21 @@ class UnicomManageControllerView(View):
         except Exception as e:
             print(e)
             return response.json(500, repr(e))
+
+    @classmethod
+    def get_iccid_info(cls, request_dict, response):
+        """
+        获取联通iccid最新状态
+        """
+        try:
+            iccid = request_dict.get('iccid', None)
+            if not iccid:
+                return response.json(444)
+            re_data = {'iccid': iccid}
+            result = UnicomObjeect().query_device_status(**re_data)
+            res_dict = UnicomObjeect().get_text_dict(result)
+            # 状态不等于1(激活)时进行激活 1:激活;2:停用
+            return response.json(0, res_dict['data']['status'])
+        except Exception as e:
+            print(e)
+            return response.json(500, repr(e))

+ 36 - 1
AdminController/UserManageController.py

@@ -310,6 +310,16 @@ class UserManagement(View):
                 return response.json(404)
 
     def getUserInfo(self, userID, request_dict, response):
+        """
+        @param userID:用户ID
+        @param request_dict:请求参数
+        @param response:响应对象
+        @param username:用户名
+        @param NickName:用户昵称
+        @param phone:电话号
+        @param userEmail:用户邮箱
+        @return:
+        """
         print('request_dict: ', request_dict)
         username = request_dict.get('username', '').strip()  # 移除字符串头尾的空格
         NickName = request_dict.get('NickName', '').strip()
@@ -369,7 +379,15 @@ class UserManagement(View):
             return response.json(500, repr(e))
 
     def AddOrEditAccount(self, userID, request_dict, response):
-        # 添加/编辑用户
+        """
+        添加/编辑用户
+        @param userID:用户ID
+        @param request_dict:请求参数
+        @param response:响应对象
+        @param roleName:用户角色
+        @param isEdit:添加用户需要输入密码
+        @return:
+        """
         print('request_dict: ', request_dict)
         username = request_dict.get('username', '').strip()  # 移除字符串头尾的空格
         userEmail = request_dict.get('userEmail', '').strip()
@@ -454,6 +472,14 @@ class UserManagement(View):
             return response.json(500, repr(e))
 
     def getFeedbackList(self, request_dict, response):
+        """
+        用户反馈查询
+        @param request_dict:请求参数
+        @param response:响应对象
+        @param status:回复状态
+        @param collectStatus:收藏状态1
+        @return:
+        """
         status = request_dict.get('status', 0)
         username = request_dict.get('username', None)
         collectStatus = request_dict.get('collectStatus', None)
@@ -542,6 +568,14 @@ class UserManagement(View):
             return response.json(500, repr(e))
 
     def sendSysMsgToUser(self, request_dict, response):
+        """
+        发送系统消息至用户
+        @param request_dict:请求参数
+        @param response:响应对象
+        @param userID:用户ID
+        @param msg:发送内容
+        @return:
+        """
         userID = request_dict.get('userID', None)
         msg = request_dict.get('msg', None)
 
@@ -571,6 +605,7 @@ class UserManagement(View):
             return response.json(500, repr(e))
 
     def getSysMessageList(self, request_dict, response):
+        # 功能群发查询
         print('request_dict: ', request_dict)
         pageNo = request_dict.get('pageNo', None)
         pageSize = request_dict.get('pageSize', None)

+ 1 - 2
AdminController/dataSystemManagement/BusinessDataController.py

@@ -8,10 +8,9 @@
 """
 
 import requests
-from django.db.models import Count, Sum
 from django.views.generic.base import View
 
-from Model.models import VodHlsModel, VodHlsSummary
+from Model.models import VodHlsSummary
 from Service.CommonService import CommonService
 
 

+ 1 - 1
AdminController/dataSystemManagement/UserDataController.py

@@ -12,7 +12,7 @@ from django.views.generic.base import View
 import datetime
 import requests
 
-from Model.models import Device_User, CountryModel, DeviceUserSummary
+from Model.models import DeviceUserSummary
 from Service.CommonService import CommonService
 
 

+ 1 - 0
Ansjer/cn_config/config_formal.py

@@ -20,6 +20,7 @@ PUSH_BUCKET = 'push'                                # 推送存储桶
 PUSH_INACCURATE_BUCKET = 'push-inaccurate'          # 推送不准确存储桶
 AVATAR_BUCKET = 'avatar-cn'                         # 头像存储桶
 LOG_BUCKET = 'ansjer-statres'                       # 日志存储桶
+PUSH_CLOUD_PHOTO = 'push-cloud-photo'               # 推送云相册存储桶
 
 # redis节点
 SERVER_HOST = 'backendserver.3xavzq.0001.cnw1.cache.amazonaws.com.cn'

+ 11 - 6
Ansjer/cn_config/config_test.py

@@ -10,16 +10,21 @@ AWS相关
 """
 # ======================================================================================================================
 # aws api key
-AWS_ARN_S3 = 'arn:aws-cn:s3'
-REGION_NAME = 'cn-northwest-1'
-ACCESS_KEY_ID = 'AKIA2MMWBR4DSFG67DTG'
-SECRET_ACCESS_KEY = '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'
+# AWS_ARN_S3 = 'arn:aws-cn:s3'
+# REGION_NAME = 'cn-northwest-1'
+# ACCESS_KEY_ID = 'AKIA2MMWBR4DSFG67DTG'
+# SECRET_ACCESS_KEY = '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'
+AWS_ARN_S3 = 'arn:aws:s3'
+REGION_NAME = 'us-east-1'
+ACCESS_KEY_ID = 'AKIA2E67UIMD45Y3HL53'
+SECRET_ACCESS_KEY = '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'
 
 # 存储桶
-PUSH_BUCKET = 'push'                                # 推送存储桶
+PUSH_BUCKET = 'foreignpush'                                # 推送存储桶
 PUSH_INACCURATE_BUCKET = 'push-inaccurate'          # 推送不准确存储桶
-AVATAR_BUCKET = 'avatar-cn'                         # 头像存储桶
+AVATAR_BUCKET = 'avatar-us'                         # 头像存储桶
 LOG_BUCKET = 'ansjer-statres'                       # 日志存储桶
+PUSH_CLOUD_PHOTO = 'push-cloud-photo'               # 推送云相册存储桶
 
 # redis节点
 SERVER_HOST = 'backendserver.3xavzq.0001.cnw1.cache.amazonaws.com.cn'

+ 5 - 5
Ansjer/cn_config/formal_settings.py

@@ -6,6 +6,8 @@ SECRET_KEY = 'c7ki2_gkg4#sjfm-u1%$s#&n#szf01f*v69rwv2qsf#-zmm@tl'
 DEBUG = False
 ALLOWED_HOSTS = ['*']
 
+DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
+
 INSTALLED_APPS = [
     'django.contrib.admin',
     'django.contrib.auth',
@@ -44,7 +46,7 @@ ADDR_URL = []
 ANONYMOUS_USER_ID = -1  # 支持匿名用户.
 
 STATIC_URL = '/static/'
-STATICFILES_DIRS = (os.path.join(BASE_DIR,'static'),)
+STATICFILES_DIRS = (os.path.join(BASE_DIR, 'static'),)
 
 # 上传路径根目录
 MEDIA_ROOT = os.path.join(BASE_DIR, 'static/Upgrate')
@@ -114,8 +116,6 @@ DATABASE_APPS_MAPPING = {
     'PushModel': 'mysql02',
 }
 
-
-
 AUTH_PASSWORD_VALIDATORS = [
     {
         'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
@@ -254,7 +254,7 @@ LOGGING = {
         # log 调用时需要当作参数传入
         'info': {
             'handlers': ['info'],
-            'level':'INFO',
+            'level': 'INFO',
             'propagate': False
         },
         'pay': {
@@ -268,4 +268,4 @@ LOGGING = {
         #     'level': 'DEBUG',
         # },
     }
-}
+}

+ 8 - 20
Ansjer/cn_config/test_settings.py

@@ -1,12 +1,13 @@
 import os
 from Ansjer.config import BASE_DIR
 
-
 SECRET_KEY = 'c7ki2_gkg4#sjfm-u1%$s#&n#szf01f*v69rwv2qsf#-zmm@tl'
 DEBUG = True
 # DEBUG = False
 ALLOWED_HOSTS = ['*']
 
+DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
+
 INSTALLED_APPS = [
     'django.contrib.admin',
     'django.contrib.auth',
@@ -18,7 +19,6 @@ INSTALLED_APPS = [
     'imagekit',
     'Model',
     'PushModel',
-    'SerialModel',
 ]
 
 MIDDLEWARE = [
@@ -27,25 +27,23 @@ MIDDLEWARE = [
     'django.middleware.security.SecurityMiddleware',
     'django.contrib.sessions.middleware.SessionMiddleware',
     'django.middleware.common.CommonMiddleware',
-    'MiddleWare.requestRecord.RequestRecordMiddleware',     # 记录请求信息
+    'MiddleWare.requestRecord.RequestRecordMiddleware',  # 记录请求信息
     # 'django.middleware.csrf.CsrfViewMiddleware',
     'corsheaders.middleware.CorsPostCsrfMiddleware',
     'django.contrib.auth.middleware.AuthenticationMiddleware',
     'django.contrib.messages.middleware.MessageMiddleware',
     'django.middleware.clickjacking.XFrameOptionsMiddleware',
     'django.middleware.security.SecurityMiddleware',
-    'django_global_request.middleware.GlobalRequestMiddleware',
 ]
 
 AUTHENTICATION_BACKENDS = (
     'django.contrib.auth.backends.ModelBackend',  # django default backend
-    'guardian.backends.ObjectPermissionBackend',
 )
 
 ADDR_URL = []
 ANONYMOUS_USER_ID = -1  # 支持匿名用户
 
-STATIC_URL = '/static/'
+STATIC_URL = './static/'
 
 # 上传路径根目录
 MEDIA_ROOT = os.path.join(BASE_DIR, 'static/Upgrate')
@@ -59,7 +57,6 @@ APPEND_SLASH = False
 TEMPLATES = [
     {
         'BACKEND': 'django.template.backends.django.DjangoTemplates',
-        # 'DIRS': [BASE_DIR + '/static/templates', ],
         'DIRS': [BASE_DIR + '/templates', ],
         'APP_DIRS': True,
         'OPTIONS': {
@@ -196,7 +193,6 @@ LOGGING = {
     'disable_existing_loggers': True,
     'formatters': {
         'error_format': {
-            # 'format': '{"asctime":"%(asctime)s","thread":"%(threadName)s:%(thread)d","errorline":"%(lineno)d","errorlevel":"%(levelname)s","errorcontent":"%(message)s"}'
             'format': '%(asctime)s %(threadName)s %(thread)d %(lineno)d %(levelname)s %(message)s'
         },
         'standard': {
@@ -256,21 +252,18 @@ LOGGING = {
     'loggers': {
         'django': {
             'handlers': ['default', 'console'],
-            # 'handlers': ['mail_admins','default','console'],
-            # 'level': 'ERROR',
             'level': 'ERROR',
             'propagate': False
         },
         # log 调用时需要当作参数传入
         'info': {
             'handlers': ['info'],
-            'level':'INFO',
+            'level': 'INFO',
             'propagate': False
         },
-
-        'device_info':{
+        'device_info': {
             'handlers': ['device_info'],
-            'level':'INFO',
+            'level': 'INFO',
             'propagate': False
         },
         'pay': {
@@ -278,10 +271,5 @@ LOGGING = {
             'level': 'INFO',
             'propagate': False
         },
-        # 'django.db.backends': {
-        #     'handlers': ['console'],
-        #     'propagate': True,
-        #     'level': 'DEBUG',
-        # },
     }
-}
+}

+ 1 - 0
Ansjer/eur_config/config_formal.py

@@ -20,6 +20,7 @@ PUSH_BUCKET = 'foreignpush'                         # 推送存储桶
 PUSH_INACCURATE_BUCKET = 'push-inaccurate'          # 推送不准确存储桶
 AVATAR_BUCKET = 'avatar-us'                         # 头像存储桶
 LOG_BUCKET = 'ansjer-statres'                       # 日志存储桶
+PUSH_CLOUD_PHOTO = 'push-cloud-photo'               # 推送云相册存储桶
 
 # redis节点
 SERVER_HOST = 'server-redis-001.av1kep.0001.euw1.cache.amazonaws.com'

+ 4 - 4
Ansjer/eur_config/formal_settings.py

@@ -6,6 +6,8 @@ SECRET_KEY = 'c7ki2_gkg4#sjfm-u1%$s#&n#szf01f*v69rwv2qsf#-zmm@tl'
 DEBUG = False
 ALLOWED_HOSTS = ['*']
 
+DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
+
 INSTALLED_APPS = [
     'django.contrib.admin',
     'django.contrib.auth',
@@ -72,7 +74,6 @@ TEMPLATES = [
 
 WSGI_APPLICATION = 'Ansjer.eur_config.formal_wsgi.application'
 
-
 # 服务器类型
 DATABASE_DATA = 'Ansjer81'
 SERVER_HOST = 'server-eur.chi0brrjyz8l.eu-west-1.rds.amazonaws.com'
@@ -112,7 +113,6 @@ DATABASE_APPS_MAPPING = {
     'PushModel': 'mysql02',
 }
 
-
 AUTH_PASSWORD_VALIDATORS = [
     {
         'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
@@ -252,7 +252,7 @@ LOGGING = {
         # log 调用时需要当作参数传入
         'info': {
             'handlers': ['info'],
-            'level':'INFO',
+            'level': 'INFO',
             'propagate': False
         },
         'pay': {
@@ -266,4 +266,4 @@ LOGGING = {
         #     'level': 'DEBUG',
         # },
     }
-}
+}

+ 1 - 0
Ansjer/local_config/config_local.py

@@ -20,6 +20,7 @@ PUSH_BUCKET = 'push'                                # 推送存储桶
 PUSH_INACCURATE_BUCKET = 'push-inaccurate'          # 推送不准确存储桶
 AVATAR_BUCKET = 'avatar-cn'                         # 头像存储桶
 LOG_BUCKET = 'ansjer-statres'                       # 日志存储桶
+PUSH_CLOUD_PHOTO = 'push-cloud-photo'               # 推送云相册存储桶
 
 # redis节点
 SERVER_HOST = '127.0.0.1'

+ 5 - 41
Ansjer/local_config/local_settings.py

@@ -1,21 +1,18 @@
 import os
 from Ansjer.config import BASE_DIR
 
-
 SECRET_KEY = 'c7ki2_gkg4#sjfm-u1%$s#&n#szf01f*v69rwv2qsf#-zmm@tl'
 DEBUG = True
 # DEBUG = False
 ALLOWED_HOSTS = ['*']
 
-
-
-
+DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
 
 ADDR_URL = []
 ANONYMOUS_USER_ID = -1  # 支持匿名用户
 
-STATIC_URL = '/static/'
-STATICFILES_DIRS = (os.path.join(BASE_DIR,'static'),)
+STATIC_URL = './static/'
+STATICFILES_DIRS = (os.path.join(BASE_DIR, 'static'),)
 
 # 上传路径根目录
 MEDIA_ROOT = os.path.join(BASE_DIR, 'static/Upgrate')
@@ -43,15 +40,6 @@ TEMPLATES = [
     },
 ]
 
-'''
-增加错误信息推送到管理员邮箱
-'''
-# 管理员邮箱
-ADMINS = (
-    ('admin', 'chanjunkai@163.com'),
-    ('admin', '1379072853@qq.com'),
-)
-
 INSTALLED_APPS = [
     'django.contrib.admin',
     'django.contrib.auth',
@@ -72,30 +60,21 @@ MIDDLEWARE = [
     'django.middleware.security.SecurityMiddleware',
     'django.contrib.sessions.middleware.SessionMiddleware',
     'django.middleware.common.CommonMiddleware',
-    'MiddleWare.requestRecord.RequestRecordMiddleware',     # 记录请求信息
+    'MiddleWare.requestRecord.RequestRecordMiddleware',  # 记录请求信息
     # 'django.middleware.csrf.CsrfViewMiddleware',
     'corsheaders.middleware.CorsPostCsrfMiddleware',
     'django.contrib.auth.middleware.AuthenticationMiddleware',
     'django.contrib.messages.middleware.MessageMiddleware',
     'django.middleware.clickjacking.XFrameOptionsMiddleware',
     'django.middleware.security.SecurityMiddleware',
-    # 'django_global_request.middleware.GlobalRequestMiddleware',
 ]
 
 AUTHENTICATION_BACKENDS = (
     'django.contrib.auth.backends.ModelBackend',  # django default backend
-    'guardian.backends.ObjectPermissionBackend',
 )
 
 WSGI_APPLICATION = 'Ansjer.local_config.local_wsgi.application'
 
-# 服务器类型
-# 国内测试数据库
-# DATABASE_DATA = 'AnsjerTest'
-# SERVER_HOST = 'business-server.cvp7gfpnmziz.rds.cn-northwest-1.amazonaws.com.cn'
-# DATABASES_USER = 'azrds'
-# DATABASES_PASS = 'UKv78ezQhiGMmSef5U5s'
-
 # 本地数据库
 DATABASE_DATA = 'ansjer'
 SERVER_HOST = '127.0.0.1'
@@ -108,11 +87,6 @@ SERVER_HOST2 = '127.0.0.1'
 DATABASES_USER2 = 'root'
 DATABASES_PASS2 = '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 +108,6 @@ 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
-    # },
 }
 DATABASE_ROUTERS = ['Ansjer.database_router.DatabaseAppsRouter']
 DATABASE_APPS_MAPPING = {
@@ -282,7 +246,7 @@ LOGGING = {
         # log 调用时需要当作参数传入
         'info': {
             'handlers': ['info'],
-            'level':'INFO',
+            'level': 'INFO',
             'propagate': False
         }
     }

+ 4 - 0
Ansjer/server_urls/algorithm_shop_url.py

@@ -9,7 +9,11 @@
 from django.urls import re_path
 
 from Controller.AlgorithmShop import AlgorithmShopController
+from Controller.CloudPhoto import CloudPhotoController
+from Controller.Cron import CronCloudPhotoController
 
 urlpatterns = [
     re_path(r'^api/(?P<operation>.*)$', AlgorithmShopController.AlgorithmShopView.as_view()),
+    re_path(r'^cron/(?P<operation>.*)$', CronCloudPhotoController.CronCloudPhotoView.as_view()),
+    re_path(r'^photo/(?P<operation>.*)$', CloudPhotoController.CronCloudPhotoView.as_view()),
 ]

+ 13 - 0
Ansjer/server_urls/kvs_url.py

@@ -0,0 +1,13 @@
+# -*- coding: utf-8 -*-
+"""
+@Author : Rocky
+@Time : 2022/10/18 10:23
+@File :kvs_url.py
+"""
+from django.urls import re_path
+from Controller.AWS import KVSController
+
+urlpatterns = [
+    re_path(r'^user-related/(?P<operation>.*)$', KVSController.UserRelatedView.as_view()),
+    re_path(r'^(?P<operation>.*)$', KVSController.KVSView.as_view()),
+]

+ 0 - 85
Ansjer/test/coposs_sts.py

@@ -1,85 +0,0 @@
-# -*- coding: utf-8 -*-
-'''
-生成sts上传授权
-'''
-'''
-
-
-
-
-tar -cvpzf ubuntu_backup@`date +%Y-%m+%d`.tar.gz --exclude=/proc --exclude=/tmp --exclude=/boot --exclude=/home --exclude=/lost+found --exclude=/media --exclude=/mnt --exclude=/run --exclude=/home/sda1 / --warning=no-file-change
-
-'''
-from aliyunsdkcore import client
-from aliyunsdksts.request.v20150401 import AssumeRoleRequest
-import json
-import oss2
-
-# Endpoint以杭州为例,其它Region请按实际情况填写。
-endpoint = 'oss-cn-shenzhen.aliyuncs.com'
-# 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建RAM账号。
-access_key_id = 'LTAIyMkGfEdogyL9'
-access_key_secret = '71uIjpsqVOmF7DAITRyRuc259jHOjO'
-bucket_name = 'cloudvod1'
-# role_arn是角色的资源名称。
-role_arn = 'acs:ram::1901342792446414:role/stsoss'
-
-clt = client.AcsClient(access_key_id, access_key_secret, 'cn-shenzhen')
-req = AssumeRoleRequest.AssumeRoleRequest()
-
-# 设置返回值格式为JSON。
-req.set_accept_format('json')
-req.set_RoleArn(role_arn)
-req.set_RoleSessionName('test')
-req.set_DurationSeconds(3600)
-policys = {
-    "Version": "1",
-    "Statement": [
-        {
-            "Action": [
-                "oss:PutObject",
-                "oss:DeleteObject",
-            ],
-            "Resource": ["acs:oss:*:*:cloudvod1/*"],
-            "Effect": "Allow",
-            "Condition": {
-                "IpAddress": {
-                    "acs:SourceIp": "120.237.157.184"
-                }
-            }
-        }
-    ]
-}
-req.set_Policy(Policy=json.dumps(policys))
-body = clt.do_action(req)
-# body = clt.do_action_with_exception(req)
-# 使用RAM账号的AccessKeyId和AccessKeySecret向STS申请临时token。
-token = json.loads(body)
-print(token)
-# exit()
-# tokens = {
-#     "Credentials":{
-#     'AccessKeySecret': 'eDwALgKkfZp6eXD2jz8ckktfduneNCjEz8NgHxcZsVe',
-#     'AccessKeyId': 'STS.NJNUa1UjHgo5idVKqY9wBLB3e',
-#     'Expiration': '2018-11-15T09:06:30Z',
-#     'SecurityToken': 'CAISwgJ1q6Ft5B2yfSjIr4n7HtuFuLVp0K3ea0Lnr3EMNfhuo4eYhzz2IHxLf3RuAe8dvvw+nGBV7vsdlqN4S5ZDR1HCbsJxtkXiZd84J9ivgde8yJBZom/MewHKeeKSvqL7Z+H+U6mSGJOEYEzFkSle2KbzcS7YMXWuLZyOj+wADLEQRRLqVSdaI91UKwB+0pN4U0HcLvGwKBXnr3PNBU5zwGpGhHh49L60z7/siGTXh0aozfQO9cajYMq4YtJwJot6S5D3pqgUF4vZ+SJc8RVR790ShadfqwzAo8uWDnhJkWzkVLOOqps1d1A/P/VlXfcU8NqEzKUi5raIyN+tkE0WZboOCh6yHt7wnJH2f8qyLcs8eLrBPHDA78uCLJGdsXl/PS1AaV0SJIFxci4oWUF0F27ASqqu6FnGZwalW1srcmfDSBocGoABBPrYt/W5rkesL4dOVkQTaYz14WpwbEQfMBi+8/T5xLEqUP4tuwsiiBbsQhfAm3QLKzGODGJB9bCcfxpQPSnZuAyCI4uSUZiuCFUzdKX/eaiurRDLMnACYx3aEzfmDCvQ6dYbbHxIdk+0UNMWk51eWKXfWnoH+udI6rkks2AWjTM='
-#   }
-# }
-# 使用临时token中的认证信息初始化StsAuth实例。
-auth = oss2.StsAuth(token['Credentials']['AccessKeyId'],
-                    token['Credentials']['AccessKeySecret'],
-                    token['Credentials']['SecurityToken'])
-print(auth)
-# 使用StsAuth实例初始化存储空间。
-bucket = oss2.Bucket(auth, endpoint, bucket_name)
-# 上传一个字符串。
-# res = bucket.put_object('oss_media_hls.ts', b'hello world')
-res = bucket.put_object('object-name.txt', b'hello world')
-print(res)
-
-
-'''
-# master 172.17.0.4
-
-slave 172.17.0.8
-'''

+ 0 - 65
Ansjer/test/oss_sts.py

@@ -1,65 +0,0 @@
-from aliyunsdkcore import client
-from aliyunsdksts.request.v20150401 import AssumeRoleRequest
-import json
-import oss2
-
-
-# Endpoint以杭州为例,其它egion请按实际情况填写。
-endpoint = 'oss-cn-shenzhen.aliyuncs.com'
-access_key_id = 'LTAIyMkGfEdogyL9'
-access_key_secret = '71uIjpsqVOmF7DAITRyRuc259jHOjO'
-bucket_name = 'cnvod1'
-# role_arn是角色的资源名称。
-role_arn = 'acs:ram::1901342792446414:role/stsoss'
-
-clt = client.AcsClient(access_key_id, access_key_secret, 'cn-shenzhen')
-req = AssumeRoleRequest.AssumeRoleRequest()
-
-# 设置返回值格式为JSON。
-req.set_accept_format('json')
-req.set_RoleArn(role_arn)
-req.set_RoleSessionName('uid13241234123')
-req.set_DurationSeconds(3600)
-policys = {
-    "Version": "1",
-    "Statement": [
-        {
-            "Action": [
-                "oss:PutObject",
-                "oss:DeleteObject",
-            ],
-            # "Resource": ["acs:oss:*:*:cloudvod1/*"],
-            "Resource": ["acs:oss:*:*:cloudvod1/test/*"],
-            "Effect": "Allow",
-            "Condition": {
-                "IpAddress": {
-                    "acs:SourceIp": "120.237.157.184"
-                }
-            }
-        }
-    ]
-}
-req.set_Policy(Policy=json.dumps(policys))
-body = clt.do_action(req)
-# body = clt.do_action_with_exception(req)
-# 使用RAM账号的AccessKeyId和AccessKeySecret向STS申请临时token。
-token = json.loads(body)
-print(token)
-exit()
-
-# 使用临时token中的认证信息初始化StsAuth实例。
-auth = oss2.StsAuth(token['Credentials']['AccessKeyId'],
-                    token['Credentials']['AccessKeySecret'],
-                    token['Credentials']['SecurityToken'])
-print(auth)
-# 使用StsAuth实例初始化存储空间。
-bucket = oss2.Bucket(auth, endpoint, bucket_name)
-# 上传一个字符串。
-# res = bucket.put_object('oss_media_hls.ts', b'hello world')
-# res = bucket.put_object('test/test-name.txt', b'hello world')
-# print(res)
-# oss append obj
-result = bucket.append_object('mio', 0, 'content of first append')
-print(result)
-# 如果不是首次上传,可以通过bucket.head_object方法或上次追加返回值的next_position属性,得到追加位置。
-# bucket.append_object('<yourObjectName>', result.next_position, 'content of second append')

+ 0 - 44
Ansjer/test/osssigput.py

@@ -1,44 +0,0 @@
-#!/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/11/8 9:23
-@Version: python3.6
-@MODIFY DECORD:ansjer dev
-@file: oss_sts.py
-@Contact: chanjunkai@163.com
-"""
-# -*- coding: utf-8 -*-
-'''
-生成sts上传授权
-'''
-from aliyunsdkcore import client
-from aliyunsdksts.request.v20150401 import AssumeRoleRequest
-import json
-import oss2
-import base64
-
-'''
-http://test.dvema.com/cloudVod/getSts?uidToken=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJjaGFubmVsIjoiNCIsInVpZCI6IkZUU0xMOEhNNDM3WjM4V1UxMTFBIn0.wkrwYvIYf5qEukOSTxALSAgSqop-gNBdEvSwScOgYB8
-'''
-endpoint = 'oss-cn-shenzhen.aliyuncs.com'
-bucket_name = 'cnvod1'
-
-tokenss ={
-    'AccessKeySecret': '7kWzxVezTBs5Qd3AArRAcuXiYaQoLYVUnLb14iuv5LWW',
-    'AccessKeyId': 'STS.NU3npZw8fkd7sSeFFrehxRmud',
-    'Expiration': '2019-12-16T04:40:40Z',
-    'SecurityToken': 'CAIS3AJ1q6Ft5B2yfSjIr5aGJcrumudH3KbccXXUokYnaedUvajehjz2IHFIf3NhAe0bv/kzm2lX7/YYlqduSpMcHhaYNJErss0NqltYtGpBI4nng4YfgbiJREJJYnyShb0WCoeUZdfZfejXOjKgvyRvwLz8WCy/Vli+S/OggoJmadJlF2vdaiFdVu9LOixoqsIRKRmpMu22YDLnhmfMAW1iuAd3lRkti8KFz9ab9wDVgXDj1+YRvP6RGJW/aNR2N5oNJbXB1edtJK3ay3wSuVoY/6NxkaBa/jue+c2QGEUWoW/CUYv16vRjIBV0fbNAf6dPt6rHkuBiseHyj/aOqXEUZ7kTCX+AAtn9n42dSL+LTo9oLe+gZy6Sg4rTasep6l8eDChFZF8QSb0IMWRtDBEgcDbeJ5K89UrCCgXZEPnZi/tniccongi0ooPVfgjVWduCzT0fIYQsyci1stvWBQcagAFYkAuSbf8lQF1U2ifn3hKAD3S5+CVRyluQoYJBnel5o1MsL6gzccGXwBC0Jpuux/tzOZBETh0DqA+BrfYsPEUdHyZ9O5wVAHym8gx9TYiZNYNkd9FXev1k5i9pOMoy+DzaF90gZBiiZv9AYhlw8k8WGo+0InLNdI8F4CcjA1oYBQ=='
-  }
-# 使用RAM账号的AccessKeyId和AccessKeySecret向STS申请临时token。
-
-# 使用临时token中的认证信息初始化StsAuth实例。
-auth = oss2.StsAuth(tokenss['AccessKeyId'],
-                    tokenss['AccessKeySecret'],
-                    tokenss['SecurityToken'])
-bucket = oss2.Bucket(auth, endpoint, bucket_name)
-result = bucket.append_object('mio', 0, 'content of first append')
-print(result)

+ 10 - 1
Ansjer/urls.py

@@ -22,13 +22,15 @@ from Controller import FeedBack, EquipmentOTA, EquipmentInfo, AdminManage, AppIn
     OrderTaskController, HistoryUIDController, UIDManageUserController, SerialNumberController, CompanyController, \
     RegionController, VPGController, LanguageController, TestController, DeviceConfirmRegion, S3GetStsController, \
     DetectControllerV2, PcInfo, PctestController, DeviceDebug, PaymentCycle, \
-    DeviceLogController, CouponController, AiController
+    DeviceLogController, CouponController, AiController, ShadowController, AppAccountManagement
 from Controller.Cron import CronTaskController
 from Controller.MessagePush import EquipmentMessagePush
 from Controller.Surveys import CloudStorageController
 from Controller.SensorGateway import SensorGatewayController, EquipmentFamilyController
 from django.urls import include
 
+from Controller.UserDevice import UserDeviceShareController
+
 urlpatterns = [
     url(r'^testApi/(?P<operation>.*)$', TestApi.testView.as_view()),
     url(r'^account/authcode$', UserController.authCodeView.as_view()),
@@ -309,6 +311,7 @@ urlpatterns = [
     path('sales', SalesController.SalesView.as_view()),
     path('device/online', SalesController.DeviceOnlineView.as_view()),
     re_path('serialNumber/(?P<operation>.*)', SerialNumberController.SerialNumberView.as_view()),
+    path('deviceShadow/update', ShadowController.update_device_shadow),
     re_path('company/(?P<operation>.*)', CompanyController.CompanyView.as_view()),
     re_path('region/(?P<operation>.*)', RegionController.RegionView.as_view()),
     re_path('vpg/(?P<operation>.*)', VPGController.VPGView.as_view()),
@@ -342,6 +345,8 @@ urlpatterns = [
 
     # 问卷调查
     url(r'^api/surveys/(?P<operation>.*)$', CloudStorageController.CloudStorageView.as_view()),
+    # 设备分享
+    url(r'^api/device/share/(?P<operation>.*)$', UserDeviceShareController.UserDeviceShareView.as_view()),
 
     # 网关家庭模块
     url(r'^app/sensor/gateway/(?P<operation>.*)$', EquipmentFamilyController.EquipmentFamilyView.as_view()),
@@ -350,6 +355,10 @@ urlpatterns = [
     url(r'^unicom/', include("Ansjer.server_urls.unicom_url")),
     # 算法小店
     url(r'^algorithm-shop/', include("Ansjer.server_urls.algorithm_shop_url")),
+    # KVS模块
+    url(r'^kvs/', include("Ansjer.server_urls.kvs_url")),
+    # 超级密码模块
+    re_path('appAccout/(?P<operation>.*)', AppAccountManagement.AppAccoutView.as_view()),
 
     # 传感器网关
     re_path('sensorGateway/(?P<operation>.*)', SensorGatewayController.SensorGateway.as_view()),

+ 1 - 0
Ansjer/us_config/config_formal.py

@@ -20,6 +20,7 @@ PUSH_BUCKET = 'foreignpush'                         # 推送存储桶
 PUSH_INACCURATE_BUCKET = 'push-inaccurate'          # 推送不准确存储桶
 AVATAR_BUCKET = 'avatar-us'                         # 头像存储桶
 LOG_BUCKET = 'ansjer-statres'                       # 日志存储桶
+PUSH_CLOUD_PHOTO = 'push-cloud-photo'               # 推送云相册存储桶
 
 # redis节点
 SERVER_HOST = 'backendserver.5tgle2.0001.usw1.cache.amazonaws.com'

+ 2 - 0
Ansjer/us_config/formal_settings.py

@@ -6,6 +6,8 @@ SECRET_KEY = 'c7ki2_gkg4#sjfm-u1%$s#&n#szf01f*v69rwv2qsf#-zmm@tl'
 DEBUG = False
 ALLOWED_HOSTS = ['*']
 
+DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
+
 INSTALLED_APPS = [
     'django.contrib.admin',
     'django.contrib.auth',

+ 472 - 0
Controller/AWS/KVSController.py

@@ -0,0 +1,472 @@
+# -*- coding: utf-8 -*-
+"""
+@Author : Rocky
+@Time : 2022/10/18 9:48
+@File :KVSController.py
+"""
+import hashlib
+import time
+import uuid
+import datetime
+
+from django.http import HttpResponse
+from django.views import View
+
+from Model.models import KVS, Device_User, Device_Info
+from Object.AWS.AmazonKinesisVideoUtil import AmazonKinesisVideoObject, AmazonKVAMObject
+from Object.RedisObject import RedisObject
+from Object.ResponseObject import ResponseObject
+from Ansjer.config import ACCESS_KEY_ID, SECRET_ACCESS_KEY, REGION_NAME, SERVER_DOMAIN
+from Object.TokenObject import TokenObject
+
+
+class UserRelatedView(View):
+    def get(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        return self.validation(request.GET, operation, request)
+
+    def post(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        return self.validation(request.POST, operation, request)
+
+    def validation(self, request_dict, operation, request):
+        response = ResponseObject()
+        if operation == 'generate-qr-code':  # 网页生成二维码
+            return self.generate_qr_code(response)
+        elif operation == 'get-scanning-status':  # 确认app是否扫码
+            return self.get_scanning_status(request_dict, response)
+        elif operation == 'web-login':  # 网页登录
+            return self.web_login(request_dict, response)
+        elif operation == 'pc-login':  # pc端登录
+            return self.pc_login(request_dict, response)
+        elif operation == 'confirm-login':  # app确认登录
+            return self.confirm_login(request_dict, response)
+        else:
+            tko = TokenObject(
+                request.META.get('HTTP_AUTHORIZATION'),
+                returntpye='pc')
+            if tko.code != 0:
+                return response.json(tko.code)
+            response.lang = tko.lang
+            user_id = tko.userID
+            if operation == 'get-device':  # 获取设备列表
+                return self.get_device(response, user_id)
+            else:
+                return response.json(404)
+
+    @staticmethod
+    def get_user_info(user_id):
+        """
+        获取用户信息
+        @param user_id: 用户id
+        @return: response
+        """
+        device_user_qs = Device_User.objects.filter(userID=user_id).values('NickName', 'userIconPath',
+                                                                           'userIconUrl')
+        if not device_user_qs.exists():
+            user_icon_url = ''
+            nick_name = ''
+        else:
+            users = device_user_qs.first()
+            nick_name = users['NickName']
+            user_icon_path = str(users['userIconPath'])
+            if user_icon_path:
+                user_icon_path = user_icon_path.replace('static/', '').replace('\\', '/')
+                user_icon_url = SERVER_DOMAIN + 'account/getAvatar/' + user_icon_path
+            else:
+                user_icon_url = ''
+        return user_icon_url, nick_name
+
+    @staticmethod
+    def generate_qr_code(response):
+        """
+        网页生成二维码
+        @param response: 响应对象
+        @return: response
+        """
+        nwo_time = time.time()
+        redis_obj = RedisObject()
+        try:
+            uuid_number = hashlib.md5((str(uuid.uuid1()) + str(nwo_time)).encode('utf-8')).hexdigest()
+            flag = redis_obj.set_ex_data(uuid_number, 0, 300)  # redis记录uuid,状态为生成二维码
+            res = {'type': 'autologin', 'id': uuid_number}
+            if flag:
+                return response.json(0, res)
+            else:
+                return response.json(119)
+        except Exception as e:
+            print(e)
+            return response.json(500)
+
+    @staticmethod
+    def get_scanning_status(request_dict, response):
+        """
+        获取app扫码状态
+        @param request_dict: 请求参数
+        @request_dict serial_number: 序列号
+        @param response: 响应对象
+        @return: response
+        """
+        uuid_number = request_dict.get('uuid', None)
+        if not uuid_number:
+            return response.json(444, {'error param': 'uuid'})
+        try:
+            redis_obj = RedisObject()
+            status = redis_obj.get_data(uuid_number)
+            if status is False:
+                return response.json(119)
+            elif status == '1' or status == '2':
+                res = {'status': 1}  # 已扫码
+            else:
+                res = {'status': 0}  # 未扫码
+            return response.json(0, res)
+        except Exception as e:
+            print(e)
+            return response.json(500)
+
+    @staticmethod
+    def pc_login(request_dict, response):
+        """
+        pc端登录
+        @param request_dict: 请求参数
+        @request_dict serial_number: 序列号
+        @param response: 响应对象
+        @return: response
+        """
+        uuid_number = request_dict.get('uuid', None)
+        if not uuid_number:
+            return response.json(444, {'error param': 'uuid'})
+        try:
+            redis_obj = RedisObject()
+            status = redis_obj.get_data(uuid_number)
+            token = redis_obj.get_data(uuid_number + 'token')
+            if status is False or token is False:
+                return response.json(119)
+            elif status == '2':  # 已登录
+                token_obj = TokenObject(token)
+                response.lang = token_obj.lang
+                if token_obj.code != 0:
+                    return response.json(token_obj.code)
+                user_id = token_obj.userID
+                user_icon_url, nick_name = UserRelatedView.get_user_info(user_id)
+                res = {'status': 1, 'userIconUrl': user_icon_url, 'nickName': nick_name, 'token': token}
+                redis_obj.del_data(uuid_number)
+                redis_obj.del_data(uuid_number + 'token')
+            else:  # 未登录
+                res = {'status': 0}
+            return response.json(0, res)
+        except Exception as e:
+            print(e)
+            return response.json(500)
+
+    @staticmethod
+    def web_login(request_dict, response):
+        """
+        网页登录
+        @param request_dict: 请求参数
+        @request_dict serial_number: 序列号
+        @param response: 响应对象
+        @return: response
+        """
+        uuid_number = request_dict.get('uuid', None)
+        confirm = request_dict.get('confirm', None)
+        if not all([uuid_number, confirm]):
+            return response.json(444, {'error param': 'uuid or confirm'})
+        try:
+            redis_obj = RedisObject()
+            if confirm == '1':  # 取消登录
+                redis_obj.del_data(uuid_number)
+                redis_obj.del_data(uuid_number + 'token')
+                return response.json(0)
+            token = redis_obj.get_data(uuid_number + 'token')
+            ttl = redis_obj.get_ttl(uuid_number)
+            if token is False or ttl <= 0:
+                return response.json(119)
+            result = redis_obj.set_ex_data(uuid_number, 2, ttl)  # 修改uuid状态为已登录
+            if result is False:
+                return response.json(119)
+            return response.json(0)
+        except Exception as e:
+            print(e)
+            return response.json(500)
+
+    @staticmethod
+    def confirm_login(request_dict, response):
+        """
+        app确认登录
+        @param request_dict: 请求参数
+        @request_dict serial_number: 序列号
+        @param response: 响应对象
+        @return: response
+        """
+        uuid_number = request_dict.get('uuid', None)
+        token = request_dict.get('token', None)
+        if not all([uuid_number, token]):
+            return response.json(444, {'error param': 'uuid or token'})
+        redis_obj = RedisObject()
+        try:
+            status = redis_obj.get_data(uuid_number)
+            ttl = redis_obj.get_ttl(uuid_number)
+            if status is False or ttl <= 0:
+                return response.json(119)
+            result1 = redis_obj.set_ex_data(uuid_number, 1, ttl)  # 修改uuid状态为已扫码
+            result2 = redis_obj.set_ex_data(uuid_number + 'token', token, ttl)
+            if result1 is False or result2 is False:
+                return response.json(119)
+            return response.json(0)
+        except Exception as e:
+            print(e)
+            return response.json(500)
+
+    @staticmethod
+    def get_device(response, user_id):
+        """
+        获取设备列表
+        @param response: 响应对象
+        @param user_id: 用户id
+        @return: response
+        """
+        try:
+            device_qs = Device_Info.objects.filter(userID=user_id).values('serial_number', 'NickName')
+            return response.json(0, list(device_qs))
+        except Exception as e:
+            print(e)
+            return response.json(500)
+
+
+class KVSView(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 == 'create-media':  # 创建视频流
+            return self.create_media(request_dict, response)
+        elif operation == 'update-data-retention':  # 修改视频流数据保留时间
+            return self.update_data_retention(request_dict, response)
+        else:
+            # tko = TokenObject(request.META.get('HTTP_AUTHORIZATION'))
+            # if tko.code != 0:
+            #     return response.json(tko.code)
+            # response.lang = tko.lang
+            # user_id = tko.userID
+            if operation == 'get-device-midea-list':  # 获取设备列表
+                return self.get_device_midea_list(request_dict, response)
+            elif operation == 'get-hls-midea':  # 获取视频播放地址
+                return self.get_hls_midea_url(request_dict, response)
+            elif operation == 'download-clip':  # 获取视频播放地址
+                return self.download_clip(request_dict, response)
+            else:
+                return response.json(404)
+
+    @staticmethod
+    def create_media(request_dict, response):
+        """
+        创建视频流
+        @param request_dict: 请求参数
+        @request_dict serial_number: 序列号
+        @param response: 响应对象
+        @return: response
+        """
+        serial_number = request_dict.get('serial_number', None)
+
+        try:
+            kvs_qs = KVS.objects.filter(stream_name=serial_number)
+            if kvs_qs.exists():
+                return response.json(174)
+            kinesis_video_obj = AmazonKinesisVideoObject(
+                aws_access_key_id=ACCESS_KEY_ID,
+                secret_access_key=SECRET_ACCESS_KEY,
+                region_name=REGION_NAME
+            )
+            stream_arn = kinesis_video_obj.create_stream(stream_name=serial_number)
+            if stream_arn:
+                now_time = int(time.time())
+                KVS.objects.create(stream_name=serial_number, stream_arn=stream_arn, created_time=now_time,
+                                   updated_time=now_time)
+                return response.json(0)
+            else:
+                return response.json(178)
+        except Exception as e:
+            print(e)
+            return response.json(500)
+
+    @staticmethod
+    def update_data_retention(request_dict, response):
+        """
+        修改视频流数据保留时间
+        @param request_dict: 请求参数
+        @request_dict serial_number: 序列号
+        @request_dict operation: 操作,增加/减少
+        @request_dict data_retention_change_in_hours: 修改的时间
+        @param response: 响应对象
+        @return: response
+        """
+        serial_number = request_dict.get('serial_number', None)
+        operation = request_dict.get('operation', None)
+        data_retention_change_in_hours = request_dict.get('data_retention_change_in_hours', None)
+
+        try:
+            kvs_qs = KVS.objects.filter(stream_name=serial_number)
+            if not kvs_qs.exists():
+                return response.json(174)
+            kinesis_video_obj = AmazonKinesisVideoObject(
+                aws_access_key_id=ACCESS_KEY_ID,
+                secret_access_key=SECRET_ACCESS_KEY,
+                region_name=REGION_NAME
+            )
+            now_time = int(time.time())
+            data_retention_change_in_hours = int(data_retention_change_in_hours)
+            kinesis_video_obj.update_data_retention(stream_name=serial_number, operation=operation,
+                                                    data_retention_change_in_hours=data_retention_change_in_hours)
+            kvs_qs.update(data_retention_in_hours=data_retention_change_in_hours, updated_time=now_time)
+            return response.json(0)
+        except Exception as e:
+            print(e)
+            return response.json(500)
+
+    @staticmethod
+    def get_hls_midea_url(request_dict, response):
+        """
+        获取视频播放地址
+        @param request_dict: 请求参数
+        @request_dict serial_number: 序列号
+        @request_dict startTime: 开始时间
+        @request_dict endTime: 结束时间
+        @request_dict playMode: 播放模式
+        @param response: 响应对象
+        @return: response
+        """
+        serial_number = request_dict.get('serial_number', None)
+        start_time = request_dict.get('startTime', None)
+        end_time = request_dict.get('endTime', None)
+        play_mode = request_dict.get('playMode', None)
+        if not all([serial_number, start_time, end_time, play_mode]):
+            return response.json(444)
+        start_time = datetime.datetime.fromtimestamp(int(start_time)) - datetime.timedelta(hours=8)
+        end_time = datetime.datetime.fromtimestamp(int(end_time)) - datetime.timedelta(hours=8)
+        play_mode = int(play_mode)
+        play_mode = 'ON_DEMAND' if play_mode == 0 else 'LIVE_REPLAY'
+        try:
+            # kvs_qs = KVS.objects.filter(stream_name=serial_number)
+            # if not kvs_qs.exists():
+            #     return response.json(174)
+            kinesis_video_obj = AmazonKVAMObject(
+                aws_access_key_id='AKIA2E67UIMD45Y3HL53',
+                secret_access_key='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',
+                region_name='us-east-1',
+                stream_name=serial_number,
+                api_name='GET_HLS_STREAMING_SESSION_URL'
+            )
+            hls_streaming_session_url = kinesis_video_obj.get_hls_streaming_session_url(serial_number, start_time,
+                                                                                        end_time, play_mode)
+            return response.json(0, {"HlsStreamingSessionUrl": hls_streaming_session_url})
+        except Exception as e:
+            print(e)
+            return response.json(500, repr(e))
+
+    @staticmethod
+    def get_device_midea_list(request_dict, response):
+        """
+        获取视频播放列表
+        @param request_dict: 请求参数
+        @request_dict serial_number: 序列号
+        @request_dict startTime: 开始时间
+        @request_dict endTime: 结束时间
+        @param response: 响应对象
+        @return: response
+        """
+        serial_number = request_dict.get('serial_number', None)
+        start_time = request_dict.get('startTime', None)
+        end_time = request_dict.get('endTime', None)
+        page = request_dict.get('page', None)
+        size = request_dict.get('size', None)
+        if not all([serial_number, start_time, end_time, page, size]):
+            return response.json(444)
+        page = int(page)
+        size = int(size)
+        start_time = datetime.datetime.fromtimestamp(int(start_time)) - datetime.timedelta(hours=8)
+        end_time = datetime.datetime.fromtimestamp(int(end_time)) - datetime.timedelta(hours=8)
+        try:
+            # kvs_qs = KVS.objects.filter(stream_name=serial_number)
+            # if not kvs_qs.exists():
+            #     return response.json(174)
+            kinesis_fragments_obj = AmazonKVAMObject(
+                aws_access_key_id='AKIA2E67UIMD45Y3HL53',
+                secret_access_key='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',
+                region_name='us-east-1',
+                stream_name=serial_number,
+                api_name='LIST_FRAGMENTS'
+            )
+            kinesis_images_obj = AmazonKVAMObject(
+                aws_access_key_id='AKIA2E67UIMD45Y3HL53',
+                secret_access_key='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',
+                region_name='us-east-1',
+                stream_name=serial_number,
+                api_name='GET_IMAGES'
+            )
+            stream_list = kinesis_fragments_obj.get_list_fragments(serial_number, start_time, end_time)
+            total_page = len(stream_list)
+            stream_list = stream_list[(page - 1) * size:page * size]
+            for item in stream_list:
+                temp_start_time = (item['startTime'] - datetime.timedelta(hours=8)).replace(tzinfo=datetime.timezone.utc)
+                temp_end_time = temp_start_time + datetime.timedelta(seconds=300)
+                item['image'] = kinesis_images_obj.get_images(serial_number, temp_start_time, temp_end_time)
+                item['startTime'] = int(item['startTime'].timestamp())
+                item['endTime'] = int(item['endTime'].timestamp())
+            res = {
+                'totalPage': total_page,
+                'fragments': stream_list
+            }
+            return response.json(0, res)
+        except Exception as e:
+            print(e)
+            return response.json(500, repr(e))
+
+    @staticmethod
+    def download_clip(request_dict, response):
+        """
+        获取视频播放地址
+        @param request_dict: 请求参数
+        @request_dict serial_number: 序列号
+        @request_dict startTime: 开始时间
+        @request_dict endTime: 结束时间
+        @param response: 响应对象
+        @return: response
+        """
+        serial_number = request_dict.get('serial_number', None)
+        start_time = request_dict.get('startTime', None)
+        end_time = request_dict.get('endTime', None)
+        if not all([serial_number, start_time, end_time]):
+            return response.json(444)
+        start_time = datetime.datetime.fromtimestamp(int(start_time)) - datetime.timedelta(hours=8)
+        end_time = datetime.datetime.fromtimestamp(int(end_time)) - datetime.timedelta(hours=8)
+        try:
+            # kvs_qs = KVS.objects.filter(stream_name=serial_number)
+            # if not kvs_qs.exists():
+            #     return response.json(174)
+            kinesis_video_obj = AmazonKVAMObject(
+                aws_access_key_id='AKIA2E67UIMD45Y3HL53',
+                secret_access_key='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',
+                region_name='us-east-1',
+                stream_name=serial_number,
+                api_name='GET_CLIP'
+            )
+            clip_obj, clip_size = kinesis_video_obj.get_clip(serial_number, start_time, end_time)
+            res = HttpResponse(clip_obj.read())
+            res["content_type"] = "video/mp4"
+            res["Content-Disposition"] = "attachment;filename=video.mp4"
+            res['Content-Length'] = str(clip_size)
+            return res
+        except Exception as e:
+            print(e)
+            return response.json(500, repr(e))

+ 2 - 3
Controller/AdminManage.py

@@ -1,16 +1,15 @@
 # -*- coding: utf-8 -*-
 import time
-from datetime import date, timedelta, timezone as asj_timezone
+from datetime import timedelta, timezone as asj_timezone
 
 import boto3
 import xlwt
-from django.db.models import Count,Q
+from django.db.models import Count, Q
 from django.http import HttpResponse
 from django.views.decorators.csrf import csrf_exempt
 from django.views.generic import TemplateView
 from django.utils.decorators import method_decorator
 from django.contrib.auth.hashers import make_password  # 对密码加密模块
-from openpyxl import workbook
 
 from Model.models import Device_Info, Role, UserExModel, User_Brand, UidSetModel, AppFrequencyYearStatisticsModel, \
     AppFrequencyStatisticsModel, EquipmentInfoExStatisticsModel, Equipment_Info

+ 173 - 0
Controller/AppAccountManagement.py

@@ -0,0 +1,173 @@
+# -*- encoding: utf-8 -*-
+"""
+@File    : UserDeviceShareController.py
+@Time    : 2023/2/3 13:25
+@Author  : guanhailong
+@Email   : guanhailong@asj6.wecom.work
+@Software: PyCharm
+"""
+import datetime
+import random
+import time
+
+from Controller.CheckUserData import RandomStr
+from Model.models import Device_User, Device_Info, DeviceSuperPassword
+from Object.RedisObject import RedisObject
+from Object.ResponseObject import ResponseObject
+from Object.TokenObject import TokenObject
+from django.views import View
+
+from Service.CommonService import CommonService
+
+
+class AppAccoutView(View):
+    def get(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        request_dict = request.GET
+        return self.validation(request_dict, request, operation)
+
+    def post(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        request_dict = request.GET
+        return self.validation(request_dict, request, operation)
+
+    def validation(self, request_dict, request, operation):
+        token = TokenObject(request.META.get('HTTP_AUTHORIZATION'))
+        lang = request_dict.get('lang', token.lang)
+        response = ResponseObject(lang)
+        userID = token.userID
+        if token.code != 0:
+            return response.json(token.code)
+        if operation == 'getAuthorizationCode':  # 获取用户请求/生成授权码
+            return self.getAuthorizationCode(request_dict, response, userID)
+        if operation == 'verifyTheVerificationCode':  # 效验验证码
+            return self.verifyTheVerificationCode(request_dict, response)
+        if operation == 'customerServiceManagement':  # 客服管理
+            return self.customerServiceManagement(request_dict, response)
+        if operation == 'getDeviceSuperPassword':  # 查询超级密码请求表
+            return self.getDeviceSuperPassword(request_dict, response)
+        else:
+            return response.json(404)
+
+    def getAuthorizationCode(self, request_dict, response, userID):
+        """
+        @param uid:设备id
+        @param request_dict:请求参数
+        @param response:响应对象
+        @param describe:需求描述
+        @param Purchase_channel:购买渠道描述
+        @param orderID:订单id
+        @param buyTime:购买时间
+        @return:
+        """
+        uid = request_dict.get('uid', None)
+        describe = request_dict.get('describe', None)
+        if not all([uid, describe]):
+            return response.json(444)
+        purchase_channel = request_dict.get('purchase_channel', None)
+        orderID = request_dict.get('orderID', None)
+        buyTime = request_dict.get('buyTime', None)
+        try:
+            now = int(time.time())
+            addTime = now
+            device_info_qs = Device_Info.objects.filter(UID=uid, userID_id=userID)
+            if not device_info_qs.exists():
+                return response.json(173)
+            if buyTime:
+                buyTime = datetime.datetime.strptime(buyTime, '%Y-%m-%d')
+                buyTime = CommonService.str_to_timestamp(str_time=str(buyTime))
+            DeviceSuperPassword.objects.create(uid=uid, orderID=orderID, describe=describe,
+                                               purchase_channel=purchase_channel, addTime=addTime, userID=userID,
+                                               buyTime=buyTime, status=0)
+            # 验证码生成
+            super_code = RandomStr(6, True)
+            super_password_id = "super_password_%s" % super_code
+            redisObj = RedisObject(db=6)
+            redisObj.set_data(key=super_password_id, val=super_code, expire=86400)
+            authcode = CommonService.encode_data(super_code)
+
+            return response.json(0, {'authcode': authcode})
+        except Exception as e:
+            print('获取验证码异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+            return response.json(500, repr(e))
+
+    def verifyTheVerificationCode(self, request_dict, response):
+        verificationCode = request_dict.get('verificationCode', None)
+        authcode = request_dict.get('authcode', None)
+
+        if verificationCode and authcode:
+
+            authcode = CommonService.decode_data(authcode)
+            super_password_id = 'super_password_' + verificationCode
+            redisObj = RedisObject(db=6)
+            # redis里面的验证码
+            redis_image_code = redisObj.get_data(key=super_password_id)
+            # 验证用户输入的验证码和redis中的验证码
+            if redis_image_code is False or authcode.lower() != redis_image_code.lower():
+                return response.json(121)
+            else:
+                return response.json(0)
+        else:
+            return response.json(444)
+
+    def customerServiceManagement(self, request_dict, response):
+        userID = request_dict.get('userID')
+        uid = request_dict.get('uid', None)
+        status = request_dict.get('status', None)
+        hint = request_dict.get('hint', None)
+        if not all({uid, userID}):
+            return response.json(444)
+        try:
+            device_super_password_qs = DeviceSuperPassword.objects.filter(uid=uid, userID=userID)
+            if not device_super_password_qs.exists():
+                return response.json(173)
+            status = int(status)
+            if status == 1:
+                device_super_password_qs.update(status=status)
+                return response.json(0)
+            else:
+                device_super_password_qs.update(status=status, hint=hint)
+                return response.json(0)
+        except Exception as e:
+            print('修改状态异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+            return response.json(500, repr(e))
+
+    def getDeviceSuperPassword(self, request_dict, response):
+        pageNo = request_dict.get('pageNo', None)
+        pageSize = request_dict.get('pageSize', None)
+        status = request_dict.get('status', None)
+        userID = request_dict.get('userID', None)
+        uid = request_dict.get('uid', None)
+        if not all([pageNo, pageSize]):
+            return response.json(444)
+        page = int(pageNo)
+        line = int(pageSize)
+        try:
+            device_super_password_qs = DeviceSuperPassword.objects.all()
+            if status:
+                device_super_password_qs = device_super_password_qs.filter(status=status)
+            if userID:
+                device_super_password_qs = device_super_password_qs.filter(userID=userID)
+            if uid:
+                device_super_password_qs = device_super_password_qs.filter(uid=uid)
+            if not device_super_password_qs.exists():
+                return response.json(0, [])
+            count = device_super_password_qs.count()
+            device_super_password_qs = device_super_password_qs.values('id',
+                                                                       'uid',
+                                                                       'userID',
+                                                                       'orderID',
+                                                                       'describe',
+                                                                       'purchase_channel',
+                                                                       'addTime',
+                                                                       'status',
+                                                                       'buyTime',
+                                                                       'hint')
+            device_super_password_qs = device_super_password_qs.order_by('-addTime')[
+                                       (page - 1) * line:page * line]
+            return response.json(0, {'list': list(device_super_password_qs), 'count': count})
+        except Exception as e:
+            print('查询异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+            return response.json(500, repr(e))

+ 7 - 7
Controller/AppInfo.py

@@ -1,7 +1,7 @@
 import time
 import traceback
 import os
-from django.shortcuts import render_to_response
+from django.shortcuts import render
 from django.utils.decorators import method_decorator
 from django.views.decorators.csrf import csrf_exempt
 from django.views.generic.base import View
@@ -263,21 +263,21 @@ class AppVersionView(View):
 
     def get(self, request, *args, **kwargs):
         request.encoding = 'utf-8'
-        return self.validation(request_dict=request.GET)
+        return self.validation(request, request_dict=request.GET)
 
     def post(self, request, *args, **kwargs):
         request.encoding = 'utf-8'
-        return self.validation(request_dict=request.POST)
+        return self.validation(request, request_dict=request.POST)
 
-    def validation(self, request_dict, *args, **kwargs):
+    def validation(self, request, request_dict, *args, **kwargs):
         appBundleId = request_dict.get('appBundleId', None)
         app_type = request_dict.get('app_type', None)
         lang = request_dict.get('lang', None)
         # print (appBundleId)
         # if lang == 'cn':
-        #     return render_to_response('appVersionLists_cn.html')
+        #     return render('appVersionLists_cn.html')
         # else:
-        #     return render_to_response('appVersionLists_en.html')
+        #     return render('appVersionLists_en.html')
         queryset = App_Colophon.objects.filter(lang=lang, app_id__appBundleId=appBundleId,
                                                app_id__app_type=app_type).order_by('-version_time', '-newApp_version')
         queryset_dict = CommonService.qs_to_dict(queryset).get('datas')
@@ -291,7 +291,7 @@ class AppVersionView(View):
             version_time = v['fields']['version_time']
             version_time = time.strftime("%Y-%m-%d", time.localtime(version_time))
             v['fields']['version_time'] = version_time
-        return render_to_response('appVerList.html', locals())
+        return render(request, 'appVerList.html', locals())
 
 
 class AppIdDataView(View):

+ 12 - 63
Controller/CDKController.py

@@ -1,51 +1,17 @@
-#!/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 json
+import hashlib
 import logging
 import time
-import urllib
 import uuid
-import hashlib
 
-import boto3
-import oss2
-import paypalrestsdk
-import threading
-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.models import F
+from django.http import StreamingHttpResponse
 from django.views.generic.base import View
 
-from Ansjer.config import OSS_STS_ACCESS_KEY, OSS_STS_ACCESS_SECRET, OSS_ROLE_ARN, SERVER_DOMAIN, PAYPAL_CRD, \
-    SERVER_DOMAIN_SSL
-from Model.models import Device_Info, Order_Model, Store_Meal, VodHlsModel, OssCrdModel, UID_Bucket, StsCrdModel, \
-    ExperienceContextModel, CDKcontextModel
-from Object.AliPayObject import AliPayObject
+from Model.models import CDKcontextModel
 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
-from django.http import StreamingHttpResponse
 
-SERVER_DOMAIN = 'http://test.dvema.com/'
 
-
-# 设备信息添加
 class CDKView(View):
 
     def get(self, request, *args, **kwargs):
@@ -65,7 +31,6 @@ class CDKView(View):
             return response.json(444, 'error path')
         else:
             token = request_dict.get('token', None)
-            # 设备主键uid
             tko = TokenObject(token)
             response.lang = tko.lang
             if tko.code != 0:
@@ -77,8 +42,6 @@ class CDKView(View):
                 return self.deleteCDK(request_dict, response)
             elif operation == 'queryCDK':
                 return self.queryCDK(request_dict, response)
-            elif operation == 'saveOrEditCDKform':
-                return self.saveOrEditCDKform(request_dict, response)
             elif operation == 'saveOrEditCDK':
                 return self.saveOrEditCDK(request_dict, response)
             elif operation == 'downloadCDK':
@@ -128,7 +91,7 @@ class CDKView(View):
         logger = logging.getLogger('info')
         logger.info('CDK测试打印1: {}'.format(time.localtime(time.time())))
         if page and line:
-            cdk_qs = CDKcontextModel.objects.filter().all()  # values('cdk','create_time','valid_time','is_activate','rank__id','order__id')
+            cdk_qs = CDKcontextModel.objects.filter().all()
             if searchVal:
                 if cdk:
                     cdk_qs = cdk_qs.filter(cdk__contains=searchVal)
@@ -137,21 +100,14 @@ class CDKView(View):
                 elif is_activate:
                     cdk_qs = cdk_qs.filter(is_activate=searchVal)
 
-
             cdk_qs = cdk_qs.filter(rank__lang__lang=lang)
             cdk_qs = cdk_qs.annotate(rank__title=F('rank__lang__title'))
             cdk_qs = cdk_qs.values('id', 'cdk', 'create_time', 'valid_time', 'is_activate', 'rank__id', 'rank__title',
-                                    'rank__bucket__mold', 'order', 'create_time')
+                                   'rank__bucket__mold', 'order', 'create_time')
             cdk_qs = cdk_qs.order_by('-create_time')  # 根据CDK创建时间降序排序
             count = cdk_qs.count()
             cdk_qs = cdk_qs[(page - 1) * line:page * line]
 
-            # cdk_dict = {}
-            # for cdk in cdk_qs:
-            #     cdk_dict[cdk['id']] = {'id': cdk['id'], 'cdk': cdk['cdk'], 'create_time': cdk['create_time'],
-            #                            'valid_time': cdk['valid_time'], 'is_activate': cdk['is_activate'],
-            #                            'rank': cdk['rank__id'], 'order': cdk['order']}
-
             res = {
                 'datas': list(cdk_qs),
                 'count': count
@@ -185,7 +141,7 @@ class CDKView(View):
                 searchVal = is_activate.strip()
 
             if page and line:
-                cdk_qs = CDKcontextModel.objects.filter().all()  # values('cdk','create_time','valid_time','is_activate','rank__id','order__id')
+                cdk_qs = CDKcontextModel.objects.filter().all()
                 if searchVal:
                     if cdk:
                         cdk_qs = cdk_qs.filter(cdk__contains=searchVal)
@@ -194,7 +150,6 @@ class CDKView(View):
                     elif is_activate:
                         cdk_qs = cdk_qs.filter(is_activate=searchVal)
 
-
                 cdk_qs = cdk_qs.filter(rank__lang__lang=lang)
                 cdk_qs = cdk_qs.annotate(rank__title=F('rank__lang__title'))
                 cdk_qs = cdk_qs.values('id', 'cdk', 'create_time', 'valid_time', 'is_activate', 'rank__id',
@@ -209,8 +164,6 @@ class CDKView(View):
                 }
                 return response.json(0, res)
 
-
-
     def saveOrEditCDK(self, request_dict, response):
         cdk_id = request_dict.get("id", None)
         cdk = request_dict.get('cdk', None)
@@ -236,28 +189,24 @@ class CDKView(View):
         else:
             return response.json(0)
 
-    def downloadCDK(self,request_dict, response):
+    def downloadCDK(self, request_dict, response):
         region = request_dict.get('region', None)
         content = ''
         if region == 'cn':
             # 下载国内未使用激活码
             content += '激活码(国内)\n'
-            cdk_inactivate_qs = CDKcontextModel.objects.filter(is_down=0, is_activate=0, rank__bucket__mold=0, rank__is_show=0).values('cdk')
+            cdk_inactivate_qs = CDKcontextModel.objects.filter(is_down=0, is_activate=0, rank__bucket__mold=0,
+                                                               rank__is_show=0).values('cdk')
         else:
             # 下载国外未使用激活码
             content += '激活码(国外)\n'
-            cdk_inactivate_qs = CDKcontextModel.objects.filter(is_down=0, is_activate=0, rank__bucket__mold=1, rank__is_show=0).values('cdk')
+            cdk_inactivate_qs = CDKcontextModel.objects.filter(is_down=0, is_activate=0, rank__bucket__mold=1,
+                                                               rank__is_show=0).values('cdk')
         for cdk_inactivate in cdk_inactivate_qs:
             content += cdk_inactivate['cdk'] + '\n'
-        # print(content)
 
         cdk_inactivate_qs.update(is_down=1)
         response = StreamingHttpResponse(content)
         response['Content-Type'] = 'application/octet-stream'
         response['Content-Disposition'] = 'attachment;filename="CDK.txt"'
         return response
-
-
-
-
-

+ 183 - 0
Controller/CloudPhoto/CloudPhotoController.py

@@ -0,0 +1,183 @@
+# -*- encoding: utf-8 -*-
+"""
+@File    : CronCloudPhotoController.py
+@Time    : 2022/11/3 10:16
+@Author  : stephen
+@Email   : zhangdongming@asj6.wecom.work
+@Software: PyCharm
+"""
+import logging
+import time
+
+from django.db import transaction
+from django.views import View
+
+from Ansjer.cn_config.config_test import PUSH_CLOUD_PHOTO
+from Ansjer.config import ACCESS_KEY_ID, SECRET_ACCESS_KEY, REGION_NAME
+from Model.models import DeviceCloudPhotoInfo, Device_Info, CloudPhotoBGM, DevicePicturePushInfo
+from Object.AWS.AmazonS3Util import AmazonS3Util
+from Object.ResponseObject import ResponseObject
+from Object.TokenObject import TokenObject
+from Object.utils import LocalDateTimeUtil
+
+LOGGER = logging.getLogger('info')
+
+
+class CronCloudPhotoView(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):
+        token = TokenObject(request.META.get('HTTP_AUTHORIZATION'))
+        lang = request_dict.get('lang', token.lang)
+        response = ResponseObject(lang)
+        if token.code != 0:
+            return response.json(token.code)
+        user_id = token.userID
+        if operation == 'save-photo':
+            return self.save_cloud_photo(user_id, request_dict, response)
+        elif operation == 'bgm-list':
+            return self.get_bgm_list(response)
+        elif operation == 'video-list':
+            return self.query_cloud_photo_page(user_id, request_dict, response)
+        elif operation == 'video-del':
+            return self.del_cloud_photo(request_dict, response)
+        else:
+            return response.json(404)
+
+    @classmethod
+    def save_cloud_photo(cls, user_id, request_dict, response):
+        """
+        保存云相册
+        """
+        try:
+            with transaction.atomic():
+                status = request_dict.get('status', None)
+                uid = request_dict.get('uid', None)
+                if not all([status, user_id]):
+                    return response(444)
+                status = int(status)
+                device_info_qs = Device_Info.objects.filter(userID_id=user_id)
+                if uid:
+                    device_info_qs = device_info_qs.filter(UID=uid)
+                device_info_qs = device_info_qs.values('vodPrimaryUserID', 'UID')
+                if not device_info_qs.exists():
+                    return response.json(14)
+                for item in device_info_qs:
+                    master_user_id = item['vodPrimaryUserID']
+                    uid = item['UID']
+                    if master_user_id == '' or master_user_id != user_id:
+                        continue
+                    now_time = int(time.time())
+                    cloud_photo_qs = DeviceCloudPhotoInfo.objects.filter(uid=uid)
+                    if not cloud_photo_qs.exists():
+                        data = {'status': status, 'user_id': user_id, 'uid': uid, 'created_time': now_time,
+                                'updated_time': now_time}
+                        DeviceCloudPhotoInfo.objects.create(**data)
+                        continue
+                    cloud_photo_qs.update(status=status, updated_time=now_time)
+                return response.json(0)
+        except Exception as e:
+            LOGGER.info('异常详情,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+            return response.json(500)
+
+    @classmethod
+    def get_bgm_list(cls, response):
+        """
+        获取背景音乐列表
+        """
+        photo_bgm = CloudPhotoBGM.objects.filter(is_show=1).values('name', 'link').order_by('sort')
+        if not photo_bgm.exists():
+            return response.json(0, [])
+        return response.json(0, list(photo_bgm))
+
+    @classmethod
+    def query_cloud_photo_page(cls, user_id, request_dict, response):
+        """
+        分页查询云相册视频
+        @param user_id: 用户id
+        @param request_dict: 请求参数
+        @param response: 响应对象
+        @return: []
+        """
+        try:
+            device_name = request_dict.get('deviceName', None)
+            start_time = request_dict.get('startTime', None)
+            end_time = request_dict.get('endTime', None)
+            page = request_dict.get('page', None)
+            size = request_dict.get('size', None)
+            if not all([page, size]):
+                return response.json(444)
+            page = int(page)
+            size = int(size)
+            video_qs = DevicePicturePushInfo.objects.filter(user_id=user_id, type=1)
+            if device_name:
+                name_list = device_name.split(',')
+                video_qs = video_qs.filter(device_nick_name__in=name_list)
+            if start_time:
+                start_time = LocalDateTimeUtil.time_stamp_to_time(int(start_time), '%Y%m')
+                video_qs = video_qs.filter(event_time__gte=int(start_time))
+            if end_time:
+                end_time = LocalDateTimeUtil.time_stamp_to_time(int(end_time), '%Y%m')
+                video_qs = video_qs.filter(event_time__lte=int(end_time))
+            video_qs = video_qs.values('id', 'uid', 'device_nick_name', 'event_time', 'created_time').order_by(
+                '-event_time')[(page - 1) * size:page * size]
+            if not video_qs.exists():
+                return response.json(0, [])
+            s3 = AmazonS3Util(ACCESS_KEY_ID, SECRET_ACCESS_KEY, REGION_NAME)
+            res_data = []
+            now_month = LocalDateTimeUtil.get_cur_month_start()
+            start_time = "{} 00:00:00".format(str(now_month))
+            time_array = time.strptime(start_time, "%Y-%m-%d %H:%M:%S")
+            for item in video_qs:
+                picture_qs = DevicePicturePushInfo.objects \
+                    .filter(uid=item['uid'], event_time__gt=int(time.mktime(time_array)), type=0).order_by('event_time')
+                event_time = picture_qs.first().event_time
+                channel = picture_qs.first().channel
+                data = {'id': item['id'], 'deviceNickname': item['device_nick_name'],
+                        'createdTime': item['created_time']}
+                picture_key = '{}/{}/{}.jpeg'.format(item['uid'], channel, event_time)
+                picture_url = s3.generate_file_obj_url(PUSH_CLOUD_PHOTO, picture_key)
+                data['picture'] = picture_url
+                key = '{}/video/{}.mp4'.format(item['uid'], str(item['event_time']))
+                obj_url = s3.generate_file_obj_url(PUSH_CLOUD_PHOTO, key)
+                data['videoLink'] = obj_url
+
+                res_data.append(data)
+            return response.json(0, res_data)
+        except Exception as e:
+            LOGGER.info('异常详情,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+            return response.json(500)
+
+    @classmethod
+    def del_cloud_photo(cls, request_dict, response):
+        """
+        根据id删除视频列表
+        @param request_dict:
+        @param response:
+        @return:
+        """
+        try:
+            ids = request_dict.get('ids', None)
+            if not ids:
+                return response.json(444)
+            cloud_photo_qs = DevicePicturePushInfo.objects.filter(id__in=ids.split(','))
+            if not cloud_photo_qs.exists():
+                return response.json(173)
+            s3 = AmazonS3Util(ACCESS_KEY_ID, SECRET_ACCESS_KEY, REGION_NAME)
+            for item in cloud_photo_qs:
+                key = '{}/video/{}.mp4'.format(item.uid, str(item.event_time))
+                s3.delete_obj(PUSH_CLOUD_PHOTO, key)
+            cloud_photo_qs.delete()
+            return response.json(0)
+        except Exception as e:
+            LOGGER.info('异常详情,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+            return response.json(500)

+ 232 - 0
Controller/Cron/CronCloudPhotoController.py

@@ -0,0 +1,232 @@
+# -*- encoding: utf-8 -*-
+"""
+@File    : CronCloudPhotoController.py
+@Time    : 2022/10/24 15:48
+@Author  : stephen
+@Email   : zhangdongming@asj6.wecom.work
+@Software: PyCharm
+"""
+import datetime
+import logging
+import os
+import time
+import traceback
+
+import cv2
+from django.db import transaction
+from django.views import View
+
+from Ansjer.config import PUSH_CLOUD_PHOTO, ACCESS_KEY_ID, SECRET_ACCESS_KEY, REGION_NAME, PUSH_BUCKET
+from Model.models import UidSetModel, DeviceCloudPhotoInfo, DevicePicturePushInfo
+from Object.AWS.AmazonS3Util import AmazonS3Util
+from Object.RedisObject import RedisObject
+from Object.ResponseObject import ResponseObject
+from Object.utils import LocalDateTimeUtil
+from Service.EquipmentInfoService import EquipmentInfoService
+
+LOGGER = logging.getLogger('info')
+UID_KEY = 'ANSJER:UID:SET:INFO'
+
+
+class CronCloudPhotoView(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 == 'get-photo':
+            return self.get_photo(response)
+        elif operation == 'cache-uid-set':
+            return self.cache_photo_uid_set(response)
+        elif operation == 'generate-video':
+            return self.generate_video(response)
+        else:
+            return response.json(404)
+
+    @classmethod
+    def get_photo(cls, response):
+        """
+        定时获取设备消息推送图
+        """
+        try:
+            now_time = int(time.time())
+            LOGGER.info('进入缓存uid进行获取消息推送图片进行对象copy:{}'.format(now_time))
+            redis = RedisObject().CONN
+            uid_set_cache = redis.lrange(UID_KEY, 0, -1)
+            if not uid_set_cache:
+                return response.json(0)
+            uid_set_cache = list(uid_set_cache)
+            today = datetime.date.today()
+            time_stamp = cls.get_month_stamp()
+            s3 = AmazonS3Util(ACCESS_KEY_ID, SECRET_ACCESS_KEY, REGION_NAME)
+            for item in uid_set_cache:
+                try:
+                    eq_qs = EquipmentInfoService.get_equipment_info_model(str(today))
+                    item = str(item, encoding="utf-8")
+                    last_date = LocalDateTimeUtil.get_cur_month_end()
+                    start_time, end_time = LocalDateTimeUtil.get_start_and_end_time(last_date, '%Y-%m-%d')
+                    eq_qs = eq_qs.filter(event_time__gt=time_stamp, event_time__lt=end_time, is_st=1, device_uid=item) \
+                        .values('device_uid', 'channel', 'event_time', 'device_nick_name')
+                    count = eq_qs.count()
+                    page = int(count / 2) if count > 1 else count
+                    redis.lrem(UID_KEY, 0, item)
+                    if page == 0:
+                        continue
+                    eq_qs = eq_qs[(page - 1) * 1:page * 1]
+                    eq_vo = eq_qs[0]
+                    file_path = '{uid}/{channel}/{event_time}.jpeg'.format(uid=eq_vo['device_uid'],
+                                                                           channel=eq_vo['channel'],
+                                                                           event_time=eq_vo['event_time'])
+                    s3.copy_obj(PUSH_BUCKET, PUSH_CLOUD_PHOTO, file_path)
+                    push_data = {'type': 0, 'uid': eq_vo['device_uid'], 'channel': eq_vo['channel'],
+                                 'event_time': eq_vo['event_time'], 'updated_time': now_time, 'created_time': now_time,
+                                 'device_nick_name': eq_vo['device_nick_name']}
+                    DevicePicturePushInfo.objects.create(**push_data)
+                except Exception as e:
+                    LOGGER.info('异常详情,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+                    redis.lrem(UID_KEY, 0, item)
+                    continue
+            return response.json(0)
+        except Exception as e:
+            print(e)
+            LOGGER.info('--->抽取推送图片异常:{}'.format(traceback.format_exc()))
+            return response.json(177, repr(e))
+
+    @classmethod
+    def cache_photo_uid_set(cls, response):
+        """
+        缓存uid_set信息
+        """
+        try:
+            now_time = int(time.time())
+            LOGGER.info('进入读取开启云相册用户并把UID存在redis:{}'.format(now_time))
+            photo_qs = DeviceCloudPhotoInfo.objects.filter(status=1).values('uid')
+            if not photo_qs.exists():
+                return response.json(0)
+            redis = RedisObject()
+            for item in photo_qs:
+                uid_set_qs = UidSetModel.objects.filter(uid=item['uid'], detect_status=1)
+                if not uid_set_qs:
+                    continue
+                redis.CONN.rpush(UID_KEY, item['uid'])
+            return response.json(0)
+        except Exception as e:
+            print(e)
+            LOGGER.info('--->获取uid_set信息异常:{}'.format(traceback.format_exc()))
+            return response.json(177, repr(e))
+
+    @classmethod
+    def generate_video(cls, response):
+        """
+        生成视频并存库
+        """
+        try:
+            now_time = int(time.time())
+            LOGGER.info('进入云相册开启用户,进行消息推送图进行合成视频:{}'.format(now_time))
+            photo_qs = DeviceCloudPhotoInfo.objects.filter(status=1).values('uid', 'user_id')
+            if not photo_qs.exists():
+                return response.json(0)
+            # 获取当前项目路径
+            poj_path = os.path.abspath(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
+            time_stamp = cls.get_month_stamp()
+            s3 = AmazonS3Util(ACCESS_KEY_ID, SECRET_ACCESS_KEY, REGION_NAME)
+            for item in photo_qs:
+                try:
+                    with transaction.atomic():
+                        last_date = LocalDateTimeUtil.get_cur_month_end()
+                        start_time, end_time = LocalDateTimeUtil.get_start_and_end_time(last_date, '%Y-%m-%d')
+                        picture_qs = DevicePicturePushInfo.objects.filter(uid=item['uid'],
+                                                                          event_time__gt=time_stamp,
+                                                                          event_time__lt=end_time,
+                                                                          type=0) \
+                            .values('uid', 'channel', 'event_time', 'device_nick_name')
+                        if not picture_qs.exists():
+                            continue
+                        device_nickname = picture_qs[0]['device_nick_name']
+                        pic_list = cls.download_push_picture(s3, item['uid'], poj_path, picture_qs)
+                        video_path = poj_path + r'\Ansjer\file\video.mp4'  # 输出视频的保存路径
+                        cls.picture_synthesis_video(video_path, poj_path, pic_list)  # 图片合成视频
+                        video_name = datetime.datetime.now().strftime('%Y%m')
+                        data = open(video_path, 'rb')
+                        key = '{}/video/{}.mp4'.format(item['uid'], video_name)
+                        s3.upload_file_obj(PUSH_CLOUD_PHOTO, key, data)  # 将视频资源上传至S3保存
+                        os.remove(video_path)  # 上传完成删除本地资源
+                        push_data = {'type': 1, 'uid': item['uid'], 'channel': 1,
+                                     'event_time': int(video_name), 'updated_time': now_time, 'created_time': now_time,
+                                     'device_nick_name': device_nickname, 'user_id': item['user_id']}
+                        DevicePicturePushInfo.objects.create(**push_data)
+                except Exception as e:
+                    LOGGER.info('异常详情,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+                    continue
+            return response.json(0)
+        except Exception as e:
+            print(e)
+            LOGGER.info('--->图片合成视频异常:{}'.format(traceback.format_exc()))
+            return response.json(177)
+
+    @staticmethod
+    def download_push_picture(s3, uid, dir_url, picture_qs):
+        """
+        下载推送图片,讲下载资源保存到项目本地
+        @param s3: s3对象
+        @param uid: 设备uid
+        @param dir_url: 项目文件路径
+        @param picture_qs: 消息推送图片对象
+        @return: pic_list 图片文件名集合
+        """
+        pic_list = []
+        for pic in picture_qs:
+            path = dir_url + r'\Ansjer\file\{}.jpeg'.format(pic['event_time'])
+            s3_key = '{}/{}/{}.jpeg'.format(uid, pic['channel'], pic['event_time'])
+            s3.download_object(PUSH_CLOUD_PHOTO, s3_key, path)
+            pic_list.append('{}.jpeg'.format(pic['event_time']))
+        return pic_list
+
+    @staticmethod
+    def picture_synthesis_video(video_path, poj_path, pic_list):
+        """
+        图片合成视频
+        @param video_path: 输出视频的保存路径
+        @param poj_path: 项目路径
+        @param pic_list: 图片文件名集合
+        @return:
+        """
+        if not pic_list:
+            raise Exception('this pic_list is null.')
+        fps = 1  # 帧率
+        img_path = poj_path + r'\Ansjer\file\{}'.format(pic_list[0])
+        image = cv2.imread(img_path)
+        size = image.shape
+        w = size[1]  # 宽度
+        h = size[0]  # 高度
+        img_size = (w, h)  # 图片尺寸
+        fourcc = cv2.VideoWriter_fourcc(*"mp4v")
+        video_writer = cv2.VideoWriter(video_path, fourcc, fps, img_size)
+        for item in pic_list:
+            img_path = poj_path + r'\Ansjer\file\{}'.format(item)
+            frame = cv2.imread(img_path)
+            if frame is None:
+                continue
+            frame = cv2.resize(frame, img_size)  # 生成视频   图片尺寸和设定尺寸相同
+            video_writer.write(frame)  # 将图片写进视频里
+            os.remove(img_path)
+        video_writer.release()  # 释放资源
+
+    @staticmethod
+    def get_month_stamp():
+        """
+        获取当月开始时间戳
+        """
+        now_month = LocalDateTimeUtil.get_cur_month_start()
+        start_time = "{} 00:00:00".format(str(now_month))
+        time_array = time.strptime(start_time, "%Y-%m-%d %H:%M:%S")
+        # 转换为时间戳
+        return int(time.mktime(time_array))

+ 32 - 6
Controller/DeviceShare.py

@@ -16,15 +16,16 @@ import json
 import time
 
 from django.views.generic.base import View
-from Object.RedisObject import RedisObject
+
 from Ansjer.config import SERVER_DOMAIN
-from Model.models import Device_Info, Device_User
+from Controller.SensorGateway.EquipmentFamilyController import EquipmentFamilyView
+from Controller.UserDevice.UserDeviceShareController import UserDeviceShareView
+from Model.models import Device_Info, Device_User, DeviceChannelUserSet, DeviceChannelUserPermission
 from Model.models import UID_Bucket
 from Object.RedisObject import RedisObject
 from Object.ResponseObject import ResponseObject
 from Object.TokenObject import TokenObject
 from Service.CommonService import CommonService
-from Controller.SensorGateway.EquipmentFamilyController import EquipmentFamilyView
 
 
 class DeviceShareView(View):
@@ -183,7 +184,7 @@ class DeviceShareView(View):
                     sharerDvqs.primaryMaster = primaryMaster
                     sharerDvqs.data_joined = None
                     sharerDvqs.save()
-
+                    UserDeviceShareView.qrcode_share_channel_permission_save(userID, UID)
                     # redisObj = RedisObject(db=8)
                     # redisObj.del_data(key='uid_qs_' + userID)
                 except Exception as e:
@@ -218,12 +219,12 @@ class DeviceShareView(View):
         if UID is not None:
             # 查询分享获得的用户
             qs = Device_Info.objects.filter(UID=UID, isShare=True, primaryUserID=userID, isExist=1). \
-                values('userID__NickName', 'userID__username', 'userID__userEmail', 'userID__phone', 'id',
+                values('userID__NickName', 'userID__username', 'userID__userEmail', 'userID__phone', 'id', 'userID',
                        'userID__userIconPath')
             data = []
             # print(qs)
             for q in qs:
-                d = {'id': q['id']}
+                d = {'id': q['id'], 'userID': q['userID']}
                 if q['userID__NickName']:
                     d['user'] = q['userID__NickName']
                 elif q['userID__username']:
@@ -262,7 +263,32 @@ class DeviceShareView(View):
             return response.json(444, 'id')
         try:
             Device_Info.objects.filter(id__in=ids.split(','), primaryUserID=userID).delete()
+
         except Exception as e:
             return response.json(10, repr(e))
         else:
             return response.json(0)
+
+    @staticmethod
+    def del_device_channel_permission(user_id, uid):
+        """
+        删除设备通道权限
+        @param user_id: 用户ID
+        @param uid: 设备UID
+        @return: True | False
+        """
+        if user_id and uid:
+            user_channel_qs = DeviceChannelUserSet.objects.filter(user_id=user_id, uid=uid)
+            if user_channel_qs.exists():
+                DeviceChannelUserPermission.objects.filter(channel_user_id=user_channel_qs.first().id).delete()
+                user_channel_qs.delete()
+            return True
+        elif uid:
+            user_channel_qs = DeviceChannelUserSet.objects.filter(uid=uid)
+            if user_channel_qs.exists():
+                channels_user_list = [val.id for val in user_channel_qs]
+                DeviceChannelUserPermission.objects.filter(channel_user_id__in=channels_user_list).delete()
+                user_channel_qs.delete()
+            return True
+        else:
+            return False

+ 3 - 0
Controller/EquipmentManager.py

@@ -14,6 +14,7 @@ from django.utils import timezone
 from Ansjer.config import OSS_STS_ACCESS_SECRET, OSS_STS_ACCESS_KEY, BASE_DIR
 from Ansjer.config import PUSH_REDIS_ADDRESS
 from Controller.DetectController import DetectControllerView
+from Controller.DeviceShare import DeviceShareView
 from Model.models import Device_User, Device_Info, UID_Bucket, UID_Preview, UidSetModel, UidPushModel, \
     UIDCompanySerialModel, iotdeviceInfoModel, UidChannelSetModel, LogModel, UnicomDeviceInfo, SysMsgModel, CountryModel
 from Object.RedisObject import RedisObject
@@ -824,6 +825,7 @@ def deleteInterface(request):
 
             if dv_qs[0].isShare:
                 dv_qs.delete()
+                DeviceShareView.del_device_channel_permission(userID, uid)
             else:
                 # a.主用户删除设备
                 dv_qs.delete()
@@ -840,6 +842,7 @@ def deleteInterface(request):
                     up_qs.delete()
                 # b.删除次用户设备
                 Device_Info.objects.filter(UID=uid, isShare=True, primaryUserID=userID).delete()
+                DeviceShareView.del_device_channel_permission('', uid)
 
             if not serial_number:
                 serial_number = CommonService.query_serial_with_uid(uid)

+ 1 - 1
Controller/EquipmentManagerV3.py

@@ -677,7 +677,7 @@ class EquipmentManagerV3(View):
 
             if p_uid in uv_dict:
                 # 获取设备信息DTO
-                UserDeviceService.get_device_info_dto(p, p_uid, uv_dict)
+                UserDeviceService.get_device_info_dto(p, p_uid, uv_dict, userID)
             else:
                 # 设备版本号
                 p['uid_version'] = ''

+ 25 - 2
Controller/PcInfo.py

@@ -12,7 +12,7 @@ from django.http import HttpResponse
 from django.views.generic.base import View
 
 from Controller.PctestController import TokenObject1
-from Model.models import Pc_Info, PctestlogModel
+from Model.models import Pc_Info, PctestlogModel, AVSSVersion
 from Object.ResponseObject import ResponseObject
 from Object.TokenObject import TokenObject
 from Service.CommonService import CommonService
@@ -71,6 +71,8 @@ class PcInfo(View):
                 return self.download(request_dict, response)
             elif operation == 'delete':
                 return self.delete(request_dict, response)
+            elif operation == 'AVSS/check-version':
+                return self.check_version(request_dict, response)
             else:
                 return response.json(414)
 
@@ -643,6 +645,28 @@ class PcInfo(View):
         else:
             return response.json(0)
 
+    @staticmethod
+    def check_version(request_dict, response):
+        """
+        AVSS检查版本
+        @param request_dict: 请求数据
+        @request_dict version: 当前版本
+        @param response: 响应
+        @return: response
+        """
+        version = request_dict.get('version', None)
+        if version is None:
+            return response.json(444)
+        avss_version_qs = AVSSVersion.objects.filter().values('online_version')
+        if not avss_version_qs.exists():
+            return response.json(173)
+        # 比较当前版本和线上版本
+        online_version = avss_version_qs[0]['online_version']
+        if version < online_version:
+            return response.json(0, {'online_version': online_version})
+        else:
+            return response.json(0)
+
 def compareVersion(s1: str, s2: str) -> Union[str, int]:
     i, j = 0, 0
     while i < len(s1) or j < len(s2):
@@ -693,4 +717,3 @@ def getMD5orSHA265(fileName, encryptionType='MD5'):
 
         f.close()
         return encryption.hexdigest()
-

+ 154 - 0
Controller/ShadowController.py

@@ -0,0 +1,154 @@
+import logging
+import time
+
+from django.http import JsonResponse
+
+from Ansjer.config import SERVER_TYPE
+from Model.models import Device_Info, UidSetModel, UID_Preview, VoicePromptModel, UID_Bucket, UidChannelSetModel, \
+    AiService, CountryModel
+from Object.ETkObject import ETkObject
+from Service.CommonService import CommonService
+
+
+# 更新设备影子
+def update_device_shadow(request):
+    request.encoding = 'utf-8'
+    if request.method == 'POST':
+        request_dict = request.POST
+    elif request.method == 'GET':
+        request_dict = request.GET
+    else:
+        return JsonResponse(status=200, data={'code': 0, 'msg': 'success', 'data': {}})
+
+    logger = logging.getLogger('info')
+    logger.info('---更新设备影子---, 使用配置:{}, 参数:{}'.format(SERVER_TYPE, request_dict.dict()))
+
+    try:
+        etk = request_dict.get('etk', None)
+        eto = ETkObject(etk)
+        uid = eto.uid
+        if not uid:
+            return JsonResponse(status=200, data={'code': 0, 'msg': 'success', 'data': {}})
+
+        nowTime = int(time.time())
+
+        # 重置按钮
+        is_reset = request_dict.get('is_reset', None)
+        # 传1则重置设备信息
+        if is_reset == '1':
+            logger.info('设备重置: {}'.format(uid))
+
+            # 重置语音提示
+            uid_channel_qs = UidChannelSetModel.objects.filter(uid__uid=uid)
+            if uid_channel_qs.exists():
+                uid_channel_qs.update(voice_prompt_intelligent_mute=0, voice_prompt_status=0, voice_prompt_enter=0,
+                                      voice_prompt_leave=0, voice_repeat_day=127, voice_start_time=0, voice_end_time=0,
+                                      voice_start_x=0, voice_start_y=18, voice_end_x=44, voice_end_y=18,
+                                      voice_direction=0)
+
+            # 购买云存套餐的设备isExist置为2
+            uid_bucket = UID_Bucket.objects.filter(uid=uid, endTime__gte=nowTime).values('id', 'has_unused').order_by(
+                'addTime')
+            if not uid_bucket.exists():
+                Device_Info.objects.filter(UID=uid).update(isExist=2)
+            # 删除预览图
+            uid_pre_qs = UID_Preview.objects.filter(uid=uid)
+            if uid_pre_qs.exists():
+                uid_pre_qs.delete()
+
+            # 删除语音提示
+            voice_qs = VoicePromptModel.objects.filter(uid=uid)
+            if voice_qs.exists():
+                voice_qs.delete()
+
+            # 关闭移动侦测的消息提醒
+            Device_Info.objects.filter(UID=uid).update(NotificationMode=0)
+
+            # 关闭AI
+            AiService.objects.filter(uid=uid, use_status=1).update(detect_status=0, detect_group='')
+            logger.info('{}重置成功'.format(uid))
+
+        ucode = request_dict.get('ucode', None)
+        version = request_dict.get('version', None)
+        p2p_region = request_dict.get('p2p_region', None)
+        tz = request_dict.get('tz', None)
+        video_code = request_dict.get('video_code', None)
+        ip = CommonService.get_ip_address(request)
+        channel = request_dict.get('channel', None)
+        cloud_vod = request_dict.get('cloud_vod', None)
+        push_status = request_dict.get('push_status', None)
+        pwd = request_dict.get('pwd', None)
+        is_alexa = request_dict.get('is_alexa', None)
+        is_human = request_dict.get('is_human', None)
+        is_custom_voice = request_dict.get('is_custom', None)
+        double_wifi = request_dict.get('double_wifi', None)
+        mobile_4g = request_dict.get('mobile4G', None)
+        is_ptz = request_dict.get('is_ptz', None)
+        is_ai = request_dict.get('is_ai', None)
+        ai_type = request_dict.get('AiType', None)
+        isSupportFourPoint = request_dict.get('isSupportFourPoint', None)
+
+        # 更新
+        qs_dict = {
+            'updTime': nowTime,
+            'ip': ip
+        }
+        if channel:
+            qs_dict['channel'] = channel
+        if p2p_region:
+            qs_dict['p2p_region'] = p2p_region
+        if ucode:
+            qs_dict['ucode'] = ucode
+        if version:
+            qs_dict['version'] = version
+        if tz:
+            qs_dict['tz'] = tz
+        if video_code:
+            qs_dict['video_code'] = video_code
+        if cloud_vod:
+            qs_dict['cloud_vod'] = cloud_vod
+        if push_status:
+            # 复位重置推送消息提醒
+            qs_dict['detect_status'] = 0 if is_reset == '1' else push_status
+        if pwd:
+            qs_dict['pwd'] = pwd
+        if is_human:
+            qs_dict['is_human'] = is_human
+        if is_custom_voice:
+            qs_dict['is_custom_voice'] = is_custom_voice
+        if double_wifi:
+            qs_dict['double_wifi'] = double_wifi
+        if mobile_4g:
+            qs_dict['mobile_4g'] = int(mobile_4g)
+        if is_ptz:
+            qs_dict['is_ptz'] = is_ptz
+        if is_ai:
+            qs_dict['is_ai'] = is_ai
+        if isSupportFourPoint:
+            qs_dict['isSupportFourPoint'] = isSupportFourPoint
+        if ai_type:
+            qs_dict['ai_type'] = ai_type
+        ipInfo = CommonService.getIpIpInfo(ip, 'CN')
+        country_qs = CountryModel.objects.filter(country_code=ipInfo['country_code']).values('id')
+        if country_qs.exists():
+            country = country_qs[0]['id']
+            qs_dict['tb_country'] = country
+        logger.info('{} qs_dict: {}'.format(uid, qs_dict))
+
+        us_qs = UidSetModel.objects.filter(uid=uid)
+        if us_qs.exists():
+            if is_alexa and us_qs[0].is_alexa == 0:
+                qs_dict['is_alexa'] = is_alexa
+            us_qs.update(**qs_dict)
+        # 新增
+        else:
+            if is_alexa:
+                qs_dict['is_alexa'] = is_alexa
+            qs_dict['uid'] = uid
+            qs_dict['addTime'] = nowTime
+            UidSetModel.objects.create(**qs_dict)
+        logger.info('***设备影子保存成功{}'.format(uid))
+        return JsonResponse(status=200, data={'code': 0, 'msg': 'success', 'data': {}})
+    except Exception as e:
+        logger.info('更新设备影子异常: {}'.format(repr(e)))
+        return JsonResponse(status=200, data={'code': 0, 'update_shadow_error': repr(e)})

+ 7 - 22
Controller/StsOssController.py

@@ -1,26 +1,12 @@
-#!/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: 2019/5/10 8:43
-@Version: python3.6
-@MODIFY DECORD:ansjer dev
-@file: StsOssController.py
-@Contact: chanjunkai@163.com
-"""
+import json
 
+from aliyunsdkcore import client
+from aliyunsdksts.request.v20150401 import AssumeRoleRequest
 from django.views.generic import View
 
+from Ansjer.config import OSS_STS_ACCESS_SECRET, OSS_STS_ACCESS_KEY, OSS_ROLE_ARN
 from Object.ResponseObject import ResponseObject
 from Object.TokenObject import TokenObject
-from Ansjer.config import OSS_STS_ACCESS_SECRET, OSS_STS_ACCESS_KEY, OSS_ROLE_ARN
-from aliyunsdkcore import client
-from aliyunsdksts.request.v20150401 import AssumeRoleRequest
-import json
-from var_dump import var_dump
 
 
 class StsOssView(View):
@@ -39,7 +25,6 @@ class StsOssView(View):
 
     def validation(self, request_dict, operation):
         response = ResponseObject()
-        from var_dump import var_dump
         # var_dump(request_dict)
         token = request_dict.get('token', None)
         if operation == 'uidPreview':
@@ -63,13 +48,13 @@ class StsOssView(View):
         req.set_RoleArn(OSS_ROLE_ARN)
         req.set_RoleSessionName(userID)
         req.set_DurationSeconds(3600)
-        Resource_access = "acs:oss:*:*:{bucket_name}/{userID}*".\
-            format(bucket_name=bucket_name,userID=userID)
+        Resource_access = "acs:oss:*:*:{bucket_name}/{userID}*". \
+            format(bucket_name=bucket_name, userID=userID)
         policys = {
             "Version": "1",
             "Statement": [
                 {
-                    "Action": ["oss:PutObject", "oss:DeleteObject", "oss:GetObject",],
+                    "Action": ["oss:PutObject", "oss:DeleteObject", "oss:GetObject", ],
                     # "Action": ["*"],
                     # "Action": ["*"],
                     "Resource": [Resource_access],

+ 1 - 0
Controller/SysMsg.py

@@ -187,6 +187,7 @@ class SysMsgView(View):
             uid_list = []
 
             for sm_q in sm_qs:
+                sm_q['jumpLink'] = ''
                 if sm_q['eventType'] > 0:
                     uid_list.append(sm_q['uid'])
                 data_res.append(sm_q)

+ 76 - 314
Controller/TestApi.py

@@ -11,11 +11,17 @@
 @file: Test.py
 @Contact: chanjunkai@163.com
 """
+import os
+import traceback
+
 import botocore
+import cv2
 from botocore import client
+
 from Controller.DeviceConfirmRegion import Device_Region
 from Object.AWS.AmazonS3Util import AmazonS3Util
 from Object.RedisObject import RedisObject
+from Service.VodHlsService import SplitVodHlsObject
 
 '''
 http://192.168.136.40:8077/Test
@@ -30,7 +36,6 @@ import oss2
 import paypalrestsdk
 import logging
 from aliyunsdkcore import client
-from aliyunsdksts.request.v20150401 import AssumeRoleRequest
 from django.http import JsonResponse, HttpResponse
 from django.utils.decorators import method_decorator
 from django.views.decorators.csrf import csrf_exempt
@@ -38,7 +43,7 @@ from django.views.generic.base import View
 from django.contrib.auth.hashers import make_password  # 对密码加密模块
 from Ansjer.config import OSS_STS_ACCESS_KEY, OSS_STS_ACCESS_SECRET, OSS_ROLE_ARN, AWS_ACCESS_KEY_ID, \
     AWS_SECRET_ACCESS_KEY, SERVER_TYPE, AWS_SES_ACCESS_REGION
-from Model.models import Order_Model, Store_Meal, VodHlsModel, OssCrdModel, StsCrdModel, DeviceLogModel
+from Model.models import Order_Model, Store_Meal, OssCrdModel, StsCrdModel, DeviceLogModel, VodBucketModel
 from Object.ResponseObject import ResponseObject
 from Object.TokenObject import TokenObject
 from Service.CommonService import CommonService
@@ -49,6 +54,7 @@ from Ansjer.config import SERVER_DOMAIN_SSL
 SERVER_DOMAIN = 'http://test.dvema.com/'
 ACCESS_KEY = "AKIA2E67UIMD3CYTIWPA"
 SECRET_KEY = "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"
+LOGGER = logging.getLogger('info')
 
 
 # 测试接口sdk
@@ -148,9 +154,47 @@ class testView(View):
             return self.read_redis_list(response)
         elif operation == 'playM3u8':
             return self.play_m3u8(request_dict, response)
+        elif operation == 'generate_video':
+            return self.generate_video(request_dict, response)
         else:
             return 123
 
+    @classmethod
+    def generate_video(cls, request_dict, response):
+        # 设计抽取图片规则通过消息随机还是时间随机,调试copy S3对象查询是否携带失效时间
+        try:
+            DIR = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
+            arr_list = ['1666756086.jpeg', '1666831275.jpeg', '1666841492.jpeg']
+            s3 = AmazonS3Util(AWS_ACCESS_KEY_ID[0], AWS_SECRET_ACCESS_KEY[0], 'cn-northwest-1')
+            bucket = 'push-cloud-photo'
+            for item in arr_list:
+                path = DIR + r'\Ansjer\file\{}'.format(item)
+                s3_key = 'HA154GVEDH41RY8Y111A/1/{}'.format(item)
+                s3.download_object(bucket, s3_key, path)
+            video_dir = DIR + r'\Ansjer\file\result.mp4'  # 输出视频的保存路径
+            fps = 0.5  # 帧率
+            img_size = (1920, 1080)  # 图片尺寸
+            fourcc = cv2.VideoWriter_fourcc(*"mp4v")
+            videoWriter = cv2.VideoWriter(video_dir, fourcc, fps, img_size)
+            for i in arr_list:
+                img_path = DIR + r'\Ansjer\file\{}'.format(i)
+                frame = cv2.imread(img_path)
+                frame = cv2.resize(frame, img_size)  # 生成视频   图片尺寸和设定尺寸相同
+                videoWriter.write(frame)  # 将图片写进视频里
+                os.remove(img_path)
+            videoWriter.release()  # 释放资源
+            data = open(video_dir, 'rb')
+            key = 'HA154GVEDH41RY8Y111A/1/20221027.mp4'
+            s3.upload_file_obj(bucket, key, data)
+            response_url = s3.generate_file_obj_url(bucket, key)
+            os.remove(video_dir)
+        except Exception as e:
+            print(e)
+            ex = traceback.format_exc()
+            LOGGER.info('--->抽取推送图片异常:{}'.format(ex))
+            return response.json(177, ex)
+        return response.json(0, response_url)
+
     @classmethod
     def head_bucket(cls, request_dict, response):
         bucket_name = request_dict.get('bucket', None)
@@ -489,294 +533,6 @@ class testView(View):
         # return response
         # return HttpResponse(status=200, content=playlist)
 
-    def do_test_get_sign_sts(self, request_dict, ip, response):
-        # uid = 'GZL2PEFJPLY7W6BG111A'
-        # channel = 2
-        uid = 'VVDHCVBYDKFMJRWA111A'
-        channel = 1
-        now_time = int(time.time())
-        ubqs = UID_Bucket.objects.filter(uid=uid, channel=channel, endTime__gte=now_time). \
-            values("bucket__mold", "bucket__bucket", "bucket__endpoint", "bucket__region", "endTime")
-        if ubqs.exists():
-            if ubqs[0]["bucket__mold"] == 0:
-                # 阿里云 oss sts
-                oc_qs = OssCrdModel.objects.filter(uid=uid, channel=channel). \
-                    values("addTime", "data")
-                if oc_qs.exists():
-                    endTime = int(oc_qs[0]["addTime"]) + 3500
-                    if endTime > now_time:
-                        print(endTime)
-                        print(now_time)
-                        res = json.loads(oc_qs[0]["data"])
-                        return JsonResponse(status=200, data=res)
-                # 套餐id
-                storage = '{uid}/vod{channel}/'.format(uid=uid, channel=channel)
-                bucket_name = ubqs[0]['bucket__bucket']
-                endpoint = ubqs[0]['bucket__endpoint']
-                access_key_id = OSS_STS_ACCESS_KEY
-                access_key_secret = OSS_STS_ACCESS_SECRET
-                region_id = ubqs[0]['bucket__region']
-                role_arn = OSS_ROLE_ARN
-                clt = client.AcsClient(access_key_id, access_key_secret, region_id)
-                req = AssumeRoleRequest.AssumeRoleRequest()
-                # 设置返回值格式为JSON。
-                req.set_accept_format('json')
-                req.set_RoleArn(role_arn)
-                req.set_RoleSessionName(uid + '_' + channel)
-                req.set_DurationSeconds(3600)
-                Resource_access = "acs:oss:*:*:{bucket_name}/{uid_channel}*". \
-                    format(bucket_name=bucket_name, uid_channel=storage)
-                print(Resource_access)
-                policys = {
-                    "Version": "1",
-                    "Statement": [
-                        {
-                            "Action": ["oss:PutObject", "oss:DeleteObject", ],
-                            "Resource": [Resource_access],
-                            "Effect": "Allow",
-                            "Condition": {
-                                "IpAddress": {"acs:SourceIp": ip}
-                                # "IpAddress": {"acs:SourceIp": "120.237.157.184"}
-                                # "IpAddress": {"acs:SourceIp": "*"}
-                            }
-                        }
-                    ]
-                }
-                req.set_Policy(Policy=json.dumps(policys))
-                body = clt.do_action(req)
-                # 使用RAM账号的AccessKeyId和AccessKeySecret向STS申请临时token。
-                token = json.loads(body.decode('utf-8'))
-                print(token)
-                res = {
-                    'AccessKeyId': token['Credentials']['AccessKeyId'],
-                    'AccessKeySecret': token['Credentials']['AccessKeySecret'],
-                    'SecurityToken': token['Credentials']['SecurityToken'],
-                    'Expiration': token['Credentials']['Expiration'],
-                    'expire': '3600',
-                    'endpoint': endpoint,
-                    'bucket_name': bucket_name,
-                    'arn': token['AssumedRoleUser']['Arn'],
-                    'code': 0,
-                    'storage': storage,
-                    'endTime': ubqs[0]['endTime'],
-                    'ip': ip}
-                if oc_qs.exists():
-                    oc_qs.update(data=json.dumps(res), addTime=now_time)
-                else:
-                    OssCrdModel.objects.create \
-                        (uid=uid, channel=channel, data=json.dumps(res), addTime=now_time)
-                return JsonResponse(status=200, data=res)
-            elif ubqs[0]["bucket__mold"] == 1:
-                # 亚马逊 s3 sts
-                sts_qs = StsCrdModel.objects.filter(uid=uid, channel=channel). \
-                    values("addTime", "data")
-                if sts_qs.exists():
-                    endTime = int(sts_qs[0]["addTime"]) + 3500
-                    if endTime > now_time:
-                        print(endTime)
-                        print(now_time)
-                        res = json.loads(sts_qs[0]["data"])
-                        return JsonResponse(status=200, data=res)
-                    # 套餐id
-                storage = '{uid}/vod{channel}/'.format(uid=uid, channel=channel)
-                bucket_name = ubqs[0]['bucket__bucket']
-                endpoint = ubqs[0]['bucket__endpoint']
-                region_id = ubqs[0]['bucket__region']
-
-                ###############
-                REGION_NAME = region_id
-                boto3_sts = boto3.client(
-                    'sts',
-                    aws_access_key_id='AKIA2E67UIMD45Y3HL53',
-                    aws_secret_access_key='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',
-                    region_name=REGION_NAME
-                )
-                Policy = {
-                    "Version": "2012-10-17",
-                    "Statement": [
-                        {
-                            "Effect": "Allow",
-                            "Action": "s3:*",
-                            "Resource": ["arn:aws:s3:::azvod1/{uid_channel}/*".
-                                             format(uid_channel=storage)]
-                        }
-                    ]
-                }
-                response = boto3_sts.get_federation_token(
-                    Name='{role_name}'.format(role_name=uid + '_' + channel),
-                    Policy=json.dumps(Policy),
-                    DurationSeconds=7200
-                )
-                ###############
-                res = {
-                    'AccessKeyId': response['Credentials']['AccessKeyId'],
-                    'AccessKeySecret': response['Credentials']['SecretAccessKey'],
-                    'SessionToken': response['Credentials']['SessionToken'],
-                    'Expiration': response['Credentials']['Expiration'],
-                    'expire': '3600',
-                    'endpoint': endpoint,
-                    'bucket_name': bucket_name,
-                    'arn': response['FederatedUser']['Arn'],
-                    'code': 0,
-                    'storage': storage,
-                    'endTime': ubqs[0]['endTime'],
-                    'ip': ip,
-                }
-                if sts_qs.exists():
-                    sts_qs.update(data=json.dumps(res, default=str), addTime=now_time)
-                else:
-                    StsCrdModel.objects.create(uid=uid, channel=channel, data=json.dumps(res, default=str),
-                                               addTime=now_time, type=1)
-                return JsonResponse(status=200, data=res)
-            else:
-                res = {'code': 404, 'msg': 'data not exists!'}
-                return HttpResponse(json.dumps(res, ensure_ascii=False),
-                                    content_type="application/json,charset=utf-8")
-
-    def do_get_sign_sts(self, request_dict, ip, response):
-        # uid = 'GZL2PEFJPLY7W6BG111A'
-        # channel = 2
-        uid = '86YC8Z192VB1VMKU111A'
-        channel = 1
-        now_time = int(time.time())
-        ubqs = UID_Bucket.objects.filter(uid=uid, channel=channel, endTime__gte=now_time). \
-            values("bucket__mold", "bucket__bucket", "bucket__endpoint", "bucket__region", "endTime")
-        if ubqs.exists():
-            if ubqs[0]["bucket__mold"] == 0:
-                # 阿里云 oss sts
-                oc_qs = OssCrdModel.objects.filter(uid=uid, channel=channel). \
-                    values("addTime", "data")
-                if oc_qs.exists():
-                    endTime = int(oc_qs[0]["addTime"]) + 3500
-                    if endTime > now_time:
-                        print(endTime)
-                        print(now_time)
-                        res = json.loads(oc_qs[0]["data"])
-                        return JsonResponse(status=200, data=res)
-                # 套餐id
-                storage = '{uid}/vod{channel}/'.format(uid=uid, channel=channel)
-                bucket_name = ubqs[0]['bucket__bucket']
-                endpoint = ubqs[0]['bucket__endpoint']
-                access_key_id = OSS_STS_ACCESS_KEY
-                access_key_secret = OSS_STS_ACCESS_SECRET
-                region_id = ubqs[0]['bucket__region']
-                role_arn = OSS_ROLE_ARN
-                clt = client.AcsClient(access_key_id, access_key_secret, region_id)
-                req = AssumeRoleRequest.AssumeRoleRequest()
-                # 设置返回值格式为JSON。
-                req.set_accept_format('json')
-                req.set_RoleArn(role_arn)
-                req.set_RoleSessionName(uid + '_' + channel)
-                req.set_DurationSeconds(3600)
-                Resource_access = "acs:oss:*:*:{bucket_name}/{uid_channel}*". \
-                    format(bucket_name=bucket_name, uid_channel=storage)
-                print(Resource_access)
-                policys = {
-                    "Version": "1",
-                    "Statement": [
-                        {
-                            "Action": ["oss:PutObject", "oss:DeleteObject", ],
-                            "Resource": [Resource_access],
-                            "Effect": "Allow",
-                            "Condition": {
-                                "IpAddress": {"acs:SourceIp": ip}
-                                # "IpAddress": {"acs:SourceIp": "120.237.157.184"}
-                                # "IpAddress": {"acs:SourceIp": "*"}
-                            }
-                        }
-                    ]
-                }
-                req.set_Policy(Policy=json.dumps(policys))
-                body = clt.do_action(req)
-                # 使用RAM账号的AccessKeyId和AccessKeySecret向STS申请临时token。
-                token = json.loads(body.decode('utf-8'))
-                print(token)
-                res = {
-                    'AccessKeyId': token['Credentials']['AccessKeyId'],
-                    'AccessKeySecret': token['Credentials']['AccessKeySecret'],
-                    'SecurityToken': token['Credentials']['SecurityToken'],
-                    'Expiration': token['Credentials']['Expiration'],
-                    'expire': '3600',
-                    'endpoint': endpoint,
-                    'bucket_name': bucket_name,
-                    'arn': token['AssumedRoleUser']['Arn'],
-                    'code': 0,
-                    'storage': storage,
-                    'endTime': ubqs[0]['endTime'],
-                    'ip': ip}
-                if oc_qs.exists():
-                    oc_qs.update(data=json.dumps(res), addTime=now_time)
-                else:
-                    OssCrdModel.objects.create \
-                        (uid=uid, channel=channel, data=json.dumps(res), addTime=now_time)
-                return JsonResponse(status=200, data=res)
-            elif ubqs[0]["bucket__mold"] == 1:
-                # 亚马逊 s3 sts
-                sts_qs = StsCrdModel.objects.filter(uid=uid, channel=channel). \
-                    values("addTime", "data")
-                if sts_qs.exists():
-                    endTime = int(sts_qs[0]["addTime"]) + 3500
-                    if endTime > now_time:
-                        print(endTime)
-                        print(now_time)
-                        res = json.loads(sts_qs[0]["data"])
-                        return JsonResponse(status=200, data=res)
-                    # 套餐id
-                storage = '{uid}/vod{channel}/'.format(uid=uid, channel=channel)
-                bucket_name = ubqs[0]['bucket__bucket']
-                endpoint = ubqs[0]['bucket__endpoint']
-                region_id = ubqs[0]['bucket__region']
-
-                ###############
-                REGION_NAME = region_id
-                boto3_sts = boto3.client(
-                    'sts',
-                    aws_access_key_id='AKIA2E67UIMD45Y3HL53',
-                    aws_secret_access_key='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',
-                    region_name=REGION_NAME
-                )
-                Policy = {
-                    "Version": "2012-10-17",
-                    "Statement": [
-                        {
-                            "Effect": "Allow",
-                            "Action": "s3:*",
-                            "Resource": ["arn:aws:s3:::azvod1/{uid_channel}/*".
-                                             format(uid_channel=storage)]
-                        }
-                    ]
-                }
-                response = boto3_sts.get_federation_token(
-                    Name='{role_name}'.format(role_name=uid + '_' + channel),
-                    Policy=json.dumps(Policy),
-                    DurationSeconds=7200
-                )
-                ###############
-                res = {
-                    'AccessKeyId': response['Credentials']['AccessKeyId'],
-                    'AccessKeySecret': response['Credentials']['SecretAccessKey'],
-                    'SessionToken': response['Credentials']['SessionToken'],
-                    'Expiration': response['Credentials']['Expiration'],
-                    'expire': '3600',
-                    'endpoint': endpoint,
-                    'bucket_name': bucket_name,
-                    'arn': response['FederatedUser']['Arn'],
-                    'code': 0,
-                    'storage': storage,
-                    'endTime': ubqs[0]['endTime'],
-                    'ip': ip,
-                }
-                if sts_qs.exists():
-                    sts_qs.update(data=json.dumps(res, default=str), addTime=now_time)
-                else:
-                    StsCrdModel.objects.create(uid=uid, channel=channel, data=json.dumps(res, default=str),
-                                               addTime=now_time, type=1)
-                return JsonResponse(status=200, data=res)
-            else:
-                res = {'code': 404, 'msg': 'data not exists!'}
-                return HttpResponse(json.dumps(res, ensure_ascii=False),
-                                    content_type="application/json,charset=utf-8")
-
     def do_pay_by_ali(self, request_dict, userID, response):
         uid = request_dict.get('uid', None)
         rank = request_dict.get('rank', None)
@@ -855,23 +611,24 @@ class testView(View):
         ubqs = UID_Bucket.objects.filter(uid=uid, channel=channel).values('status')
         if not ubqs.exists():
             return response.json(10, '设备未购买')
-        nowTime = int(time.time())
-        # vodqs = VodHlsModel.objects.filter(uid=uid, channel=channel, time__range=(startTime, endTime),
-        #                                    endTime__gte=nowTime) \
-        #     .values("time", "sec", "bucket__bucket", "bucket__endpoint", "bucket__region")
-        vodqs = VodHlsModel.objects.filter(uid=uid, channel=channel) \
-            .values("time", "sec", "bucket__bucket", "bucket__endpoint", "bucket__region")
+        split_vod_hls_obj = SplitVodHlsObject()
+        vodqs = split_vod_hls_obj.get_vod_hls_data(uid=uid, channel=channel).values("start_time", "sec", "bucket_id")
+        if not vodqs.exists():
+            return response.json(173)
         vod_play_list = []
-        print(vodqs)
         auth = oss2.Auth(OSS_STS_ACCESS_KEY, OSS_STS_ACCESS_SECRET)
+        bucket_id = vodqs[0]['bucket_id']
+        vod_bucket_qs = VodBucketModel.objects.filter(id=bucket_id).values('bucket', 'endpoint')
+        if not vod_bucket_qs.exists():
+            return response.json(173)
+        bucket_name = vod_bucket_qs[0]["bucket"]
+        endpoint = vod_bucket_qs[0]["endpoint"]
         for vod in vodqs:
-            bucket_name = vod["bucket__bucket"]
-            endpoint = vod["bucket__endpoint"]
             bucket = oss2.Bucket(auth, endpoint, bucket_name)
             m3u8 = '{uid}/vod{channel}/{time}/{time}.m3u8'. \
-                format(uid=uid, channel=channel, time=vod['time'])
+                format(uid=uid, channel=channel, time=vod['start_time'])
             ts = '{uid}/vod{channel}/{time}/ts0.ts'. \
-                format(uid=uid, channel=channel, time=vod['time'])
+                format(uid=uid, channel=channel, time=vod['start_time'])
             url = bucket.sign_url('GET', m3u8, 3600, params={'x-oss-process': 'hls/sign'})
             urllst = url.split('?')
             url_start = urllib.parse.unquote(urllst[0])
@@ -880,7 +637,8 @@ class testView(View):
                 format(url_start=url_start, url_end=url_end)
             thumb = bucket.sign_url('GET', ts, 3600,
                                     params={'x-oss-process': 'video/snapshot,t_10000,m_fast,w_300'})
-            vod_play_list.append({'name': vod['time'], 'sign_url': vod_play_url, 'thumb': thumb, 'sec': vod['sec']})
+            vod_play_list.append(
+                {'name': vod['start_time'], 'sign_url': vod_play_url, 'thumb': thumb, 'sec': vod['sec']})
         return response.json(0, vod_play_list)
 
     def generate_token(self, request_dict, userID):
@@ -977,7 +735,8 @@ class testView(View):
         month = int(month)
         startTime = CommonService.str_to_timestamp('{year}-{month}'.format(year=year, month=month), '%Y-%m')
         endTime = CommonService.str_to_timestamp('{year}-{month}'.format(year=year, month=month + 1), '%Y-%m') - 1
-        qsTs = VodHlsModel.objects.filter(time__gte=startTime, time__lte=endTime).values('fg')
+        split_vod_hls_obj = SplitVodHlsObject()
+        qsTs = split_vod_hls_obj.get_vod_hls_data(time__gte=startTime, time__lte=endTime).values('fg')
         if not qsTs.exists():
             return HttpResponse('查无数据')
         sumTs = 0  # 总ts个数
@@ -1020,22 +779,25 @@ class testView(View):
         storeTime = request_dict.get('time', None)
         now_time = int(time.time())
         try:
-            vh_qs = VodHlsModel.objects.filter(uid=uid, channel=channel, time=storeTime, endTime__gte=now_time). \
-                values("sec", "fg", "bucket__bucket", "bucket__endpoint", "bucket__region", "bucket__mold")
+            split_vod_hls_obj = SplitVodHlsObject()
+            vh_qs = split_vod_hls_obj.get_vod_hls_data(uid=uid, channel=channel, start_time=storeTime,
+                                                       end_time__gte=now_time).values("sec", "fg", "bucket_id")
             if not vh_qs.exists():
                 return response.json(173)
-            fg = vh_qs[0]['fg']
-            bucket__region = vh_qs[0]['bucket__region']
-            bucket_name = vh_qs[0]['bucket__bucket']
-
+            vod_bucket_qs = VodBucketModel.objects.filter(id=vh_qs[0]['bucket_id']).values('bucket', 'region', 'mold')
+            if not vod_bucket_qs.exists():
+                return response.json(173)
+            fg = int(vh_qs[0]['fg'])
+            bucket_region = vod_bucket_qs[0]['region']
+            bucket_name = vod_bucket_qs[0]['bucket']
+            mold = vod_bucket_qs[0]['mold']
             session = Session(
-                aws_access_key_id=AWS_ACCESS_KEY_ID[vh_qs[0]["bucket__mold"]],
-                aws_secret_access_key=AWS_SECRET_ACCESS_KEY[vh_qs[0]["bucket__mold"]],
-                region_name=bucket__region
+                aws_access_key_id=AWS_ACCESS_KEY_ID[mold],
+                aws_secret_access_key=AWS_SECRET_ACCESS_KEY[mold],
+                region_name=bucket_region
             )
             conn = session.client('s3')
             playlist_entries = []
-            fg = int(fg)
             # ts_count = fg & 0xf
             # fg 64位整型,低四位代表ts文件总数,然后进行位运算,一次移四位,每四位转为十进制即为当前ts文件的秒数
             for i in range(15):
@@ -1050,7 +812,7 @@ class testView(View):
                             'Bucket': bucket_name,
                             'Key': tsFile
                         },
-                        ExpiresIn=24*60*60
+                        ExpiresIn=24 * 60 * 60
                     )
                     playlist_entries.append({
                         'name': response_url,

+ 2 - 2
Controller/UserBrandController.py

@@ -618,7 +618,7 @@ class UserBrandInfo(View):
             check_perm = ModelService.check_perm(userID=userID, permID=30)
             page_value = []
             if check_perm is True:
-                if username is None or username is '':
+                if username is None or username == '':
                     # table_Limit_value = my.get_page_line(page,line,user_brand,None,page_value)
                     # # 页面减1
                     # page = page-1
@@ -689,7 +689,7 @@ class UserBrandInfo(View):
             check_perm = ModelService.check_perm(userID=userID, permID=30)
             page_value = []
             if check_perm is True:
-                if username is None or username is '':
+                if username is None or username == '':
                     return response.json(0, {'datas': {}, 'count': 0})
                 else:
                     # 查询

+ 23 - 24
Controller/UserController.py

@@ -35,10 +35,10 @@ from django.views.decorators.csrf import csrf_exempt
 from django.views.generic import TemplateView
 from django.views.generic import View
 from jwt.algorithms import RSAAlgorithm
-from ratelimit.decorators import ratelimit
+from ratelimit import limits
 
 from Ansjer.config import AuthCode_Expire, SERVER_DOMAIN, APNS_CONFIG, JPUSH_CONFIG, FCM_CONFIG, TUTK_PUSH_DOMAIN
-from Ansjer.config import BASE_DIR, CONFIG_US, CONFIG_EUR, CONFIG_INFO, SERVER_DOMAIN_EUR, CONFIG_CN
+from Ansjer.config import BASE_DIR, CONFIG_EUR, CONFIG_INFO, SERVER_DOMAIN_EUR
 from Controller.CheckUserData import DataValid, date_handler, RandomStr
 from Model.models import Device_User, Role, UidPushModel, UserOauth2Model, UserExModel, Device_Info, UidSetModel, \
     UserAppFrequencyModel, CountryIPModel, CountryModel, UidChannelSetModel, Order_Model, UID_Bucket, Unused_Uid_Meal, \
@@ -62,7 +62,7 @@ class authCodeView(TemplateView):
         # testtest11111111111111
         return super(authCodeView, self).dispatch(*args, **kwargs)
 
-    @ratelimit(key='ip', rate='2/m')
+    @limits(calls=2, period=60)
     def post(self, request, *args, **kwargs):
         request.encoding = 'utf-8'
         lang = request.POST.get('language', None)
@@ -74,7 +74,7 @@ class authCodeView(TemplateView):
         useremail = request.POST.get('userEmail', None)
         return self.ValidationError(username, useremail, response)
 
-    # @ratelimit(key='ip', rate='2/m')
+    # @limits(calls=2, period=60)
     def get(self, request, *args, **kwargs):
         # Device_User.objects.filter(userEmail='chanjunkai@163.com').delete()
         request.encoding = 'utf-8'
@@ -320,6 +320,7 @@ class LogoutView(TemplateView):
         Device_User.objects.filter(userID=tko.userID).update(online=False)
         redisObj = RedisObject(db=3)
         redisObj.del_data(key=tko.userID)
+        Device_Info.objects.filter(userID=tko.userID).update(NotificationMode=0)
         m_code = request_dict.get('m_code', None)
         if m_code:
             userID = tko.userID
@@ -499,7 +500,7 @@ class ForgetPwdView(TemplateView):
     def dispatch(self, *args, **kwargs):
         return super(ForgetPwdView, self).dispatch(*args, **kwargs)
 
-    @ratelimit(key='ip', rate='1/m')
+    @limits(calls=2, period=60)
     def get(self, request, *args, **kwargs):
         request.encoding = 'utf-8'
         response = ResponseObject()
@@ -509,7 +510,7 @@ class ForgetPwdView(TemplateView):
         userName = request.GET.get('userName', None)
         return self.ValidationError(userName, response)
 
-    @ratelimit(key='ip', rate='1/m')
+    @limits(calls=2, period=60)
     def post(self, request):
         request.encoding = 'utf-8'
         userName = request.POST.get('userName', None)
@@ -695,7 +696,7 @@ class refreshTokenViewV3(TemplateView):
             url_list.remove(SERVER_DOMAIN_EUR)
         if CONFIG_INFO != CONFIG_EUR:
             for url in url_list:
-                requests.post(url=url+'v3/account/deleteUser', data=data, timeout=3)
+                requests.post(url=url + 'v3/account/deleteUser', data=data, timeout=3)
 
     def validation(self, request_dict):
         token = request_dict.get('token', None)
@@ -756,7 +757,7 @@ class v2authCodeView(TemplateView):
     def dispatch(self, *args, **kwargs):
         return super(v2authCodeView, self).dispatch(*args, **kwargs)
 
-    @ratelimit(key='ip', rate='2/m')
+    @limits(calls=2, period=60)
     def post(self, request, *args, **kwargs):
         request.encoding = 'utf-8'
         lang = request.POST.get('lang', None)
@@ -771,7 +772,7 @@ class v2authCodeView(TemplateView):
                 return response.json(5)
         return self.ValidationError(request_dict, response)
 
-    @ratelimit(key='ip', rate='2/m')
+    @limits(calls=2, period=60)
     def get(self, request, *args, **kwargs):
         # Device_User.objects.filter(userEmail='chanjunkai@163.com').delete()
         request.encoding = 'utf-8'
@@ -1330,7 +1331,7 @@ class v2forgetPwdCodeView(TemplateView):
     def dispatch(self, *args, **kwargs):
         return super(v2forgetPwdCodeView, self).dispatch(*args, **kwargs)
 
-    @ratelimit(key='ip', rate='1/m')
+    @limits(calls=2, period=60)
     def get(self, request, *args, **kwargs):
         request.encoding = 'utf-8'
         request_dict = request.GET
@@ -1341,7 +1342,7 @@ class v2forgetPwdCodeView(TemplateView):
             return response.json(5)
         return self.ValidationError(request_dict, response)
 
-    @ratelimit(key='ip', rate='1/m')
+    @limits(calls=2, period=60)
     def post(self, request):
         request.encoding = 'utf-8'
         request_dict = request.POST
@@ -1525,7 +1526,7 @@ class v2forgetPwdCodeView(TemplateView):
         language_qs = LanguageModel.objects.filter(lang=lang).values('id')
         if not language_qs.exists():
             language_qs = LanguageModel.objects.filter(lang='en').values('id')
-        region_qs = CountryLanguageModel.objects.filter(country_id=region_country, language_id=language_qs[0]['id']).\
+        region_qs = CountryLanguageModel.objects.filter(country_id=region_country, language_id=language_qs[0]['id']). \
             values('country_name')
         res['region'] = region_qs[0]['country_name'] if region_qs.exists() else ''
 
@@ -1840,7 +1841,7 @@ class v2LoginView(TemplateView):
     def dispatch(self, *args, **kwargs):
         return super(v2LoginView, self).dispatch(*args, **kwargs)
 
-    @ratelimit(key='ip', rate='5/m')
+    @limits(calls=2, period=60)
     def post(self, request, *args, **kwargs):
         request.encoding = 'utf-8'
         request_dict = request.POST
@@ -1851,7 +1852,6 @@ class v2LoginView(TemplateView):
             return response.json(5)
         return self.validates(request_dict, response)
 
-    # @ratelimit(key='ip', rate='5/m')
     def get(self, request, *args, **kwargs):
         print("进来了")
         request.encoding = 'utf-8'
@@ -1940,7 +1940,7 @@ class noPasslogin(TemplateView):
     def dispatch(self, *args, **kwargs):
         return super(noPasslogin, self).dispatch(*args, **kwargs)
 
-    @ratelimit(key='ip', rate='5/m')
+    @limits(calls=2, period=60)
     def post(self, request, *args, **kwargs):
         request.encoding = 'utf-8'
         request_dict = request.POST
@@ -1951,7 +1951,6 @@ class noPasslogin(TemplateView):
             return response.json(5)
         return self.validates(request_dict, response)
 
-    # @ratelimit(key='ip', rate='5/m')
     def get(self, request, *args, **kwargs):
         print("进来了")
         request.encoding = 'utf-8'
@@ -2031,7 +2030,7 @@ class v3LoginView(TemplateView):
     def dispatch(self, *args, **kwargs):
         return super(v3LoginView, self).dispatch(*args, **kwargs)
 
-    @ratelimit(key='ip', rate='5/m')
+    @limits(calls=2, period=60)
     def post(self, request, *args, **kwargs):
         request.encoding = 'utf-8'
         request_dict = request.POST
@@ -2162,13 +2161,13 @@ class v3LoginView(TemplateView):
         else:
             # 判断所选地区和用户注册地区是否一致
             number = int(number)
-            if number != region_country and region_country != 0:    # 不一致
+            if number != region_country and region_country != 0:  # 不一致
                 res['status'] = 1
                 user_qs.update(last_login=now_time, language=response.lang)
-            else:   # 一致
+            else:  # 一致
                 res['status'] = 0
                 user_qs.update(last_login=now_time, language=response.lang, region_country=number)
-        region_qs = CountryLanguageModel.objects.filter(country_id=region_country, language_id=language_qs[0]['id']).\
+        region_qs = CountryLanguageModel.objects.filter(country_id=region_country, language_id=language_qs[0]['id']). \
             values('country_name')
 
         res['rid'] = users['role__rid']
@@ -2760,7 +2759,7 @@ class OauthAuthCodeView(TemplateView):
     def dispatch(self, *args, **kwargs):
         return super(OauthAuthCodeView, self).dispatch(*args, **kwargs)
 
-    @ratelimit(key='ip', rate='2/m')
+    @limits(calls=2, period=60)
     def post(self, request, *args, **kwargs):
         request.encoding = 'utf-8'
         lang = request.POST.get('lang', None)
@@ -2775,7 +2774,7 @@ class OauthAuthCodeView(TemplateView):
                 return response.json(5)
         return self.ValidationError(request_dict, response)
 
-    @ratelimit(key='ip', rate='2/m')
+    @limits(calls=2, period=60)
     def get(self, request, *args, **kwargs):
         # Device_User.objects.filter(userEmail='chanjunkai@163.com').delete()
         request.encoding = 'utf-8'
@@ -3647,7 +3646,7 @@ class loginCodeView(View):
     def dispatch(self, *args, **kwargs):
         return super(loginCodeView, self).dispatch(*args, **kwargs)
 
-    @ratelimit(key='ip', rate='2/m')
+    @limits(calls=2, period=60)
     def post(self, request, *args, **kwargs):
         request.encoding = 'utf-8'
         lang = request.POST.get('lang', None)
@@ -3662,7 +3661,7 @@ class loginCodeView(View):
                 return response.json(5)
         return self.validate(request_dict, response)
 
-    @ratelimit(key='ip', rate='2/m')
+    @limits(calls=2, period=60)
     def get(self, request, *args, **kwargs):
         request.encoding = 'utf-8'
         lang = request.GET.get('lang', None)

+ 195 - 0
Controller/UserDevice/UserDeviceShareController.py

@@ -0,0 +1,195 @@
+# -*- encoding: utf-8 -*-
+"""
+@File    : UserDeviceShareController.py
+@Time    : 2023/1/7 15:05
+@Author  : stephen
+@Email   : zhangdongming@asj6.wecom.work
+@Software: PyCharm
+"""
+import logging
+import time
+
+from django.db import transaction
+from django.db.models import Q
+from django.views import View
+
+from Model.models import DeviceSharePermission, DeviceChannelUserSet, DeviceChannelUserPermission, UidChannelSetModel, \
+    Device_Info
+from Object.ResponseObject import ResponseObject
+from Object.TokenObject import TokenObject
+from Service.UserDeviceService import UserDeviceService
+
+LOGGER = logging.getLogger('info')
+
+
+class UserDeviceShareView(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):
+        token = TokenObject(request.META.get('HTTP_AUTHORIZATION'))
+        lang = request_dict.get('lang', token.lang)
+        response = ResponseObject(lang)
+        if token.code != 0:
+            return response.json(token.code)
+        if operation == 'user-permissions':
+            return self.get_user_share_permission(request_dict, response)
+        elif operation == 'permissions-save':
+            return self.user_channel_permission_save(request_dict, response)
+        elif operation == 'permissions-test':
+            return self.synch_share_device_permission(response)
+        else:
+            return response.json(404)
+
+    @classmethod
+    def get_user_share_permission(cls, request_dict, response):
+        """
+        获取用户分享权限
+        @param request_dict: 设备uid
+        @param response: 响应对象
+        @return: permission List
+        """
+        try:
+            uid = request_dict.get('uid', None)
+            user_id = request_dict.get('userId', None)
+            channel_count = request_dict.get('channelCount', None)
+            if not all([user_id, uid, channel_count]):
+                return response(444, 'uid, userId and channelCount is required')
+            user_permission_qs = DeviceChannelUserSet.objects.filter(user_id=user_id, uid=uid) \
+                .values('id', 'channels')
+            if not user_permission_qs.exists():
+                return response.json(0, {})
+            up_id = user_permission_qs[0]['id']
+            channel_permission_qs = DeviceChannelUserPermission.objects.filter(channel_user_id=up_id) \
+                .values('permission_id', 'channel_user_id')
+            if not channel_permission_qs.exists():
+                return response.json(0, {})
+            channel_list = list(range(1, int(channel_count) + 1))
+            share_channel_list = user_permission_qs[0]['channels'].split(',')
+            c_list = []
+            for channel in channel_list:
+                is_select = 1 if str(channel) in share_channel_list else 0
+                c_list.append({'channelIndex': channel, 'isSelect': is_select})
+            p_list = []
+            permission_qs = DeviceSharePermission.objects.all()
+            share_permission_list = [item['permission_id'] for item in channel_permission_qs]
+            for item in permission_qs:
+                is_select = 1 if item.id in share_permission_list else 0
+                p_list.append({'permissionId': item.id, 'code': item.code, 'isSelect': is_select})
+            data = {'channels': c_list, 'permissions': p_list}
+            return response.json(0, data)
+        except Exception as e:
+            LOGGER.info('异常详情,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+            return response.json(500, repr(e))
+
+    @classmethod
+    def user_channel_permission_save(cls, request_dict, response):
+        """
+        主用户分享设备时设置通道权限保存
+        """
+        try:
+            uid = request_dict.get('uid', None)
+            channels = request_dict.get('channels', None)  # 通道集合,多个','隔开
+            user_id = request_dict.get('userId', None)
+            permission_ids = request_dict.get('permissionIds', None)  # 权限集合,多个','隔开
+            if not all([user_id, uid, channels, permission_ids]):
+                return response.json(444)
+            p_ids = []
+            device_user_set = DeviceChannelUserSet.objects.filter(user_id=user_id, uid=uid)
+            now_time = int(time.time())
+            with transaction.atomic():
+                is_delete = False
+                if not device_user_set.exists():
+                    device_set = {'uid': uid, 'user_id': user_id, 'channels': channels,
+                                  'created_time': now_time, 'updated_time': now_time}
+                    device_user_set = DeviceChannelUserSet.objects.create(**device_set)
+                    channel_user_id = device_user_set.id
+                else:
+                    DeviceChannelUserSet.objects.update(channels=channels, updated_time=now_time)
+                    channel_user_id = device_user_set.first().id
+                    is_delete = True
+                if ',' in permission_ids:
+                    p_ids = [int(val) for val in permission_ids.split(',')]
+                if is_delete:
+                    DeviceChannelUserPermission.objects.filter(
+                        channel_user_id=channel_user_id).delete()
+                if not p_ids:
+                    channel_permission = {'permission_id': int(permission_ids),
+                                          'channel_user_id': channel_user_id,
+                                          'created_time': now_time}
+                    DeviceChannelUserPermission.objects.create(**channel_permission)
+                else:
+                    channel_permission_list = []
+                    for item in p_ids:
+                        channel_permission_list.append(DeviceChannelUserPermission(
+                            permission_id=int(item),
+                            channel_user_id=channel_user_id,
+                            created_time=now_time))
+                    DeviceChannelUserPermission.objects.bulk_create(channel_permission_list)
+                return response.json(0)
+        except Exception as e:
+            LOGGER.info('异常详情,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+            return response.json(500, repr(e))
+
+    @staticmethod
+    def qrcode_share_channel_permission_save(user_id, uid):
+        """
+        二维码分享保存通道权限
+        @param user_id: 用户id
+        @param uid: 用户设备ID
+        @return: True | False
+        """
+        try:
+            if not all([user_id, uid]):
+                return False
+            with transaction.atomic():
+                ds_qs = DeviceChannelUserSet.objects.filter(user_id=user_id, uid=uid)
+                if ds_qs.exists():
+                    return True
+                UserDeviceService.update_device_channel(uid)
+                channel_qs = UidChannelSetModel.objects.filter(uid__uid=uid).values('channel')
+                if not channel_qs.exists():
+                    return False
+                channel_list = [str(val['channel']) for val in channel_qs]
+                channel_str = ','.join(channel_list)
+                now_time = int(time.time())
+                device_set = {'uid': uid, 'user_id': user_id, 'channels': channel_str,
+                              'created_time': now_time, 'updated_time': now_time}
+                device_user_set = DeviceChannelUserSet.objects.create(**device_set)
+                channel_permission_qs = DeviceSharePermission.objects \
+                    .all().values('id', 'code').order_by('sort')
+                user_set_id = device_user_set.id
+                channel_permission_list = []
+                for item in channel_permission_qs:
+                    channel_permission_list.append(DeviceChannelUserPermission(
+                        permission_id=item['id'],
+                        channel_user_id=user_set_id,
+                        created_time=now_time))
+                DeviceChannelUserPermission.objects.bulk_create(channel_permission_list)
+            return True
+        except Exception as e:
+            LOGGER.info('异常详情,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+            return False
+
+    @staticmethod
+    def synch_share_device_permission(response):
+        """
+        同步分析设备权限
+        @param response: 响应结果
+        """
+        device_info_qs = Device_Info.objects \
+            .filter(~Q(Type__in=[1, 2, 3, 4, 10001]), ~Q(primaryUserID=''), isShare=1) \
+            .values('userID_id', 'UID').order_by('-data_joined')
+        if not device_info_qs.exists():
+            return response.json(0)
+        for item in device_info_qs:
+            UserDeviceShareView.qrcode_share_channel_permission_save(item['userID_id'], item['UID'])
+        return response.json(0)

+ 2 - 1
Controller/UserExController.py

@@ -21,8 +21,9 @@ from django.views.generic.base import View
 import datetime, simplejson as json
 from Ansjer.config import OSS_STS_ACCESS_SECRET, OSS_STS_ACCESS_KEY
 from Model.models import Device_Info, Role, UserExModel, Device_User
+from Object.RedisObject import RedisObject
 from Object.ResponseObject import ResponseObject
-from Object.TokenObject import TokenObject, RedisObject
+from Object.TokenObject import TokenObject
 from Service.CommonService import CommonService
 from Service.ModelService import ModelService
 class UserExView(View):

+ 1 - 1
Controller/shareUserPermission.py

@@ -80,7 +80,7 @@ class searchUserView(View):
             sqlDict = dict(zip(["datas"], [sqlList]))
             return response.json(0, sqlDict)
         else:
-            return response.json(102)
+            return response.json(104)
 
     def searchUserPCSQL(self, fieldDict, response):
         try:

+ 227 - 10
Model/models.py

@@ -2,7 +2,6 @@ from itertools import chain
 
 from django.contrib.auth.models import BaseUserManager, AbstractBaseUser
 from django.db import models
-from django.utils import six
 from django.utils import timezone
 from imagekit.models import ProcessedImageField
 from imagekit.processors import ResizeToFill
@@ -63,10 +62,6 @@ class Permissions(models.Model):
     description = models.CharField(blank=True, null=True, max_length=128, verbose_name=u'描述信息', default='')
     objects = PermissionsManager()
 
-    def __str__(self):
-        return "%s" % (
-            six.text_type(self.description))
-
     class Meta:
         ordering = ['permName']
         db_table = 'permissions'
@@ -207,8 +202,6 @@ class Device_User(AbstractBaseUser):
 
     def get_all_permission(self):
         roles = self.role.all()
-        perms = self.permission.all()
-
         permslist = []
         for role in roles:
             if role.rid == 100:
@@ -217,9 +210,6 @@ class Device_User(AbstractBaseUser):
                     permslist.append(perm.permName)
                 return permslist
 
-        for perm in perms:
-            permslist.append(perm.permName)
-
         permSet = set(permslist)
         for role in roles:
             permlist_tmp = []
@@ -847,6 +837,15 @@ class Equipment_Version(models.Model):
         db_table = 'equipment_version'
 
 
+class AVSSVersion(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name='主键')
+    online_version = models.CharField(default='', max_length=32, verbose_name='线上版本')
+
+    class Meta:
+        verbose_name = 'AVSS版本'
+        db_table = 'avss_version'
+
+
 class App_Info(models.Model):
     id = models.AutoField(primary_key=True, verbose_name=u'自增标记ID')
     appBundleId = models.CharField(blank=True, max_length=32, verbose_name=u'appID')
@@ -1073,6 +1072,139 @@ class VodHlsModel(models.Model):
         ordering = ('-id',)
 
 
+class VodHlsMon(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name='主键')
+    uid = models.CharField(max_length=20, db_index=True, verbose_name='uid')
+    channel = models.SmallIntegerField(default=0, verbose_name='通道')
+    start_time = models.IntegerField(default=0, db_index=True, verbose_name='开始时间')
+    end_time = models.IntegerField(default=0, db_index=True, verbose_name='结束时间')
+    sec = models.IntegerField(default=0, verbose_name='秒数')
+    bucket_id = models.SmallIntegerField(default=1, blank=True, verbose_name='关联vod_bucket表id')
+    fg = models.CharField(max_length=20, verbose_name='ts文件信息数据')
+
+    def __str__(self):
+        return self.id
+
+    class Meta:
+        db_table = 'vod_hls_mon'
+        verbose_name = '星期一云存回放信息表'
+        ordering = ('-id',)
+
+
+class VodHlsTues(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name='主键')
+    uid = models.CharField(max_length=20, db_index=True, verbose_name='uid')
+    channel = models.SmallIntegerField(default=0, verbose_name='通道')
+    start_time = models.IntegerField(default=0, db_index=True, verbose_name='开始时间')
+    end_time = models.IntegerField(default=0, db_index=True, verbose_name='结束时间')
+    sec = models.IntegerField(default=0, verbose_name='秒数')
+    bucket_id = models.SmallIntegerField(default=1, blank=True, verbose_name='关联vod_bucket表id')
+    fg = models.CharField(max_length=20, verbose_name='ts文件信息数据')
+
+    def __str__(self):
+        return self.id
+
+    class Meta:
+        db_table = 'vod_hls_tues'
+        verbose_name = '星期二云存回放信息表'
+        ordering = ('-id',)
+
+
+class VodHlsWed(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name='主键')
+    uid = models.CharField(max_length=20, db_index=True, verbose_name='uid')
+    channel = models.SmallIntegerField(default=0, verbose_name='通道')
+    start_time = models.IntegerField(default=0, db_index=True, verbose_name='开始时间')
+    end_time = models.IntegerField(default=0, db_index=True, verbose_name='结束时间')
+    sec = models.IntegerField(default=0, verbose_name='秒数')
+    bucket_id = models.SmallIntegerField(default=1, blank=True, verbose_name='关联vod_bucket表id')
+    fg = models.CharField(max_length=20, verbose_name='ts文件信息数据')
+
+    def __str__(self):
+        return self.id
+
+    class Meta:
+        db_table = 'vod_hls_wed'
+        verbose_name = '星期三云存回放信息表'
+        ordering = ('-id',)
+
+
+class VodHlsThur(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name='主键')
+    uid = models.CharField(max_length=20, db_index=True, verbose_name='uid')
+    channel = models.SmallIntegerField(default=0, verbose_name='通道')
+    start_time = models.IntegerField(default=0, db_index=True, verbose_name='开始时间')
+    end_time = models.IntegerField(default=0, db_index=True, verbose_name='结束时间')
+    sec = models.IntegerField(default=0, verbose_name='秒数')
+    bucket_id = models.SmallIntegerField(default=1, blank=True, verbose_name='关联vod_bucket表id')
+    fg = models.CharField(max_length=20, verbose_name='ts文件信息数据')
+
+    def __str__(self):
+        return self.id
+
+    class Meta:
+        db_table = 'vod_hls_thur'
+        verbose_name = '星期四云存回放信息表'
+        ordering = ('-id',)
+
+
+class VodHlsFri(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name='主键')
+    uid = models.CharField(max_length=20, db_index=True, verbose_name='uid')
+    channel = models.SmallIntegerField(default=0, verbose_name='通道')
+    start_time = models.IntegerField(default=0, db_index=True, verbose_name='开始时间')
+    end_time = models.IntegerField(default=0, db_index=True, verbose_name='结束时间')
+    sec = models.IntegerField(default=0, verbose_name='秒数')
+    bucket_id = models.SmallIntegerField(default=1, blank=True, verbose_name='关联vod_bucket表id')
+    fg = models.CharField(max_length=20, verbose_name='ts文件信息数据')
+
+    def __str__(self):
+        return self.id
+
+    class Meta:
+        db_table = 'vod_hls_fri'
+        verbose_name = '星期五云存回放信息表'
+        ordering = ('-id',)
+
+
+class VodHlsSat(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name='主键')
+    uid = models.CharField(max_length=20, db_index=True, verbose_name='uid')
+    channel = models.SmallIntegerField(default=0, verbose_name='通道')
+    start_time = models.IntegerField(default=0, db_index=True, verbose_name='开始时间')
+    end_time = models.IntegerField(default=0, db_index=True, verbose_name='结束时间')
+    sec = models.IntegerField(default=0, verbose_name='秒数')
+    bucket_id = models.SmallIntegerField(default=1, blank=True, verbose_name='关联vod_bucket表id')
+    fg = models.CharField(max_length=20, verbose_name='ts文件信息数据')
+
+    def __str__(self):
+        return self.id
+
+    class Meta:
+        db_table = 'vod_hls_sat'
+        verbose_name = '星期六云存回放信息表'
+        ordering = ('-id',)
+
+
+class VodHlsSun(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name='主键')
+    uid = models.CharField(max_length=20, db_index=True, verbose_name='uid')
+    channel = models.SmallIntegerField(default=0, verbose_name='通道')
+    start_time = models.IntegerField(default=0, db_index=True, verbose_name='开始时间')
+    end_time = models.IntegerField(default=0, db_index=True, verbose_name='结束时间')
+    sec = models.IntegerField(default=0, verbose_name='秒数')
+    bucket_id = models.SmallIntegerField(default=1, blank=True, verbose_name='关联vod_bucket表id')
+    fg = models.CharField(max_length=20, verbose_name='ts文件信息数据')
+
+    def __str__(self):
+        return self.id
+
+    class Meta:
+        db_table = 'vod_hls_sun'
+        verbose_name = '星期天云存回放信息表'
+        ordering = ('-id',)
+
+
 class OssCrdModel(models.Model):
     id = models.AutoField(primary_key=True, verbose_name='主键')
     uid = models.CharField(max_length=20, verbose_name='设备UID')
@@ -3116,3 +3248,88 @@ class UidCloudStorageCount(models.Model):
         db_table = 'uid_cloud_storage_count'
         verbose_name = '云存储uid日上传次数统计'
         verbose_name_plural = verbose_name
+
+
+class DeviceChannelUserSet(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name='自增id')
+    uid = models.CharField(blank=True, db_index=True, max_length=32, verbose_name=u'设备UID')
+    channels = models.CharField(default='', blank=True, max_length=128, verbose_name=u'用户通道多个逗号隔开')
+    user_id = models.CharField(default='', db_index=True, max_length=32, verbose_name=u'用户id')
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+    updated_time = models.IntegerField(default=0, verbose_name='更新时间')
+
+    class Meta:
+        db_table = 'device_channel_user_set'
+        verbose_name = '设备通道用户设置'
+        verbose_name_plural = verbose_name
+
+
+class DeviceSharePermission(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name='自增id')
+    code = models.CharField(blank=True, db_index=True, max_length=32, verbose_name=u'权限编码')
+    sort = models.IntegerField(default=99, blank=True, verbose_name=u'排序,越小越靠前')
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+    updated_time = models.IntegerField(default=0, verbose_name='更新时间')
+
+    class Meta:
+        db_table = 'device_share_permission'
+        verbose_name = '设备分享权限'
+        verbose_name_plural = verbose_name
+
+
+class DevicePermissionLang(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name='自增id')
+    permission_id = models.IntegerField(default=0, verbose_name=u'关联设备权限ID')
+    name = models.CharField(default='', max_length=50, verbose_name=u'权限名称')
+    desc = models.CharField(blank=True, max_length=64, default='', verbose_name=u'描述')
+    lang = models.CharField(default='', max_length=20, db_index=True, verbose_name='例如:cn')
+    sort = models.IntegerField(default=99, blank=True, verbose_name=u'排序,越小越靠前')
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+    updated_time = models.IntegerField(default=0, verbose_name='更新时间')
+
+    class Meta:
+        db_table = 'device_permission_lang'
+        verbose_name = '设备分享权限语言描述'
+        verbose_name_plural = verbose_name
+
+
+class DeviceChannelUserPermission(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name='自增id')
+    permission_id = models.IntegerField(default=0, verbose_name=u'关联设备权限ID')
+    channel_user_id = models.IntegerField(default=0, verbose_name=u'通道用户id')
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+
+    class Meta:
+        db_table = 'device_channel_user_permission'
+        verbose_name = '设备分享权限关联通道用户'
+        verbose_name_plural = verbose_name
+
+
+class DeviceTypeSharePermission(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name='自增id')
+    permission_id = models.IntegerField(default=0, verbose_name=u'关联设备权限ID')
+    type = models.SmallIntegerField(default=0, verbose_name='设备类型')
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+
+    class Meta:
+        db_table = 'device_type_share_permission'
+        verbose_name = '设备类型关联分享权限'
+        verbose_name_plural = verbose_name
+
+
+class DeviceSuperPassword(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name='自增id')
+    uid = models.CharField(blank=True, db_index=True, max_length=32, verbose_name=u'设备UID')
+    userID = models.ForeignKey(Device_User, blank=True, to_field='userID', on_delete=models.CASCADE)
+    orderID = models.CharField(max_length=30, db_index=True, verbose_name='订单ID', blank=True, default='')
+    describe = models.CharField(max_length=128, blank=True, verbose_name='需求描述', default=0)
+    purchase_channel = models.CharField(max_length=128, blank=True, verbose_name='购买渠道描述', default='')
+    addTime = models.IntegerField(default=0, verbose_name='添加时间')
+    status = models.SmallIntegerField(default=0, verbose_name='0:未通过,1:通过')
+    buyTime = models.IntegerField(default=0, verbose_name='购买时间')
+    hint = models.CharField(max_length=128, blank=True, verbose_name='温馨提示', default='')
+
+    class Meta:
+        db_table = 'device_super_password'
+        verbose_name = '超级密码请求表'
+        verbose_name_plural = verbose_name

+ 34 - 0
Object/AWS/AmazonKVSUtil.py

@@ -0,0 +1,34 @@
+# -*- coding: utf-8 -*-
+"""
+@Author : Rocky
+@Time : 2022/10/17 16:57
+@File :AmazonKVSUtil.py
+"""
+import boto3
+
+
+class AmazonKVSObject:
+    def __init__(self, aws_access_key_id, secret_access_key, region_name):
+        self.access_id = aws_access_key_id
+        self.access_secret = secret_access_key
+        self.region_name = region_name
+        self.client_conn = boto3.client(
+            'kinesis-video-media',
+            aws_access_key_id=aws_access_key_id,
+            aws_secret_access_key=secret_access_key,
+            region_name=region_name
+        )
+
+    def get_media(self, stream_name):
+        """
+        获取视频流数据保留时间
+        @param stream_name: 视频流名称
+        @param shard_count: 碎片数量
+        @return : boolean
+        """
+        try:
+            self.client_conn.get_media(StreamName=stream_name)
+            return True
+        except Exception as e:
+            print(e)
+            return False

+ 187 - 0
Object/AWS/AmazonKinesisVideoUtil.py

@@ -0,0 +1,187 @@
+# -*- coding: utf-8 -*-
+"""
+@Author : Rocky
+@Time : 2022/10/18 17:13
+@File :AmazonKinesisVideoUtil.py
+"""
+import datetime
+
+import boto3
+
+
+class AmazonKinesisVideoObject:
+    """
+    Amazon Kinesis Video Streams对象
+    api文档链接: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/kinesisvideo.html
+    """
+
+    def __init__(self, aws_access_key_id, secret_access_key, region_name):
+        self.access_id = aws_access_key_id
+        self.access_secret = secret_access_key
+        self.region_name = region_name
+        self.client_conn = boto3.client(
+            'kinesisvideo',
+            aws_access_key_id=aws_access_key_id,
+            aws_secret_access_key=secret_access_key,
+            region_name=region_name
+        )
+
+    def create_stream(self, stream_name):
+        """
+        创建视频流
+        @param stream_name: 视频流名称
+        @return : stream_arn or False
+        """
+        tags = {'project_kvs': 'kvs'}
+        try:
+            stream_arn = self.client_conn.create_stream(StreamName=stream_name, Tags=tags)['StreamARN']
+            return stream_arn
+        except Exception as e:
+            print(e)
+            return False
+
+    def update_data_retention(self, stream_name, operation, data_retention_change_in_hours):
+        """
+        修改视频流数据保留时间
+        @param stream_name: 视频流名称
+        @param operation: 增加/减少, 'INCREASE_DATA_RETENTION'|'DECREASE_DATA_RETENTION'
+        @param data_retention_change_in_hours: 修改的时间
+        @return : True or False
+        """
+        try:
+            version = self.describe_stream(stream_name)['Version']
+            self.client_conn.update_data_retention(StreamName=stream_name, Operation=operation, CurrentVersion=version,
+                                                   DataRetentionChangeInHours=data_retention_change_in_hours)
+            return True
+        except Exception as e:
+            print(e)
+            return False
+
+    def describe_stream(self, stream_name):
+        """
+        获取视频流信息数据
+        @param stream_name: 视频流名称
+        @return stream_info: 视频流信息数据
+        """
+        return self.client_conn.describe_stream(StreamName=stream_name)['StreamInfo']
+
+    def get_data_endpoint(self, stream_name, api_name):
+        """
+        获取指定流的终端节点以读取或写入
+        @param api_name: API名称
+        @param stream_name: 视频流名称
+        @return stream_info: 视频流信息数据
+        """
+        return self.client_conn.get_data_endpoint(StreamName=stream_name, APIName=api_name)['DataEndpoint']
+
+
+class AmazonKVAMObject:
+    def __init__(self, aws_access_key_id, secret_access_key, region_name, stream_name, api_name):
+        self.access_id = aws_access_key_id
+        self.access_secret = secret_access_key
+        self.region_name = region_name
+        self.kv_client_conn = AmazonKinesisVideoObject(aws_access_key_id, secret_access_key, region_name)
+        self.endpoint = self.kv_client_conn.get_data_endpoint(stream_name, api_name)
+        self.kvam_client_coon = boto3.client(
+            'kinesis-video-archived-media',
+            endpoint_url=self.endpoint,
+            aws_access_key_id=aws_access_key_id,
+            aws_secret_access_key=secret_access_key,
+            region_name=region_name
+        )
+
+    def get_hls_streaming_session_url(self, stream_name, start_time, end_time, play_mode):
+        """
+        获取视频流数据保留时间
+        @param stream_name: 视频流名称
+        @param start_time: 开始时间
+        @param end_time: 结束时间
+        @param play_mode: 播放模式
+        @return HLSStreamingSessionURL: 媒体播放器可用于检索HLS主播放列表的URL
+        """
+        return self.kvam_client_coon.get_hls_streaming_session_url(StreamName=stream_name,
+                                                                   PlaybackMode=play_mode,
+                                                                   HLSFragmentSelector={
+                                                                       'FragmentSelectorType': 'PRODUCER_TIMESTAMP',
+                                                                       'TimestampRange': {
+                                                                           'StartTimestamp': start_time,
+                                                                           'EndTimestamp': end_time
+                                                                       }
+                                                                   },
+                                                                   ContainerFormat='FRAGMENTED_MP4',
+                                                                   DiscontinuityMode='ON_DISCONTINUITY',
+                                                                   DisplayFragmentTimestamp='ALWAYS',
+                                                                   Expires=43200,
+                                                                   MaxMediaPlaylistFragmentResults=5000)[
+            'HLSStreamingSessionURL']
+
+    def get_list_fragments(self, stream_name, start_time, end_time):
+        """
+        获取视频流片段
+        @param stream_name: 视频流名称
+        @param start_time: 开始时间
+        @param end_time: 结束时间
+        @return HLSStreamingSessionURL: 视频流片段列表信息
+        """
+        stream_list = []
+        result = self.kvam_client_coon.list_fragments(StreamName=stream_name, FragmentSelector={
+            'FragmentSelectorType': 'PRODUCER_TIMESTAMP',
+            'TimestampRange': {
+                'StartTimestamp': start_time,
+                'EndTimestamp': end_time
+            }}, MaxResults=1000)
+        fragments_list = result['Fragments']
+        while 'NextToken' in result:
+            result = self.kvam_client_coon.list_fragments(StreamName=stream_name, NextToken=result['NextToken'])
+            fragments_list.extend(result['Fragments'])
+        fragments_list = sorted(fragments_list, key=lambda item: item['FragmentNumber'])
+        for item in fragments_list:
+            stream_list.append({'startTime': item['ProducerTimestamp'],
+                                'endTime': item['ProducerTimestamp'] + datetime.timedelta(
+                                    milliseconds=item['FragmentLengthInMilliseconds']),
+                                'duration': item['FragmentLengthInMilliseconds']})
+        return stream_list
+
+    def get_images(self, stream_name, start_time, end_time):
+        """
+        获取视频流片段封面图片
+        @param stream_name: 视频流名称
+        @param start_time: 开始时间
+        @param end_time: 结束时间
+        @return HLSStreamingSessionURL: 视频流片段列表信息
+        """
+        try:
+            images_list = self.kvam_client_coon.get_images(StreamName=stream_name,
+                                                           ImageSelectorType='PRODUCER_TIMESTAMP',
+                                                           StartTimestamp=start_time,
+                                                           EndTimestamp=end_time,
+                                                           SamplingInterval=3000,
+                                                           MaxResults=100,
+                                                           Format='JPEG')['Images']
+            for image in images_list:
+                if 'ImageContent' in image:
+                    return image['ImageContent']
+        except Exception as e:
+            return ''
+
+    def get_clip(self, stream_name, start_time, end_time):
+        """
+        获取视频流片段封面图片
+        @param stream_name: 视频流名称
+        @param start_time: 开始时间
+        @param end_time: 结束时间
+        @return HLSStreamingSessionURL: 视频流片段列表信息
+        """
+        try:
+            clip = self.kvam_client_coon.get_clip(StreamName=stream_name,
+                                                  ClipFragmentSelector={
+                                                      'FragmentSelectorType': 'PRODUCER_TIMESTAMP',
+                                                      'TimestampRange': {
+                                                          'StartTimestamp': start_time,
+                                                          'EndTimestamp': end_time
+                                                      }
+                                                  })
+
+            return clip['Payload'], clip['ResponseMetadata']['HTTPHeaders']['content-length']
+        except Exception as e:
+            return ''

+ 15 - 2
Object/AWS/AmazonS3Util.py

@@ -72,8 +72,7 @@ class AmazonS3Util:
             Params={
                 'Bucket': bucket,
                 'Key': file_key
-            },
-            ExpiresIn=3600
+            }
         )
         return response_url
 
@@ -124,6 +123,20 @@ class AmazonS3Util:
         except self.client_conn.exceptions.NoSuchKey:
             return False
 
+    def download_object(self, bucket, key, file_name):
+        """
+        下载对象至本地
+        @param file_name: 保存位置以及名称
+        @param bucket: 存储桶
+        @param key: 文件
+        @return : boolean
+        """
+        try:
+            self.client_conn.download_file(bucket, key, file_name)
+            return True
+        except Exception as e:
+            return e.args
+
     def copy_obj(self, source_bucket, to_bucket, file_key):
         """
         复制对象

+ 8 - 0
Object/RedisObject.py

@@ -98,3 +98,11 @@ class RedisObject:
             return keys
         else:
             return False
+
+    def set_ex_data(self, key, val, expire=0):
+        try:
+            self.CONN.setex(name=key, time=expire, value=val)
+        except Exception as e:
+            return False
+        else:
+            return True

+ 15 - 38
Object/TokenObject.py

@@ -1,20 +1,7 @@
-#!/usr/bin/env python3  
-# -*- coding: utf-8 -*-  
-"""
-@Copyright (C) ansjer cop Video Technology Co.,Ltd.All rights reserved.
-@AUTHOR: ASJRD018
-@NAME: AnsjerOA
-@software: PyCharm
-@DATE: 2018/8/13 15:36
-@Version: python3.6
-@MODIFY DECORD:ansjer dev
-@file: TokenObject.py
-@Contact: chanjunkai@163.com
-"""
+import jwt
+import time
 from Ansjer.config import OAUTH_ACCESS_TOKEN_SECRET, OAUTH_REFRESH_TOKEN_SECRET, OAUTH_ACCESS_TOKEN_TIME, \
     OAUTH_REFRESH_TOKEN_TIME
-import jwt, time
-from Object.RedisObject import RedisObject
 
 
 class TokenObject:
@@ -29,7 +16,6 @@ class TokenObject:
         self.userID = None
         self.user = ''
         self.code = 0
-        # 令牌校验
         self.valid()
         self.returntpye = returntpye
 
@@ -38,10 +24,9 @@ class TokenObject:
             self.code = 309
             return
         try:
-            self.token= self.token.replace("Bearer ", "")
+            self.token = self.token.replace("Bearer ", "")
 
             res = jwt.decode(self.token, OAUTH_ACCESS_TOKEN_SECRET, algorithms='HS256')
-            # print(res)
             self.userID = res.get('userID', None)
             self.lang = res.get('lang', None)
             self.user = res.get('user', '')
@@ -52,8 +37,6 @@ class TokenObject:
             #     redisObj.set_data(key=self.userID, val=self.user, expire=300)
 
         except jwt.ExpiredSignatureError as e:
-            print('过期')
-            print(repr(e))
             self.code = 309
             return
         except Exception as e:
@@ -70,8 +53,10 @@ class TokenObject:
                 else:
                     self.code = 309
                     return
-    # token加密
-    def generate(self, data={}):
+
+    def generate(self, data=None):
+        if data is None:
+            data = {}
         try:
             access_expire = int(OAUTH_ACCESS_TOKEN_TIME.total_seconds())
             refresh_expire = int(OAUTH_REFRESH_TOKEN_TIME.total_seconds())
@@ -89,18 +74,18 @@ class TokenObject:
                 algorithm='HS256')
 
             res = {
-                'access_token': access_token.decode('utf-8'),
+                'access_token': access_token,
                 'access_expire': access_expire,
                 'refresh_expire': refresh_expire,
-                'refresh_token': refresh_token.decode('utf-8'),
+                'refresh_token': refresh_token,
             }
 
             if self.returntpye=='pc':
                 res = {
-                    'token': access_token.decode('utf-8'),
+                    'token': access_token,
                     'access_expire': access_expire,
                     'refresh_expire': refresh_expire,
-                    'refresh_token': refresh_token.decode('utf-8'),
+                    'refresh_token': refresh_token,
                 }
 
         except Exception as e:
@@ -110,7 +95,9 @@ class TokenObject:
             self.code = 0
             return res
 
-    def encryption(self, data={}):
+    def encryption(self, data=None):
+        if data is None:
+            data = {}
         try:
             access_expire = int(OAUTH_ACCESS_TOKEN_TIME.total_seconds())
             refresh_expire = int(OAUTH_REFRESH_TOKEN_TIME.total_seconds())
@@ -122,13 +109,10 @@ class TokenObject:
             access_token = jwt.encode(access_data,
                                       OAUTH_ACCESS_TOKEN_SECRET,
                                       algorithm='HS256')
-            return access_token.decode('utf-8')
+            return access_token
         except Exception as e:
             self.code = 309
             print(repr(e))
-        else:
-            self.code = 0
-            return res
 
     def refresh(self):
         if not self.token:
@@ -152,10 +136,3 @@ class TokenObject:
             self.user = user
             refreshRes = self.generate(data={'userID': userID, 'lang': lang, 'user': user})
             return refreshRes
-
-# import jwt
-#
-#
-# token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySUQiOiIxNTMzODg0NDE4NTE5MTM4MDAxMzgwMDAiLCJleHAiOjE1NTU1NTEwNjUsInVzZXIiOiIxMTFAcXEuY29tIiwibGFuZyI6ImVuIn0.waPlfIBucSA7rFfnsxOKIVJ_cL6xiP33cAiz1IDoteY'
-# res = jwt.decode(token, 'a+jbgnw%@1%zy^=@dn62%', algorithms='HS256')
-# print(res)

+ 6 - 27
Object/UidTokenObject.py

@@ -1,19 +1,5 @@
-#!/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 11:52
-@Version: python3.6
-@MODIFY DECORD:ansjer dev
-@file: UidTokenObject.py
-@Contact: chanjunkai@163.com
-"""
-from Ansjer.config import UID_TOKEN_KEY
 import jwt
-# UID_TOKEN_KEY = 'c+565*j@%^'
+from Ansjer.config import UID_TOKEN_KEY
 
 
 class UidTokenObject:
@@ -43,16 +29,9 @@ class UidTokenObject:
         except Exception as e:
             print(repr(e))
 
-    def generate(self, data={}):
-        token = jwt.encode(data, UID_TOKEN_KEY, algorithm='HS256').decode('utf-8')
-        self.token= token
+    def generate(self, data=None):
+        if data is None:
+            data = {}
+        token = jwt.encode(data, UID_TOKEN_KEY, algorithm='HS256')
+        self.token = token
         return token
-# uidToken = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1aWQiOiJNVUo4ODdOTFI4SzhHQk05MTExQSJ9.NHYNwmcRLCRBv2FUMA-FlM1Gtx4ir8rrwfoz7QQ67bM'
-# utko = UidTokenObject(uidToken)
-#
-# utko = UidTokenObject()
-# rr = utko.generate(data={'uid':'JW3684H8BSHG9TTM111A','channel':1})
-# print(rr)
-
-# print(utko)
-

+ 1 - 1
Object/UrlTokenObject.py

@@ -52,6 +52,6 @@ class UrlTokenObject:
         # print (now_stamp)
         # 过期时间为两天
         data['exp'] = 172800 + now_stamp
-        token = jwt.encode(data, '12345', algorithm='HS256').decode('utf-8')
+        token = jwt.encode(data, '12345', algorithm='HS256')
         self.token = token
         return token

+ 0 - 58
README.md

@@ -1,58 +0,0 @@
-### 软件版本:V2.0.0.2020-2-10
-    1,自主推送方案 移动侦测,图片推送
-    2,alexa oauth2 rtsp
-### 软件版本:V1.5.0.2019-2-12
-    1,云存功能第二版测试完成,功能完善,bug修正,使用公司提供账号
-    2,新版本ota功能(主要未dvr)
-### 软件版本:V1.4.0.2018-12-12
-	1,云存基础架构(完成)
-	2,付款(完成)
-	3,签名(完成)
-	4,云存视频流存储设计并实现(完成)
-    5,多语言OTA功能
-
-### 软件版本:V1.1.1.2018-9-12
-	1,令牌加密方案使用jwt
-	2,重写response类,redis类
-	3,无用预定义变量,加快交互速度
-
-### 软件版本:V1.0.3.2018-7-23
-    1.增加报警推送信息
-    2.增加设备操作日志
-    3.设备昵称支持emoji
-    4.支持多设备多终端进行登录
-    5.更改邮件发送为亚马逊aws
-    6.修改邮件模板,发件人
-    7.设备第一次添加为绑定人(其他人只能通过解绑,或者分享,或者通过密码添加获得,暂时未更新到正式)
-    8.增加操作文档
-    9.增加p2p定时发送邮件脚本
-### 软件版本:V1.0.1.2018-5-15  
-    1.用户管理下的反馈问题界面(分页,显示,编辑,删除),排序功能(反馈时间排序,状态排序,更新时间排序)     
-	2.版本管理下的APP界面(分页,显示,编辑,删除,添加,重置) 
-	3.帮助管理下的访问日志界面(分页,显示),搜索功能(用户名搜索,ip地址搜索,访问状态搜索,访问路径搜索,访问参数搜索)排序功能(时间排序) 
-	4.用户管理下的用户信息(显示,分页),要求用安卓APP与IOS测试注册的功能。注意:(尽量进行极限测试,比如国外手机是否有非11位的,邮箱长度是否有50位以上的) 
-	管理员账号: 
-	1.用户管理下的反馈问题界面(分页,显示),排序功能(反馈时间排序,状态排序,更新时间排序) 
-	2.版本管理下的APP界面(分页,显示)  
-	3.帮助管理下的访问日志界面(分页,显示),搜索功能(用户名搜索,ip地址搜索,访问状态搜索,访问路径搜索,访问参数搜索)  排序功能(时间排序) 
-	版本上传管理员: 
-	1.没有该功能 
-### 软件版本:V1.0.0.2018-4-23
-	1.登录功能,权限,角色添加,权限控制功能          
-	2.用户列表添加,删除,编辑(是否激活),显示功能,分页功能 
-	3.设备列表搜索(设备名称搜索),显示,传感器功能(修改,删除,显示的操作)         
-	4.版本列表上传版本,添加版本的信息,显示功能 
-	5.帮助管理的更新日志显示,数据统计显示,分页功能        
-	6.导航栏的全屏,修改密码,退出登录功能,显示账户资料,编辑用户的邮箱,昵称,是否在线      
-	管理员账号:         
-	1.登录功能          
-	2.用户列表显示功能        
-	3.设备列表搜索(设备名称搜索),显示功能,分页功能          
-	4.版本列表上传版本显示功能  
-	5.帮助管理的更新日志显示,数据统计显示,分页功能         
-	6.导航栏的全屏,显示账户资料,编辑用户的邮箱,昵称,是否在线,修改密码,退出登录功能 
-	版本上传管理员: 
-	1.登录功能   
-	2.版本列表上传版本,添加版本信息功能  
-	3.帮助管理的更新日志显示,数据统计显示,分页功能 
-	4.导航栏的全屏,修改密码,退出登录功能,显示账户资料,编辑用户的邮箱,昵称,是否在线

+ 0 - 0
SerialModel/__init__.py


+ 0 - 3
SerialModel/admin.py

@@ -1,3 +0,0 @@
-from django.contrib import admin
-
-# Register your models here.

+ 0 - 5
SerialModel/apps.py

@@ -1,5 +0,0 @@
-from django.apps import AppConfig
-
-
-class SerialmodelConfig(AppConfig):
-    name = 'SerialModel'

+ 0 - 0
SerialModel/migrations/__init__.py


+ 0 - 3
SerialModel/models.py

@@ -1,3 +0,0 @@
-from django.db import models
-
-# Create your models here.

+ 0 - 3
SerialModel/tests.py

@@ -1,3 +0,0 @@
-from django.test import TestCase
-
-# Create your tests here.

+ 0 - 3
SerialModel/views.py

@@ -1,3 +0,0 @@
-from django.shortcuts import render
-
-# Create your views here.

+ 37 - 90
Service/CommonService.py

@@ -1,17 +1,15 @@
-# -*- coding: utf-8 -*-
-# 高复用性函数封装到CommonService类
 import base64
 import datetime
+import ipdb
 import time
 from base64 import encodebytes
 from pathlib import Path
 from random import Random
-from dateutil.relativedelta import relativedelta
 
 import OpenSSL.crypto as ct
-import ipdb
 import requests
 import simplejson as json
+from dateutil.relativedelta import relativedelta
 from django.core import serializers
 from django.utils import timezone
 from pyipip import IPIPDatabase
@@ -19,15 +17,17 @@ from pyipip import IPIPDatabase
 from Ansjer.config import BASE_DIR, SERVER_DOMAIN_SSL, CONFIG_INFO, CONFIG_TEST, CONFIG_CN, SERVER_DOMAIN_TEST, \
     SERVER_DOMAIN_CN, SERVER_DOMAIN_US, CONFIG_US, CONFIG_EUR, SERVER_DOMAIN_LIST, SERVER_DOMAIN_EUR
 from Controller.CheckUserData import RandomStr
-from Model.models import iotdeviceInfoModel, Device_Info, CountryModel, RegionModel, UIDModel
+from Model.models import iotdeviceInfoModel, Device_Info, UIDModel
 from Object.ResponseObject import ResponseObject
 from Object.TokenObject import TokenObject
 
 
 class CommonService:
-    # 添加模糊搜索
+    # 高复用性函数类
+
     @staticmethod
     def get_kwargs(data=None):
+        # 添加模糊搜索
         if data is None:
             data = {}
         kwargs = {}
@@ -36,10 +36,9 @@ class CommonService:
                 kwargs[k + '__icontains'] = v
         return kwargs
 
-    # 定义静态方法
-    # 格式化query_set转dict
     @staticmethod
     def qs_to_dict(query_set):
+        # 格式化query_set转dict
         sqlJSON = serializers.serialize('json', query_set)
         sqlList = json.loads(sqlJSON)
         sqlDict = dict(zip(["datas"], [sqlList]))
@@ -265,43 +264,37 @@ class CommonService:
         return str
 
     @staticmethod
-    def decode_data(content, start=1, end=4):
+    def encode_data(content, start=1, end=4):
+        """
+        数据加密
+        @param content: 数据内容
+        @param start: 起始长度
+        @param end: 结束长度
+        @return content: 加密的数据
+        """
         if not content:
             return ''
-        try:
-            for i in range(start, end):
-                if i == 1:
-                    content = base64.b64decode(content)
-                    content = content.decode('utf-8')
-                    content = content[1:-1]
-                if i == 2:
-                    content = base64.b64decode(content)
-                    content = content.decode('utf-8')
-                    content = content[2:-2]
-                if i == 3:
-                    content = base64.b64decode(content)
-                    content = content.decode('utf-8')
-                    content = content[3:-3]
-
-            return content
-        except Exception as e:
-            print(e)
-            return None
+        for i in range(start, end):
+            length = end - i
+            content = RandomStr(length, False) + content + RandomStr(length, False)
+            content = base64.b64encode(str(content).encode('utf-8')).decode('utf8')
+        return content
 
     @staticmethod
-    def encode_data(content, start=1, end=4):
+    def decode_data(content, start=1, end=4):
+        """
+        数据解密
+        @param content: 数据内容
+        @param start: 起始长度
+        @param end: 结束长度
+        @return content: 解密的数据
+        """
         if not content:
             return ''
         for i in range(start, end):
-            if i == 1:
-                content = RandomStr(3, False) + content + RandomStr(3, False)
-                content = base64.b64encode(str(content).encode("utf-8")).decode('utf8')
-            if i == 2:
-                content = RandomStr(2, False) + str(content) + RandomStr(2, False)
-                content = base64.b64encode(str(content).encode("utf-8")).decode('utf8')
-            if i == 3:
-                content = RandomStr(1, False) + str(content) + RandomStr(1, False)
-                content = base64.b64encode(str(content).encode("utf-8")).decode('utf8')
+            content = base64.b64decode(content)
+            content = content.decode('utf-8')
+            content = content[i:-i]
         return content
 
     # 把格式化时间转换成时间戳
@@ -347,6 +340,7 @@ class CommonService:
             else:
                 now_month += 1
 
+        timestamps = 0
         for is_format in range(4):
             try:
                 date_format = '{now_year}-{now_month}-{now_day} {now_hour}:{now_min}:{now_second}' \
@@ -369,11 +363,6 @@ class CommonService:
         second = int(macArray[4], 16)
         three = int(macArray[3], 16)
 
-        # print(macArray)
-        # print(first)
-        # print(second)
-        # print(three)
-
         if first == 255 and second == 255 and three == 255:
             return None
 
@@ -390,53 +379,10 @@ class CommonService:
         macArray[3] = three
         macArray[4] = second
         macArray[5] = first
-        # print(macArray)
 
         tmp = ':'.join(map(lambda x: "%02x" % x, macArray))
-        # print(tmp)
         return tmp.upper()
 
-    @staticmethod
-    def decode_data(content, start=1, end=4):
-        if not content:
-            return ''
-        try:
-            for i in range(start, end):
-                if i == 1:
-                    content = base64.b64decode(content)
-                    content = content.decode('utf-8')
-                    content = content[1:-1]
-                if i == 2:
-                    content = base64.b64decode(content)
-                    content = content.decode('utf-8')
-                    content = content[2:-2]
-                if i == 3:
-                    content = base64.b64decode(content)
-                    content = content.decode('utf-8')
-                    content = content[3:-3]
-                    print(content)
-
-            return content
-        except Exception as e:
-            print(e)
-            return None
-
-    @staticmethod
-    def encode_data(content, start=1, end=4):
-        if not content:
-            return ''
-        for i in range(start, end):
-            if i == 1:
-                content = CommonService.RandomStr(3, False) + content + CommonService.RandomStr(3, False)
-                content = base64.b64encode(str(content).encode("utf-8")).decode('utf8')
-            if i == 2:
-                content = CommonService.RandomStr(2, False) + str(content) + CommonService.RandomStr(2, False)
-                content = base64.b64encode(str(content).encode("utf-8")).decode('utf8')
-            if i == 3:
-                content = CommonService.RandomStr(1, False) + str(content) + CommonService.RandomStr(1, False)
-                content = base64.b64encode(str(content).encode("utf-8")).decode('utf8')
-        return content
-
     @staticmethod
     def encode_data_without_salt(content):
         return base64.b64encode(str(content).encode("utf-8")).decode('utf8')
@@ -631,13 +577,13 @@ GCqvlyw5dfxNA+EtxNE2wCW/LW7ENJlACgcfgPlBZtpLheWoZB/maw4=
         @return: region_id
         """
         region_id = 3
-        if CONFIG_INFO == CONFIG_US:        # 美洲
+        if CONFIG_INFO == CONFIG_US:  # 美洲
             region_id = 3
-        elif CONFIG_INFO == CONFIG_EUR:     # 欧洲
+        elif CONFIG_INFO == CONFIG_EUR:  # 欧洲
             region_id = 4
-        elif CONFIG_INFO == CONFIG_CN:      # 中国
+        elif CONFIG_INFO == CONFIG_CN:  # 中国
             region_id = 1
-        elif CONFIG_INFO == CONFIG_TEST:    # 测试
+        elif CONFIG_INFO == CONFIG_TEST:  # 测试
             region_id = 5
         return region_id
 
@@ -656,6 +602,7 @@ GCqvlyw5dfxNA+EtxNE2wCW/LW7ENJlACgcfgPlBZtpLheWoZB/maw4=
             return token_obj.code, token_obj.userID, response
         except Exception as e:
             print(e)
+            return 309, None, None
 
     @staticmethod
     def cutting_time(start_time, end_time, time_unit):

+ 86 - 5
Service/UserDeviceService.py

@@ -6,12 +6,16 @@
 @Email   : zhangdongming@asj6.wecom.work
 @Software: PyCharm
 """
+import logging
+
 from django.db.models import Q
 
 from Model.models import Device_Info, UID_Bucket, UID_Preview, UidSetModel, UidChannelSetModel, UnicomDeviceInfo, \
-    UIDModel
+    UIDModel, DeviceChannelUserSet, DeviceChannelUserPermission, DeviceSharePermission
 from Service.CommonService import CommonService
 
+LOGGER = logging.getLogger('info')
+
 
 class UserDeviceService:
 
@@ -195,12 +199,13 @@ class UserDeviceService:
             p_vo['initStringApp'] = uid_qs[0]['init_string_app']
 
     @classmethod
-    def get_device_info_dto(cls, p_vo, p_uid, uv_dict):
+    def get_device_info_dto(cls, p_vo, p_uid, uv_dict, user_id=None):
         """
         获取设备信息DTO
-        @param p_vo: 设备对象
+        @param user_id: 用户ID
+        @param p_vo: 设备信息
         @param p_uid: 设备uid
-        @param uv_dict: 设备通道字典
+        @param uv_dict: 设备通道信息
         """
         uidversion = uv_dict[p_uid]['version']
         if len(uidversion) > 6:
@@ -226,7 +231,8 @@ class UserDeviceService:
         p_vo['is_human'] = uv_dict[p_uid]['is_human']
         p_vo['is_custom_voice'] = uv_dict[p_uid]['is_custom_voice']
         p_vo['is_ptz'] = uv_dict[p_uid]['is_ptz']
-        p_vo['channels'] = uv_dict[p_uid]['channels']
+        p_vo['channels'] = cls.get_channel_permission_by_user(user_id, p_vo['isShare'], p_uid,
+                                                              uv_dict[p_uid]['channels'])
         p_vo['double_wifi'] = uv_dict[p_uid]['double_wifi']
         p_vo['mobile4G'] = uv_dict[p_uid]['mobile4G']
         p_vo['isCameraOpenCloud'] = 0 if uv_dict[p_uid]['mobile4G'] == 1 else p_vo['isCameraOpenCloud']
@@ -236,3 +242,78 @@ class UserDeviceService:
         # 设备昵称 调用影子信息昵称,先阶段不可
         if uv_dict[p_uid]['nickname']:
             p_vo['NickName'] = uv_dict[p_uid]['nickname']
+
+    @staticmethod
+    def get_channel_permission_by_user(user_id, is_share, uid, channels):
+        """
+        根据用户获取设备通道权限
+        @param user_id: 用户ID
+        @param is_share: 是否分享设备
+        @param uid: 设备UID
+        @param channels: 通道信息
+        @return: channels
+        """
+        try:
+            if not is_share:
+                return channels
+            # 获取设备权限
+            channel_set_qs = DeviceChannelUserSet.objects.filter(user_id=user_id, uid=uid).values('id', 'channels')
+            if not channel_set_qs.exists() or not channels:
+                return channels
+            channel_list = [int(val) for val in channel_set_qs[0]['channels'].split(',')]
+            channel_permission_qs = DeviceChannelUserPermission.objects \
+                .filter(channel_user_id=channel_set_qs[0]['id']).values('permission_id')
+            ids = [val['permission_id'] for val in channel_permission_qs]
+            channel_permission_qs = DeviceSharePermission.objects \
+                .all().values('id', 'code').order_by('sort')
+            channel_permission_list = []
+            default_permissions = []
+            if not channel_permission_qs.exists():
+                return channels
+
+            for item in channel_permission_qs:
+                default_permissions.append({'permissionId': item['id'], 'code': item['code'], 'isSelect': 0})
+                p_data = {'permissionId': item['id'], 'code': item['code'], 'isSelect': 1 if item['id'] in ids else 0}
+                channel_permission_list.append(p_data)
+
+            for item in channels:
+                channel = item['channel']
+                if channel in channel_list:
+                    item['channelPermissions'] = channel_permission_list
+                else:
+                    item['channelPermissions'] = default_permissions
+            return channels
+        except Exception as e:
+            LOGGER.info('异常详情,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+            return channels
+
+    @staticmethod
+    def update_device_channel(uid):
+        """
+        UID通道同步更新
+        @param uid: 设备UID
+        @return: True | False
+        """
+        try:
+            uid_set_qs = UidSetModel.objects.filter(uid=uid).values('id', 'channel')
+            if not uid_set_qs.exists():
+                return False
+            uid_set_id = uid_set_qs[0]['id']
+            channel_index = uid_set_qs[0]['channel']
+            uid_channel_qs = UidChannelSetModel.objects.filter(uid_id=uid_set_id).values('channel')
+            if uid_channel_qs.exists() and uid_channel_qs.count() != channel_index:
+                uid_channel_list = []
+                channels = [val['channel'] for val in uid_channel_qs]
+                for i in range(1, channel_index + 1):
+                    if i in channels:
+                        continue
+                    channel_name = 'channel' + str(i)  # channel1,channel2...
+                    UidChannelSet = UidChannelSetModel(uid_id=uid_set_id, channel=i, channel_name=channel_name)
+                    uid_channel_list.append(UidChannelSet)
+                if not uid_channel_list:
+                    return True
+                UidChannelSetModel.objects.bulk_create(uid_channel_list)
+            return True
+        except Exception as e:
+            LOGGER.info('异常详情,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+            return False

+ 137 - 0
Service/VodHlsService.py

@@ -0,0 +1,137 @@
+# @Author    : Rocky
+# @File      : VodHlsService.py
+# @Time      : 2023/2/1 15:57
+import datetime
+from Model.models import VodHlsMon, VodHlsTues, VodHlsWed, VodHlsThur, VodHlsFri, VodHlsSat, VodHlsSun
+from Service.CommonService import CommonService
+from django.db.models import Count
+
+class SplitVodHlsObject:
+    # VodHls分表功能类
+
+    def creat_vod_hls_data(self, **kwargs):
+        """
+        分表保存云存信息数据
+        """
+        start_time = kwargs.get('start_time')
+        week = datetime.datetime.fromtimestamp(int(start_time)).isoweekday()
+        if week == 1:
+            VodHlsMon.objects.create(**kwargs)
+        elif week == 2:
+            VodHlsTues.objects.create(**kwargs)
+        elif week == 3:
+            VodHlsWed.objects.create(**kwargs)
+        elif week == 4:
+            VodHlsThur.objects.create(**kwargs)
+        elif week == 5:
+            VodHlsFri.objects.create(**kwargs)
+        elif week == 6:
+            VodHlsSat.objects.create(**kwargs)
+        elif week == 7:
+            VodHlsSun.objects.create(**kwargs)
+
+    def del_vod_hls_data(self, **kwargs):
+        """
+        分表删除云存信息数据
+        """
+        VodHlsMon.objects.filter(**kwargs).delete()
+        VodHlsTues.objects.filter(**kwargs).delete()
+        VodHlsWed.objects.filter(**kwargs).delete()
+        VodHlsThur.objects.filter(**kwargs).delete()
+        VodHlsFri.objects.filter(**kwargs).delete()
+        VodHlsSat.objects.filter(**kwargs).delete()
+        VodHlsSun.objects.filter(**kwargs).delete()
+
+    def get_vod_hls_data(self, **kwargs):
+        """
+        分表获取云存信息数据
+        @return: vod_hls
+        """
+        vod_hls = VodHlsMon.objects.filter(pk=-1)
+        if 'start_time' in kwargs:
+            start_time = kwargs.get('start_time')
+            week = datetime.datetime.fromtimestamp(int(start_time)).isoweekday()
+            if week == 1:
+                vod_hls = VodHlsMon.objects.filter(**kwargs)
+            elif week == 2:
+                vod_hls = VodHlsTues.objects.filter(**kwargs)
+            elif week == 3:
+                vod_hls = VodHlsWed.objects.filter(**kwargs)
+            elif week == 4:
+                vod_hls = VodHlsThur.objects.filter(**kwargs)
+            elif week == 5:
+                vod_hls = VodHlsFri.objects.filter(**kwargs)
+            elif week == 6:
+                vod_hls = VodHlsSat.objects.filter(**kwargs)
+            elif week == 7:
+                vod_hls = VodHlsSun.objects.filter(**kwargs)
+            return vod_hls
+        if 'start_time__range' in kwargs:
+            start_time, end_time = kwargs.get('start_time__range')
+            vod_hls_mon = VodHlsMon.objects.filter(pk=-1)
+            vod_hls_tus = VodHlsTues.objects.filter(pk=-1)
+            vod_hls_wed = VodHlsWed.objects.filter(pk=-1)
+            vod_hls_thur = VodHlsThur.objects.filter(pk=-1)
+            vod_hls_fri = VodHlsFri.objects.filter(pk=-1)
+            vod_hls_sat = VodHlsSat.objects.filter(pk=-1)
+            vod_hls_sun = VodHlsSun.objects.filter(pk=-1)
+            start_time = datetime.datetime.fromtimestamp(int(start_time))
+            end_time = datetime.datetime.fromtimestamp(int(end_time))
+            time_list = CommonService.cutting_time(start_time, end_time, 'day')
+            day_list = []
+            for time_item in time_list:
+                week = datetime.datetime.fromtimestamp(int(time_item[0])).isoweekday()
+                if week not in day_list:
+                    day_list.append(week)
+            for week in day_list:
+                if week == 1:
+                    vod_hls_mon = VodHlsMon.objects.filter(**kwargs)
+                elif week == 2:
+                    vod_hls_tus = VodHlsTues.objects.filter(**kwargs)
+                elif week == 3:
+                    vod_hls_wed = VodHlsWed.objects.filter(**kwargs)
+                elif week == 4:
+                    vod_hls_thur = VodHlsThur.objects.filter(**kwargs)
+                elif week == 5:
+                    vod_hls_fri = VodHlsFri.objects.filter(**kwargs)
+                elif week == 6:
+                    vod_hls_sat = VodHlsSat.objects.filter(**kwargs)
+                elif week == 7:
+                    vod_hls_sun = VodHlsSun.objects.filter(**kwargs)
+            vod_hls = vod_hls.union(vod_hls_mon, vod_hls_tus, vod_hls_wed, vod_hls_thur, vod_hls_fri, vod_hls_sat,
+                                    vod_hls_sun)
+            return vod_hls
+        vod_hls_mon = VodHlsMon.objects.filter(**kwargs)
+        vod_hls_tus = VodHlsTues.objects.filter(**kwargs)
+        vod_hls_wed = VodHlsWed.objects.filter(**kwargs)
+        vod_hls_thur = VodHlsThur.objects.filter(**kwargs)
+        vod_hls_fri = VodHlsFri.objects.filter(**kwargs)
+        vod_hls_sat = VodHlsSat.objects.filter(**kwargs)
+        vod_hls_sun = VodHlsSun.objects.filter(**kwargs)
+
+        vod_hls = vod_hls.union(vod_hls_mon, vod_hls_tus, vod_hls_wed, vod_hls_thur, vod_hls_fri, vod_hls_sat, vod_hls_sun)
+        return vod_hls
+
+    def get_vod_hls_date(self, **kwargs):
+        """
+        分表获取云存日期信息数据
+        @return: vod_hls
+        """
+
+        vod_hls_mon = VodHlsMon.objects.extra(select={'date': "FROM_UNIXTIME(start_time,'%%Y-%%m-%%d')"}).values(
+             'date').filter(**kwargs).annotate(count=Count('start_time')).order_by('-date')
+        vod_hls_tus = VodHlsTues.objects.extra(select={'date': "FROM_UNIXTIME(start_time,'%%Y-%%m-%%d')"}).values(
+             'date').filter(**kwargs).annotate(count=Count('start_time')).order_by('-date')
+        vod_hls_wed = VodHlsWed.objects.extra(select={'date': "FROM_UNIXTIME(start_time,'%%Y-%%m-%%d')"}).values(
+             'date').filter(**kwargs).annotate(count=Count('start_time')).order_by('-date')
+        vod_hls_thur = VodHlsThur.objects.extra(select={'date': "FROM_UNIXTIME(start_time,'%%Y-%%m-%%d')"}).values(
+             'date').filter(**kwargs).annotate(count=Count('start_time')).order_by('-date')
+        vod_hls_fri = VodHlsFri.objects.extra(select={'date': "FROM_UNIXTIME(start_time,'%%Y-%%m-%%d')"}).values(
+             'date').filter(**kwargs).annotate(count=Count('start_time')).order_by('-date')
+        vod_hls_sat = VodHlsSat.objects.extra(select={'date': "FROM_UNIXTIME(start_time,'%%Y-%%m-%%d')"}).values(
+             'date').filter(**kwargs).annotate(count=Count('start_time')).order_by('-date')
+        vod_hls_sun = VodHlsSun.objects.extra(select={'date': "FROM_UNIXTIME(start_time,'%%Y-%%m-%%d')"}).values(
+             'date').filter(**kwargs).annotate(count=Count('start_time')).order_by('-date')
+
+        vod_hls = vod_hls_mon.union(vod_hls_tus, vod_hls_wed, vod_hls_thur, vod_hls_fri, vod_hls_sat, vod_hls_sun)
+        return vod_hls

BIN
requirements.txt