Просмотр исходного кода

用户订阅 - 邮件订阅 + 定制化推送的订阅

linhaohong 1 год назад
Родитель
Сommit
02bd4402f0

+ 2 - 0
Ansjer/urls.py

@@ -27,6 +27,7 @@ from Controller import FeedBack, EquipmentOTA, EquipmentInfo, AdminManage, AppIn
 from Controller.Cron import CronTaskController
 from Controller.MessagePush import EquipmentMessagePush
 from Controller.Surveys import CloudStorageController
+from Controller.UserDevice import UserSubscriptionController
 from Controller.SensorGateway import SensorGatewayController, EquipmentFamilyController
 from django.urls import include
 
@@ -370,6 +371,7 @@ urlpatterns = [
     re_path('sensorGateway/(?P<operation>.*)', SensorGatewayController.SensorGateway.as_view()),
     re_path(r'^weather/(?P<operation>.*)$', WeatherControl.WeatherView.as_view()),
     re_path(r'^alexaApi/', include("Ansjer.server_urls.alexa_url")),
+    re_path('customSubscription/(?P<operation>.*)', UserSubscriptionController.UserSubscriptionControllerView.as_view()),
 
     # 后台界面接口 -----------------------------------------------------
     # 用户登录信息等

+ 47 - 8
Controller/UserController.py

@@ -2,6 +2,7 @@ import base64
 import datetime
 import logging
 import random
+import threading
 import time
 import traceback
 from io import BytesIO
@@ -28,9 +29,10 @@ from Ansjer.config import AuthCode_Expire, SERVER_DOMAIN, TUTK_PUSH_DOMAIN, \
     LOGGER, CONFIG_US
 from Ansjer.config import BASE_DIR, CONFIG_EUR, CONFIG_INFO, SERVER_DOMAIN_EUR, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY
 from Controller.CheckUserData import DataValid, date_handler, RandomStr
+from Controller.UserDevice.UserSubscriptionController import UserSubscriptionControllerView
 from Model.models import Device_User, Role, UidPushModel, UserOauth2Model, UserExModel, Device_Info, UidSetModel, \
     UserAppFrequencyModel, CountryIPModel, CountryModel, UidChannelSetModel, Order_Model, UID_Bucket, Unused_Uid_Meal, \
-    GatewayPush, CountryLanguageModel, LanguageModel, VodBucketModel, LogModel
+    GatewayPush, CountryLanguageModel, LanguageModel, VodBucketModel, LogModel, UserEmailSubscriptions
 from Object.AWS.AmazonS3Util import AmazonS3Util
 from Object.AWS.SesClassObject import SesClassObject
 from Object.AliSmsObject import AliSmsObject
@@ -1200,6 +1202,8 @@ class v3registerView(TemplateView):
         unique = request_dict.get('unique', None)
         number = request_dict.get('number', None)
         region_status = request_dict.get('region_status', None)
+        email_scription = request_dict.get('email_scription', None)
+        push_scription = request_dict.get('push_scription', None)
 
         if unique:
             delete_local_account(unique)
@@ -1247,13 +1251,14 @@ class v3registerView(TemplateView):
                 return response.json(444, 'identifyingCode')
 
             if phone is not None:
-                return self.do_phone_register(phone, password, authcode, number, region_status, response)
+                return self.do_phone_register(phone, password, authcode, number, region_status, response, push_scription)
             elif email is not None:
-                return self.do_email_register(email, password, authcode, number, region_status, response)
+                return self.do_email_register(email, password, authcode, number, region_status, response,
+                                              email_scription, push_scription)
             else:
                 return response.json(444, 'phone or email')
 
-    def do_phone_register(self, phone, password, authcode, number, region_status, response):
+    def do_phone_register(self, phone, password, authcode, number, region_status, response, push_scription):
         data_valid = DataValid()
         if data_valid.mobile_validate(phone) is not True:
             return response.json(100)
@@ -1272,12 +1277,13 @@ class v3registerView(TemplateView):
         if phone_qs.exists():
             return response.json(101)
         try:
+            userID = CommonService.getUserID(μs=False, setOTAID=True)
             create_data = {
                 "username": phone,
                 "NickName": phone,
                 "phone": phone,
                 "password": make_password(password),
-                "userID": CommonService.getUserID(μs=False, setOTAID=True),
+                "userID": userID,
                 "is_active": True,
                 "user_isValid": True,
                 "region_status": region_status
@@ -1285,6 +1291,10 @@ class v3registerView(TemplateView):
             if number:
                 create_data["region_country"] = number
             Device_User.objects.create(**create_data)
+            if push_scription:
+                UserEmailSubscriptions.objects.create(phone=phone, user_id=userID, push_sub_status=1)
+            else:
+                UserEmailSubscriptions.objects.create(phone=phone, user_id=userID, push_sub_status=0)
 
         except Exception as e:
             errorInfo = traceback.format_exc()
@@ -1323,7 +1333,8 @@ class v3registerView(TemplateView):
         res['phone'] = user_list[0]["phone"] if user_list[0]["phone"] is not None else ''
         return response.json(0, res)
 
-    def do_email_register(self, email, password, authcode, number, region_status, response):
+    def do_email_register(self, email, password, authcode, number, region_status, response, email_scription,
+                          push_scription):
         data_valid = DataValid()
         if data_valid.email_validate(email) is not True:
             return response.json(105)
@@ -1343,12 +1354,13 @@ class v3registerView(TemplateView):
         if email_qs.exists():
             return response.json(103)
         try:
+            userID = CommonService.getUserID(μs=False, setOTAID=True)
             create_data = {
                 "username": email,
                 "NickName": email,
                 "userEmail": email,
                 "password": make_password(password),
-                "userID": CommonService.getUserID(μs=False, setOTAID=True),
+                "userID": userID,
                 "is_active": True,
                 "user_isValid": True,
                 "region_status": region_status
@@ -1356,6 +1368,18 @@ class v3registerView(TemplateView):
             if number:
                 create_data["region_country"] = number
             Device_User.objects.create(**create_data)
+            if push_scription:
+                UserEmailSubscriptions.objects.create(user_id=userID, email=email, push_sub_status=1)
+            else:
+                UserEmailSubscriptions.objects.create(user_id=userID, email=email, push_sub_status=0)
+            if email_scription:
+                subscribers = {
+                    "userEmail": email,
+                    "region_country": number
+                }
+                subscription_thread = threading.Thread(target=UserSubscriptionControllerView.subscription,
+                                                       args=(subscribers,))
+                subscription_thread.start()
 
         except Exception as e:
             errorInfo = traceback.format_exc()
@@ -3570,6 +3594,8 @@ class Image_Code_RegisterView(TemplateView):
         region_status = request_dict.get('region_status', None)
         lang = request_dict.get('lang', None)
         response = ResponseObject(lang)
+        email_scription = request_dict.get('email_scription', None)
+        push_scription = request_dict.get('push_scription', None)
 
         if not all([userEmail, password, lang, imageCodeId, valid_code]):
             return response.json(444)
@@ -3638,12 +3664,13 @@ class Image_Code_RegisterView(TemplateView):
             return response.json(103)
 
         # 创建用户
+        userID = CommonService.getUserID(μs=False, setOTAID=True)
         create_data = {
             "username": username,
             "NickName": username,
             "userEmail": userEmail,
             "password": make_password(password),
-            "userID": CommonService.getUserID(μs=False, setOTAID=True),
+            "userID": userID,
             "is_active": True,
             "user_isValid": True,
             "region_status": region_status
@@ -3651,6 +3678,18 @@ class Image_Code_RegisterView(TemplateView):
         if number:
             create_data["region_country"] = number
         Device_User.objects.create(**create_data)
+        if push_scription:
+            UserEmailSubscriptions.objects.create(email=userEmail, user_id=userID, push_sub_status=1)
+        else:
+            UserEmailSubscriptions.objects.create(email=userEmail, user_id=userID, push_sub_status=0)
+        if email_scription:
+            subscribers = {
+                "userEmail": userEmail,
+                "region_country": number
+            }
+            subscription_thread = threading.Thread(target=UserSubscriptionControllerView.subscription,
+                                                   args=(subscribers,))
+            subscription_thread.start()
         return self.do_login(email_qs, response)
 
     @staticmethod

+ 223 - 0
Controller/UserDevice/UserSubscriptionController.py

@@ -0,0 +1,223 @@
+# -*- encoding: utf-8 -*-
+"""
+@File    : UserSubscriptionController.py
+@Time    : 2024/5/21 16:31
+@Author  : stephen
+@Email   : zhangdongming@asj6.wecom.work
+@Software: PyCharm
+"""
+import threading
+import time
+
+from django.http import QueryDict
+from django.views import View
+
+from Model.models import Device_User, CountryModel, UserEmailSubscriptions
+from Object.ResponseObject import ResponseObject
+from Object.TokenObject import TokenObject
+from Object.YotpoCoreObject import YotpoCoreObject
+from Ansjer.config import LOGGER
+
+
+class UserSubscriptionControllerView(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 delete(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        delete = QueryDict(request.body)
+        if not delete:
+            delete = request.GET
+        return self.validation(delete, request, operation)
+
+    def put(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        put = QueryDict(request.body)
+        return self.validation(put, request, operation)
+
+    def validation(self, request_dict, request, operation):
+        response = ResponseObject('cn')
+        tko = TokenObject(request.META.get('HTTP_AUTHORIZATION'))
+        if tko.code != 0:
+            return response.json(tko.code)
+        response.lang = tko.lang
+        userID = tko.userID
+        if operation == 'checkSubscriptionStatus':
+            return self.check_subscription_status(userID, response)
+        elif operation == 'switchSubscription':
+            return self.switch_subscription(userID, request_dict, response)
+        else:
+            return response.json(414)
+
+    @staticmethod
+    def check_subscription_status(user_id, response):
+        """
+        检查订阅状态
+        @param user_id: str
+        @param response: 响应
+        @return: response
+        """
+        user_qs = Device_User.objects.filter(userID=user_id)
+        if not user_qs.exists():
+            return response.json(104)
+        user_sub = UserEmailSubscriptions.objects.filter(user_id=user_id).values('status', 'push_sub_status').first()
+        if not user_sub:
+            UserEmailSubscriptions.objects.create(user_id=user_id, status=0, push_sub_status=1,
+                                                  updated_time=int(time.time()), created_time=int(time.time()))
+            return response.json(0, {"emailSubStatus": 0, 'pushSubStatus': 1})
+        email_sub_status = 1 if user_sub["status"] == 1 else 0
+        push_sub_status = 0 if user_sub["push_sub_status"] == 0 else 1
+        user_sub = {"emailSubStatus": email_sub_status, 'pushSubStatus': push_sub_status}
+        return response.json(0, user_sub)
+
+    def switch_subscription(self, user_id, request_dict, response):
+        """
+        邮件订阅开关
+        @param user_id: str
+        @param request_dict: dict
+        @param response
+        """
+        user_qs = Device_User.objects.filter(userID=user_id)
+        email_sub_status = request_dict.get('emailSubStatus', None)
+        push_sub_status = request_dict.get('pushSubStatus', None)
+        if not email_sub_status and not push_sub_status:
+            return response.json(444, "emailSubStatus or pushSubStatus")
+        if not user_qs.exists():
+            return response.json(104)
+
+        # 用户推送订阅
+        if push_sub_status:
+            push_sub_status = int(push_sub_status)
+            user_sub_qs = UserEmailSubscriptions.objects.filter(user_id=user_id)
+            if user_sub_qs.exists():
+                user_sub_qs.update(push_sub_status=push_sub_status)
+            else:
+                user = user_qs.values('userEmail', 'phone').first()
+                push_sub = {
+                    "user_id": user_id,
+                    "push_sub_status": push_sub_status,
+                    "created_time": int(time.time()),
+                    "updated_time": int(time.time())
+                }
+                if user["userEmail"]:
+                    push_sub["email"] = user["userEmail"]
+                if user["phone"]:
+                    push_sub["phone"] = user["phone"]
+                UserEmailSubscriptions.objects.create(**push_sub)
+        else:
+            user_sub = UserEmailSubscriptions.objects.filter(user_id=user_id).values('status',
+                                                                                     'push_sub_status').first()
+            if not user_sub:
+                push_sub_status = 1
+            else:
+                push_sub_status = user_sub["push_sub_status"]
+
+        if email_sub_status:
+            # 修改数据库中订阅状态
+            email_sub_status = int(email_sub_status)
+            user_sub_qs = UserEmailSubscriptions.objects.filter(user_id=user_id)
+            # 邮件订阅
+            if email_sub_status == 1:
+                subscribers = user_qs.values('NickName', 'userEmail', 'region_country').first()
+                if not subscribers["userEmail"]:
+                    LOGGER.info(f'subscribers{user_id}邮箱为空,无法订阅')
+                    return response.json(183)
+                if user_sub_qs.exists():
+                    user_sub_qs.update(email=subscribers["userEmail"], status=1, updated_time=int(time.time()))
+                else:
+                    UserEmailSubscriptions.objects.create(user_id=user_id, status=1, email=subscribers["userEmail"],
+                                                          created_time=int(time.time()), updated_time=int(time.time()))
+                subscription_thread = threading.Thread(target=self.subscription, args=(subscribers,))
+                subscription_thread.start()
+            # 取消订阅
+            elif email_sub_status == 0:
+                device_user = Device_User.objects.filter(userID=user_id).values('userEmail').first()
+                if device_user:
+                    customer = {
+                        "email": device_user["userEmail"],
+                        "first_name": device_user["userEmail"],
+                        "last_name": "APP",
+                    }
+                    yotpo = YotpoCoreObject()
+                    list_id = 8589406
+                    subscription_thread = threading.Thread(target=yotpo.close_subscribers, args=(customer, list_id))
+                    subscription_thread.start()
+                    if user_sub_qs.exists():
+                        customer["status"] = "unsubscription"
+                        user_sub_qs.update(email=device_user["userEmail"], status=0, sub_result=customer)
+        else:
+            user_sub = UserEmailSubscriptions.objects.filter(user_id=user_id).values('status').first()
+            if not user_sub:
+                email_sub_status = 0
+            else:
+                email_sub_status = user_sub["status"]
+
+        return response.json(0, {"emailSubStatus": email_sub_status, "pushSubStatus": push_sub_status})
+
+    @staticmethod
+    def subscription(subscribers):
+        """
+        订阅
+        @param subscribers: dict
+        @return: boolean
+        """
+
+        yotpo = YotpoCoreObject()
+
+        try:
+            # 查询顾客所在地区
+            if subscribers["region_country"]:
+                country = CountryModel.objects.filter(id=subscribers["region_country"]).values('country_code').first()
+                if country:
+                    country_code = country["country_code"]
+                else:
+                    country_code = ''
+                # 构建顾客订阅格式
+                customer = {
+                    "email": subscribers["userEmail"],
+                    "first_name": subscribers["userEmail"],
+                    "last_name": "APP",
+                    'address': {
+                        "country_code": country_code,
+                    },
+                    "custom_properties": {
+                        "subscription_office": "ZosiApp",
+                    }
+                }
+            else:
+                customer = {
+                    "email": subscribers["userEmail"],
+                    "first_name": subscribers["userEmail"],
+                    "last_name": "APP",
+                    "custom_properties": {
+                        "subscription_office": "ZosiApp",
+                    }
+                }
+
+            result = yotpo.creat_and_update_customers(customer)
+            list_id = 8589406
+            sub_status, sub_result = yotpo.create_subscribers(customer, list_id)
+
+            if result and sub_status:
+                # 创建结果写入数据库
+                user_sub_qs = UserEmailSubscriptions.objects.filter(email=subscribers["userEmail"])
+                if user_sub_qs.exists():
+                    user_sub_qs.update(email=subscribers["userEmail"], status=1, sub_result=sub_result, list_id=list_id,
+                                       updated_time=int(time.time()))
+                    LOGGER.info(f'在yotpo创建客户并订阅成功,customer:{customer}')
+                return True
+            else:
+                LOGGER.info(f'在yotpo创建客户并订阅失败,customer:{customer}')
+            return False
+        except Exception as e:
+            LOGGER.error(f'{subscribers["userEmail"]}订阅失败:{e}')
+            return False

+ 15 - 0
Model/models.py

@@ -4762,3 +4762,18 @@ class AccessNumberTaskQueue(models.Model):
         verbose_name = '接入号码任务队列'
         verbose_name_plural = verbose_name
 
+class UserEmailSubscriptions(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name='主键')
+    user_id = models.CharField(default='', max_length=32, verbose_name='用户id')
+    email = models.CharField(default='', max_length=32, verbose_name='邮箱')
+    phone = models.CharField(default='', max_length=32, verbose_name='手机号')
+    status = models.SmallIntegerField(default=0, verbose_name='订阅状态,0未订阅,1订阅')
+    push_sub_status = models.SmallIntegerField(default=0, verbose_name='定制化推送订阅状态,0未订阅,1订阅')
+    list_id = models.CharField(default='', max_length=32, verbose_name='订阅列表id')
+    sub_result = models.JSONField(null=True, verbose_name='订阅结果')
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+    updated_time = models.IntegerField(default=0, verbose_name='更新时间')
+
+    class Meta:
+        db_table = 'user_email_subscriptions'
+        verbose_name = '用户邮件订阅记录表'

+ 208 - 0
Object/YotpoCoreObject.py

@@ -0,0 +1,208 @@
+# -*- encoding: utf-8 -*-
+"""
+@File    : YotpoCoreObject.py
+@Time    : 2024/5/17 9:36
+@Author  : stephen
+@Email   : zhangdongming@asj6.wecom.work
+@Software: PyCharm
+"""
+# -*- encoding: utf-8 -*-
+"""
+@File    : EDM.py
+@Time    : 2024/5/16 11:16
+@Author  : stephen
+@Email   : zhangdongming@asj6.wecom.work
+@Software: PyCharm
+"""
+import datetime
+import json
+import requests
+from Ansjer.config import LOGGER
+
+STORE_ID = "LIKwYlx6uonKqN91fXiGFb4FHqVLpvMUdGNU5Zf9"
+YOTPO_URL = f"https://api.yotpo.com/core/v3/stores/{STORE_ID}/"
+secret = 'isb8EOQs8bkjrksLHN73o3HIkrhoW539IXhULfdh'
+
+
+class YotpoCoreObject:
+
+    def get_token(self):
+        try:
+            url = YOTPO_URL + "access_tokens"
+
+            payload = {'secret': secret}
+            headers = {
+                "accept": "application/json",
+                "Content-Type": "application/json"
+            }
+
+            response = requests.post(url, json=payload, headers=headers)
+            if response.status_code != 200:
+                LOGGER.info(f'yotpo获取token失败, response.status_code请求不为200')
+                return ""
+            token = json.loads(response.text).get("access_token")
+            return token
+        except Exception as e:
+            LOGGER.info(f'yotpo获取token失败, {e}')
+            return ""
+
+    def creat_and_update_customers(self, customers):
+        """
+        创建和更新用户
+        """
+        try:
+            url = YOTPO_URL + "customers"
+            yotpo_token = self.get_token()
+            if yotpo_token == "":
+                LOGGER.info(f'yotpo创建顾客失败, yotpo_token为空 ,customers:{customers}')
+                return False
+            headers = {
+                "accept": "application/json",
+                "X-Yotpo-Token": yotpo_token,
+                "Content-Type": "application/json"
+            }
+            payload = {
+                "customer": customers
+            }
+            response = requests.patch(url, json=payload, headers=headers)
+            if response.status_code != 200:
+                LOGGER.info(f'yotpo创建顾客失败,response.status_code != 200,customers:{customers}')
+                return False
+            LOGGER.info(f'yotpo创建顾客成功,customers:{customers}')
+            return True
+        except Exception as e:
+            LOGGER.info(f'yotpo创建顾客失败, customers:{customers},{e}')
+            return False
+
+    def get_customers_list(self, email):
+        """
+        查用户信息
+        """
+        url = YOTPO_URL + f"customers?include_custom_properties=true&email={email}"
+        yotpo_token = self.get_token()
+        headers = {
+            "accept": "application/json",
+            "X-Yotpo-Token": yotpo_token,
+            "Content-Type": "application/json"
+        }
+        response = requests.get(url, headers=headers)
+        assert response.status_code == 200
+        return response.text
+
+    def create_subscribers(self, customer_params, list_id):
+        """
+        创建订阅
+        """
+        url = f"https://api.yotpo.com/messaging/v3/stores/{STORE_ID}/subscribers"
+        if "custom_properties" in customer_params:
+            del customer_params["custom_properties"]
+        payload = {
+            "customer": customer_params,
+            "channels": {
+                "email": {
+                    "marketing": {
+                        "consent": "subscribed",
+                        "list_id": list_id,
+                    },
+                    "suppression": {
+                        "suppress_email": True,
+                        "suppression_reason": "soft_bounce",
+                        "timestamp": datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ")
+                    }
+                },
+            },
+        }
+        headers = {
+            "accept": "application/json",
+            "content-type": "application/json",
+            "X-Yotpo-Token": self.get_token()
+        }
+        response = requests.post(url, json=payload, headers=headers)
+        if response.status_code != 200:
+            LOGGER.info(f'yotpo创建订阅失败, customer_params:{customer_params}')
+            return False, ""
+        return True, response.text
+
+    def close_subscribers(self, customer, list_id):
+        """
+        关闭订阅
+        """
+        url = f"https://api.yotpo.com/messaging/v3/stores/{STORE_ID}/subscribers"
+        payload = {
+            "customer": customer,
+            "channels": {
+                "email": {"marketing": {
+                    "consent": "unsubscribed",
+                    "list_id": list_id,
+                    "source": "post_purchase_popup"
+                }}
+            }
+        }
+        headers = {
+            "accept": "application/json",
+            "content-type": "application/json",
+            "X-Yotpo-Token": self.get_token()
+        }
+        response = requests.post(url, json=payload, headers=headers)
+        if response.status_code != 200:
+            LOGGER.info(f'yotpo关闭订阅失败, customer:{customer}')
+            return False
+        LOGGER.info(f'yotpo关闭订阅成功, customer:{customer}')
+        return True
+
+    def get_all_list_ids(self):
+        """
+        获取所有list_id
+        """
+        authentication_token = self.get_token()
+
+        url = f"https://api.yotpo.com/core/v3/stores/{STORE_ID}/lists"
+        headers = {
+            "accept": "application/json",
+            "content-type": "application/json",
+            "X-Yotpo-Token": authentication_token
+        }
+        response = requests.get(url, headers=headers)
+        response_data = response.json()
+
+        if response.status_code == 200:
+            print(response_data)
+        else:
+            print(f"Error: {response_data['message']}")
+            return []
+
+    def check_api(self):
+
+        """
+        注册成功后 进行yotpo api创建用户,并订阅邮件通知
+        @return:
+        """
+        email = '1920098158@qq.com'
+        customer = {
+            "email": email, "first_name": "test", "last_name": "22",
+            'address': {
+                "country_code": 'GB',
+            }
+        }
+
+        result = self.creat_and_update_customers(customer)
+        print(result)
+
+        list_id = 8589406
+        subscribers_result = self.create_subscribers(customer, list_id)
+        print(subscribers_result)
+
+        # customer_result = self.get_customers_list(email)
+        # customer = json.loads(customer_result)
+        # if customer['customers']:
+        #     external_id = customer['customers'][0]['external_id']
+        #
+        #     country_code = 'LU'
+        #     customer = {
+        #         "external_id": external_id,
+        #         "address": {
+        #             "country_code": country_code,
+        #         }
+        #     }
+        #     self.creat_and_update_customers(customer)
+        print('success')