ShopifyController.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. from datetime import datetime
  2. import concurrent.futures
  3. import pytz
  4. import requests
  5. from django.db.models import Q
  6. from django.views import View
  7. from Crypto.Cipher import AES
  8. from Crypto.Util.Padding import pad
  9. from django.contrib.auth.hashers import check_password, make_password
  10. import concurrent.futures
  11. from Controller.CheckUserData import DataValid
  12. from Model.models import Device_User, CountryModel
  13. from Object.RedisObject import RedisObject
  14. from Object.ResponseObject import ResponseObject
  15. import base64
  16. import hmac
  17. import hashlib
  18. import os
  19. import json
  20. from Ansjer.config import SHOPIFY_CONFIG
  21. from Service.CommonService import CommonService
  22. class ShopifyMultipass:
  23. @staticmethod
  24. def generate_multipass_token(secret, customer_data):
  25. """
  26. 使用指定的密钥对加密并签名JSON数据,返回Base64编码的Multipass令牌
  27. """
  28. # 第一步:将客户数据转换为JSON格式
  29. json_data = json.dumps(customer_data)
  30. # 第二步:生成加密密钥和签名密钥
  31. hash_digest = hashlib.sha256(secret.encode()).digest()
  32. encryption_key = hash_digest[:16] # 128位加密密钥
  33. signature_key = hash_digest[16:32] # 128位签名密钥
  34. # 第三步:加密JSON数据
  35. iv = os.urandom(16) # 随机初始化向量
  36. cipher = AES.new(encryption_key, AES.MODE_CBC, iv)
  37. ciphertext = cipher.encrypt(pad(json_data.encode(), AES.block_size))
  38. # 第四步:签名加密数据
  39. data_to_sign = iv + ciphertext
  40. signature = hmac.new(signature_key, data_to_sign, hashlib.sha256).digest()
  41. # 第五步:Base64编码
  42. multipass_token = base64.urlsafe_b64encode(iv + ciphertext + signature).decode()
  43. return multipass_token
  44. @staticmethod
  45. def search_customer_by_email(store_name, access_token, email):
  46. # 设置请求URL
  47. url = f"https://{store_name}.myshopify.com/admin/api/2024-10/customers/search.json"
  48. params = {
  49. "query": f"email:{email}"
  50. }
  51. # 设置请求头
  52. headers = {
  53. "X-Shopify-Access-Token": access_token,
  54. }
  55. # 发送GET请求
  56. response = requests.get(url, headers=headers, params=params)
  57. # 返回响应的JSON数据
  58. return response.json()
  59. class ShopifyView(View):
  60. def get(self, request, *args, **kwargs):
  61. request.encoding = 'utf-8'
  62. operation = kwargs.get('operation')
  63. request_dict = request.GET
  64. return self.validation(request, request_dict, operation)
  65. def post(self, request, *args, **kwargs):
  66. request.encoding = 'utf-8'
  67. operation = kwargs.get('operation')
  68. request_dict = request.POST
  69. return self.validation(request, request_dict, operation)
  70. def validation(self, request, request_dict, operation):
  71. language = request_dict.get('language', 'cn')
  72. response = ResponseObject(language)
  73. if operation == 'shopifyLogin':
  74. return self.shopify_login(request_dict, response)
  75. elif operation == 'shopifyRegister':
  76. return self.shopify_register(request_dict, response)
  77. elif operation == 'searchCustomer': # 查询APP注册账号情况
  78. return self.search_customer(request_dict, response)
  79. elif operation == 'searchAccount': # 官网检测账号接口
  80. return self.search_account(request_dict, response)
  81. else:
  82. return response.json(414)
  83. @staticmethod
  84. def shopify_login(request_dict, response):
  85. email = request_dict.get("email", None)
  86. password = request_dict.get("password", None)
  87. account_region = request_dict.get("accountRegion", "")
  88. account_iso2 = request_dict.get("accountIso2", "")
  89. shopify_country = request_dict.get("shopifyCountry", "")
  90. if not all([email, password]):
  91. return response.json(444)
  92. user_qs = Device_User.objects.filter(Q(username=email) | Q(userEmail=email))
  93. if not user_qs.exists():
  94. return response.json(104)
  95. users = user_qs.values(
  96. 'role__rid', 'role__roleName', 'userID', 'NickName',
  97. 'username', 'userEmail', 'phone', 'password', 'userIconPath'
  98. )[0]
  99. if not check_password(password, users['password']):
  100. return response.json(111)
  101. # 获取当前时间并格式化时间戳
  102. now = datetime.now(pytz.timezone('America/New_York'))
  103. timestamp = now.strftime('%Y-%m-%dT%H:%M:%S%z')
  104. timestamp = timestamp[:-2] + ':' + timestamp[-2:]
  105. customer_data = {
  106. "email": email,
  107. "created_at": timestamp,
  108. }
  109. # 定义默认配置键
  110. secret_key = "eu_multipass_secret"
  111. store_name_key = "eu_store_name"
  112. # 根据条件选择配置键
  113. if shopify_country:
  114. secret_key = f"{shopify_country}_multipass_secret"
  115. store_name_key = f"{shopify_country}_store_name"
  116. elif account_region == "us" and account_iso2 == "jp":
  117. secret_key = "jp_multipass_secret"
  118. store_name_key = "jp_store_name"
  119. elif account_region == "us":
  120. secret_key = "us_multipass_secret"
  121. store_name_key = "us_store_name"
  122. elif account_region == "eu" and account_iso2 == "de":
  123. secret_key = "de_multipass_secret"
  124. store_name_key = "de_store_name"
  125. elif account_region == "eu" and account_iso2 == "uk":
  126. secret_key = "uk_multipass_secret"
  127. store_name_key = "uk_store_name"
  128. # 获取配置并生成重定向URL
  129. multipass_secret = SHOPIFY_CONFIG[secret_key]
  130. store_name = SHOPIFY_CONFIG[store_name_key]
  131. token = ShopifyMultipass.generate_multipass_token(multipass_secret, customer_data)
  132. redirect_url = f"https://{store_name}.zositech.com/account/login/multipass/{token}"
  133. return response.json(0, redirect_url)
  134. @staticmethod
  135. def shopify_register(request_dict, response):
  136. email = request_dict.get("email", None)
  137. password = request_dict.get("password", None)
  138. authcode = request_dict.get("authCode", None)
  139. if not all([email, password, authcode]):
  140. return response.json(444)
  141. reds = RedisObject()
  142. identifyingCode = reds.get_data(key=email + '_identifyingCode')
  143. # 判断验证码是否过期
  144. if identifyingCode is False:
  145. return response.json(120)
  146. # 验证码是否正确
  147. if authcode != identifyingCode:
  148. return response.json(121)
  149. # 注册
  150. if Device_User.objects.filter(Q(username=email) | Q(userEmail=email)).exists():
  151. return response.json(103)
  152. # 创建用户
  153. password = make_password(password)
  154. new_userID = CommonService.getUserID(μs=False, setOTAID=True)
  155. user_data = {
  156. "username": email,
  157. "NickName": email,
  158. "userEmail": email,
  159. "password": password,
  160. "userID": new_userID,
  161. "is_active": True,
  162. "user_isValid": True,
  163. }
  164. Device_User.objects.create(**user_data)
  165. return response.json(0)
  166. def search_account(self, request_dict, response):
  167. email = request_dict.get("email")
  168. if not email:
  169. return response.json(444)
  170. store_configs = [
  171. ("us", SHOPIFY_CONFIG["us_store_name"], SHOPIFY_CONFIG["us_token"]),
  172. ("eu", SHOPIFY_CONFIG["eu_store_name"], SHOPIFY_CONFIG["eu_token"]),
  173. ("de", SHOPIFY_CONFIG["de_store_name"], SHOPIFY_CONFIG["de_token"]),
  174. ("uk", SHOPIFY_CONFIG["uk_store_name"], SHOPIFY_CONFIG["uk_token"]),
  175. ("jp", SHOPIFY_CONFIG["jp_store_name"], SHOPIFY_CONFIG["jp_token"]),
  176. ]
  177. def search_customer(store_name, token):
  178. return ShopifyMultipass.search_customer_by_email(store_name, token, email)
  179. try:
  180. shopify_results = {}
  181. with concurrent.futures.ThreadPoolExecutor() as executor:
  182. future_to_country = {executor.submit(search_customer, store_name, token): country for
  183. country, store_name, token in store_configs}
  184. for future in concurrent.futures.as_completed(future_to_country):
  185. country = future_to_country[future]
  186. shopify_results[country] = future.result()
  187. shopify_country = next((country for country, result in shopify_results.items() if result["customers"]), "")
  188. account_country = self.call_search_customer(email)
  189. servers_continent = "us" if account_country["us"] else "eu" if account_country["eu"] else ""
  190. if servers_continent:
  191. account_region_list = []
  192. if account_country.get("us"):
  193. account_region_list.append({
  194. "region": "us",
  195. "url": "https://www.dvema.com/shopify/shopifyLogin",
  196. "accountCountry": account_country["us"],
  197. "shopifyCountry": shopify_country
  198. })
  199. if account_country.get("eu"):
  200. account_region_list.append({
  201. "region": "eu",
  202. "url": "https://api.zositeche.com/shopify/shopifyLogin",
  203. "accountCountry": account_country["eu"],
  204. "shopifyCountry": shopify_country
  205. })
  206. return response.json(0, {"accountStatus": 3, "accountRegionList": account_region_list})
  207. elif shopify_country:
  208. if shopify_country == "eu":
  209. url = "https://eu.zositech.com/account/login"
  210. elif shopify_country == "jp":
  211. url = "https://www.zosi.jp/account/login"
  212. elif shopify_country == "de":
  213. url = "https://www.zositech.de/account/login"
  214. elif shopify_country == "uk":
  215. url = "https://www.zositech.co.uk/account/login"
  216. else:
  217. url = "https://www.zositech.com/account/login"
  218. return response.json(0, {"accountStatus": 2, "url": url})
  219. else:
  220. url = "注册链接"
  221. return response.json(0, {"accountStatus": 1, "url": url})
  222. except Exception as e:
  223. print(e)
  224. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  225. @staticmethod
  226. def call_search_customer(email):
  227. urls = {
  228. "us": "https://test.zositechc.cn/shopify/searchCustomer",
  229. "eu": "https://test.zositechc.cn/shopify/searchCustomer"
  230. }
  231. params = {"email": email} # Use the provided email parameter
  232. customer_region = {}
  233. def fetch_customer(region, url):
  234. try:
  235. response = requests.get(url=url, params=params)
  236. response.raise_for_status() # Raise an error for bad responses
  237. customer_country = response.json().get("result", None)
  238. return region, customer_country if not all(customer_country) else None
  239. except requests.RequestException:
  240. return region, None
  241. with concurrent.futures.ThreadPoolExecutor() as executor:
  242. future_to_region = {executor.submit(fetch_customer, region, url): region for region, url in urls.items()}
  243. for future in concurrent.futures.as_completed(future_to_region):
  244. region, customer_country = future.result()
  245. customer_region[region] = customer_country
  246. return customer_region
  247. @staticmethod
  248. def search_customer(request_dict, response):
  249. email = request_dict.get("email")
  250. user_qs = Device_User.objects.filter(Q(username=email) | Q(userEmail=email))
  251. if not user_qs.exists():
  252. return response.json(104)
  253. user_region_id = user_qs.values_list('region_country', flat=True).first()
  254. country_code = CountryModel.objects.filter(id=user_region_id).values_list("country_code", flat=True).first()
  255. return response.json(0, country_code)