最新版本
This commit is contained in:
parent
0fca263911
commit
3f369584fb
4
--ini
Executable file
4
--ini
Executable file
@ -0,0 +1,4 @@
|
|||||||
|
unable to find logger stdout
|
||||||
|
unable to find logger stdout
|
||||||
|
unable to find logger stdout
|
||||||
|
unable to find logger stdout
|
7652
API日志.log
Executable file → Normal file
7652
API日志.log
Executable file → Normal file
File diff suppressed because one or more lines are too long
34459
API日志.log.2024-08-29
34459
API日志.log.2024-08-29
File diff suppressed because one or more lines are too long
@ -1 +0,0 @@
|
|||||||
2024-09-04 13:54:21,364 - API日志 - INFO - {'frameRate': 60, 'resolution': '720p', 'frameDurationMultiplier': 18, 'webhook': 'https://www.typeframes.cc/api/webhook/?userid=10&videoid=1725429259_10', 'creationParams': {'mediaType': 'stockVideo', 'origin': '/create', 'inputText': '宇宙的故事始于138亿年前的一场大爆炸,从这一点爆发出无尽的能量和物质,逐渐形成了今天我们所见的银河系、恒星和行星。在这一过程中,重力将物质聚集成团,恒星点燃,行星诞生,生命在地球上萌芽。然而,这一壮丽的宇宙图景可能终将走向衰亡', 'flowType': 'text-to-video', 'slug': 'create-tiktok-video', 'disableCaptions': True, 'hasToGenerateVoice': False, 'hasToTranscript': False, 'hasToSearchMedia': True, 'hasAvatar': False, 'hasWebsiteRecorder': False, 'hasTextSmallAtBottom': False, 'captionPresetName': 'Wrap 1', 'captionPositionName': 'bottom', 'disableAudio': True, 'ratio': '16 / 9', 'selectedAudio': 'Bladerunner 2049', 'selectedVoice': 'zh-CN-YunxiNeural', 'sourceType': 'contentScraping', 'selectedStoryStyle': {'value': 'custom', 'label': 'Custom'}, 'hasToGenerateVideos': False, 'selectedRecording': 'https://www.typeframes.cc/media/63508bd2-3d2a-418b-900b-4de3457f243c.mp3', 'selectedRecordingType': 'audio', 'generationPreset': 'LEONARDO', 'audioUrl': 'https://cdn.tfrv.xyz/audio/_bladerunner-2049.mp3'}}
|
|
164
API日志.log.2024-09-20
Normal file
164
API日志.log.2024-09-20
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
2024-09-21 14:02:29,146 - API日志 - INFO - [支付执行] 获取的访问令牌: A21AAIVwWsRmSYRX_McyZN1RISbr4rs-amzjrc5R8H2rYRMZfH_Ia3QNs4HvEFVKxK2VAEMVe2dWfciYCJ5yhzGlbJgMBDuYQ
|
||||||
|
2024-09-21 14:02:50,451 - API日志 - INFO - [支付执行] 接收到来自前端的 POST 请求,开始处理支付...
|
||||||
|
2024-09-21 14:02:50,452 - API日志 - INFO - [支付执行] 请求内容: paymentId=PAYID-M3XGC5I9U46968696522382D, PayerID=8RSF8T3UK8NT2
|
||||||
|
2024-09-21 14:02:50,454 - API日志 - INFO - [支付执行] 获取到的订单信息: Order PAYID-M3XGC5I9U46968696522382D - pending
|
||||||
|
2024-09-21 14:02:50,527 - API日志 - INFO - [支付执行] 获取的访问令牌: A21AAIVwWsRmSYRX_McyZN1RISbr4rs-amzjrc5R8H2rYRMZfH_Ia3QNs4HvEFVKxK2VAEMVe2dWfciYCJ5yhzGlbJgMBDuYQ
|
||||||
|
2024-09-21 14:02:50,527 - API日志 - INFO - [支付执行] 获取到的 PayPal 访问令牌: A21AAIVwWsRmSYRX_McyZN1RISbr4rs-amzjrc5R8H2rYRMZfH_Ia3QNs4HvEFVKxK2VAEMVe2dWfciYCJ5yhzGlbJgMBDuYQ
|
||||||
|
2024-09-21 14:02:50,528 - API日志 - INFO - [支付执行] 发送支付请求,URL: https://api.sandbox.paypal.com/v1/payments/payment/PAYID-M3XGC5I9U46968696522382D/execute, 请求头: {'Content-Type': 'application/json', 'Authorization': 'Bearer A21AAIVwWsRmSYRX_McyZN1RISbr4rs-amzjrc5R8H2rYRMZfH_Ia3QNs4HvEFVKxK2VAEMVe2dWfciYCJ5yhzGlbJgMBDuYQ'}, 请求体: {'payer_id': '8RSF8T3UK8NT2'}
|
||||||
|
2024-09-21 14:02:51,294 - API日志 - INFO - [支付执行] PayPal API 响应状态码: 200
|
||||||
|
2024-09-21 14:02:51,295 - API日志 - INFO - [支付执行] PayPal API 响应内容: {'id': 'PAYID-M3XGC5I9U46968696522382D', 'intent': 'sale', 'state': 'approved', 'cart': '2Y943631F86154047', 'payer': {'payment_method': 'paypal', 'status': 'VERIFIED', 'payer_info': {'email': 'sb-pztpq32086919@personal.example.com', 'first_name': 'John', 'last_name': 'Doe', 'payer_id': '8RSF8T3UK8NT2', 'shipping_address': {'recipient_name': 'Doe John', 'line1': 'NO 1 Nan Jin Road', 'city': 'Shanghai', 'state': 'Shanghai', 'postal_code': '200000', 'country_code': 'C2'}, 'country_code': 'C2'}}, 'transactions': [{'amount': {'total': '1.00', 'currency': 'USD', 'details': {'subtotal': '1.00', 'shipping': '0.00', 'insurance': '0.00', 'handling_fee': '0.00', 'shipping_discount': '0.00', 'discount': '0.00'}}, 'payee': {'merchant_id': 'AQJTM59Z4T3EG', 'email': 'sb-05ob032098751@business.example.com'}, 'description': '购买 Hobby 计划', 'item_list': {'items': [{'name': 'Hobby', 'sku': '1', 'price': '1.00', 'currency': 'USD', 'tax': '0.00', 'quantity': 1, 'image_url': ''}], 'shipping_address': {'recipient_name': 'Doe John', 'line1': 'NO 1 Nan Jin Road', 'city': 'Shanghai', 'state': 'Shanghai', 'postal_code': '200000', 'country_code': 'C2'}}, 'related_resources': [{'sale': {'id': '40C15537SF235414R', 'state': 'completed', 'amount': {'total': '1.00', 'currency': 'USD', 'details': {'subtotal': '1.00', 'shipping': '0.00', 'insurance': '0.00', 'handling_fee': '0.00', 'shipping_discount': '0.00', 'discount': '0.00'}}, 'payment_mode': 'INSTANT_TRANSFER', 'protection_eligibility': 'ELIGIBLE', 'protection_eligibility_type': 'ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE', 'transaction_fee': {'value': '0.33', 'currency': 'USD'}, 'parent_payment': 'PAYID-M3XGC5I9U46968696522382D', 'create_time': '2024-09-21T06:02:50Z', 'update_time': '2024-09-21T06:02:50Z', 'links': [{'href': 'https://api.sandbox.paypal.com/v1/payments/sale/40C15537SF235414R', 'rel': 'self', 'method': 'GET'}, {'href': 'https://api.sandbox.paypal.com/v1/payments/sale/40C15537SF235414R/refund', 'rel': 'refund', 'method': 'POST'}, {'href': 'https://api.sandbox.paypal.com/v1/payments/payment/PAYID-M3XGC5I9U46968696522382D', 'rel': 'parent_payment', 'method': 'GET'}]}}]}], 'failed_transactions': [], 'create_time': '2024-09-21T06:02:29Z', 'update_time': '2024-09-21T06:02:50Z', 'links': [{'href': 'https://api.sandbox.paypal.com/v1/payments/payment/PAYID-M3XGC5I9U46968696522382D', 'rel': 'self', 'method': 'GET'}]}
|
||||||
|
2024-09-21 14:02:51,295 - API日志 - INFO - [支付执行] 支付成功,订单状态更新为 'approved'
|
||||||
|
2024-09-21 14:02:51,352 - API日志 - INFO - [支付执行] 用户 19978615506 当前积分: 50
|
||||||
|
2024-09-21 14:02:51,352 - API日志 - ERROR - [支付执行] 支付执行过程中发生异常: 'Plan' object has no attribute 'name'
|
||||||
|
2024-09-21 14:03:02,480 - API日志 - INFO - 接收到 PayPal Webhook 请求...
|
||||||
|
2024-09-21 14:03:02,481 - API日志 - INFO - 验证 PayPal Webhook 签名...
|
||||||
|
2024-09-21 14:03:02,661 - API日志 - INFO - 获取的访问令牌: A21AAIVwWsRmSYRX_McyZN1RISbr4rs-amzjrc5R8H2rYRMZfH_Ia3QNs4HvEFVKxK2VAEMVe2dWfciYCJ5yhzGlbJgMBDuYQ
|
||||||
|
2024-09-21 14:03:02,784 - API日志 - INFO - Webhook 签名验证成功
|
||||||
|
2024-09-21 14:03:02,784 - API日志 - INFO - 接收到 PayPal Webhook 事件: PAYMENTS.PAYMENT.CREATED
|
||||||
|
2024-09-21 14:03:02,785 - API日志 - INFO - Webhook payload: {
|
||||||
|
"id": "WH-53X19961TT501671H-9G343651RY447041V",
|
||||||
|
"event_version": "1.0",
|
||||||
|
"create_time": "2024-09-21T06:02:53.663Z",
|
||||||
|
"resource_type": "payment",
|
||||||
|
"event_type": "PAYMENTS.PAYMENT.CREATED",
|
||||||
|
"summary": "Checkout payment is created and approved by buyer",
|
||||||
|
"resource": {
|
||||||
|
"update_time": "2024-09-21T06:02:50Z",
|
||||||
|
"create_time": "2024-09-21T06:02:29Z",
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-M3XGC5I9U46968696522382D",
|
||||||
|
"rel": "self",
|
||||||
|
"method": "GET"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "PAYID-M3XGC5I9U46968696522382D",
|
||||||
|
"state": "approved",
|
||||||
|
"transactions": [
|
||||||
|
{
|
||||||
|
"amount": {
|
||||||
|
"total": "1.00",
|
||||||
|
"currency": "USD",
|
||||||
|
"details": {
|
||||||
|
"subtotal": "1.00",
|
||||||
|
"shipping": "0.00",
|
||||||
|
"insurance": "0.00",
|
||||||
|
"handling_fee": "0.00",
|
||||||
|
"shipping_discount": "0.00",
|
||||||
|
"discount": "0.00"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"payee": {
|
||||||
|
"merchant_id": "AQJTM59Z4T3EG",
|
||||||
|
"email": "sb-05ob032098751@business.example.com"
|
||||||
|
},
|
||||||
|
"description": "\u8d2d\u4e70 Hobby \u8ba1\u5212",
|
||||||
|
"item_list": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "Hobby",
|
||||||
|
"sku": "1",
|
||||||
|
"price": "1.00",
|
||||||
|
"currency": "USD",
|
||||||
|
"tax": "0.00",
|
||||||
|
"quantity": 1,
|
||||||
|
"image_url": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"shipping_address": {
|
||||||
|
"recipient_name": "John Doe",
|
||||||
|
"line1": "NO 1 Nan Jin Road",
|
||||||
|
"city": "Shanghai",
|
||||||
|
"state": "Shanghai",
|
||||||
|
"postal_code": "200000",
|
||||||
|
"country_code": "C2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"related_resources": [
|
||||||
|
{
|
||||||
|
"sale": {
|
||||||
|
"id": "40C15537SF235414R",
|
||||||
|
"state": "completed",
|
||||||
|
"amount": {
|
||||||
|
"total": "1.00",
|
||||||
|
"currency": "USD",
|
||||||
|
"details": {
|
||||||
|
"subtotal": "1.00",
|
||||||
|
"shipping": "0.00",
|
||||||
|
"insurance": "0.00",
|
||||||
|
"handling_fee": "0.00",
|
||||||
|
"shipping_discount": "0.00",
|
||||||
|
"discount": "0.00"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"payment_mode": "INSTANT_TRANSFER",
|
||||||
|
"protection_eligibility": "ELIGIBLE",
|
||||||
|
"protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE",
|
||||||
|
"transaction_fee": {
|
||||||
|
"value": "0.33",
|
||||||
|
"currency": "USD"
|
||||||
|
},
|
||||||
|
"parent_payment": "PAYID-M3XGC5I9U46968696522382D",
|
||||||
|
"create_time": "2024-09-21T06:02:50Z",
|
||||||
|
"update_time": "2024-09-21T06:02:50Z",
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"href": "https://api.sandbox.paypal.com/v1/payments/sale/40C15537SF235414R",
|
||||||
|
"rel": "self",
|
||||||
|
"method": "GET"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"href": "https://api.sandbox.paypal.com/v1/payments/sale/40C15537SF235414R/refund",
|
||||||
|
"rel": "refund",
|
||||||
|
"method": "POST"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-M3XGC5I9U46968696522382D",
|
||||||
|
"rel": "parent_payment",
|
||||||
|
"method": "GET"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"intent": "sale",
|
||||||
|
"payer": {
|
||||||
|
"payment_method": "paypal",
|
||||||
|
"status": "VERIFIED",
|
||||||
|
"payer_info": {
|
||||||
|
"email": "sb-pztpq32086919@personal.example.com",
|
||||||
|
"first_name": "John",
|
||||||
|
"last_name": "Doe",
|
||||||
|
"payer_id": "8RSF8T3UK8NT2",
|
||||||
|
"shipping_address": {
|
||||||
|
"recipient_name": "John Doe",
|
||||||
|
"line1": "NO 1 Nan Jin Road",
|
||||||
|
"city": "Shanghai",
|
||||||
|
"state": "Shanghai",
|
||||||
|
"postal_code": "200000",
|
||||||
|
"country_code": "C2"
|
||||||
|
},
|
||||||
|
"phone": "2192589204",
|
||||||
|
"country_code": "C2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cart": "2Y943631F86154047"
|
||||||
|
},
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"href": "https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-53X19961TT501671H-9G343651RY447041V",
|
||||||
|
"rel": "self",
|
||||||
|
"method": "GET"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"href": "https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-53X19961TT501671H-9G343651RY447041V/resend",
|
||||||
|
"rel": "resend",
|
||||||
|
"method": "POST"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
2024-09-21 14:03:02,785 - API日志 - INFO - 回调接收到 开始执行支付,订单ID: PAYID-M3XGC5I9U46968696522382D, 付款人ID: 8RSF8T3UK8NT2
|
||||||
|
2024-09-21 14:03:02,795 - API日志 - INFO - 订单 PAYID-M3XGC5I9U46968696522382D 已经支付,不需要再次执行支付
|
||||||
|
2024-09-21 14:06:05,605 - API日志 - INFO - [支付执行] 获取的访问令牌: A21AAIVwWsRmSYRX_McyZN1RISbr4rs-amzjrc5R8H2rYRMZfH_Ia3QNs4HvEFVKxK2VAEMVe2dWfciYCJ5yhzGlbJgMBDuYQ
|
7
API日志.log.2024-09-21
Normal file
7
API日志.log.2024-09-21
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
2024-09-22 18:04:02,758 - API日志 - INFO - [支付执行] 获取的访问令牌: A21AAMX8udSqwN2hgx455qnPAztVrGR8JEIEml8vS52RV_fA0EhIk78KooWj4TccndnZ2M7RFuVn8fnxikBQF8Qhmy7giu35w
|
||||||
|
2024-09-22 18:09:52,408 - API日志 - INFO - [支付执行] 获取的访问令牌: A21AAMX8udSqwN2hgx455qnPAztVrGR8JEIEml8vS52RV_fA0EhIk78KooWj4TccndnZ2M7RFuVn8fnxikBQF8Qhmy7giu35w
|
||||||
|
2024-09-22 18:18:20,687 - API日志 - INFO - 接收到 PayPal Webhook 请求...
|
||||||
|
2024-09-22 18:18:20,688 - API日志 - INFO - 验证 PayPal Webhook 签名...
|
||||||
|
2024-09-22 18:18:20,768 - API日志 - INFO - 获取的访问令牌: A21AAMX8udSqwN2hgx455qnPAztVrGR8JEIEml8vS52RV_fA0EhIk78KooWj4TccndnZ2M7RFuVn8fnxikBQF8Qhmy7giu35w
|
||||||
|
2024-09-22 18:18:20,943 - API日志 - ERROR - Webhook 签名验证失败: {"verification_status":"FAILURE"}
|
||||||
|
2024-09-22 18:18:20,944 - API日志 - ERROR - Webhook 签名验证失败
|
22296
Illuminix-history_logs/Illuminix_2024-09-21_020002_log.log
Normal file
22296
Illuminix-history_logs/Illuminix_2024-09-21_020002_log.log
Normal file
File diff suppressed because it is too large
Load Diff
13633
Illuminix-history_logs/Illuminix_2024-09-22_020001_log.log
Normal file
13633
Illuminix-history_logs/Illuminix_2024-09-22_020001_log.log
Normal file
File diff suppressed because it is too large
Load Diff
4126
Illuminix-history_logs/Illuminix_2024-09-23_020002_log.log
Normal file
4126
Illuminix-history_logs/Illuminix_2024-09-23_020002_log.log
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,331 +1,337 @@
|
|||||||
import json
|
import json
|
||||||
import traceback
|
import traceback
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
from django.http import JsonResponse
|
from django.http import JsonResponse
|
||||||
from alipay.aop.api.AlipayClientConfig import AlipayClientConfig
|
from alipay.aop.api.AlipayClientConfig import AlipayClientConfig
|
||||||
from alipay.aop.api.DefaultAlipayClient import DefaultAlipayClient
|
from alipay.aop.api.DefaultAlipayClient import DefaultAlipayClient
|
||||||
from alipay.aop.api.domain.AlipayTradeAppPayModel import AlipayTradeAppPayModel
|
from alipay.aop.api.domain.AlipayTradeAppPayModel import AlipayTradeAppPayModel
|
||||||
from alipay.aop.api.domain.AlipayTradePagePayModel import AlipayTradePagePayModel
|
from alipay.aop.api.domain.AlipayTradePagePayModel import AlipayTradePagePayModel
|
||||||
from alipay.aop.api.request.AlipayTradePagePayRequest import AlipayTradePagePayRequest
|
from alipay.aop.api.request.AlipayTradePagePayRequest import AlipayTradePagePayRequest
|
||||||
from alipay.aop.api.request.AlipayTradeAppPayRequest import AlipayTradeAppPayRequest
|
from alipay.aop.api.request.AlipayTradeAppPayRequest import AlipayTradeAppPayRequest
|
||||||
from .models import Order, User, Plan
|
from .models import Order, User, Plan
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from alipay.aop.api.domain.AlipayTradeWapPayModel import AlipayTradeWapPayModel
|
from alipay.aop.api.domain.AlipayTradeWapPayModel import AlipayTradeWapPayModel
|
||||||
from alipay.aop.api.request.AlipayTradeWapPayRequest import AlipayTradeWapPayRequest
|
from alipay.aop.api.request.AlipayTradeWapPayRequest import AlipayTradeWapPayRequest
|
||||||
import requests
|
import requests
|
||||||
from decimal import Decimal, getcontext
|
from decimal import Decimal, getcontext
|
||||||
|
|
||||||
# 设置 Decimal 的精度
|
# 设置 Decimal 的精度
|
||||||
getcontext().prec = 28
|
getcontext().prec = 28
|
||||||
|
|
||||||
|
|
||||||
def get_usd_to_cny_rate():
|
def get_usd_to_cny_rate():
|
||||||
a = 7.2
|
a = 7.2
|
||||||
return a
|
return a
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_alipay_client_config(client_type='pc'):
|
def get_alipay_client_config(client_type='pc'):
|
||||||
"""
|
"""
|
||||||
根据环境和客户端类型返回支付宝配置
|
根据环境和客户端类型返回支付宝配置
|
||||||
"""
|
"""
|
||||||
alipay_client_config = AlipayClientConfig()
|
alipay_client_config = AlipayClientConfig()
|
||||||
|
|
||||||
if settings.ALIPAY_DEBUG:
|
if settings.ALIPAY_DEBUG:
|
||||||
print('请求沙箱支付')
|
print('请求沙箱支付')
|
||||||
alipay_client_config.server_url = 'https://openapi-sandbox.dl.alipaydev.com/gateway.do'
|
alipay_client_config.server_url = 'https://openapi-sandbox.dl.alipaydev.com/gateway.do'
|
||||||
if client_type == 'pc':
|
if client_type == 'pc':
|
||||||
alipay_client_config.app_id = settings.ALIPAY_APP_ID_SANDBOX_PC
|
alipay_client_config.app_id = settings.ALIPAY_APP_ID_SANDBOX_PC
|
||||||
alipay_client_config.app_private_key = settings.ALIPAY_APP_PRIVATE_KEY_SANDBOX_PC
|
alipay_client_config.app_private_key = settings.ALIPAY_APP_PRIVATE_KEY_SANDBOX_PC
|
||||||
alipay_client_config.alipay_public_key = settings.ALIPAY_PUBLIC_KEY_SANDBOX_PC
|
alipay_client_config.alipay_public_key = settings.ALIPAY_PUBLIC_KEY_SANDBOX_PC
|
||||||
elif client_type == 'mobile':
|
elif client_type == 'mobile':
|
||||||
alipay_client_config.app_id = settings.ALIPAY_APP_ID_SANDBOX_MOBILE
|
alipay_client_config.app_id = settings.ALIPAY_APP_ID_SANDBOX_MOBILE
|
||||||
alipay_client_config.app_private_key = settings.ALIPAY_APP_PRIVATE_KEY_SANDBOX_MOBILE
|
alipay_client_config.app_private_key = settings.ALIPAY_APP_PRIVATE_KEY_SANDBOX_MOBILE
|
||||||
alipay_client_config.alipay_public_key = settings.ALIPAY_PUBLIC_KEY_SANDBOX_MOBILE
|
alipay_client_config.alipay_public_key = settings.ALIPAY_PUBLIC_KEY_SANDBOX_MOBILE
|
||||||
else:
|
else:
|
||||||
print('请求生产支付')
|
print('请求生产支付')
|
||||||
alipay_client_config.server_url = 'https://openapi.alipay.com/gateway.do'
|
alipay_client_config.server_url = 'https://openapi.alipay.com/gateway.do'
|
||||||
if client_type == 'pc':
|
if client_type == 'pc':
|
||||||
alipay_client_config.app_id = settings.ALIPAY_APP_ID_PRODUCTION_PC
|
alipay_client_config.app_id = settings.ALIPAY_APP_ID_PRODUCTION_PC
|
||||||
alipay_client_config.app_private_key = settings.ALIPAY_APP_PRIVATE_KEY_PRODUCTION_PC
|
alipay_client_config.app_private_key = settings.ALIPAY_APP_PRIVATE_KEY_PRODUCTION_PC
|
||||||
alipay_client_config.alipay_public_key = settings.ALIPAY_PUBLIC_KEY_PRODUCTION_PC
|
alipay_client_config.alipay_public_key = settings.ALIPAY_PUBLIC_KEY_PRODUCTION_PC
|
||||||
elif client_type == 'mobile':
|
elif client_type == 'mobile':
|
||||||
alipay_client_config.app_id = settings.ALIPAY_APP_ID_PRODUCTION_MOBILE
|
alipay_client_config.app_id = settings.ALIPAY_APP_ID_PRODUCTION_MOBILE
|
||||||
alipay_client_config.app_private_key = settings.ALIPAY_APP_PRIVATE_KEY_PRODUCTION_MOBILE
|
alipay_client_config.app_private_key = settings.ALIPAY_APP_PRIVATE_KEY_PRODUCTION_MOBILE
|
||||||
alipay_client_config.alipay_public_key = settings.ALIPAY_PUBLIC_KEY_PRODUCTION_MOBILE
|
alipay_client_config.alipay_public_key = settings.ALIPAY_PUBLIC_KEY_PRODUCTION_MOBILE
|
||||||
|
|
||||||
return alipay_client_config
|
return alipay_client_config
|
||||||
def convert_cny_to_usd(price_cny):
|
def convert_cny_to_usd(price_cny):
|
||||||
"""
|
"""
|
||||||
将人民币价格转换为美元价格
|
将人民币价格转换为美元价格
|
||||||
:param price_cny: 人民币价格
|
:param price_cny: 人民币价格
|
||||||
:return: 美元价格,保留两位小数
|
:return: 美元价格,保留两位小数
|
||||||
"""
|
"""
|
||||||
# 获取美元对人民币的汇率
|
# 获取美元对人民币的汇率
|
||||||
usd_to_cny_rate = get_usd_to_cny_rate()
|
usd_to_cny_rate = get_usd_to_cny_rate()
|
||||||
print("原价:", price_cny)
|
print("原价:", price_cny)
|
||||||
print("汇率:", usd_to_cny_rate)
|
print("汇率:", usd_to_cny_rate)
|
||||||
return (Decimal(price_cny) * Decimal(usd_to_cny_rate)).quantize(Decimal('0.00'))
|
return (Decimal(price_cny) * Decimal(usd_to_cny_rate)).quantize(Decimal('0.00'))
|
||||||
@csrf_exempt
|
@csrf_exempt
|
||||||
def create_alipay_order(request):
|
def create_alipay_order(request):
|
||||||
"""
|
"""
|
||||||
创建支付宝订单并生成支付链接(电脑端)
|
创建支付宝订单并生成支付链接(电脑端)
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# 检查用户是否已登录
|
# 检查用户是否已登录
|
||||||
if not request.user.is_authenticated:
|
if not request.user.is_authenticated:
|
||||||
print("用户未登录")
|
print("用户未登录")
|
||||||
return JsonResponse({"code": 401, "message": "用户未登录"})
|
return JsonResponse({"code": 401, "message": "用户未登录"})
|
||||||
|
|
||||||
# 获取前端传递的数据
|
# 获取前端传递的数据
|
||||||
data = json.loads(request.body)
|
data = json.loads(request.body)
|
||||||
print(f"接收到的请求数据: {data}")
|
print(f"接收到的请求数据: {data}")
|
||||||
plan_title = data.get('title')
|
plan_title = data.get('title')
|
||||||
price = Decimal(data.get('price')) # 将价格转换为 Decimal 类型
|
price = Decimal(data.get('price')) # 将价格转换为 Decimal 类型
|
||||||
plan_id = data.get('id')
|
plan_id = data.get('id')
|
||||||
|
|
||||||
# 从数据库获取对应的套餐信息
|
# 从数据库获取对应的套餐信息
|
||||||
plan = Plan.objects.get(id=plan_id)
|
plan = Plan.objects.get(id=plan_id)
|
||||||
print(f"数据库中获取的套餐信息: {plan}")
|
print(f"数据库中获取的套餐信息: {plan}")
|
||||||
if not plan:
|
if not plan:
|
||||||
print("套餐信息不存在")
|
print("套餐信息不存在")
|
||||||
return JsonResponse({"code": 400, "message": "套餐信息不存在"})
|
return JsonResponse({"code": 400, "message": "套餐信息不存在"})
|
||||||
|
|
||||||
# 检查汇率是否有效
|
# 检查汇率是否有效
|
||||||
# 获取美元对人民币的汇率
|
# 获取美元对人民币的汇率
|
||||||
usd_to_cny_rate = get_usd_to_cny_rate()
|
usd_to_cny_rate = get_usd_to_cny_rate()
|
||||||
if not usd_to_cny_rate:
|
if not usd_to_cny_rate:
|
||||||
print("无法进行价格转换,汇率不可用")
|
print("无法进行价格转换,汇率不可用")
|
||||||
return JsonResponse({"code": 500, "message": "汇率不可用,无法创建订单"})
|
return JsonResponse({"code": 500, "message": "汇率不可用,无法创建订单"})
|
||||||
|
|
||||||
# 将套餐的人民币价格转换为美元价格
|
# 将套餐的人民币价格转换为美元价格
|
||||||
plan_price_usd = convert_cny_to_usd(plan.price)
|
plan_price_usd = convert_cny_to_usd(plan.price)
|
||||||
|
|
||||||
# 将人民币价格转换为美元价格
|
# 将人民币价格转换为美元价格
|
||||||
price_usd = convert_cny_to_usd(price)
|
price_usd = convert_cny_to_usd(price)
|
||||||
|
|
||||||
# 比较转换后的美元价格
|
# 比较转换后的美元价格
|
||||||
if not price_usd or plan_price_usd != price_usd:
|
if not price_usd or plan_price_usd != price_usd:
|
||||||
print(f"{plan_price_usd}套餐信息不匹配或价格不正确{price_usd}")
|
print(f"{plan_price_usd}套餐信息不匹配或价格不正确{price_usd}")
|
||||||
return JsonResponse({"code": 400, "message": "套餐信息不匹配或价格不正确"})
|
return JsonResponse({"code": 400, "message": "套餐信息不匹配或价格不正确"})
|
||||||
|
|
||||||
final_price = price_usd
|
final_price = price_usd
|
||||||
|
|
||||||
# 获取当前用户信息
|
# 获取当前用户信息
|
||||||
user = request.user
|
user = request.user
|
||||||
|
|
||||||
# 生成订单
|
# 生成订单
|
||||||
order_id = f"order_{datetime.now().strftime('%Y%m%d%H%M%S')}_{user.id}"
|
order_id = f"order_{datetime.now().strftime('%Y%m%d%H%M%S')}_{user.id}"
|
||||||
order = Order.objects.create(
|
order = Order.objects.create(
|
||||||
order_id=order_id,
|
order_id=order_id,
|
||||||
user=user,
|
user=user,
|
||||||
plan=plan,
|
plan=plan,
|
||||||
username=user.username,
|
username=user.username,
|
||||||
amount=final_price,
|
amount=final_price,
|
||||||
payment_method='alipay',
|
payment_method='alipay',
|
||||||
status='pending'
|
status='pending'
|
||||||
)
|
)
|
||||||
print(f"创建的订单信息: {order}")
|
print(f"创建的订单信息: {order}")
|
||||||
|
|
||||||
# 获取支付宝电脑端客户端配置
|
# 获取支付宝电脑端客户端配置
|
||||||
alipay_client_config = get_alipay_client_config(client_type='pc')
|
alipay_client_config = get_alipay_client_config(client_type='pc')
|
||||||
client = DefaultAlipayClient(alipay_client_config=alipay_client_config)
|
client = DefaultAlipayClient(alipay_client_config=alipay_client_config)
|
||||||
|
|
||||||
# 构造支付宝支付请求对象
|
# 构造支付宝支付请求对象
|
||||||
model = AlipayTradePagePayModel()
|
model = AlipayTradePagePayModel()
|
||||||
model.out_trade_no = order_id # 订单ID
|
model.out_trade_no = order_id # 订单ID
|
||||||
model.total_amount = str(final_price) # 订单金额
|
model.total_amount = str(final_price) # 订单金额
|
||||||
model.subject = plan_title # 商品名称
|
model.subject = plan_title # 商品名称
|
||||||
model.product_code = "FAST_INSTANT_TRADE_PAY" # 产品码
|
model.product_code = "FAST_INSTANT_TRADE_PAY" # 产品码
|
||||||
print(f"生成订单请求体: {model}")
|
print(f"生成订单请求体: {model}")
|
||||||
|
|
||||||
request = AlipayTradePagePayRequest(biz_model=model)
|
request = AlipayTradePagePayRequest(biz_model=model)
|
||||||
request.notify_url = settings.ALIPAY_NOTIFY_URL # 异步通知URL
|
request.notify_url = settings.ALIPAY_NOTIFY_URL # 异步通知URL
|
||||||
request.return_url = settings.ALIPAY_RETURN_URL # 同步返回URL
|
request.return_url = settings.ALIPAY_RETURN_URL # 同步返回URL
|
||||||
print(f"回调地址: {settings.ALIPAY_NOTIFY_URL}")
|
print(f"回调地址: {settings.ALIPAY_NOTIFY_URL}")
|
||||||
|
|
||||||
response = client.page_execute(request, http_method="GET")
|
response = client.page_execute(request, http_method="GET")
|
||||||
print(f"支付宝请求响应: {response}")
|
print(f"支付宝请求响应: {response}")
|
||||||
|
|
||||||
# 返回支付URL
|
# 返回支付URL
|
||||||
return JsonResponse({"code": 200, "message": "订单创建成功", "data": {'alipay_url': response}})
|
return JsonResponse({"code": 200, "message": "订单创建成功", "data": {'alipay_url': response}})
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"创建订单时出错: {traceback.format_exc()}")
|
print(f"创建订单时出错: {traceback.format_exc()}")
|
||||||
return JsonResponse({"code": 500, "message": f"创建订单时出错: {str(e)}"})
|
return JsonResponse({"code": 500, "message": f"创建订单时出错: {str(e)}"})
|
||||||
|
|
||||||
@csrf_exempt
|
@csrf_exempt
|
||||||
def create_alipay_h5_order(request):
|
def create_alipay_h5_order(request):
|
||||||
"""
|
"""
|
||||||
创建支付宝H5订单并生成支付链接
|
创建支付宝H5订单并生成支付链接
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# 检查用户是否已登录
|
# 检查用户是否已登录
|
||||||
if not request.user.is_authenticated:
|
if not request.user.is_authenticated:
|
||||||
return JsonResponse({"code": 401, "message": "用户未登录"})
|
return JsonResponse({"code": 401, "message": "用户未登录"})
|
||||||
|
|
||||||
# 获取前端传递的数据
|
# 获取前端传递的数据
|
||||||
data = json.loads(request.body)
|
data = json.loads(request.body)
|
||||||
plan_id = data.get('id')
|
plan_id = data.get('id')
|
||||||
plan_title = data.get('title')
|
plan_title = data.get('title')
|
||||||
price = Decimal(data.get('price')) # 将价格转换为 Decimal 类型
|
price = Decimal(data.get('price')) # 将价格转换为 Decimal 类型
|
||||||
|
|
||||||
# 获取对应套餐信息
|
# 获取对应套餐信息
|
||||||
plan = Plan.objects.get(id=plan_id)
|
plan = Plan.objects.get(id=plan_id)
|
||||||
if not plan:
|
if not plan:
|
||||||
return JsonResponse({"code": 400, "message": "套餐信息不存在"})
|
return JsonResponse({"code": 400, "message": "套餐信息不存在"})
|
||||||
|
|
||||||
# 检查汇率是否有效
|
# 检查汇率是否有效
|
||||||
# 获取美元对人民币的汇率
|
# 获取美元对人民币的汇率
|
||||||
usd_to_cny_rate = get_usd_to_cny_rate()
|
usd_to_cny_rate = get_usd_to_cny_rate()
|
||||||
if not usd_to_cny_rate:
|
if not usd_to_cny_rate:
|
||||||
print("无法进行价格转换,汇率不可用")
|
print("无法进行价格转换,汇率不可用")
|
||||||
return JsonResponse({"code": 500, "message": "汇率不可用,无法创建订单"})
|
return JsonResponse({"code": 500, "message": "汇率不可用,无法创建订单"})
|
||||||
|
|
||||||
# 将套餐的人民币价格转换为美元价格
|
# 将套餐的人民币价格转换为美元价格
|
||||||
plan_price_usd = convert_cny_to_usd(plan.price)
|
plan_price_usd = convert_cny_to_usd(plan.price)
|
||||||
|
|
||||||
# 将人民币价格转换为美元价格
|
# 将人民币价格转换为美元价格
|
||||||
price_usd = convert_cny_to_usd(price)
|
price_usd = convert_cny_to_usd(price)
|
||||||
|
|
||||||
# 比较转换后的美元价格
|
# 比较转换后的美元价格
|
||||||
if not price_usd or plan_price_usd != price_usd:
|
if not price_usd or plan_price_usd != price_usd:
|
||||||
return JsonResponse({"code": 400, "message": "套餐信息不匹配或价格不正确"})
|
return JsonResponse({"code": 400, "message": "套餐信息不匹配或价格不正确"})
|
||||||
|
|
||||||
final_price = price_usd
|
final_price = price_usd
|
||||||
|
|
||||||
# 创建订单
|
# 创建订单
|
||||||
user = request.user
|
user = request.user
|
||||||
order_id = f"order_{datetime.now().strftime('%Y%m%d%H%M%S')}_{user.id}"
|
order_id = f"order_{datetime.now().strftime('%Y%m%d%H%M%S')}_{user.id}"
|
||||||
order = Order.objects.create(
|
order = Order.objects.create(
|
||||||
order_id=order_id,
|
order_id=order_id,
|
||||||
user=user,
|
user=user,
|
||||||
plan=plan,
|
plan=plan,
|
||||||
username=user.username,
|
username=user.username,
|
||||||
amount=final_price,
|
amount=final_price,
|
||||||
payment_method='alipay',
|
payment_method='alipay',
|
||||||
status='pending'
|
status='pending'
|
||||||
)
|
)
|
||||||
|
|
||||||
# 获取支付宝H5客户端配置
|
# 获取支付宝H5客户端配置
|
||||||
alipay_client_config = get_alipay_client_config(client_type='mobile')
|
alipay_client_config = get_alipay_client_config(client_type='mobile')
|
||||||
client = DefaultAlipayClient(alipay_client_config=alipay_client_config)
|
client = DefaultAlipayClient(alipay_client_config=alipay_client_config)
|
||||||
|
|
||||||
# 构造支付宝H5支付请求对象
|
# 构造支付宝H5支付请求对象
|
||||||
model = AlipayTradeWapPayModel()
|
model = AlipayTradeWapPayModel()
|
||||||
model.out_trade_no = order_id
|
model.out_trade_no = order_id
|
||||||
model.total_amount = str(final_price)
|
model.total_amount = str(final_price)
|
||||||
model.subject = plan_title
|
model.subject = plan_title
|
||||||
model.product_code = "QUICK_WAP_WAY"
|
model.product_code = "QUICK_WAP_WAY"
|
||||||
|
|
||||||
request = AlipayTradeWapPayRequest(biz_model=model)
|
request = AlipayTradeWapPayRequest(biz_model=model)
|
||||||
request.notify_url = settings.ALIPAY_NOTIFY_URL # 异步通知URL
|
request.notify_url = settings.ALIPAY_NOTIFY_URL # 异步通知URL
|
||||||
request.return_url = settings.ALIPAY_RETURN_URL # 同步返回URL
|
request.return_url = settings.ALIPAY_RETURN_URL # 同步返回URL
|
||||||
|
|
||||||
# 执行请求,获取支付宝H5支付跳转链接
|
# 执行请求,获取支付宝H5支付跳转链接
|
||||||
response = client.page_execute(request, http_method="GET")
|
response = client.page_execute(request, http_method="GET")
|
||||||
|
|
||||||
return JsonResponse({"code": 200, "message": "订单创建成功", "data": {'alipay_url': response}})
|
return JsonResponse({"code": 200, "message": "订单创建成功", "data": {'alipay_url': response}})
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return JsonResponse({"code": 500, "message": f"创建H5订单时出错: {str(e)}"})
|
return JsonResponse({"code": 500, "message": f"创建H5订单时出错: {str(e)}"})
|
||||||
|
|
||||||
|
|
||||||
def update_user_membership(order):
|
def update_user_membership(order):
|
||||||
"""
|
"""
|
||||||
更新用户积分信息
|
更新用户积分信息
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# 验证订单状态是否为成功
|
# 如果订单已经是 'completed' 状态,说明已经处理过,跳过处理
|
||||||
if order.status not in ("completed", "TRADE_SUCCESS", "TRADE_FINISHED"):
|
if order.status == 'completed':
|
||||||
print("订单未成功")
|
print("订单已处理,无需再次更新")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# 从订单中获取关联的套餐信息
|
# 获取套餐信息
|
||||||
plan = order.plan
|
plan = order.plan
|
||||||
|
|
||||||
# 检查汇率是否有效
|
# 检查汇率是否有效
|
||||||
# 获取美元对人民币的汇率
|
usd_to_cny_rate = get_usd_to_cny_rate()
|
||||||
usd_to_cny_rate = get_usd_to_cny_rate()
|
if not usd_to_cny_rate:
|
||||||
if not usd_to_cny_rate:
|
print("无法进行价格转换,汇率不可用")
|
||||||
print("无法进行价格转换,汇率不可用")
|
return False
|
||||||
return False
|
|
||||||
|
|
||||||
# 将订单金额从美元转换回人民币
|
# 确保订单的套餐与实际套餐详情匹配
|
||||||
order_amount_cny = order.amount
|
if not plan or convert_cny_to_usd(plan.price) != order.amount:
|
||||||
|
print(f"订单的套餐信息与实际套餐不匹配convert_cny_to_usd(plan.price):{convert_cny_to_usd(plan.price)}--order_amount_cny{order.amount}")
|
||||||
# 确保订单的套餐与实际套餐详情匹配
|
return False
|
||||||
if not plan or convert_cny_to_usd(plan.price) != order_amount_cny:
|
|
||||||
print(f"订单的套餐信息与实际套餐不匹配plan.price{plan.price}---")
|
# 获取用户信息
|
||||||
return False
|
user = order.user
|
||||||
|
|
||||||
# 获取用户信息
|
# 更新用户的积分
|
||||||
user = order.user
|
user.points += plan.credits_per_month
|
||||||
|
user.save()
|
||||||
# 更新用户的积分
|
|
||||||
user.points += plan.credits_per_month
|
# 更新订单状态为 'completed'
|
||||||
user.save()
|
order.status = 'completed'
|
||||||
|
order.save()
|
||||||
print(f"用户 {user.username} 的积分已更新")
|
|
||||||
return True
|
print(f"用户 {user.username} 的积分已更新--增加{plan.credits_per_month}--现在{user.points}")
|
||||||
|
return True
|
||||||
except Exception as e:
|
|
||||||
print(f"更新用户积分信息时出错: {e}")
|
except Exception as e:
|
||||||
return False
|
print(f"更新用户积分信息时出错: {e}")
|
||||||
|
return False
|
||||||
@csrf_exempt
|
|
||||||
def alipay_notify(request):
|
|
||||||
"""
|
@csrf_exempt
|
||||||
支付宝异步通知处理,验证支付结果
|
def alipay_notify(request):
|
||||||
"""
|
"""
|
||||||
try:
|
支付宝异步通知处理,验证支付结果
|
||||||
data = request.POST.dict()
|
"""
|
||||||
print(f"接收到的异步通知数据: {data}")
|
try:
|
||||||
|
data = request.POST.dict()
|
||||||
# 直接使用返回的数据处理逻辑
|
print(f"接收到的异步通知数据: {data}")
|
||||||
order_id = data.get('out_trade_no')
|
|
||||||
trade_status = data.get('trade_status')
|
# 获取订单ID和交易状态
|
||||||
print(f"订单ID: {order_id}, 支付状态: {trade_status}")
|
order_id = data.get('out_trade_no')
|
||||||
|
trade_status = data.get('trade_status')
|
||||||
try:
|
print(f"订单ID: {order_id}, 支付状态: {trade_status}")
|
||||||
order = Order.objects.get(order_id=order_id)
|
|
||||||
except Order.DoesNotExist:
|
try:
|
||||||
print(f"订单 {order_id} 不存在")
|
order = Order.objects.get(order_id=order_id)
|
||||||
return JsonResponse({"code": 400, "message": "订单不存在"})
|
except Order.DoesNotExist:
|
||||||
|
print(f"订单 {order_id} 不存在")
|
||||||
if trade_status in ("TRADE_SUCCESS", "TRADE_FINISHED"):
|
return JsonResponse({"code": 400, "message": "订单不存在"})
|
||||||
order.status = 'completed'
|
|
||||||
order.save()
|
# 如果订单状态已经是 'completed',表示已经处理过,无需再次处理
|
||||||
print(f"订单 {order_id} 支付成功")
|
if order.status == 'completed':
|
||||||
update_user_membership(order)
|
print(f"订单 {order_id} 已处理,无需再次更新")
|
||||||
return JsonResponse({"code": 200, "message": "支付成功"})
|
return JsonResponse({"code": 200, "message": "订单已处理"})
|
||||||
else:
|
|
||||||
order.status = 'failed'
|
# 如果支付成功或交易完成,更新订单状态并处理会员更新
|
||||||
order.save()
|
if trade_status in ("TRADE_SUCCESS", "TRADE_FINISHED"):
|
||||||
print(f"订单 {order_id} 支付失败或未成功")
|
print(f"订单 {order_id} 支付成功")
|
||||||
return JsonResponse({"code": 400, "message": "支付未成功或失败"})
|
update_user_membership(order)
|
||||||
|
return JsonResponse({"code": 200, "message": "支付成功"})
|
||||||
except Exception as e:
|
else:
|
||||||
print(f"处理异步通知时出错: {traceback.format_exc()}")
|
order.status = 'failed'
|
||||||
return JsonResponse({"code": 500, "message": f"处理异步通知时出错: {str(e)}"})
|
order.save()
|
||||||
|
print(f"订单 {order_id} 支付失败或未成功")
|
||||||
@csrf_exempt
|
return JsonResponse({"code": 400, "message": "支付未成功或失败"})
|
||||||
def alipay_return(request):
|
|
||||||
"""
|
except Exception as e:
|
||||||
支付宝同步返回处理,用于用户支付后的页面跳转
|
print(f"处理异步通知时出错: {traceback.format_exc()}")
|
||||||
"""
|
return JsonResponse({"code": 500, "message": f"处理异步通知时出错: {str(e)}"})
|
||||||
try:
|
|
||||||
data = request.GET.dict()
|
@csrf_exempt
|
||||||
print(f"接收到的同步返回数据: {data}")
|
def alipay_return(request):
|
||||||
|
"""
|
||||||
# 直接使用返回的数据处理逻辑
|
支付宝同步返回处理,用于用户支付后的页面跳转
|
||||||
order_id = data.get('out_trade_no')
|
"""
|
||||||
print(f"订单 {order_id} 支付成功")
|
try:
|
||||||
return JsonResponse({"code": 200, "message": f"支付成功,订单号:{order_id}"})
|
data = request.GET.dict()
|
||||||
|
print(f"接收到的同步返回数据: {data}")
|
||||||
except Exception as e:
|
|
||||||
print(f"处理同步返回时出错: {traceback.format_exc()}")
|
# 直接使用返回的数据处理逻辑
|
||||||
return JsonResponse({"code": 500, "message": f"处理同步返回时出错: {str(e)}"})
|
order_id = data.get('out_trade_no')
|
||||||
|
print(f"订单 {order_id} 支付成功")
|
||||||
|
return JsonResponse({"code": 200, "message": f"支付成功,订单号:{order_id}"})
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"处理同步返回时出错: {traceback.format_exc()}")
|
||||||
|
return JsonResponse({"code": 500, "message": f"处理同步返回时出错: {str(e)}"})
|
||||||
|
1008
WebAdmin/api.py
1008
WebAdmin/api.py
File diff suppressed because it is too large
Load Diff
@ -1,332 +1,401 @@
|
|||||||
import json
|
import json
|
||||||
import time
|
import time
|
||||||
import requests
|
import requests
|
||||||
from django.http import JsonResponse
|
from django.http import JsonResponse
|
||||||
from .models import VideoGeneration
|
from .models import VideoGeneration
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
from .base import logger,deduct_points
|
from .base import logger,deduct_points
|
||||||
def generate_video_id(user_id):
|
import http.client
|
||||||
"""
|
import random
|
||||||
根据用户ID和当前时间戳生成唯一的视频ID
|
import urllib
|
||||||
"""
|
import hashlib
|
||||||
timestamp = int(time.time())
|
from langdetect import detect
|
||||||
video_id = f"{timestamp}_{user_id}"
|
from langdetect.lang_detect_exception import LangDetectException
|
||||||
print(f"生成的视频ID: {video_id}")
|
def generate_video_id(user_id):
|
||||||
return video_id
|
"""
|
||||||
|
根据用户ID和当前时间戳生成唯一的视频ID
|
||||||
def get_dimensions(model, width=None, height=None):
|
"""
|
||||||
"""
|
timestamp = int(time.time())
|
||||||
根据模型返回相应的宽高分辨率:
|
video_id = f"{timestamp}_{user_id}"
|
||||||
gen3: 最大1280x768
|
print(f"生成的视频ID: {video_id}")
|
||||||
gen2: 可传入前端指定的宽高,默认最大1920x1080
|
return video_id
|
||||||
"""
|
|
||||||
if model == 'gen3':
|
appid = '20240601002067404' # 填写你的appid
|
||||||
return 1280, 768
|
secretKey = '6pRZ9HCSqGuMqzLO55hB' # 填写你的密钥
|
||||||
elif model == 'gen2':
|
|
||||||
# 如果前端提供了 width 和 height,则使用传入的值,否则使用默认值
|
def translate(text, from_lang='auto', to_lang='en'):
|
||||||
if width and height:
|
myurl = '/api/trans/vip/translate'
|
||||||
return width, height
|
salt = random.randint(32768, 65536)
|
||||||
return 1920, 1080
|
sign = appid + text + str(salt) + secretKey
|
||||||
else:
|
sign = hashlib.md5(sign.encode()).hexdigest()
|
||||||
raise ValueError(f"不支持的模型: {model}")
|
myurl = (myurl + '?appid=' + appid + '&q=' + urllib.parse.quote(text) +
|
||||||
|
'&from=' + from_lang + '&to=' + to_lang + '&salt=' + str(salt) +
|
||||||
def get_headers():
|
'&sign=' + sign)
|
||||||
"""
|
|
||||||
返回统一的请求头
|
try:
|
||||||
"""
|
httpClient = http.client.HTTPConnection('api.fanyi.baidu.com')
|
||||||
return {
|
httpClient.request('GET', myurl)
|
||||||
"accept": "application/json",
|
|
||||||
"content-type": "application/json",
|
# response是HTTPResponse对象
|
||||||
"Authorization": "12e76710fad2047db8c0cc6b25987e2a2" # 替换为你的真实授权密钥
|
response = httpClient.getresponse()
|
||||||
}
|
result_all = response.read().decode("utf-8")
|
||||||
|
result = json.loads(result_all)
|
||||||
@csrf_exempt
|
print(f'请求结果{result}')
|
||||||
def text_to_video(request):
|
return result['trans_result'][0]['dst']
|
||||||
"""
|
|
||||||
文本生成视频接口
|
except Exception as e:
|
||||||
"""
|
return str(e)
|
||||||
if request.method == "POST":
|
|
||||||
try:
|
finally:
|
||||||
if not request.user.is_authenticated:
|
if httpClient:
|
||||||
return JsonResponse({'code': 401, 'message': '用户未登录'})
|
httpClient.close()
|
||||||
user = request.user
|
|
||||||
data = json.loads(request.body)
|
|
||||||
|
def get_dimensions(model, width=None, height=None):
|
||||||
# 获取参数
|
"""
|
||||||
text_prompt = data.get('text_prompt')
|
根据模型返回相应的宽高分辨率:
|
||||||
style = data.get('style', '') # 选择的风格,默认是 'general'
|
gen3: 最大1280x768
|
||||||
model = data.get('model', 'gen3') # 选择模型,默认是 'gen3'
|
gen2: 可传入前端指定的宽高,默认最大1920x1080
|
||||||
time_duration = int(data.get('time', 5)) # 视频时长
|
"""
|
||||||
motion = int(data.get('motion', 5)) # 视频丰富度参数
|
if model == 'gen3':
|
||||||
width = data.get('width') # 由前端传入的宽度(仅限gen2)
|
return 1280, 768
|
||||||
height = data.get('height') # 由前端传入的高度(仅限gen2)
|
elif model == 'gen2':
|
||||||
|
# 如果前端提供了 width 和 height,则使用传入的值,否则使用默认值
|
||||||
print(f"生成模型: {model}, 时长: {time_duration}, 文本: {text_prompt}, 宽高: {width}x{height}, 画面丰富度: {motion}")
|
if width and height:
|
||||||
|
return width, height
|
||||||
result = deduct_points(user, "text-to-video")
|
return 1920, 1080
|
||||||
if result is not True:
|
else:
|
||||||
return result # 返回积分不足的响应
|
raise ValueError(f"不支持的模型: {model}")
|
||||||
|
|
||||||
# 验证模型和时长限制
|
def get_headers():
|
||||||
if model == 'gen3' and time_duration not in [5, 10]:
|
"""
|
||||||
return JsonResponse({'code': 400, 'message': 'gen3 模型只支持 5s 或 10s 的时长'})
|
返回统一的请求头
|
||||||
if model == 'gen2' and time_duration != 4:
|
"""
|
||||||
return JsonResponse({'code': 400, 'message': 'gen2 模型只支持 4s 的时长'})
|
return {
|
||||||
|
"accept": "application/json",
|
||||||
# 生成视频ID
|
"content-type": "application/json",
|
||||||
video_id = generate_video_id(user.id)
|
"Authorization": "12e76710fad2047db8c0cc6b25987e2a2" # 替换为你的真实授权密钥
|
||||||
|
}
|
||||||
# 根据模型获取宽高
|
|
||||||
width, height = get_dimensions(model, width, height)
|
|
||||||
print(f"生成的视频分辨率: {width}x{height}")
|
|
||||||
|
@csrf_exempt
|
||||||
# 准备POST请求数据
|
def text_to_video(request):
|
||||||
payload = {
|
"""
|
||||||
"text_prompt": f"{text_prompt}. Style: {style}",
|
文本生成视频接口
|
||||||
"model": model,
|
"""
|
||||||
"width": width,
|
if request.method == "POST":
|
||||||
"height": height,
|
try:
|
||||||
"motion": motion, # 视频画面丰富度
|
if not request.user.is_authenticated:
|
||||||
"seed": 0,
|
return JsonResponse({'code': 401, 'message': '用户未登录'})
|
||||||
"upscale": False,
|
user = request.user
|
||||||
"interpolate": False,
|
data = json.loads(request.body)
|
||||||
"callback_url": "https://www.typeframes.ai/api/callback/",
|
text_prompt = data.get('text_prompt')
|
||||||
"time": time_duration # 视频时长
|
print(f'文生视频原内容---:{text_prompt}')
|
||||||
}
|
|
||||||
print(f'text_to_video 请求体: {payload}')
|
# 判断是否需要翻译
|
||||||
|
try:
|
||||||
# 发送请求到API
|
language = detect(text_prompt)
|
||||||
response = requests.post('https://api.aivideoapi.com/runway/generate/text', json=payload, headers=get_headers())
|
print(f"检测到的语言: {language}")
|
||||||
print(f"API响应状态码: {response.status_code}")
|
if language == 'en':
|
||||||
print(f"API响应内容: {response.text}")
|
description = text_prompt # 英文无需翻译
|
||||||
|
else:
|
||||||
# 解析响应数据
|
description = translate(text_prompt, 'auto', 'en') # 翻译成英文
|
||||||
if response.status_code == 200:
|
print(f'文生视频翻译内容---:{description}')
|
||||||
res_data = response.json()
|
except LangDetectException:
|
||||||
uuid = res_data.get('uuid')
|
return JsonResponse({'code': 400, 'message': '无法检测语言,请输入有效文本'})
|
||||||
|
|
||||||
# 保存生成记录到数据库
|
# 获取参数
|
||||||
video_generation = VideoGeneration.objects.create(
|
style = data.get('style', '') # 选择的风格,默认是 'general'
|
||||||
video_id=video_id,
|
model = data.get('model', 'gen3') # 选择模型,默认是 'gen3'
|
||||||
user=user,
|
time_duration = int(data.get('time', 5)) # 视频时长
|
||||||
text=text_prompt,
|
motion = int(data.get('motion', 5)) # 视频丰富度参数
|
||||||
status='in_progress',
|
width = data.get('width') # 由前端传入的宽度(仅限gen2)
|
||||||
pid=uuid,
|
height = data.get('height') # 由前端传入的高度(仅限gen2)
|
||||||
media_type=f'{model}_text_to_video',
|
|
||||||
slug=f'text-to-video',
|
print(f"生成模型: {model}, 时长: {time_duration}, 文本: {text_prompt}, 宽高: {width}x{height}, 画面丰富度: {motion}")
|
||||||
ratio=f"{width}:{height}"
|
|
||||||
)
|
result = deduct_points(user, "text-to-video")
|
||||||
video_generation.save()
|
if result is not True:
|
||||||
|
return result # 返回积分不足的响应
|
||||||
# 返回成功响应
|
|
||||||
return JsonResponse({
|
# 验证模型和时长限制
|
||||||
'code': 200,
|
if model == 'gen3' and time_duration not in [5, 10]:
|
||||||
'message': '请求成功,视频正在生成中',
|
return JsonResponse({'code': 400, 'message': 'gen3 模型只支持 5s 或 10s 的时长'})
|
||||||
'data': {
|
if model == 'gen2' and time_duration != 4:
|
||||||
'video_id': video_generation.video_id,
|
return JsonResponse({'code': 400, 'message': 'gen2 模型只支持 4s 的时长'})
|
||||||
'status': video_generation.status,
|
|
||||||
'pid': uuid
|
# 生成视频ID
|
||||||
}
|
video_id = generate_video_id(user.id)
|
||||||
})
|
|
||||||
else:
|
# 根据模型获取宽高
|
||||||
return JsonResponse({'code': response.status_code, 'message': 'API请求失败', 'data': {}})
|
width, height = get_dimensions(model, width, height)
|
||||||
|
print(f"生成的视频分辨率: {width}x{height}")
|
||||||
except Exception as e:
|
|
||||||
print(f"发生错误: {str(e)}")
|
# 准备POST请求数据
|
||||||
return JsonResponse({'code': 500, 'message': f'内部错误: {str(e)}', 'data': {}})
|
payload = {
|
||||||
|
"text_prompt": f"{description}. Style: {style}",
|
||||||
return JsonResponse({'code': 405, 'message': '请求方法错误', 'data': {}})
|
"model": model,
|
||||||
|
"width": width,
|
||||||
|
"height": height,
|
||||||
|
"motion": motion, # 视频画面丰富度
|
||||||
@csrf_exempt
|
"seed": 0,
|
||||||
def image_to_video(request):
|
"upscale": True,
|
||||||
"""
|
"interpolate": True,
|
||||||
图片生成视频接口,图片宽高自适应
|
"callback_url": "https://www.typeframes.ai/api/callback/",
|
||||||
"""
|
"time": time_duration # 视频时长
|
||||||
if request.method == "POST":
|
}
|
||||||
try:
|
print(f'text_to_video 请求体: {payload}')
|
||||||
if not request.user.is_authenticated:
|
|
||||||
return JsonResponse({'code': 401, 'message': '用户未登录'})
|
# 发送请求到API
|
||||||
user = request.user
|
response = requests.post('https://api.aivideoapi.com/runway/generate/text', json=payload, headers=get_headers())
|
||||||
data = json.loads(request.body)
|
print(f"API响应状态码: {response.status_code}")
|
||||||
|
print(f"API响应内容: {response.text}")
|
||||||
# 获取参数
|
|
||||||
text_prompt = data.get('text_prompt')
|
# 解析响应数据
|
||||||
image_url = data.get('image_url')
|
if response.status_code == 200:
|
||||||
model = data.get('model', 'gen3') # 选择模型,默认是 'gen3'
|
res_data = response.json()
|
||||||
time_duration = int(data.get('time', 5)) # 视频时长
|
uuid = res_data.get('uuid')
|
||||||
motion = int(data.get('motion', 5)) # 视频丰富度
|
|
||||||
|
# 保存生成记录到数据库
|
||||||
print(f"生成模型: {model}, 图片地址: {image_url}, 时长: {time_duration}, 画面丰富度: {motion}")
|
video_generation = VideoGeneration.objects.create(
|
||||||
|
video_id=video_id,
|
||||||
result = deduct_points(user, "img-to-video")
|
user=user,
|
||||||
if result is not True:
|
text=text_prompt,
|
||||||
return result # 返回积分不足的响应
|
status='in_progress',
|
||||||
|
pid=uuid,
|
||||||
# 验证模型和时长限制
|
media_type=f'{model}_text_to_video',
|
||||||
if model == 'gen3' and time_duration not in [5, 10]:
|
slug=f'text-to-video',
|
||||||
return JsonResponse({'code': 400, 'message': 'gen3 模型只支持 5s 或 10s 的时长'})
|
ratio=f"{width}:{height}"
|
||||||
if model == 'gen2' and time_duration != 4:
|
)
|
||||||
return JsonResponse({'code': 400, 'message': 'gen2 模型只支持 4s 的时长'})
|
video_generation.save()
|
||||||
|
|
||||||
# 生成视频ID
|
# 返回成功响应
|
||||||
video_id = generate_video_id(user.id)
|
return JsonResponse({
|
||||||
|
'code': 200,
|
||||||
# 准备POST请求数据,宽高不需要传入,图片自适应
|
'message': '请求成功,视频正在生成中',
|
||||||
payload = {
|
'data': {
|
||||||
"text_prompt": text_prompt,
|
'video_id': video_generation.video_id,
|
||||||
"model": model,
|
'status': video_generation.status,
|
||||||
"img_prompt": image_url,
|
'pid': uuid
|
||||||
"image_as_end_frame": False, # 图片不作为最后一帧
|
}
|
||||||
"motion": motion, # 视频丰富度
|
})
|
||||||
"seed": 0,
|
else:
|
||||||
"upscale": False,
|
return JsonResponse({'code': response.status_code, 'message': 'API请求失败', 'data': {}})
|
||||||
"interpolate": False,
|
|
||||||
"callback_url": "https://www.typeframes.ai/api/callback/",
|
except Exception as e:
|
||||||
"time": time_duration # 视频时长
|
print(f"发生错误: {str(e)}")
|
||||||
}
|
return JsonResponse({'code': 500, 'message': f'内部错误: {str(e)}', 'data': {}})
|
||||||
print(f'img_to_video 请求体: {payload}')
|
|
||||||
|
return JsonResponse({'code': 405, 'message': '请求方法错误', 'data': {}})
|
||||||
# 请求头
|
|
||||||
headers = get_headers()
|
|
||||||
|
|
||||||
# 发送请求到API
|
|
||||||
response = requests.post('https://api.aivideoapi.com/runway/generate/imageDescription', json=payload, headers=headers)
|
|
||||||
print(f"API响应状态码: {response.status_code}")
|
|
||||||
print(f"API响应内容: {response.text}")
|
@csrf_exempt
|
||||||
|
def image_to_video(request):
|
||||||
# 解析响应数据
|
"""
|
||||||
if response.status_code == 200:
|
图片生成视频接口,图片宽高自适应
|
||||||
res_data = response.json()
|
"""
|
||||||
uuid = res_data.get('uuid')
|
if request.method == "POST":
|
||||||
|
try:
|
||||||
# 保存生成记录到数据库
|
if not request.user.is_authenticated:
|
||||||
video_generation = VideoGeneration.objects.create(
|
return JsonResponse({'code': 401, 'message': '用户未登录'})
|
||||||
video_id=video_id,
|
user = request.user
|
||||||
user=user,
|
data = json.loads(request.body)
|
||||||
text=text_prompt,
|
|
||||||
status='in_progress',
|
# 获取参数
|
||||||
pid=uuid,
|
text_prompt = data.get('text_prompt')
|
||||||
media_type=f'{model}_img_to_video',
|
print(f' 图片生视频原内容---:{text_prompt}')
|
||||||
slug=f'img-to-video',
|
|
||||||
ratio="auto" # 图片自适应宽高
|
# 判断是否需要翻译
|
||||||
)
|
try:
|
||||||
video_generation.save()
|
language = detect(text_prompt)
|
||||||
|
print(f"检测到的语言: {language}")
|
||||||
# 返回成功响应
|
if language == 'en':
|
||||||
return JsonResponse({
|
description = text_prompt # 英文无需翻译
|
||||||
'code': 200,
|
else:
|
||||||
'message': '请求成功,视频正在生成中',
|
description = translate(text_prompt, 'auto', 'en') # 翻译成英文
|
||||||
'data': {
|
print(f'图片生视翻译内容---:{description}')
|
||||||
'video_id': video_generation.video_id,
|
except LangDetectException:
|
||||||
'status': video_generation.status,
|
return JsonResponse({'code': 400, 'message': '无法检测语言,请输入有效文本'})
|
||||||
'pid': uuid
|
|
||||||
}
|
image_url = data.get('image_url')
|
||||||
})
|
model = data.get('model', 'gen3') # 选择模型,默认是 'gen3'
|
||||||
else:
|
time_duration = int(data.get('time', 5)) # 视频时长
|
||||||
return JsonResponse({'code': response.status_code, 'message': 'API请求失败', 'data': {}})
|
motion = int(data.get('motion', 5)) # 视频丰富度
|
||||||
|
|
||||||
except Exception as e:
|
print(f"生成模型: {model}, 图片地址: {image_url}, 时长: {time_duration}, 画面丰富度: {motion}")
|
||||||
print(f"发生错误: {str(e)}")
|
|
||||||
return JsonResponse({'code': 500, 'message': f'内部错误: {str(e)}', 'data': {}})
|
result = deduct_points(user, "img-to-video")
|
||||||
|
if result is not True:
|
||||||
return JsonResponse({'code': 405, 'message': '请求方法错误', 'data': {}})
|
return result # 返回积分不足的响应
|
||||||
|
|
||||||
|
# 验证模型和时长限制
|
||||||
|
if model == 'gen3' and time_duration not in [5, 10]:
|
||||||
@csrf_exempt
|
return JsonResponse({'code': 400, 'message': 'gen3 模型只支持 5s 或 10s 的时长'})
|
||||||
def extend_video(request):
|
if model == 'gen2' and time_duration != 4:
|
||||||
"""
|
return JsonResponse({'code': 400, 'message': 'gen2 模型只支持 4s 的时长'})
|
||||||
延长视频的函数,发送请求到 /runway/extend
|
|
||||||
"""
|
# 生成视频ID
|
||||||
if request.method == "POST":
|
video_id = generate_video_id(user.id)
|
||||||
try:
|
|
||||||
if not request.user.is_authenticated:
|
# 准备POST请求数据,宽高不需要传入,图片自适应
|
||||||
return JsonResponse({'code': 401, 'message': '用户未登录'})
|
payload = {
|
||||||
user = request.user
|
"text_prompt": description,
|
||||||
data = json.loads(request.body)
|
"model": model,
|
||||||
|
"img_prompt": image_url,
|
||||||
# 获取参数
|
"image_as_end_frame": False, # 图片不作为最后一帧
|
||||||
pid = data.get('pid')
|
"motion": motion, # 视频丰富度
|
||||||
motion = int(data.get('motion', 5)) # 视频丰富度
|
"seed": 0,
|
||||||
|
"upscale": True,
|
||||||
# 获取当前视频生成记录
|
"interpolate": True,
|
||||||
video_generation = VideoGeneration.objects.get(pid=pid)
|
"callback_url": "https://www.typeframes.ai/api/callback/",
|
||||||
|
"time": time_duration # 视频时长
|
||||||
# 通过 media_type 判断模型是 gen3 还是 gen2
|
}
|
||||||
if 'gen3' in video_generation.media_type:
|
print(f'img_to_video 请求体: {payload}')
|
||||||
model = 'gen3'
|
|
||||||
# 验证 gen3 的延长逻辑
|
# 请求头
|
||||||
if video_generation.extension_count >= 1 or video_generation.time_duration >= 10:
|
headers = get_headers()
|
||||||
return JsonResponse({'code': 400, 'message': 'gen3 最大时长为 10s,无法继续延长'})
|
|
||||||
time_extension = 5 # 每次延长 5 秒
|
# 发送请求到API
|
||||||
|
response = requests.post('https://api.aivideoapi.com/runway/generate/imageDescription', json=payload, headers=headers)
|
||||||
elif 'gen2' in video_generation.media_type:
|
print(f"API响应状态码: {response.status_code}")
|
||||||
model = 'gen2'
|
print(f"API响应内容: {response.text}")
|
||||||
# 验证 gen2 的延长逻辑
|
|
||||||
if video_generation.extension_count >= 2 or video_generation.time_duration >= 12:
|
# 解析响应数据
|
||||||
return JsonResponse({'code': 400, 'message': 'gen2 最大时长为 12s,无法继续延长'})
|
if response.status_code == 200:
|
||||||
time_extension = 4 # 每次延长 4 秒
|
res_data = response.json()
|
||||||
|
uuid = res_data.get('uuid')
|
||||||
else:
|
|
||||||
return JsonResponse({'code': 400, 'message': '未知的模型类型'})
|
# 保存生成记录到数据库
|
||||||
|
video_generation = VideoGeneration.objects.create(
|
||||||
result = deduct_points(user, video_generation.slug)
|
video_id=video_id,
|
||||||
if result is not True:
|
user=user,
|
||||||
return result # 返回积分不足的响应
|
text=text_prompt,
|
||||||
|
status='in_progress',
|
||||||
# 生成新的视频ID
|
pid=uuid,
|
||||||
new_video_id = generate_video_id(user.id)
|
media_type=f'{model}_img_to_video',
|
||||||
|
slug=f'img-to-video',
|
||||||
# 默认请求体
|
ratio="auto" # 图片自适应宽高
|
||||||
payload = {
|
)
|
||||||
"uuid": pid, # 视频的 UUID
|
video_generation.save()
|
||||||
"motion": motion, # 视频丰富度
|
|
||||||
"seed": 0, # 默认 seed 为 0
|
# 返回成功响应
|
||||||
"upscale": False, # 默认开启 upscale
|
return JsonResponse({
|
||||||
"interpolate": False, # 默认开启 interpolate
|
'code': 200,
|
||||||
"callback_url": "https://www.typeframes.ai/api/callback/"
|
'message': '请求成功,视频正在生成中',
|
||||||
}
|
'data': {
|
||||||
print(f"extend_video 请求体: {payload}")
|
'video_id': video_generation.video_id,
|
||||||
|
'status': video_generation.status,
|
||||||
headers = get_headers()
|
'pid': uuid
|
||||||
|
}
|
||||||
# 发送 POST 请求
|
})
|
||||||
response = requests.post('https://api.aivideoapi.com/runway/extend', json=payload, headers=headers)
|
else:
|
||||||
print(f"API响应状态码: {response.status_code}")
|
return JsonResponse({'code': response.status_code, 'message': 'API请求失败', 'data': {}})
|
||||||
print(f"API响应内容: {response.text}")
|
|
||||||
|
except Exception as e:
|
||||||
# 解析响应内容
|
print(f"发生错误: {str(e)}")
|
||||||
if response.status_code == 200:
|
return JsonResponse({'code': 500, 'message': f'内部错误: {str(e)}', 'data': {}})
|
||||||
res_data = response.json()
|
|
||||||
new_pid = res_data.get('uuid')
|
return JsonResponse({'code': 405, 'message': '请求方法错误', 'data': {}})
|
||||||
|
|
||||||
# 创建新的延长视频记录,复制上一条视频的参数
|
|
||||||
new_video_generation = VideoGeneration.objects.create(
|
|
||||||
video_id=new_video_id,
|
@csrf_exempt
|
||||||
user=user,
|
def extend_video(request):
|
||||||
text=video_generation.text,
|
"""
|
||||||
voice_name=video_generation.voice_name,
|
延长视频的函数,发送请求到 /runway/extend
|
||||||
style=video_generation.style,
|
"""
|
||||||
rate=video_generation.rate,
|
if request.method == "POST":
|
||||||
media_type=video_generation.media_type,
|
try:
|
||||||
ratio=video_generation.ratio,
|
if not request.user.is_authenticated:
|
||||||
status='in_progress',
|
return JsonResponse({'code': 401, 'message': '用户未登录'})
|
||||||
pid=new_pid,
|
user = request.user
|
||||||
time_duration=video_generation.time_duration + time_extension, # 增加对应模型的时长
|
data = json.loads(request.body)
|
||||||
extension_count=video_generation.extension_count + 1, # 增加延长次数
|
print(data)
|
||||||
slug=video_generation.slug # slug 使用中划线
|
# 获取参数
|
||||||
)
|
pid = data.get('task_id')
|
||||||
print(f"延长视频成功: {res_data}")
|
motion = 6 # 视频丰富度
|
||||||
|
|
||||||
return JsonResponse({'code': 200, 'message': '视频延长请求成功', 'data': {'new_pid': new_pid}})
|
# 获取当前视频生成记录
|
||||||
|
video_generation = VideoGeneration.objects.get(pid=pid)
|
||||||
else:
|
|
||||||
return JsonResponse({'code': response.status_code, 'message': 'API请求失败', 'data': {}})
|
# 通过 media_type 判断模型是 gen3 还是 gen2
|
||||||
|
if 'gen3' in video_generation.media_type:
|
||||||
except Exception as e:
|
model = 'gen3'
|
||||||
print(f"发生错误: {str(e)}")
|
# 验证 gen3 的延长逻辑
|
||||||
return JsonResponse({'code': 500, 'message': f'内部错误: {str(e)}', 'data': {}})
|
if video_generation.extension_count >= 1 or video_generation.time_duration >= 10:
|
||||||
|
return JsonResponse({'code': 400, 'message': 'gen3 最大时长为 10s,无法继续延长'})
|
||||||
return JsonResponse({'code': 405, 'message': '请求方法错误', 'data': {}})
|
time_extension = 5 # 每次延长 5 秒
|
||||||
|
|
||||||
|
elif 'gen2' in video_generation.media_type:
|
||||||
|
model = 'gen2'
|
||||||
|
# 验证 gen2 的延长逻辑
|
||||||
|
if video_generation.extension_count >= 2 or video_generation.time_duration >= 12:
|
||||||
|
return JsonResponse({'code': 400, 'message': 'gen2 最大时长为 12s,无法继续延长'})
|
||||||
|
time_extension = 4 # 每次延长 4 秒
|
||||||
|
|
||||||
|
else:
|
||||||
|
return JsonResponse({'code': 400, 'message': '未知的模型类型'})
|
||||||
|
|
||||||
|
result = deduct_points(user, video_generation.slug)
|
||||||
|
if result is not True:
|
||||||
|
return result # 返回积分不足的响应
|
||||||
|
|
||||||
|
# 生成新的视频ID
|
||||||
|
new_video_id = generate_video_id(user.id)
|
||||||
|
|
||||||
|
# 默认请求体
|
||||||
|
payload = {
|
||||||
|
"uuid": pid, # 视频的 UUID
|
||||||
|
"motion": motion, # 视频丰富度
|
||||||
|
"seed": 0, # 默认 seed 为 0
|
||||||
|
"upscale": True, # 默认开启 upscale
|
||||||
|
"interpolate": True, # 默认开启 interpolate
|
||||||
|
"callback_url": "https://www.typeframes.ai/api/callback/"
|
||||||
|
}
|
||||||
|
print(f"extend_video 请求体: {payload}")
|
||||||
|
|
||||||
|
headers = get_headers()
|
||||||
|
|
||||||
|
# 发送 POST 请求
|
||||||
|
response = requests.post('https://api.aivideoapi.com/runway/extend', json=payload, headers=headers)
|
||||||
|
print(f"API响应状态码: {response.status_code}")
|
||||||
|
print(f"API响应内容: {response.text}")
|
||||||
|
|
||||||
|
# 解析响应内容
|
||||||
|
if response.status_code == 200:
|
||||||
|
res_data = response.json()
|
||||||
|
new_pid = res_data.get('uuid')
|
||||||
|
|
||||||
|
# 创建新的延长视频记录,复制上一条视频的参数
|
||||||
|
new_video_generation = VideoGeneration.objects.create(
|
||||||
|
video_id=new_video_id,
|
||||||
|
user=user,
|
||||||
|
text=video_generation.text,
|
||||||
|
voice_name=video_generation.voice_name,
|
||||||
|
style=video_generation.style,
|
||||||
|
rate=video_generation.rate,
|
||||||
|
media_type=video_generation.media_type,
|
||||||
|
ratio=video_generation.ratio,
|
||||||
|
status='in_progress',
|
||||||
|
pid=new_pid,
|
||||||
|
time_duration=video_generation.time_duration + time_extension, # 增加对应模型的时长
|
||||||
|
extension_count=video_generation.extension_count + 1, # 增加延长次数
|
||||||
|
slug=video_generation.slug # slug 使用中划线
|
||||||
|
)
|
||||||
|
print(f"延长视频成功: {res_data}")
|
||||||
|
|
||||||
|
return JsonResponse({'code': 200, 'message': '视频延长请求成功', 'data': {'new_pid': new_pid}})
|
||||||
|
|
||||||
|
else:
|
||||||
|
return JsonResponse({'code': response.status_code, 'message': 'API请求失败', 'data': {}})
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"发生错误: {str(e)}")
|
||||||
|
return JsonResponse({'code': 500, 'message': f'内部错误: {str(e)}', 'data': {}})
|
||||||
|
|
||||||
|
return JsonResponse({'code': 405, 'message': '请求方法错误', 'data': {}})
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,199 +1,265 @@
|
|||||||
import requests
|
import requests
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.http import JsonResponse
|
from django.http import JsonResponse
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from .models import Order, Plan, User
|
from .models import Order, Plan, User
|
||||||
import json
|
import json
|
||||||
import logging
|
from .base import logger
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
def get_paypal_access_token():
|
||||||
|
"""获取 PayPal 访问令牌"""
|
||||||
def get_paypal_access_token():
|
print("正在获取 PayPal 访问令牌...")
|
||||||
"""获取 PayPal 访问令牌"""
|
|
||||||
print("正在获取 PayPal 访问令牌...")
|
# 根据配置文件选择 PayPal URL
|
||||||
url = f"https://api.{settings.PAYPAL_MODE}.paypal.com/v1/oauth2/token"
|
paypal_base_url = "https://api.sandbox.paypal.com" if settings.PAYPAL_MODE == 'sandbox' else "https://api.paypal.com"
|
||||||
auth = (
|
url = f"{paypal_base_url}/v1/oauth2/token"
|
||||||
settings.PAYPAL_CLIENT_ID_SANDBOX if settings.PAYPAL_MODE == 'sandbox' else settings.PAYPAL_CLIENT_ID_PRODUCTION,
|
|
||||||
settings.PAYPAL_SECRET_KEY_SANDBOX if settings.PAYPAL_MODE == 'sandbox' else settings.PAYPAL_SECRET_KEY_PRODUCTION
|
auth = (
|
||||||
)
|
settings.PAYPAL_CLIENT_ID_SANDBOX if settings.PAYPAL_MODE == 'sandbox' else settings.PAYPAL_CLIENT_ID_PRODUCTION,
|
||||||
|
settings.PAYPAL_SECRET_KEY_SANDBOX if settings.PAYPAL_MODE == 'sandbox' else settings.PAYPAL_SECRET_KEY_PRODUCTION
|
||||||
headers = {
|
)
|
||||||
"Accept": "application/json",
|
|
||||||
"Accept-Language": "en_US"
|
headers = {
|
||||||
}
|
"Accept": "application/json",
|
||||||
data = {
|
"Accept-Language": "en_US"
|
||||||
"grant_type": "client_credentials"
|
}
|
||||||
}
|
data = {
|
||||||
|
"grant_type": "client_credentials"
|
||||||
response = requests.post(url, headers=headers, data=data, auth=auth)
|
}
|
||||||
|
|
||||||
if response.status_code == 200:
|
response = requests.post(url, headers=headers, data=data, auth=auth)
|
||||||
access_token = response.json().get('access_token')
|
|
||||||
print(f"获取的访问令牌: {access_token}")
|
if response.status_code == 200:
|
||||||
return access_token
|
access_token = response.json().get('access_token')
|
||||||
else:
|
logger.info(f"[支付执行] 获取的访问令牌: {access_token}")
|
||||||
print(f"获取 PayPal 访问令牌失败: {response.text}")
|
print(f"获取的访问令牌: {access_token}")
|
||||||
return None
|
return access_token
|
||||||
|
else:
|
||||||
@csrf_exempt
|
logger.error(f"[支付执行] 获取 PayPal 访问令牌失败: {response.text}")
|
||||||
def create_paypal_payment(request):
|
print(f"获取 PayPal 访问令牌失败: {response.text}")
|
||||||
"""创建 PayPal 支付"""
|
return None
|
||||||
if request.method == 'POST':
|
@csrf_exempt
|
||||||
try:
|
def create_paypal_payment(request):
|
||||||
print("创建 PayPal 支付开始...")
|
"""创建 PayPal 支付"""
|
||||||
data = json.loads(request.body)
|
if request.method == 'POST':
|
||||||
plan_id = data.get('plan_id')
|
try:
|
||||||
payment_method = data.get('payment_method', 'paypal')
|
print("创建 PayPal 支付开始...")
|
||||||
|
data = json.loads(request.body)
|
||||||
# 获取当前用户信息
|
plan_id = data.get('plan_id')
|
||||||
user = request.user
|
payment_method = data.get('payment_method', 'paypal')
|
||||||
|
|
||||||
# 验证用户和计划是否存在
|
# 获取当前用户信息
|
||||||
if not user.is_authenticated:
|
user = request.user
|
||||||
print("用户未认证")
|
|
||||||
return JsonResponse({"code": 401, "message": "用户未认证", "data": {}})
|
# 验证用户和计划是否存在
|
||||||
|
if not user.is_authenticated:
|
||||||
try:
|
print("用户未认证")
|
||||||
plan = Plan.objects.get(id=plan_id)
|
return JsonResponse({"code": 401, "message": "用户未认证", "data": {}})
|
||||||
print(f"找到的套餐: {plan.title}")
|
|
||||||
except Plan.DoesNotExist:
|
try:
|
||||||
print("套餐不存在")
|
plan = Plan.objects.get(id=plan_id)
|
||||||
return JsonResponse({"code": 400, "message": "套餐不存在", "data": {}})
|
print(f"找到的套餐: {plan.title}")
|
||||||
|
except Plan.DoesNotExist:
|
||||||
access_token = get_paypal_access_token()
|
print("套餐不存在")
|
||||||
if not access_token:
|
return JsonResponse({"code": 400, "message": "套餐不存在", "data": {}})
|
||||||
return JsonResponse({"code": 500, "message": "无法获取支付访问令牌", "data": {}})
|
|
||||||
|
access_token = get_paypal_access_token()
|
||||||
# 配置支付请求
|
if not access_token:
|
||||||
url = f"https://api.{settings.PAYPAL_MODE}.paypal.com/v1/payments/payment"
|
return JsonResponse({"code": 500, "message": "无法获取支付访问令牌", "data": {}})
|
||||||
headers = {
|
|
||||||
"Content-Type": "application/json",
|
# 配置支付请求
|
||||||
"Authorization": f"Bearer {access_token}"
|
url = f"https://api.paypal.com/v1/payments/payment"
|
||||||
}
|
headers = {
|
||||||
payload = {
|
"Content-Type": "application/json",
|
||||||
"intent": "sale",
|
"Authorization": f"Bearer {access_token}"
|
||||||
"payer": {"payment_method": "paypal"},
|
}
|
||||||
"redirect_urls": {
|
payload = {
|
||||||
"return_url": f"{settings.PAYPAL_RETURN_URL}",
|
"intent": "sale",
|
||||||
"cancel_url": f"{settings.PAYPAL_CANCEL_URL}"
|
"payer": {"payment_method": "paypal"},
|
||||||
},
|
"redirect_urls": {
|
||||||
"transactions": [{
|
"return_url": f"{settings.PAYPAL_RETURN_URL}",
|
||||||
"item_list": {
|
"cancel_url": f"{settings.PAYPAL_CANCEL_URL}"
|
||||||
"items": [{
|
},
|
||||||
"name": plan.title,
|
"transactions": [{
|
||||||
"sku": str(plan.id),
|
"item_list": {
|
||||||
"price": str(plan.price),
|
"items": [{
|
||||||
"currency": "USD",
|
"name": plan.title,
|
||||||
"quantity": 1
|
"sku": str(plan.id),
|
||||||
}]
|
"price": str(plan.price),
|
||||||
},
|
"currency": "USD",
|
||||||
"amount": {
|
"quantity": 1
|
||||||
"total": str(plan.price),
|
}]
|
||||||
"currency": "USD"
|
},
|
||||||
},
|
"amount": {
|
||||||
"description": f"购买 {plan.title} 计划"
|
"total": str(plan.price),
|
||||||
}]
|
"currency": "USD"
|
||||||
}
|
},
|
||||||
|
"description": f"购买 {plan.title} 计划"
|
||||||
print(f"支付请求Payload: {json.dumps(payload, indent=2)}")
|
}]
|
||||||
|
}
|
||||||
response = requests.post(url, headers=headers, json=payload)
|
|
||||||
|
print(f"支付请求Payload: {json.dumps(payload, indent=2)}")
|
||||||
if response.status_code == 201:
|
|
||||||
payment_id = response.json().get('id')
|
response = requests.post(url, headers=headers, json=payload)
|
||||||
approval_url = None
|
|
||||||
for link in response.json().get('links', []):
|
if response.status_code == 201:
|
||||||
if link.get('rel') == "approval_url":
|
payment_id = response.json().get('id')
|
||||||
approval_url = link.get('href')
|
approval_url = None
|
||||||
break
|
for link in response.json().get('links', []):
|
||||||
|
if link.get('rel') == "approval_url":
|
||||||
# 检查订单是否已经存在,防止重复创建订单
|
approval_url = link.get('href')
|
||||||
if Order.objects.filter(order_id=payment_id).exists():
|
break
|
||||||
return JsonResponse({"code": 400, "message": "订单已存在", "data": {}})
|
|
||||||
|
# 检查订单是否已经存在,防止重复创建订单
|
||||||
# 创建订单并使用PayPal返回的paymentId作为order_id
|
if Order.objects.filter(order_id=payment_id).exists():
|
||||||
order = Order.objects.create(
|
return JsonResponse({"code": 400, "message": "订单已存在", "data": {}})
|
||||||
order_id=payment_id, # 使用PayPal的支付ID作为订单ID
|
|
||||||
user=user,
|
# 创建订单并使用PayPal返回的paymentId作为order_id
|
||||||
username=user.username,
|
order = Order.objects.create(
|
||||||
plan=plan,
|
order_id=payment_id, # 使用PayPal的支付ID作为订单ID
|
||||||
amount=plan.price,
|
user=user,
|
||||||
payment_method=payment_method,
|
username=user.username,
|
||||||
status='pending'
|
plan=plan,
|
||||||
)
|
amount=plan.price,
|
||||||
print(f"订单创建成功,订单ID: {order.order_id}")
|
payment_method=payment_method,
|
||||||
|
status='pending'
|
||||||
if approval_url:
|
)
|
||||||
print(f"支付批准URL: {approval_url}")
|
print(f"订单创建成功,订单ID: {order.order_id}")
|
||||||
return JsonResponse({"code": 200, "message": "支付创建成功", "data": {"approval_url": approval_url}})
|
|
||||||
else:
|
if approval_url:
|
||||||
print("未找到支付批准URL")
|
print(f"支付批准URL: {approval_url}")
|
||||||
return JsonResponse({"code": 400, "message": "未找到支付批准URL", "data": {}})
|
return JsonResponse({"code": 200, "message": "支付创建成功", "data": {"approval_url": approval_url}})
|
||||||
else:
|
else:
|
||||||
print(f"支付创建失败: {response.status_code}, {response.json()}")
|
print("未找到支付批准URL")
|
||||||
return JsonResponse({"code": 400, "message": "支付创建失败", "data": response.json()})
|
return JsonResponse({"code": 400, "message": "未找到支付批准URL", "data": {}})
|
||||||
|
else:
|
||||||
except json.JSONDecodeError:
|
print(f"支付创建失败: {response.status_code}, {response.json()}")
|
||||||
print("请求体不是有效的JSON")
|
return JsonResponse({"code": 400, "message": "支付创建失败", "data": response.json()})
|
||||||
return JsonResponse({"code": 400, "message": "请求体不是有效的JSON", "data": {}})
|
|
||||||
except Exception as e:
|
except json.JSONDecodeError:
|
||||||
print(f"支付创建过程中发生异常: {str(e)}")
|
print("请求体不是有效的JSON")
|
||||||
return JsonResponse({"code": 500, "message": f"支付创建过程中发生异常: {str(e)}", "data": {}})
|
return JsonResponse({"code": 400, "message": "请求体不是有效的JSON", "data": {}})
|
||||||
else:
|
except Exception as e:
|
||||||
return JsonResponse({"code": 405, "message": "方法不允许", "data": {}})
|
print(f"支付创建过程中发生异常: {str(e)}")
|
||||||
|
return JsonResponse({"code": 500, "message": f"支付创建过程中发生异常: {str(e)}", "data": {}})
|
||||||
@csrf_exempt
|
else:
|
||||||
def execute_paypal_payment(request):
|
return JsonResponse({"code": 405, "message": "方法不允许", "data": {}})
|
||||||
"""执行 PayPal 支付"""
|
|
||||||
if request.method == 'POST':
|
|
||||||
try:
|
@csrf_exempt
|
||||||
data = json.loads(request.body)
|
def execute_paypal_payment(request):
|
||||||
payment_id = data.get('paymentId')
|
"""执行 PayPal 支付"""
|
||||||
payer_id = data.get('PayerID')
|
if request.method == 'POST':
|
||||||
|
try:
|
||||||
if not payment_id or not payer_id:
|
logger.info("[支付执行] 接收到来自前端的 POST 请求,开始处理支付...")
|
||||||
return JsonResponse({"code": 400, "message": "缺少支付ID或付款人ID", "data": {}})
|
|
||||||
order = Order.objects.get(order_id=payment_id)
|
# 解析请求体
|
||||||
if order.status == 'completed':
|
data = json.loads(request.body)
|
||||||
return JsonResponse({"code": 400, "message": "订单已支付", "data": {}})
|
payment_id = data.get('paymentId')
|
||||||
# 获取PayPal访问令牌
|
payer_id = data.get('PayerID')
|
||||||
access_token = get_paypal_access_token()
|
|
||||||
if not access_token:
|
logger.info(f"[支付执行] 请求内容: paymentId={payment_id}, PayerID={payer_id}")
|
||||||
return JsonResponse({"code": 500, "message": "无法获取支付访问令牌", "data": {}})
|
print(f"请求内容: paymentId={payment_id}, PayerID={payer_id}")
|
||||||
|
|
||||||
# 执行支付确认请求
|
if not payment_id or not payer_id:
|
||||||
url = f"https://api.{settings.PAYPAL_MODE}.paypal.com/v1/payments/payment/{payment_id}/execute"
|
logger.error("[支付执行] 缺少支付ID或付款人ID")
|
||||||
headers = {
|
return JsonResponse({"code": 400, "message": "缺少支付ID或付款人ID", "data": {}})
|
||||||
"Content-Type": "application/json",
|
|
||||||
"Authorization": f"Bearer {access_token}"
|
# 获取订单信息
|
||||||
}
|
try:
|
||||||
payload = {
|
order = Order.objects.get(order_id=payment_id)
|
||||||
"payer_id": payer_id
|
logger.info(f"[支付执行] 获取到的订单信息: {order}")
|
||||||
}
|
except Order.DoesNotExist:
|
||||||
|
logger.error("[支付执行] 订单不存在")
|
||||||
response = requests.post(url, headers=headers, json=payload)
|
return JsonResponse({"code": 400, "message": "订单不存在", "data": {}})
|
||||||
|
|
||||||
if response.status_code == 200:
|
# 检查订单是否已经支付
|
||||||
try:
|
if order.status == 'completed':
|
||||||
order.status = 'completed'
|
logger.info(f"[支付执行] 订单 {payment_id} 已支付,无需再次执行")
|
||||||
order.updated_at = datetime.now()
|
print(f"订单 {payment_id} 已支付,无需再次执行")
|
||||||
order.save()
|
return JsonResponse({"code": 400, "message": "订单已支付", "data": {}})
|
||||||
|
|
||||||
# 更新用户积分
|
# 获取 PayPal 访问令牌
|
||||||
user = order.user
|
access_token = get_paypal_access_token()
|
||||||
user.points += order.plan.credits_per_month
|
if not access_token:
|
||||||
user.save()
|
logger.error("[支付执行] 无法获取支付访问令牌")
|
||||||
|
return JsonResponse({"code": 500, "message": "无法获取支付访问令牌", "data": {}})
|
||||||
return JsonResponse({"code": 200, "message": "支付成功", "data": {}})
|
logger.info(f"[支付执行] 获取到的 PayPal 访问令牌: {access_token}")
|
||||||
except Order.DoesNotExist:
|
|
||||||
return JsonResponse({"code": 400, "message": "订单不存在", "data": {}})
|
# 设置 PayPal API 请求的 URL 和头部信息
|
||||||
else:
|
paypal_base_url = "https://api.sandbox.paypal.com" if settings.PAYPAL_MODE == 'sandbox' else "https://api.paypal.com"
|
||||||
return JsonResponse({"code": 400, "message": "支付执行失败", "data": response.json()})
|
url = f"{paypal_base_url}/v1/payments/payment/{payment_id}/execute"
|
||||||
|
headers = {
|
||||||
except json.JSONDecodeError:
|
"Content-Type": "application/json",
|
||||||
return JsonResponse({"code": 400, "message": "请求体不是有效的JSON", "data": {}})
|
"Authorization": f"Bearer {access_token}"
|
||||||
except Exception as e:
|
}
|
||||||
return JsonResponse({"code": 500, "message": f"支付执行过程中发生异常: {str(e)}", "data": {}})
|
payload = {
|
||||||
else:
|
"payer_id": payer_id
|
||||||
return JsonResponse({"code": 405, "message": "方法不允许", "data": {}})
|
}
|
||||||
|
|
||||||
|
logger.info(f"[支付执行] 发送支付请求,URL: {url}, 请求头: {headers}, 请求体: {payload}")
|
||||||
|
print(f"发送支付请求,URL: {url}, 请求体: {payload}")
|
||||||
|
|
||||||
|
# 执行 PayPal 支付请求
|
||||||
|
response = requests.post(url, headers=headers, json=payload)
|
||||||
|
|
||||||
|
# 打印 PayPal API 请求的响应
|
||||||
|
logger.info(f"[支付执行] PayPal API 响应状态码: {response.status_code}")
|
||||||
|
print(f"PayPal API 响应状态码: {response.status_code}")
|
||||||
|
logger.info(f"[支付执行] PayPal API 响应内容: {response.json()}")
|
||||||
|
print(f"PayPal API 响应内容: {response.json()}")
|
||||||
|
|
||||||
|
# 判断支付是否成功
|
||||||
|
if response.status_code == 200:
|
||||||
|
payment_data = response.json()
|
||||||
|
if payment_data['state'] == 'approved':
|
||||||
|
logger.info(f"[支付执行] 支付成功,订单状态更新为 'approved'")
|
||||||
|
|
||||||
|
# 确保订单未完成过
|
||||||
|
if order.status != 'completed':
|
||||||
|
order.status = 'completed'
|
||||||
|
order.updated_at = datetime.now()
|
||||||
|
order.save()
|
||||||
|
|
||||||
|
# 获取用户当前积分并进行累加
|
||||||
|
user = order.user
|
||||||
|
current_points = user.points if user.points else 0 # 防止积分为 None
|
||||||
|
added_points = order.plan.credits_per_month
|
||||||
|
user.points = current_points + added_points
|
||||||
|
user.save()
|
||||||
|
|
||||||
|
# 打印用户当前积分、购买的套餐和增加的积分
|
||||||
|
logger.info(f"[支付执行] 用户 {user.username} 当前积分: {current_points}")
|
||||||
|
logger.info(f"[支付执行] 购买的套餐: {order.plan.title}")
|
||||||
|
logger.info(f"[支付执行] 增加的积分: {added_points}")
|
||||||
|
logger.info(f"[支付执行] 用户新的总积分: {user.points}")
|
||||||
|
|
||||||
|
print(f"用户 {user.username} 当前积分: {current_points}")
|
||||||
|
print(f"购买的套餐: {order.plan.title}")
|
||||||
|
print(f"增加的积分: {added_points}")
|
||||||
|
print(f"新的总积分: {user.points}")
|
||||||
|
|
||||||
|
return JsonResponse({"code": 200, "message": "支付成功,积分已更新", "data": {}})
|
||||||
|
else:
|
||||||
|
logger.info(f"[支付执行] 订单 {payment_id} 已支付,无需再次更新积分")
|
||||||
|
return JsonResponse({"code": 400, "message": "订单已支付,积分不重复增加", "data": {}})
|
||||||
|
else:
|
||||||
|
logger.error(f"[支付执行] 支付未完成,状态为: {payment_data['state']}")
|
||||||
|
print(f"支付未完成,状态为: {payment_data['state']}")
|
||||||
|
return JsonResponse({"code": 400, "message": "支付状态未完成", "data": payment_data})
|
||||||
|
else:
|
||||||
|
logger.error(f"[支付执行] 支付执行失败,状态码: {response.status_code}")
|
||||||
|
print(f"支付执行失败,状态码: {response.status_code}")
|
||||||
|
return JsonResponse({"code": 400, "message": "支付执行失败", "data": response.json()})
|
||||||
|
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
logger.error("[支付执行] 请求体不是有效的 JSON 格式")
|
||||||
|
return JsonResponse({"code": 400, "message": "请求体不是有效的JSON", "data": {}})
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"[支付执行] 支付执行过程中发生异常: {str(e)}")
|
||||||
|
print(f"支付执行过程中发生异常: {str(e)}")
|
||||||
|
return JsonResponse({"code": 500, "message": f"支付执行过程中发生异常: {str(e)}", "data": {}})
|
||||||
|
else:
|
||||||
|
logger.error(f"[支付执行] 请求方法 {request.method} 不被允许")
|
||||||
|
return JsonResponse({"code": 405, "message": "方法不允许", "data": {}})
|
||||||
|
@ -1,165 +1,237 @@
|
|||||||
import requests
|
import requests
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.http import JsonResponse
|
from django.http import JsonResponse
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from .models import Order
|
from .models import Order
|
||||||
import json
|
import json
|
||||||
import logging
|
from .base import logger
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
def get_paypal_access_token():
|
||||||
|
"""获取 PayPal 访问令牌"""
|
||||||
def get_paypal_access_token():
|
print("正在获取 PayPal 访问令牌...")
|
||||||
"""获取 PayPal 访问令牌"""
|
url = f"https://api.paypal.com/v1/oauth2/token"
|
||||||
print("正在获取 PayPal 访问令牌...")
|
auth = (
|
||||||
url = f"https://api.{settings.PAYPAL_MODE}.paypal.com/v1/oauth2/token"
|
settings.PAYPAL_CLIENT_ID_SANDBOX if settings.PAYPAL_MODE == 'sandbox' else settings.PAYPAL_CLIENT_ID_PRODUCTION,
|
||||||
auth = (
|
settings.PAYPAL_SECRET_KEY_SANDBOX if settings.PAYPAL_MODE == 'sandbox' else settings.PAYPAL_SECRET_KEY_PRODUCTION
|
||||||
settings.PAYPAL_CLIENT_ID_SANDBOX if settings.PAYPAL_MODE == 'sandbox' else settings.PAYPAL_CLIENT_ID_PRODUCTION,
|
)
|
||||||
settings.PAYPAL_SECRET_KEY_SANDBOX if settings.PAYPAL_MODE == 'sandbox' else settings.PAYPAL_SECRET_KEY_PRODUCTION
|
|
||||||
)
|
headers = {
|
||||||
|
"Accept": "application/json",
|
||||||
headers = {
|
"Accept-Language": "en_US"
|
||||||
"Accept": "application/json",
|
}
|
||||||
"Accept-Language": "en_US"
|
data = {
|
||||||
}
|
"grant_type": "client_credentials"
|
||||||
data = {
|
}
|
||||||
"grant_type": "client_credentials"
|
|
||||||
}
|
response = requests.post(url, headers=headers, data=data, auth=auth)
|
||||||
|
|
||||||
response = requests.post(url, headers=headers, data=data, auth=auth)
|
if response.status_code == 200:
|
||||||
|
access_token = response.json().get('access_token')
|
||||||
if response.status_code == 200:
|
logger.info(f"获取的访问令牌: {access_token}")
|
||||||
access_token = response.json().get('access_token')
|
print(f"获取的访问令牌: {access_token}")
|
||||||
print(f"获取的访问令牌: {access_token}")
|
return access_token
|
||||||
return access_token
|
else:
|
||||||
else:
|
logger.error(f"获取 PayPal 访问令牌失败: {response.text}")
|
||||||
print(f"获取 PayPal 访问令牌失败: {response.text}")
|
print(f"获取 PayPal 访问令牌失败: {response.text}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def verify_paypal_webhook(headers, body):
|
|
||||||
"""使用 PayPal API 验证 Webhook 签名"""
|
def verify_paypal_webhook(headers, body):
|
||||||
print("验证 PayPal Webhook 签名...")
|
"""使用 PayPal API 验证 Webhook 签名"""
|
||||||
verify_url = f"https://api.{settings.PAYPAL_MODE}.paypal.com/v1/notifications/verify-webhook-signature"
|
logger.info("验证 PayPal Webhook 签名...")
|
||||||
auth_token = get_paypal_access_token()
|
print("验证 PayPal Webhook 签名...")
|
||||||
if not auth_token:
|
verify_url = f"https://api.paypal.com/v1/notifications/verify-webhook-signature"
|
||||||
print("无法获取 PayPal 访问令牌,无法验证 Webhook 签名")
|
|
||||||
return False
|
auth_token = get_paypal_access_token()
|
||||||
|
if not auth_token:
|
||||||
verify_headers = {
|
logger.error("无法获取 PayPal 访问令牌,无法验证 Webhook 签名")
|
||||||
"Content-Type": "application/json",
|
print("无法获取 PayPal 访问令牌,无法验证 Webhook 签名")
|
||||||
"Authorization": f"Bearer {auth_token}"
|
return False
|
||||||
}
|
|
||||||
|
verify_headers = {
|
||||||
verify_payload = {
|
"Content-Type": "application/json",
|
||||||
"auth_algo": headers.get('Paypal-Auth-Algo'),
|
"Authorization": f"Bearer {auth_token}"
|
||||||
"cert_url": headers.get('Paypal-Cert-Url'),
|
}
|
||||||
"transmission_id": headers.get('Paypal-Transmission-Id'),
|
|
||||||
"transmission_sig": headers.get('Paypal-Transmission-Sig'),
|
verify_payload = {
|
||||||
"transmission_time": headers.get('Paypal-Transmission-Time'),
|
"auth_algo": headers.get('Paypal-Auth-Algo'),
|
||||||
"webhook_id": settings.PAYPAL_WEBHOOK_ID,
|
"cert_url": headers.get('Paypal-Cert-Url'),
|
||||||
"webhook_event": json.loads(body)
|
"transmission_id": headers.get('Paypal-Transmission-Id'),
|
||||||
}
|
"transmission_sig": headers.get('Paypal-Transmission-Sig'),
|
||||||
|
"transmission_time": headers.get('Paypal-Transmission-Time'),
|
||||||
response = requests.post(verify_url, headers=verify_headers, json=verify_payload)
|
"webhook_id": settings.PAYPAL_WEBHOOK_ID,
|
||||||
if response.status_code == 200 and response.json().get('verification_status') == 'SUCCESS':
|
"webhook_event": json.loads(body)
|
||||||
print("Webhook 签名验证成功")
|
}
|
||||||
return True
|
|
||||||
else:
|
response = requests.post(verify_url, headers=verify_headers, json=verify_payload)
|
||||||
print(f"Webhook 签名验证失败: {response.text}")
|
|
||||||
return False
|
if response.status_code == 200 and response.json().get('verification_status') == 'SUCCESS':
|
||||||
|
logger.info("Webhook 签名验证成功")
|
||||||
@csrf_exempt
|
print("Webhook 签名验证成功")
|
||||||
def paypal_webhook(request):
|
return True
|
||||||
"""PayPal Webhook 处理函数,用于接收和处理 PayPal 异步通知"""
|
else:
|
||||||
try:
|
logger.error(f"Webhook 签名验证失败: {response.text}")
|
||||||
print("接收到 PayPal Webhook 请求...")
|
print(f"Webhook 签名验证失败: {response.text}")
|
||||||
headers = request.headers
|
return False
|
||||||
payload = json.loads(request.body)
|
|
||||||
|
|
||||||
# 验证 Webhook 签名
|
@csrf_exempt
|
||||||
if not verify_paypal_webhook(headers, request.body):
|
def execute_paypal_payment(payment_id, payer_id):
|
||||||
return JsonResponse({"code": 400, "message": "Webhook 签名验证失败", "data": {}})
|
"""执行 PayPal 支付"""
|
||||||
|
try:
|
||||||
event_type = payload.get('event_type')
|
logger.info(f"回调接收到 开始执行支付,订单ID: {payment_id}, 付款人ID: {payer_id}")
|
||||||
|
order = Order.objects.get(order_id=payment_id)
|
||||||
# 打印接收到的 Webhook payload 以供调试
|
|
||||||
print(f"接收到 PayPal Webhook 事件: {event_type}")
|
if order.status == 'completed':
|
||||||
print(f"Webhook payload: {json.dumps(payload, indent=2)}")
|
logger.info(f"订单 {payment_id} 已经支付,不需要再次执行支付")
|
||||||
|
print(f"订单 {payment_id} 已经支付,不需要再次执行支付")
|
||||||
# 处理不同类型的事件
|
return JsonResponse({"code": 400, "message": "订单已支付", "data": {}})
|
||||||
if event_type == 'PAYMENT.SALE.COMPLETED':
|
|
||||||
sale_id = payload['resource'].get('id')
|
# 获取 PayPal 访问令牌
|
||||||
parent_payment = payload['resource'].get('parent_payment') # 使用parent_payment作为订单ID
|
access_token = get_paypal_access_token()
|
||||||
if parent_payment:
|
if not access_token:
|
||||||
try:
|
logger.error("无法获取支付访问令牌")
|
||||||
order = Order.objects.get(order_id=parent_payment)
|
return JsonResponse({"code": 500, "message": "无法获取支付访问令牌", "data": {}})
|
||||||
|
|
||||||
# 检查订单状态,防止重复更新
|
# 根据配置文件选择 PayPal URL
|
||||||
if order.status == 'completed':
|
paypal_base_url = "https://api.sandbox.paypal.com" if settings.PAYPAL_MODE == 'sandbox' else "https://api.paypal.com"
|
||||||
print(f"订单 {parent_payment} 已经完成,不重复更新")
|
url = f"{paypal_base_url}/v1/payments/payment/{payment_id}/execute"
|
||||||
return JsonResponse({"code": 200, "message": "订单已处理", "data": {}})
|
headers = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
# 再次向 PayPal 查询订单状态,确保支付确实完成
|
"Authorization": f"Bearer {access_token}"
|
||||||
access_token = get_paypal_access_token()
|
}
|
||||||
if not access_token:
|
payload = {
|
||||||
print("无法获取 PayPal 访问令牌,无法验证订单状态")
|
"payer_id": payer_id
|
||||||
return JsonResponse({"code": 500, "message": "无法获取支付访问令牌", "data": {}})
|
}
|
||||||
|
|
||||||
payment_details_url = f"https://api.{settings.PAYPAL_MODE}.paypal.com/v1/payments/payment/{parent_payment}"
|
logger.info(f"执行 PayPal 支付请求, URL: {url}, 请求体: {payload}")
|
||||||
headers = {
|
print(f"执行 PayPal 支付请求, URL: {url}, 请求体: {payload}")
|
||||||
"Content-Type": "application/json",
|
|
||||||
"Authorization": f"Bearer {access_token}"
|
response = requests.post(url, headers=headers, json=payload)
|
||||||
}
|
|
||||||
payment_details_response = requests.get(payment_details_url, headers=headers)
|
# 处理支付执行结果
|
||||||
|
if response.status_code == 200:
|
||||||
if payment_details_response.status_code == 200:
|
order.status = 'completed'
|
||||||
payment_details = payment_details_response.json()
|
order.updated_at = datetime.now()
|
||||||
if payment_details['state'] == 'approved':
|
order.save()
|
||||||
order.status = 'completed'
|
|
||||||
order.updated_at = datetime.now()
|
# 更新用户积分
|
||||||
order.save()
|
user = order.user
|
||||||
|
user.points += order.plan.credits_per_month
|
||||||
# 更新用户积分
|
user.save()
|
||||||
user = order.user
|
|
||||||
user.points += order.plan.credits_per_month
|
logger.info(f"订单 {payment_id} 支付成功,用户积分已更新: {order.plan.credits_per_month}")
|
||||||
user.save()
|
print(f"订单 {payment_id} 支付成功,用户积分已更新: {order.plan.credits_per_month}")
|
||||||
|
return JsonResponse({"code": 200, "message": "支付成功", "data": {}})
|
||||||
print(f"订单 {parent_payment} 状态更新为 'completed' 并已更新用户积分")
|
else:
|
||||||
else:
|
logger.error(f"支付执行失败: {response.text}")
|
||||||
print(f"支付未完成,状态: {payment_details['state']}")
|
print(f"支付执行失败: {response.text}")
|
||||||
else:
|
return JsonResponse({"code": 400, "message": "支付执行失败", "data": response.json()})
|
||||||
print(f"查询支付状态失败: {payment_details_response.text}")
|
|
||||||
return JsonResponse({"code": 500, "message": "查询支付状态失败", "data": {}})
|
except Order.DoesNotExist:
|
||||||
|
logger.error(f"订单 {payment_id} 不存在")
|
||||||
except Order.DoesNotExist:
|
print(f"订单 {payment_id} 不存在")
|
||||||
print(f"未找到订单 {parent_payment}")
|
return JsonResponse({"code": 400, "message": "订单不存在", "data": {}})
|
||||||
return JsonResponse({"code": 400, "message": "订单不存在", "data": {}})
|
except Exception as e:
|
||||||
else:
|
logger.error(f"支付执行过程中发生异常: {str(e)}")
|
||||||
print("Webhook payload 中缺少 parent_payment")
|
print(f"支付执行过程中发生异常: {str(e)}")
|
||||||
return JsonResponse({"code": 400, "message": "Webhook payload 中缺少 parent_payment", "data": {}})
|
return JsonResponse({"code": 500, "message": f"支付执行过程中发生异常: {str(e)}", "data": {}})
|
||||||
|
|
||||||
elif event_type == 'PAYMENT.SALE.DENIED':
|
|
||||||
sale_id = payload['resource'].get('id')
|
@csrf_exempt
|
||||||
parent_payment = payload['resource'].get('parent_payment')
|
def paypal_webhook(request):
|
||||||
if parent_payment:
|
"""PayPal Webhook 处理函数,用于接收和处理 PayPal 异步通知"""
|
||||||
try:
|
try:
|
||||||
order = Order.objects.get(order_id=parent_payment)
|
logger.info("接收到 PayPal Webhook 请求...")
|
||||||
order.status = 'failed'
|
print("接收到 PayPal Webhook 请求...")
|
||||||
order.updated_at = datetime.now()
|
|
||||||
order.save()
|
headers = request.headers
|
||||||
print(f"订单 {parent_payment} 状态更新为 'failed'")
|
payload = json.loads(request.body)
|
||||||
except Order.DoesNotExist:
|
|
||||||
print(f"未找到订单 {parent_payment}")
|
# 验证 Webhook 签名
|
||||||
return JsonResponse({"code": 400, "message": "订单不存在", "data": {}})
|
if not verify_paypal_webhook(headers, request.body):
|
||||||
else:
|
logger.error("Webhook 签名验证失败")
|
||||||
print("Webhook payload 中缺少 parent_payment")
|
return JsonResponse({"code": 400, "message": "Webhook 签名验证失败", "data": {}})
|
||||||
return JsonResponse({"code": 400, "message": "Webhook payload 中缺少 parent_payment", "data": {}})
|
|
||||||
|
event_type = payload.get('event_type')
|
||||||
return JsonResponse({"code": 200, "message": "Webhook 处理成功", "data": {}})
|
|
||||||
|
# 打印接收到的 Webhook payload 以供调试
|
||||||
except json.JSONDecodeError:
|
logger.info(f"接收到 PayPal Webhook 事件: {event_type}")
|
||||||
print("请求体不是有效的JSON")
|
print(f"接收到 PayPal Webhook 事件: {event_type}")
|
||||||
return JsonResponse({"code": 400, "message": "请求体不是有效的JSON", "data": {}})
|
logger.info(f"Webhook payload: {json.dumps(payload, indent=2)}")
|
||||||
except Exception as e:
|
|
||||||
print(f"处理 PayPal Webhook 时发生错误: {e}")
|
# 处理不同类型的事件
|
||||||
return JsonResponse({"code": 500, "message": f"处理 PayPal Webhook 时发生错误: {str(e)}", "data": {}})
|
if event_type == 'PAYMENT.SALE.COMPLETED':
|
||||||
|
parent_payment = payload['resource'].get('parent_payment') # 使用 parent_payment 作为订单 ID
|
||||||
|
state = payload['resource'].get('state') # 获取支付状态
|
||||||
|
|
||||||
|
if parent_payment:
|
||||||
|
try:
|
||||||
|
order = Order.objects.get(order_id=parent_payment)
|
||||||
|
|
||||||
|
# 通过 state 判断支付是否完成
|
||||||
|
if state == 'completed':
|
||||||
|
if order.status == 'completed':
|
||||||
|
logger.info(f"订单 {parent_payment} 已经完成,不重复更新")
|
||||||
|
print(f"订单 {parent_payment} 已经完成,不重复更新")
|
||||||
|
return JsonResponse({"code": 200, "message": "订单已处理", "data": {}})
|
||||||
|
|
||||||
|
# 更新订单状态为已完成
|
||||||
|
order.status = 'completed'
|
||||||
|
order.updated_at = datetime.now()
|
||||||
|
order.save()
|
||||||
|
|
||||||
|
# 更新用户积分
|
||||||
|
user = order.user
|
||||||
|
user.points += order.plan.credits_per_month
|
||||||
|
user.save()
|
||||||
|
|
||||||
|
logger.info(f"订单 {parent_payment} 状态更新为 'completed' 并已更新用户积分")
|
||||||
|
print(f"订单 {parent_payment} 状态更新为 'completed' 并已更新用户积分")
|
||||||
|
return JsonResponse({"code": 200, "message": "支付完成,订单更新成功", "data": {}})
|
||||||
|
else:
|
||||||
|
logger.error(f"支付状态为 {state},未完成支付")
|
||||||
|
print(f"支付状态为 {state},未完成支付")
|
||||||
|
return JsonResponse({"code": 400, "message": f"支付状态为 {state},未完成支付", "data": {}})
|
||||||
|
|
||||||
|
except Order.DoesNotExist:
|
||||||
|
logger.error(f"未找到订单 {parent_payment}")
|
||||||
|
print(f"未找到订单 {parent_payment}")
|
||||||
|
return JsonResponse({"code": 400, "message": "订单不存在", "data": {}})
|
||||||
|
else:
|
||||||
|
logger.error("Webhook payload 中缺少 parent_payment")
|
||||||
|
print("Webhook payload 中缺少 parent_payment")
|
||||||
|
return JsonResponse({"code": 400, "message": "Webhook payload 中缺少 parent_payment", "data": {}})
|
||||||
|
|
||||||
|
elif event_type == 'PAYMENTS.PAYMENT.CREATED':
|
||||||
|
# 支付创建时的逻辑,可以执行支付
|
||||||
|
payment_id = payload['resource']['id']
|
||||||
|
payer_id = payload['resource']['payer']['payer_info']['payer_id']
|
||||||
|
execute_paypal_payment(payment_id, payer_id)
|
||||||
|
|
||||||
|
elif event_type == 'PAYMENT.SALE.DENIED':
|
||||||
|
parent_payment = payload['resource'].get('parent_payment')
|
||||||
|
if parent_payment:
|
||||||
|
try:
|
||||||
|
order = Order.objects.get(order_id=parent_payment)
|
||||||
|
order.status = 'failed'
|
||||||
|
order.updated_at = datetime.now()
|
||||||
|
order.save()
|
||||||
|
logger.info(f"订单 {parent_payment} 状态更新为 'failed'")
|
||||||
|
print(f"订单 {parent_payment} 状态更新为 'failed'")
|
||||||
|
except Order.DoesNotExist:
|
||||||
|
logger.error(f"未找到订单 {parent_payment}")
|
||||||
|
print(f"未找到订单 {parent_payment}")
|
||||||
|
return JsonResponse({"code": 400, "message": "订单不存在", "data": {}})
|
||||||
|
|
||||||
|
return JsonResponse({"code": 200, "message": "Webhook 处理成功", "data": {}})
|
||||||
|
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
logger.error("请求体不是有效的JSON")
|
||||||
|
print("请求体不是有效的JSON")
|
||||||
|
return JsonResponse({"code": 400, "message": "请求体不是有效的JSON", "data": {}})
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"处理 PayPal Webhook 时发生错误: {str(e)}")
|
||||||
|
print(f"处理 PayPal Webhook 时发生错误: {str(e)}")
|
||||||
|
return JsonResponse({"code": 500, "message": f"处理 PayPal Webhook 时发生错误: {str(e)}", "data": {}})
|
||||||
|
@ -5,33 +5,63 @@ from .models import User, UserSource
|
|||||||
|
|
||||||
@receiver(user_logged_in)
|
@receiver(user_logged_in)
|
||||||
def user_logged_in_handler(request, user, **kwargs):
|
def user_logged_in_handler(request, user, **kwargs):
|
||||||
print('1111111111111111111111111')
|
print('信号处理开始: user_logged_in_handler 被触发')
|
||||||
|
|
||||||
|
# 防止信号被重复处理
|
||||||
|
if hasattr(request, '_google_user_logged_in_handled'):
|
||||||
|
print('重复信号,跳过处理')
|
||||||
|
return
|
||||||
|
request._google_user_logged_in_handled = True
|
||||||
|
print('处理信号标志设置完成')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
social_account = SocialAccount.objects.get(user=user, provider='google')
|
social_account = SocialAccount.objects.get(user=user, provider='google')
|
||||||
print(social_account.extra_data) # 打印 extra_data 内容以进行调试
|
print(f'找到 social_account,用户ID: {user.id}')
|
||||||
|
google_id = social_account.extra_data.get('sub')
|
||||||
google_id = social_account.extra_data['sub'] # 使用 'sub' 字段
|
email = social_account.extra_data.get('email')
|
||||||
email = social_account.extra_data['email']
|
username = social_account.extra_data.get('name')
|
||||||
username = social_account.extra_data['name']
|
print(f'从 social_account 获取的 google_id: {google_id}, email: {email}, username: {username}')
|
||||||
|
|
||||||
|
if not google_id:
|
||||||
|
# 如果 google_id 为空,不要继续创建用户,记录日志或处理错误
|
||||||
|
print('google_id 为空,终止处理')
|
||||||
|
return
|
||||||
|
|
||||||
|
# 优化:根据 google_id 和 email 双重检查用户是否已存在
|
||||||
try:
|
try:
|
||||||
custom_user = User.objects.get(google_id=google_id)
|
custom_user = User.objects.get(google_id=google_id)
|
||||||
|
print(f'根据 google_id 找到用户: {custom_user.username}')
|
||||||
except User.DoesNotExist:
|
except User.DoesNotExist:
|
||||||
custom_user = User.objects.create(
|
print(f'没有找到 google_id 为 {google_id} 的用户,检查 email: {email}')
|
||||||
username=username,
|
# 进一步检查是否有相同的 email 用户存在
|
||||||
email=email,
|
if User.objects.filter(email=email).exists():
|
||||||
google_id=google_id,
|
custom_user = User.objects.get(email=email)
|
||||||
password_hash='', # Google 登录不需要密码
|
print(f'找到 email 为 {email} 的用户: {custom_user.username}')
|
||||||
)
|
# 如果用户存在但 google_id 不同,更新 google_id
|
||||||
UserSource.objects.create(user=custom_user, source='Google')
|
custom_user.google_id = google_id
|
||||||
|
custom_user.save()
|
||||||
# 更新登录次数和最后登录IP
|
print(f'更新用户的 google_id 为: {google_id}')
|
||||||
|
else:
|
||||||
|
custom_user = User.objects.create(
|
||||||
|
username=username,
|
||||||
|
email=email,
|
||||||
|
google_id=google_id,
|
||||||
|
# password_hash='', # Google 登录不需要密码
|
||||||
|
)
|
||||||
|
print(f'创建新用户: {custom_user.username},google_id: {google_id}')
|
||||||
|
UserSource.objects.create(user=custom_user, source='Google')
|
||||||
|
print(f'创建 UserSource 记录,来源为 Google')
|
||||||
|
|
||||||
|
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
|
||||||
|
if x_forwarded_for:
|
||||||
|
ip = x_forwarded_for.split(',')[0] # 可能有多个 IP 地址,取第一个
|
||||||
|
else:
|
||||||
|
ip = request.META.get('REMOTE_ADDR') # 使用 REMOTE_ADDR 作为备用
|
||||||
|
# 更新登录次数和 IP 地址
|
||||||
custom_user.login_count += 1
|
custom_user.login_count += 1
|
||||||
custom_user.last_login_ip = request.META.get('REMOTE_ADDR')
|
custom_user.last_login_ip = ip
|
||||||
custom_user.save()
|
custom_user.save()
|
||||||
|
print(f'更新用户信息: 登录次数 {custom_user.login_count}, IP 地址 {custom_user.last_login_ip}')
|
||||||
|
|
||||||
# 确保 Django 用户同步
|
|
||||||
user.username = custom_user.username
|
|
||||||
user.save()
|
|
||||||
except SocialAccount.DoesNotExist:
|
except SocialAccount.DoesNotExist:
|
||||||
pass
|
print('未找到与用户关联的 Google social_account')
|
||||||
|
@ -22,6 +22,7 @@ from .aliyun_sms import send_verification_sms, verify_sms_code
|
|||||||
# 定义积分奖励值
|
# 定义积分奖励值
|
||||||
REWARD_POINTS = 50 # 例如奖励50积分
|
REWARD_POINTS = 50 # 例如奖励50积分
|
||||||
|
|
||||||
|
|
||||||
def check_and_reward_points(user, openid):
|
def check_and_reward_points(user, openid):
|
||||||
"""
|
"""
|
||||||
根据 openid 查询原系统会员状态,为原系统的用户增加一天会员时长(不论是否为会员)。
|
根据 openid 查询原系统会员状态,为原系统的用户增加一天会员时长(不论是否为会员)。
|
||||||
@ -151,7 +152,7 @@ def send_verification_email_view(request):
|
|||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
try:
|
try:
|
||||||
body = json.loads(request.body)
|
body = json.loads(request.body)
|
||||||
email = body.get('phone_number')
|
email = body.get('email')
|
||||||
if not email:
|
if not email:
|
||||||
return JsonResponse({'code': 400, 'message': '邮箱地址是必须的'})
|
return JsonResponse({'code': 400, 'message': '邮箱地址是必须的'})
|
||||||
|
|
||||||
@ -193,8 +194,8 @@ def send_verification_sms_view(request):
|
|||||||
if not phone_number:
|
if not phone_number:
|
||||||
return JsonResponse({'code': 400, 'message': '手机号码是必须的'})
|
return JsonResponse({'code': 400, 'message': '手机号码是必须的'})
|
||||||
|
|
||||||
sign_name = "福铭科技" # 替换为实际的签名名称
|
sign_name = "光映" # 替换为实际的签名名称
|
||||||
template_code = "SMS_299200388" # 替换为实际的短信模板代码
|
template_code = "SMS_473670066" # 替换为实际的短信模板代码
|
||||||
|
|
||||||
response = send_verification_sms(phone_number, sign_name, template_code)
|
response = send_verification_sms(phone_number, sign_name, template_code)
|
||||||
return JsonResponse(response)
|
return JsonResponse(response)
|
||||||
@ -379,7 +380,7 @@ def send_verification_code_view(request):
|
|||||||
if '@' in identifier:
|
if '@' in identifier:
|
||||||
response = send_verification_email(identifier)
|
response = send_verification_email(identifier)
|
||||||
else:
|
else:
|
||||||
response = send_verification_sms(identifier, "福铭科技", "SMS_299200388")
|
response = send_verification_sms(identifier, "光映", "SMS_473670066")
|
||||||
|
|
||||||
return JsonResponse(response)
|
return JsonResponse(response)
|
||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
|
BIN
WebSite.zip
BIN
WebSite.zip
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -23,7 +23,7 @@ BASE_DIR = Path(__file__).resolve().parent.parent
|
|||||||
SECRET_KEY = "django-insecure-!4a*kl(!=s*76xngra89q*86d&e8ya=l49!bibepo6p1(50+$s"
|
SECRET_KEY = "django-insecure-!4a*kl(!=s*76xngra89q*86d&e8ya=l49!bibepo6p1(50+$s"
|
||||||
|
|
||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
DEBUG = True
|
DEBUG = False
|
||||||
|
|
||||||
ALLOWED_HOSTS = ['*']
|
ALLOWED_HOSTS = ['*']
|
||||||
# settings.py
|
# settings.py
|
||||||
@ -63,7 +63,7 @@ AUTHENTICATION_BACKENDS = (
|
|||||||
'django.contrib.auth.backends.ModelBackend',
|
'django.contrib.auth.backends.ModelBackend',
|
||||||
'allauth.account.auth_backends.AuthenticationBackend',
|
'allauth.account.auth_backends.AuthenticationBackend',
|
||||||
)
|
)
|
||||||
LOGIN_REDIRECT_URL = '/user/userinfo/' # 登录后重定向的URL
|
LOGIN_REDIRECT_URL = '/create' # 登录后重定向的URL
|
||||||
LOGIN_URL = '/'
|
LOGIN_URL = '/'
|
||||||
LOGOUT_REDIRECT_URL = '/'
|
LOGOUT_REDIRECT_URL = '/'
|
||||||
|
|
||||||
@ -159,10 +159,10 @@ DATABASES = {
|
|||||||
{
|
{
|
||||||
'ENGINE': 'django.db.backends.mysql', # 数据库引擎
|
'ENGINE': 'django.db.backends.mysql', # 数据库引擎
|
||||||
'NAME': 'admin_data', # 数据库名称
|
'NAME': 'admin_data', # 数据库名称
|
||||||
'HOST': '1Panel-mysql-61G1', # 数据库地址,本机 ip 地址 127.0.0.1
|
'HOST': '127.0.0.1', # 数据库地址,本机 ip 地址 127.0.0.1
|
||||||
'PORT': 3306, # mysql端口
|
'PORT': 3306, # mysql端口
|
||||||
'USER': 'admin_data', # 数据库用户名
|
'USER': 'admin_data', # 数据库用户名
|
||||||
'PASSWORD': 'mPmFz2NeXSYbzrt5', # 数据库密码
|
'PASSWORD': 'kyRz3c3hGMmDADrW', # 数据库密码
|
||||||
'OPTIONS': {
|
'OPTIONS': {
|
||||||
'charset': 'utf8mb4',
|
'charset': 'utf8mb4',
|
||||||
'use_unicode': True,
|
'use_unicode': True,
|
||||||
@ -231,7 +231,7 @@ AZURE_CONTAINER_NAME = 'audio'
|
|||||||
|
|
||||||
#支付宝电脑版支付配置
|
#支付宝电脑版支付配置
|
||||||
# 支付宝配置
|
# 支付宝配置
|
||||||
ALIPAY_DEBUG = True # True 表示沙箱环境,False 表示生产环境
|
ALIPAY_DEBUG = False # True 表示沙箱环境,False 表示生产环境
|
||||||
|
|
||||||
# 沙箱环境配 电脑支付宝
|
# 沙箱环境配 电脑支付宝
|
||||||
ALIPAY_APP_ID_SANDBOX_PC = '9021000139657593' # 沙箱环境电脑端应用ID
|
ALIPAY_APP_ID_SANDBOX_PC = '9021000139657593' # 沙箱环境电脑端应用ID
|
||||||
@ -250,20 +250,19 @@ ALIPAY_PUBLIC_KEY_PRODUCTION_PC = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo
|
|||||||
ALIPAY_APP_ID_PRODUCTION_MOBILE = '2021004169658094' # 生产环境移动端应用ID
|
ALIPAY_APP_ID_PRODUCTION_MOBILE = '2021004169658094' # 生产环境移动端应用ID
|
||||||
ALIPAY_APP_PRIVATE_KEY_PRODUCTION_MOBILE = 'MIIEowIBAAKCAQEAlkLen9IPB0OhhRnDw0Ks1yX74oXSLJ4hEaqQmJqXI8qfNFL+DiuEWs+yAZRad8mDOUqERka1YrMI9Y7iVyGWhcFRHe91+oNNDZlrXp1K/SzPWtA1tPbkBrgxV5lgj/fGKJrMlJhlfF7Bio8b9jOfyMtaqolP777tD0zMAdIbKYCW1wmUgUeRsNplDO/8GIDoJV+qGxTEd2TN3eJfC9MBIkCW/b1QHTXukJIFzKGufNRNJIWbPi/wmyMaUd+lyemz//sNhD2+CpiuB4pi/v3c8tQsPJeOslRpo9+T0lg9wLlDgMMeajf+PMzjErRmiOxI1ZwNn8xkaE6ZfeDhh18v1wIDAQABAoIBAQCQ225bjNpIGn8AHdKHzyNpVoj53CC+OsOOkGxNcdr6+j945fleF73E/i2RMD/28yG6fYf/Z/M9b3PXpyO09AB0eeWFgnCuTR5fWeQUlnbQk/5igg8Eom85uyB2XrqkkC1Mv88yAaj0uTTEKyq9sw77OG/zr+SML/fBpDuYFcFxw7JnD+TxKBeqT6gd1RHcfeyta1MWiEsQeX7y2PGicn5HjbGLCsJxvJVGyvaQFPBN5eoIesSm74DEFL25ZdR1vpaWYGm7XZgAY6dgzPbijFx2nLMRAM9e+M6I0u75k0mDSVb9y+1TXqEKPSG7FegIbzhylj20ZcwWYb0SgJ8sHuvBAoGBAOcRBlbtkq4uGqFyTY1y1WedxSMJf0bMfYum3CvT7YAOVffVxye2I3s4v1Os1NPR5M+om7eEtgN+9Zl2DIagPlTB6CrYRg26hwnDuNhLqLZHo8IW0IK2xY8QSPzvRJcx1sSvTqLXG/MdsFDV9SGNxYazYpIqlL2Q2cUHImc6+JqZAoGBAKZ5rnVPlOQ20aXCe/0nn7K6PIFCQhBHayBjXmqaNi7ZGVgM1CXrvFffpGrc7e60gVfbOkZjzUy0XJAmagYTNZ8+HDh52y6YRoMR3XjPKgrs4+hdraG1vBVSmxRpzUfYqqq+k9T2dnK3pjkYIrDZiiwsT57o2EispQBWRfNmKZPvAoGAeclBXCPPgbqPErTaJ0l1LS28r+DbkodJTIff18HVlf74VK36T/Xx8YpRXVrkudgRD1pA6JMsE9+gtwe/Rl3DPI0PPzXKhoXfksfz7xzBiYFs0GmR8LNAoUzmC1pY/o+oMPZtLerOsm7ddV2v28WLbJmzxHJo/xkPjodaHKq6SVECgYAxGLHa5x2CMKijujfW8Vin3UT62g+hvW5anvO5fMF+D4jp7t6iUGO7hrl2yrFhNNrwjjchi02A0bB60tlx8ThfPnIUNdvuYfpprVsjxfUgQ7zzSq1qg650m2ghHRLtnXi34ny20fkc3AypyfRxM7cMUAUrWIBw7nm7H7aBkh+xAQKBgH4Zaxjcn/OsF4QPCJqzf02+zHh7FGGLnsjZXmtVoNDmmFJFXj5ey05jfcNyoRdtffl0Fa/mbkiL1YcAUoBmkyS7MA4mrrM5vG5ZKtLcul1qeC9JrJ2FEcZBmny2fdbfzFFuBdhz0jbOGoDOKl5KWM7EQoxk377DQVRQ884B0Cc+' # 生产环境移动端应用私钥
|
ALIPAY_APP_PRIVATE_KEY_PRODUCTION_MOBILE = 'MIIEowIBAAKCAQEAlkLen9IPB0OhhRnDw0Ks1yX74oXSLJ4hEaqQmJqXI8qfNFL+DiuEWs+yAZRad8mDOUqERka1YrMI9Y7iVyGWhcFRHe91+oNNDZlrXp1K/SzPWtA1tPbkBrgxV5lgj/fGKJrMlJhlfF7Bio8b9jOfyMtaqolP777tD0zMAdIbKYCW1wmUgUeRsNplDO/8GIDoJV+qGxTEd2TN3eJfC9MBIkCW/b1QHTXukJIFzKGufNRNJIWbPi/wmyMaUd+lyemz//sNhD2+CpiuB4pi/v3c8tQsPJeOslRpo9+T0lg9wLlDgMMeajf+PMzjErRmiOxI1ZwNn8xkaE6ZfeDhh18v1wIDAQABAoIBAQCQ225bjNpIGn8AHdKHzyNpVoj53CC+OsOOkGxNcdr6+j945fleF73E/i2RMD/28yG6fYf/Z/M9b3PXpyO09AB0eeWFgnCuTR5fWeQUlnbQk/5igg8Eom85uyB2XrqkkC1Mv88yAaj0uTTEKyq9sw77OG/zr+SML/fBpDuYFcFxw7JnD+TxKBeqT6gd1RHcfeyta1MWiEsQeX7y2PGicn5HjbGLCsJxvJVGyvaQFPBN5eoIesSm74DEFL25ZdR1vpaWYGm7XZgAY6dgzPbijFx2nLMRAM9e+M6I0u75k0mDSVb9y+1TXqEKPSG7FegIbzhylj20ZcwWYb0SgJ8sHuvBAoGBAOcRBlbtkq4uGqFyTY1y1WedxSMJf0bMfYum3CvT7YAOVffVxye2I3s4v1Os1NPR5M+om7eEtgN+9Zl2DIagPlTB6CrYRg26hwnDuNhLqLZHo8IW0IK2xY8QSPzvRJcx1sSvTqLXG/MdsFDV9SGNxYazYpIqlL2Q2cUHImc6+JqZAoGBAKZ5rnVPlOQ20aXCe/0nn7K6PIFCQhBHayBjXmqaNi7ZGVgM1CXrvFffpGrc7e60gVfbOkZjzUy0XJAmagYTNZ8+HDh52y6YRoMR3XjPKgrs4+hdraG1vBVSmxRpzUfYqqq+k9T2dnK3pjkYIrDZiiwsT57o2EispQBWRfNmKZPvAoGAeclBXCPPgbqPErTaJ0l1LS28r+DbkodJTIff18HVlf74VK36T/Xx8YpRXVrkudgRD1pA6JMsE9+gtwe/Rl3DPI0PPzXKhoXfksfz7xzBiYFs0GmR8LNAoUzmC1pY/o+oMPZtLerOsm7ddV2v28WLbJmzxHJo/xkPjodaHKq6SVECgYAxGLHa5x2CMKijujfW8Vin3UT62g+hvW5anvO5fMF+D4jp7t6iUGO7hrl2yrFhNNrwjjchi02A0bB60tlx8ThfPnIUNdvuYfpprVsjxfUgQ7zzSq1qg650m2ghHRLtnXi34ny20fkc3AypyfRxM7cMUAUrWIBw7nm7H7aBkh+xAQKBgH4Zaxjcn/OsF4QPCJqzf02+zHh7FGGLnsjZXmtVoNDmmFJFXj5ey05jfcNyoRdtffl0Fa/mbkiL1YcAUoBmkyS7MA4mrrM5vG5ZKtLcul1qeC9JrJ2FEcZBmny2fdbfzFFuBdhz0jbOGoDOKl5KWM7EQoxk377DQVRQ884B0Cc+' # 生产环境移动端应用私钥
|
||||||
ALIPAY_PUBLIC_KEY_PRODUCTION_MOBILE = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAomw6g4rBmCr/QoX3NI3DVLyDpkaUytZ2uFhdfQaegIDAuUfZfgpTCASlAtO82t8ISAbSOSyp9CUpwdGV4EYOiCBbLxMYB6taaHPiIjJ1zNT1EakJzWgU53hz1AVeABB9kdAvMqSvjH6KLoVupmqm4Li8ZwDW9M2ANAmyDfKgiF0Lt4aUUnaZktoCrTWTkpmtfRZCHNACj851IllvN2wyC4OL7dJq5UzOFxmn07Dy/2z4UAhaaSAyRVawpOui5AIYJTXZERLYL3KMyRnMuZoFq3xltzVTzRPM06nRa9RfeVNVwWVtGBIe/r8tcg5wyhI57KUszGNOmUIm/se6G2lnAQIDAQAB' # 生产环境移动端支付宝公钥
|
ALIPAY_PUBLIC_KEY_PRODUCTION_MOBILE = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAomw6g4rBmCr/QoX3NI3DVLyDpkaUytZ2uFhdfQaegIDAuUfZfgpTCASlAtO82t8ISAbSOSyp9CUpwdGV4EYOiCBbLxMYB6taaHPiIjJ1zNT1EakJzWgU53hz1AVeABB9kdAvMqSvjH6KLoVupmqm4Li8ZwDW9M2ANAmyDfKgiF0Lt4aUUnaZktoCrTWTkpmtfRZCHNACj851IllvN2wyC4OL7dJq5UzOFxmn07Dy/2z4UAhaaSAyRVawpOui5AIYJTXZERLYL3KMyRnMuZoFq3xltzVTzRPM06nRa9RfeVNVwWVtGBIe/r8tcg5wyhI57KUszGNOmUIm/se6G2lnAQIDAQAB' # 生产环境移动端支付宝公钥
|
||||||
|
|
||||||
ALIPAY_NOTIFY_URL = 'https://www.typeframes.com.cn/api/alipay/notify/'
|
ALIPAY_NOTIFY_URL = 'https://www.typeframes.com.cn/api/alipay/notify/'
|
||||||
ALIPAY_RETURN_URL = 'https://www.typeframes.com.cn/user/userinfo/'
|
ALIPAY_RETURN_URL = 'https://www.typeframes.com.cn/create'
|
||||||
|
|
||||||
# settings.py
|
# settings.py
|
||||||
|
|
||||||
# PayPal 配置
|
# PayPal 配置
|
||||||
PAYPAL_CLIENT_ID_SANDBOX = 'AfwWNEZE92XpbmoHywwdDEXH2x2Elak1Gxbireb5bv-u17OtKiJUuz7CMLnqayAZkqeU2kGtWXHXcXGS'
|
PAYPAL_CLIENT_ID_SANDBOX = 'AfwWNEZE92XpbmoHywwdDEXH2x2Elak1Gxbireb5bv-u17OtKiJUuz7CMLnqayAZkqeU2kGtWXHXcXGS'
|
||||||
PAYPAL_SECRET_KEY_SANDBOX = 'ELmuFW7AspHp4km8amEhlM-NB3OGGx_iuqQbntTQ-2RTnJWbxdLTl6xlET1F1ezxSHbU1CUpK0_8ToI3'
|
PAYPAL_SECRET_KEY_SANDBOX = 'ELmuFW7AspHp4km8amEhlM-NB3OGGx_iuqQbntTQ-2RTnJWbxdLTl6xlET1F1ezxSHbU1CUpK0_8ToI3'
|
||||||
PAYPAL_CLIENT_ID_PRODUCTION = 'YOUR_PRODUCTION_CLIENT_ID' # 替换为实际的生产环境客户端ID
|
PAYPAL_CLIENT_ID_PRODUCTION = 'Aelz9E_u5mlLP_-8nOGuXS14P-osTWYqxPx8HknC1PNBqRtG_RzAtWblryvr0o8pIyqIomI-2KMFagk2' # 替换为实际的生产环境客户端ID
|
||||||
PAYPAL_SECRET_KEY_PRODUCTION = 'YOUR_PRODUCTION_SECRET_KEY' # 替换为实际的生产环境密钥
|
PAYPAL_SECRET_KEY_PRODUCTION = 'EIA_O_JeOWUjolXK3yi4VC88wpcZaIYgQvAPJ251LX_OTsatYzjt_Y2aFKLjXt5fInRkdTfeIbrwlZEh' # 替换为实际的生产环境密钥
|
||||||
|
|
||||||
PAYPAL_MODE = 'sandbox' #'sandbox' if DEBUG else 'live' # 根据DEBUG模式选择环境
|
PAYPAL_MODE = 'sandbox' if DEBUG else 'live' # 根据DEBUG模式选择环境
|
||||||
PAYPAL_RETURN_URL = 'https://www.typeframes.ai/user/plan_list/' # 支付成功后跳转的URL
|
PAYPAL_RETURN_URL = 'https://www.typeframes.ai/create' # 支付成功后跳转的URL
|
||||||
PAYPAL_CANCEL_URL = 'https://www.typeframes.ai/user/plan_list/' # 支付取消后跳转的URL
|
PAYPAL_CANCEL_URL = 'https://www.typeframes.ai/create' # 支付取消后跳转的URL
|
||||||
|
|
||||||
PAYPAL_WEBHOOK_ID = '5L31025588094031T' # 替换为你的实际 Webhook ID
|
PAYPAL_WEBHOOK_ID = '1Y325150YP471005S' # 替换为你的实际 Webhook ID
|
||||||
|
0
gunicorn_acess.log
Executable file
0
gunicorn_acess.log
Executable file
0
gunicorn_error.log
Executable file
0
gunicorn_error.log
Executable file
40
uwsgi.ini
40
uwsgi.ini
@ -1,11 +1,25 @@
|
|||||||
[uwsgi]
|
[uwsgi]
|
||||||
chdir = /app
|
# 项目目录
|
||||||
|
chdir = /www/wwwroot/Ai_Admin
|
||||||
|
|
||||||
|
# 指定项目application
|
||||||
module = WebSite.wsgi:application
|
module = WebSite.wsgi:application
|
||||||
|
|
||||||
|
# 进程个数
|
||||||
processes = 4
|
processes = 4
|
||||||
|
|
||||||
|
# 线程个数
|
||||||
threads = 2
|
threads = 2
|
||||||
|
|
||||||
|
# 指定启动时的pid文件路径(用于停止服务和重启服务,请勿删除)
|
||||||
|
pidfile = /www/wwwroot/Ai_Admin/uwsgi.pid
|
||||||
|
|
||||||
# 指定ip及端口
|
# 指定ip及端口
|
||||||
http = 0.0.0.0:3001
|
http=0.0.0.0:3001
|
||||||
|
|
||||||
|
# 启动uwsgi的用户名和用户组
|
||||||
|
uid = root
|
||||||
|
gid = root
|
||||||
|
|
||||||
# 启用主进程
|
# 启用主进程
|
||||||
master = true
|
master = true
|
||||||
@ -14,20 +28,18 @@ master = true
|
|||||||
buffer-size = 32768
|
buffer-size = 32768
|
||||||
|
|
||||||
http-timeout = 60
|
http-timeout = 60
|
||||||
|
|
||||||
post-buffering = 8192
|
post-buffering = 8192
|
||||||
|
|
||||||
|
# 后台运行,并输出日志
|
||||||
|
daemonize = /www/wwwroot/Ai_Admin/uwsgi.log
|
||||||
|
|
||||||
# 处理 SIGTERM 信号以便优雅地关闭
|
# 处理 SIGTERM 信号以便优雅地关闭
|
||||||
die-on-term = true
|
die-on-term = true
|
||||||
|
|
||||||
# 处理静态和媒体文件
|
# 添加以下配置以处理静态和媒体文件
|
||||||
static-map = /static=/app/static
|
static-map = /static=/www/wwwroot/Ai_Admin/static
|
||||||
static-map = /media=/app/media
|
static-map = /media=/www/wwwroot/Ai_Admin/media
|
||||||
static-map = /media/avatars=/app/media/avatars
|
static-map = /media/avatars=/www/wwwroot/Ai_Admin/media/avatars
|
||||||
static-map = /media/audios=/app/media/audios
|
static-map = /media/audios=/www/wwwroot/Ai_Admin/media/audios
|
||||||
static-map = /.well-known/acme-challenge/=/app/.well-known/acme-challenge
|
static-map = /.well-known/acme-challenge/=/www/wwwroot/java_node_ssl/.well-known/acme-challenge
|
||||||
|
|
||||||
# 日志输出到标准输出
|
|
||||||
logger = stdout
|
|
||||||
|
|
||||||
# 启用thunder lock
|
|
||||||
thunder-lock = true
|
|
Loading…
Reference in New Issue
Block a user