最新版本
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
|
7634
API日志.log
Executable file → Normal file
7634
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.
@ -239,27 +239,24 @@ def update_user_membership(order):
|
||||
更新用户积分信息
|
||||
"""
|
||||
try:
|
||||
# 验证订单状态是否为成功
|
||||
if order.status not in ("completed", "TRADE_SUCCESS", "TRADE_FINISHED"):
|
||||
print("订单未成功")
|
||||
# 如果订单已经是 'completed' 状态,说明已经处理过,跳过处理
|
||||
if order.status == 'completed':
|
||||
print("订单已处理,无需再次更新")
|
||||
return False
|
||||
|
||||
# 从订单中获取关联的套餐信息
|
||||
# 获取套餐信息
|
||||
plan = order.plan
|
||||
|
||||
# 检查汇率是否有效
|
||||
# 获取美元对人民币的汇率
|
||||
usd_to_cny_rate = get_usd_to_cny_rate()
|
||||
if not usd_to_cny_rate:
|
||||
print("无法进行价格转换,汇率不可用")
|
||||
return False
|
||||
|
||||
# 将订单金额从美元转换回人民币
|
||||
order_amount_cny = order.amount
|
||||
|
||||
# 确保订单的套餐与实际套餐详情匹配
|
||||
if not plan or convert_cny_to_usd(plan.price) != order_amount_cny:
|
||||
print(f"订单的套餐信息与实际套餐不匹配plan.price{plan.price}---")
|
||||
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
|
||||
|
||||
# 获取用户信息
|
||||
@ -269,13 +266,18 @@ def update_user_membership(order):
|
||||
user.points += plan.credits_per_month
|
||||
user.save()
|
||||
|
||||
print(f"用户 {user.username} 的积分已更新")
|
||||
# 更新订单状态为 'completed'
|
||||
order.status = 'completed'
|
||||
order.save()
|
||||
|
||||
print(f"用户 {user.username} 的积分已更新--增加{plan.credits_per_month}--现在{user.points}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"更新用户积分信息时出错: {e}")
|
||||
return False
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
def alipay_notify(request):
|
||||
"""
|
||||
@ -285,7 +287,7 @@ def alipay_notify(request):
|
||||
data = request.POST.dict()
|
||||
print(f"接收到的异步通知数据: {data}")
|
||||
|
||||
# 直接使用返回的数据处理逻辑
|
||||
# 获取订单ID和交易状态
|
||||
order_id = data.get('out_trade_no')
|
||||
trade_status = data.get('trade_status')
|
||||
print(f"订单ID: {order_id}, 支付状态: {trade_status}")
|
||||
@ -296,9 +298,13 @@ def alipay_notify(request):
|
||||
print(f"订单 {order_id} 不存在")
|
||||
return JsonResponse({"code": 400, "message": "订单不存在"})
|
||||
|
||||
# 如果订单状态已经是 'completed',表示已经处理过,无需再次处理
|
||||
if order.status == 'completed':
|
||||
print(f"订单 {order_id} 已处理,无需再次更新")
|
||||
return JsonResponse({"code": 200, "message": "订单已处理"})
|
||||
|
||||
# 如果支付成功或交易完成,更新订单状态并处理会员更新
|
||||
if trade_status in ("TRADE_SUCCESS", "TRADE_FINISHED"):
|
||||
order.status = 'completed'
|
||||
order.save()
|
||||
print(f"订单 {order_id} 支付成功")
|
||||
update_user_membership(order)
|
||||
return JsonResponse({"code": 200, "message": "支付成功"})
|
||||
|
@ -270,8 +270,6 @@ def webhook(request):
|
||||
if not data:
|
||||
return HttpResponse(status=400) # Bad Request
|
||||
|
||||
# 记录完整的接收到的数据
|
||||
logger.info("Received complete callback data:\n%s\n", json.dumps(data, indent=4))
|
||||
|
||||
# 提取基本信息
|
||||
video_url = data.get('videoUrl', '') # 编辑视频 URL
|
||||
@ -316,8 +314,6 @@ def webhook(request):
|
||||
else:
|
||||
return HttpResponse(status=405) # Method Not Allowed
|
||||
|
||||
|
||||
#获取视频列表
|
||||
@csrf_exempt
|
||||
@require_http_methods(["GET"])
|
||||
@login_required
|
||||
@ -328,26 +324,30 @@ def get_video_list(request):
|
||||
try:
|
||||
user = request.user
|
||||
|
||||
# 检查是否有用户ID参数
|
||||
user_id = request.GET.get('user_id', None)
|
||||
|
||||
# 获取分页参数
|
||||
page = request.GET.get('page', 1)
|
||||
page_size = request.GET.get('page_size', 10)
|
||||
|
||||
# 如果有user_id参数,并且当前用户是管理员,则获取该用户的视频列表
|
||||
if user_id and user.is_staff:
|
||||
# 检查是否有user_id参数,并且当前用户是管理员
|
||||
user_id = request.GET.get('user_id', None)
|
||||
|
||||
if user.is_staff:
|
||||
# 管理员可以查看指定用户的视频列表,或查看所有用户视频列表
|
||||
if user_id:
|
||||
try:
|
||||
specific_user = User.objects.get(id=user_id)
|
||||
video_list = VideoGeneration.objects.filter(user=specific_user).order_by('-created_at')
|
||||
except ObjectDoesNotExist:
|
||||
return JsonResponse({'code': 404, 'message': '用户不存在'}, status=404)
|
||||
# 如果没有user_id参数或者当前用户不是管理员,则获取当前用户的视频列表
|
||||
elif not user.is_staff:
|
||||
video_list = VideoGeneration.objects.filter(user=user).order_by('-created_at')
|
||||
print(f"管理员查询用户 {specific_user.username} 的视频列表")
|
||||
except User.DoesNotExist:
|
||||
return JsonResponse({'code': 404, 'message': '用户不存在', 'data': {}}, status=404)
|
||||
else:
|
||||
# 管理员返回所有记录
|
||||
# 没有指定用户ID,管理员查询所有用户的视频列表
|
||||
video_list = VideoGeneration.objects.all().order_by('-created_at')
|
||||
print("管理员查询所有用户的视频列表")
|
||||
else:
|
||||
# 普通用户只能查看自己的视频列表,忽略传入的 user_id 参数
|
||||
video_list = VideoGeneration.objects.filter(user=user).order_by('-created_at')
|
||||
print(f"普通用户 {user.username} 查询自己的视频列表")
|
||||
|
||||
# 使用Paginator进行分页
|
||||
paginator = Paginator(video_list, page_size)
|
||||
@ -355,10 +355,12 @@ def get_video_list(request):
|
||||
try:
|
||||
videos = paginator.page(page)
|
||||
except PageNotAnInteger:
|
||||
videos = paginator.page(1)
|
||||
videos = paginator.page(1) # 如果页码不是整数,返回第一页
|
||||
except EmptyPage:
|
||||
videos = paginator.page(paginator.num_pages)
|
||||
# 如果页码超出范围,返回空列表
|
||||
return JsonResponse({'code': 200, 'message': '没有更多数据', 'data': {'list': [], 'page': page, 'page_size': page_size, 'total_pages': paginator.num_pages, 'total_videos': paginator.count}}, status=200)
|
||||
|
||||
# 组织视频数据
|
||||
video_data = []
|
||||
for video in videos:
|
||||
video_data.append({
|
||||
@ -374,24 +376,30 @@ def get_video_list(request):
|
||||
'status': video.status,
|
||||
'created_at': video.created_at,
|
||||
'updated_at': video.updated_at,
|
||||
'pid':video.pid,
|
||||
'video_id':video.video_id,
|
||||
'pid': video.pid,
|
||||
'video_id': video.video_id,
|
||||
'slug': video.slug,
|
||||
})
|
||||
|
||||
# 响应数据
|
||||
response_data = {
|
||||
'code': 200,
|
||||
'data': {"list":video_data,'page': videos.number,
|
||||
'message': '成功获取视频列表',
|
||||
'data': {
|
||||
'list': video_data,
|
||||
'page': videos.number,
|
||||
'page_size': paginator.per_page,
|
||||
'total_pages': paginator.num_pages,
|
||||
'total_videos': paginator.count}
|
||||
'total_videos': paginator.count
|
||||
}
|
||||
}
|
||||
|
||||
return JsonResponse(response_data)
|
||||
return JsonResponse(response_data, status=200)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error fetching video list: {str(e)}")
|
||||
return JsonResponse({"code": 500, "message": str(e)}, status=500)
|
||||
return JsonResponse({"code": 500, "message": f"服务器错误: {str(e)}", "data": {}}, status=500)
|
||||
|
||||
|
||||
@require_http_methods(["GET"])
|
||||
def get_plans(request):
|
||||
|
@ -5,6 +5,12 @@ from django.http import JsonResponse
|
||||
from .models import VideoGeneration
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from .base import logger,deduct_points
|
||||
import http.client
|
||||
import random
|
||||
import urllib
|
||||
import hashlib
|
||||
from langdetect import detect
|
||||
from langdetect.lang_detect_exception import LangDetectException
|
||||
def generate_video_id(user_id):
|
||||
"""
|
||||
根据用户ID和当前时间戳生成唯一的视频ID
|
||||
@ -14,6 +20,37 @@ def generate_video_id(user_id):
|
||||
print(f"生成的视频ID: {video_id}")
|
||||
return video_id
|
||||
|
||||
appid = '20240601002067404' # 填写你的appid
|
||||
secretKey = '6pRZ9HCSqGuMqzLO55hB' # 填写你的密钥
|
||||
|
||||
def translate(text, from_lang='auto', to_lang='en'):
|
||||
myurl = '/api/trans/vip/translate'
|
||||
salt = random.randint(32768, 65536)
|
||||
sign = appid + text + str(salt) + secretKey
|
||||
sign = hashlib.md5(sign.encode()).hexdigest()
|
||||
myurl = (myurl + '?appid=' + appid + '&q=' + urllib.parse.quote(text) +
|
||||
'&from=' + from_lang + '&to=' + to_lang + '&salt=' + str(salt) +
|
||||
'&sign=' + sign)
|
||||
|
||||
try:
|
||||
httpClient = http.client.HTTPConnection('api.fanyi.baidu.com')
|
||||
httpClient.request('GET', myurl)
|
||||
|
||||
# response是HTTPResponse对象
|
||||
response = httpClient.getresponse()
|
||||
result_all = response.read().decode("utf-8")
|
||||
result = json.loads(result_all)
|
||||
print(f'请求结果{result}')
|
||||
return result['trans_result'][0]['dst']
|
||||
|
||||
except Exception as e:
|
||||
return str(e)
|
||||
|
||||
finally:
|
||||
if httpClient:
|
||||
httpClient.close()
|
||||
|
||||
|
||||
def get_dimensions(model, width=None, height=None):
|
||||
"""
|
||||
根据模型返回相应的宽高分辨率:
|
||||
@ -40,6 +77,8 @@ def get_headers():
|
||||
"Authorization": "12e76710fad2047db8c0cc6b25987e2a2" # 替换为你的真实授权密钥
|
||||
}
|
||||
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
def text_to_video(request):
|
||||
"""
|
||||
@ -51,9 +90,22 @@ def text_to_video(request):
|
||||
return JsonResponse({'code': 401, 'message': '用户未登录'})
|
||||
user = request.user
|
||||
data = json.loads(request.body)
|
||||
text_prompt = data.get('text_prompt')
|
||||
print(f'文生视频原内容---:{text_prompt}')
|
||||
|
||||
# 判断是否需要翻译
|
||||
try:
|
||||
language = detect(text_prompt)
|
||||
print(f"检测到的语言: {language}")
|
||||
if language == 'en':
|
||||
description = text_prompt # 英文无需翻译
|
||||
else:
|
||||
description = translate(text_prompt, 'auto', 'en') # 翻译成英文
|
||||
print(f'文生视频翻译内容---:{description}')
|
||||
except LangDetectException:
|
||||
return JsonResponse({'code': 400, 'message': '无法检测语言,请输入有效文本'})
|
||||
|
||||
# 获取参数
|
||||
text_prompt = data.get('text_prompt')
|
||||
style = data.get('style', '') # 选择的风格,默认是 'general'
|
||||
model = data.get('model', 'gen3') # 选择模型,默认是 'gen3'
|
||||
time_duration = int(data.get('time', 5)) # 视频时长
|
||||
@ -82,14 +134,14 @@ def text_to_video(request):
|
||||
|
||||
# 准备POST请求数据
|
||||
payload = {
|
||||
"text_prompt": f"{text_prompt}. Style: {style}",
|
||||
"text_prompt": f"{description}. Style: {style}",
|
||||
"model": model,
|
||||
"width": width,
|
||||
"height": height,
|
||||
"motion": motion, # 视频画面丰富度
|
||||
"seed": 0,
|
||||
"upscale": False,
|
||||
"interpolate": False,
|
||||
"upscale": True,
|
||||
"interpolate": True,
|
||||
"callback_url": "https://www.typeframes.ai/api/callback/",
|
||||
"time": time_duration # 视频时长
|
||||
}
|
||||
@ -139,6 +191,9 @@ def text_to_video(request):
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
def image_to_video(request):
|
||||
"""
|
||||
@ -153,6 +208,20 @@ def image_to_video(request):
|
||||
|
||||
# 获取参数
|
||||
text_prompt = data.get('text_prompt')
|
||||
print(f' 图片生视频原内容---:{text_prompt}')
|
||||
|
||||
# 判断是否需要翻译
|
||||
try:
|
||||
language = detect(text_prompt)
|
||||
print(f"检测到的语言: {language}")
|
||||
if language == 'en':
|
||||
description = text_prompt # 英文无需翻译
|
||||
else:
|
||||
description = translate(text_prompt, 'auto', 'en') # 翻译成英文
|
||||
print(f'图片生视翻译内容---:{description}')
|
||||
except LangDetectException:
|
||||
return JsonResponse({'code': 400, 'message': '无法检测语言,请输入有效文本'})
|
||||
|
||||
image_url = data.get('image_url')
|
||||
model = data.get('model', 'gen3') # 选择模型,默认是 'gen3'
|
||||
time_duration = int(data.get('time', 5)) # 视频时长
|
||||
@ -175,14 +244,14 @@ def image_to_video(request):
|
||||
|
||||
# 准备POST请求数据,宽高不需要传入,图片自适应
|
||||
payload = {
|
||||
"text_prompt": text_prompt,
|
||||
"text_prompt": description,
|
||||
"model": model,
|
||||
"img_prompt": image_url,
|
||||
"image_as_end_frame": False, # 图片不作为最后一帧
|
||||
"motion": motion, # 视频丰富度
|
||||
"seed": 0,
|
||||
"upscale": False,
|
||||
"interpolate": False,
|
||||
"upscale": True,
|
||||
"interpolate": True,
|
||||
"callback_url": "https://www.typeframes.ai/api/callback/",
|
||||
"time": time_duration # 视频时长
|
||||
}
|
||||
@ -246,10 +315,10 @@ def extend_video(request):
|
||||
return JsonResponse({'code': 401, 'message': '用户未登录'})
|
||||
user = request.user
|
||||
data = json.loads(request.body)
|
||||
|
||||
print(data)
|
||||
# 获取参数
|
||||
pid = data.get('pid')
|
||||
motion = int(data.get('motion', 5)) # 视频丰富度
|
||||
pid = data.get('task_id')
|
||||
motion = 6 # 视频丰富度
|
||||
|
||||
# 获取当前视频生成记录
|
||||
video_generation = VideoGeneration.objects.get(pid=pid)
|
||||
@ -284,8 +353,8 @@ def extend_video(request):
|
||||
"uuid": pid, # 视频的 UUID
|
||||
"motion": motion, # 视频丰富度
|
||||
"seed": 0, # 默认 seed 为 0
|
||||
"upscale": False, # 默认开启 upscale
|
||||
"interpolate": False, # 默认开启 interpolate
|
||||
"upscale": True, # 默认开启 upscale
|
||||
"interpolate": True, # 默认开启 interpolate
|
||||
"callback_url": "https://www.typeframes.ai/api/callback/"
|
||||
}
|
||||
print(f"extend_video 请求体: {payload}")
|
||||
|
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.
@ -5,14 +5,16 @@ from django.views.decorators.csrf import csrf_exempt
|
||||
from datetime import datetime
|
||||
from .models import Order, Plan, User
|
||||
import json
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
from .base import logger
|
||||
|
||||
def get_paypal_access_token():
|
||||
"""获取 PayPal 访问令牌"""
|
||||
print("正在获取 PayPal 访问令牌...")
|
||||
url = f"https://api.{settings.PAYPAL_MODE}.paypal.com/v1/oauth2/token"
|
||||
|
||||
# 根据配置文件选择 PayPal URL
|
||||
paypal_base_url = "https://api.sandbox.paypal.com" if settings.PAYPAL_MODE == 'sandbox' else "https://api.paypal.com"
|
||||
url = f"{paypal_base_url}/v1/oauth2/token"
|
||||
|
||||
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
|
||||
@ -30,12 +32,13 @@ def get_paypal_access_token():
|
||||
|
||||
if response.status_code == 200:
|
||||
access_token = response.json().get('access_token')
|
||||
logger.info(f"[支付执行] 获取的访问令牌: {access_token}")
|
||||
print(f"获取的访问令牌: {access_token}")
|
||||
return access_token
|
||||
else:
|
||||
logger.error(f"[支付执行] 获取 PayPal 访问令牌失败: {response.text}")
|
||||
print(f"获取 PayPal 访问令牌失败: {response.text}")
|
||||
return None
|
||||
|
||||
@csrf_exempt
|
||||
def create_paypal_payment(request):
|
||||
"""创建 PayPal 支付"""
|
||||
@ -66,7 +69,7 @@ def create_paypal_payment(request):
|
||||
return JsonResponse({"code": 500, "message": "无法获取支付访问令牌", "data": {}})
|
||||
|
||||
# 配置支付请求
|
||||
url = f"https://api.{settings.PAYPAL_MODE}.paypal.com/v1/payments/payment"
|
||||
url = f"https://api.paypal.com/v1/payments/payment"
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": f"Bearer {access_token}"
|
||||
@ -143,27 +146,50 @@ def create_paypal_payment(request):
|
||||
else:
|
||||
return JsonResponse({"code": 405, "message": "方法不允许", "data": {}})
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
def execute_paypal_payment(request):
|
||||
"""执行 PayPal 支付"""
|
||||
if request.method == 'POST':
|
||||
try:
|
||||
logger.info("[支付执行] 接收到来自前端的 POST 请求,开始处理支付...")
|
||||
|
||||
# 解析请求体
|
||||
data = json.loads(request.body)
|
||||
payment_id = data.get('paymentId')
|
||||
payer_id = data.get('PayerID')
|
||||
|
||||
logger.info(f"[支付执行] 请求内容: paymentId={payment_id}, PayerID={payer_id}")
|
||||
print(f"请求内容: paymentId={payment_id}, PayerID={payer_id}")
|
||||
|
||||
if not payment_id or not payer_id:
|
||||
logger.error("[支付执行] 缺少支付ID或付款人ID")
|
||||
return JsonResponse({"code": 400, "message": "缺少支付ID或付款人ID", "data": {}})
|
||||
|
||||
# 获取订单信息
|
||||
try:
|
||||
order = Order.objects.get(order_id=payment_id)
|
||||
logger.info(f"[支付执行] 获取到的订单信息: {order}")
|
||||
except Order.DoesNotExist:
|
||||
logger.error("[支付执行] 订单不存在")
|
||||
return JsonResponse({"code": 400, "message": "订单不存在", "data": {}})
|
||||
|
||||
# 检查订单是否已经支付
|
||||
if order.status == 'completed':
|
||||
logger.info(f"[支付执行] 订单 {payment_id} 已支付,无需再次执行")
|
||||
print(f"订单 {payment_id} 已支付,无需再次执行")
|
||||
return JsonResponse({"code": 400, "message": "订单已支付", "data": {}})
|
||||
# 获取PayPal访问令牌
|
||||
|
||||
# 获取 PayPal 访问令牌
|
||||
access_token = get_paypal_access_token()
|
||||
if not access_token:
|
||||
logger.error("[支付执行] 无法获取支付访问令牌")
|
||||
return JsonResponse({"code": 500, "message": "无法获取支付访问令牌", "data": {}})
|
||||
logger.info(f"[支付执行] 获取到的 PayPal 访问令牌: {access_token}")
|
||||
|
||||
# 执行支付确认请求
|
||||
url = f"https://api.{settings.PAYPAL_MODE}.paypal.com/v1/payments/payment/{payment_id}/execute"
|
||||
# 设置 PayPal API 请求的 URL 和头部信息
|
||||
paypal_base_url = "https://api.sandbox.paypal.com" if settings.PAYPAL_MODE == 'sandbox' else "https://api.paypal.com"
|
||||
url = f"{paypal_base_url}/v1/payments/payment/{payment_id}/execute"
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": f"Bearer {access_token}"
|
||||
@ -172,28 +198,68 @@ def execute_paypal_payment(request):
|
||||
"payer_id": payer_id
|
||||
}
|
||||
|
||||
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:
|
||||
try:
|
||||
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
|
||||
user.points += order.plan.credits_per_month
|
||||
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()
|
||||
|
||||
return JsonResponse({"code": 200, "message": "支付成功", "data": {}})
|
||||
except Order.DoesNotExist:
|
||||
return JsonResponse({"code": 400, "message": "订单不存在", "data": {}})
|
||||
# 打印用户当前积分、购买的套餐和增加的积分
|
||||
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": {}})
|
||||
|
@ -5,14 +5,12 @@ from django.views.decorators.csrf import csrf_exempt
|
||||
from datetime import datetime
|
||||
from .models import Order
|
||||
import json
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
from .base import logger
|
||||
|
||||
def get_paypal_access_token():
|
||||
"""获取 PayPal 访问令牌"""
|
||||
print("正在获取 PayPal 访问令牌...")
|
||||
url = f"https://api.{settings.PAYPAL_MODE}.paypal.com/v1/oauth2/token"
|
||||
url = f"https://api.paypal.com/v1/oauth2/token"
|
||||
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
|
||||
@ -30,18 +28,24 @@ def get_paypal_access_token():
|
||||
|
||||
if response.status_code == 200:
|
||||
access_token = response.json().get('access_token')
|
||||
logger.info(f"获取的访问令牌: {access_token}")
|
||||
print(f"获取的访问令牌: {access_token}")
|
||||
return access_token
|
||||
else:
|
||||
logger.error(f"获取 PayPal 访问令牌失败: {response.text}")
|
||||
print(f"获取 PayPal 访问令牌失败: {response.text}")
|
||||
return None
|
||||
|
||||
|
||||
def verify_paypal_webhook(headers, body):
|
||||
"""使用 PayPal API 验证 Webhook 签名"""
|
||||
logger.info("验证 PayPal Webhook 签名...")
|
||||
print("验证 PayPal Webhook 签名...")
|
||||
verify_url = f"https://api.{settings.PAYPAL_MODE}.paypal.com/v1/notifications/verify-webhook-signature"
|
||||
verify_url = f"https://api.paypal.com/v1/notifications/verify-webhook-signature"
|
||||
|
||||
auth_token = get_paypal_access_token()
|
||||
if not auth_token:
|
||||
logger.error("无法获取 PayPal 访问令牌,无法验证 Webhook 签名")
|
||||
print("无法获取 PayPal 访问令牌,无法验证 Webhook 签名")
|
||||
return False
|
||||
|
||||
@ -61,60 +65,53 @@ def verify_paypal_webhook(headers, body):
|
||||
}
|
||||
|
||||
response = requests.post(verify_url, headers=verify_headers, json=verify_payload)
|
||||
|
||||
if response.status_code == 200 and response.json().get('verification_status') == 'SUCCESS':
|
||||
logger.info("Webhook 签名验证成功")
|
||||
print("Webhook 签名验证成功")
|
||||
return True
|
||||
else:
|
||||
logger.error(f"Webhook 签名验证失败: {response.text}")
|
||||
print(f"Webhook 签名验证失败: {response.text}")
|
||||
return False
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
def paypal_webhook(request):
|
||||
"""PayPal Webhook 处理函数,用于接收和处理 PayPal 异步通知"""
|
||||
def execute_paypal_payment(payment_id, payer_id):
|
||||
"""执行 PayPal 支付"""
|
||||
try:
|
||||
print("接收到 PayPal Webhook 请求...")
|
||||
headers = request.headers
|
||||
payload = json.loads(request.body)
|
||||
logger.info(f"回调接收到 开始执行支付,订单ID: {payment_id}, 付款人ID: {payer_id}")
|
||||
order = Order.objects.get(order_id=payment_id)
|
||||
|
||||
# 验证 Webhook 签名
|
||||
if not verify_paypal_webhook(headers, request.body):
|
||||
return JsonResponse({"code": 400, "message": "Webhook 签名验证失败", "data": {}})
|
||||
|
||||
event_type = payload.get('event_type')
|
||||
|
||||
# 打印接收到的 Webhook payload 以供调试
|
||||
print(f"接收到 PayPal Webhook 事件: {event_type}")
|
||||
print(f"Webhook payload: {json.dumps(payload, indent=2)}")
|
||||
|
||||
# 处理不同类型的事件
|
||||
if event_type == 'PAYMENT.SALE.COMPLETED':
|
||||
sale_id = payload['resource'].get('id')
|
||||
parent_payment = payload['resource'].get('parent_payment') # 使用parent_payment作为订单ID
|
||||
if parent_payment:
|
||||
try:
|
||||
order = Order.objects.get(order_id=parent_payment)
|
||||
|
||||
# 检查订单状态,防止重复更新
|
||||
if order.status == 'completed':
|
||||
print(f"订单 {parent_payment} 已经完成,不重复更新")
|
||||
return JsonResponse({"code": 200, "message": "订单已处理", "data": {}})
|
||||
logger.info(f"订单 {payment_id} 已经支付,不需要再次执行支付")
|
||||
print(f"订单 {payment_id} 已经支付,不需要再次执行支付")
|
||||
return JsonResponse({"code": 400, "message": "订单已支付", "data": {}})
|
||||
|
||||
# 再次向 PayPal 查询订单状态,确保支付确实完成
|
||||
# 获取 PayPal 访问令牌
|
||||
access_token = get_paypal_access_token()
|
||||
if not access_token:
|
||||
print("无法获取 PayPal 访问令牌,无法验证订单状态")
|
||||
logger.error("无法获取支付访问令牌")
|
||||
return JsonResponse({"code": 500, "message": "无法获取支付访问令牌", "data": {}})
|
||||
|
||||
payment_details_url = f"https://api.{settings.PAYPAL_MODE}.paypal.com/v1/payments/payment/{parent_payment}"
|
||||
# 根据配置文件选择 PayPal URL
|
||||
paypal_base_url = "https://api.sandbox.paypal.com" if settings.PAYPAL_MODE == 'sandbox' else "https://api.paypal.com"
|
||||
url = f"{paypal_base_url}/v1/payments/payment/{payment_id}/execute"
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": f"Bearer {access_token}"
|
||||
}
|
||||
payment_details_response = requests.get(payment_details_url, headers=headers)
|
||||
payload = {
|
||||
"payer_id": payer_id
|
||||
}
|
||||
|
||||
if payment_details_response.status_code == 200:
|
||||
payment_details = payment_details_response.json()
|
||||
if payment_details['state'] == 'approved':
|
||||
logger.info(f"执行 PayPal 支付请求, URL: {url}, 请求体: {payload}")
|
||||
print(f"执行 PayPal 支付请求, URL: {url}, 请求体: {payload}")
|
||||
|
||||
response = requests.post(url, headers=headers, json=payload)
|
||||
|
||||
# 处理支付执行结果
|
||||
if response.status_code == 200:
|
||||
order.status = 'completed'
|
||||
order.updated_at = datetime.now()
|
||||
order.save()
|
||||
@ -124,22 +121,96 @@ def paypal_webhook(request):
|
||||
user.points += order.plan.credits_per_month
|
||||
user.save()
|
||||
|
||||
print(f"订单 {parent_payment} 状态更新为 'completed' 并已更新用户积分")
|
||||
logger.info(f"订单 {payment_id} 支付成功,用户积分已更新: {order.plan.credits_per_month}")
|
||||
print(f"订单 {payment_id} 支付成功,用户积分已更新: {order.plan.credits_per_month}")
|
||||
return JsonResponse({"code": 200, "message": "支付成功", "data": {}})
|
||||
else:
|
||||
print(f"支付未完成,状态: {payment_details['state']}")
|
||||
else:
|
||||
print(f"查询支付状态失败: {payment_details_response.text}")
|
||||
return JsonResponse({"code": 500, "message": "查询支付状态失败", "data": {}})
|
||||
logger.error(f"支付执行失败: {response.text}")
|
||||
print(f"支付执行失败: {response.text}")
|
||||
return JsonResponse({"code": 400, "message": "支付执行失败", "data": response.json()})
|
||||
|
||||
except Order.DoesNotExist:
|
||||
logger.error(f"订单 {payment_id} 不存在")
|
||||
print(f"订单 {payment_id} 不存在")
|
||||
return JsonResponse({"code": 400, "message": "订单不存在", "data": {}})
|
||||
except Exception as e:
|
||||
logger.error(f"支付执行过程中发生异常: {str(e)}")
|
||||
print(f"支付执行过程中发生异常: {str(e)}")
|
||||
return JsonResponse({"code": 500, "message": f"支付执行过程中发生异常: {str(e)}", "data": {}})
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
def paypal_webhook(request):
|
||||
"""PayPal Webhook 处理函数,用于接收和处理 PayPal 异步通知"""
|
||||
try:
|
||||
logger.info("接收到 PayPal Webhook 请求...")
|
||||
print("接收到 PayPal Webhook 请求...")
|
||||
|
||||
headers = request.headers
|
||||
payload = json.loads(request.body)
|
||||
|
||||
# 验证 Webhook 签名
|
||||
if not verify_paypal_webhook(headers, request.body):
|
||||
logger.error("Webhook 签名验证失败")
|
||||
return JsonResponse({"code": 400, "message": "Webhook 签名验证失败", "data": {}})
|
||||
|
||||
event_type = payload.get('event_type')
|
||||
|
||||
# 打印接收到的 Webhook payload 以供调试
|
||||
logger.info(f"接收到 PayPal Webhook 事件: {event_type}")
|
||||
print(f"接收到 PayPal Webhook 事件: {event_type}")
|
||||
logger.info(f"Webhook payload: {json.dumps(payload, indent=2)}")
|
||||
|
||||
# 处理不同类型的事件
|
||||
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':
|
||||
sale_id = payload['resource'].get('id')
|
||||
parent_payment = payload['resource'].get('parent_payment')
|
||||
if parent_payment:
|
||||
try:
|
||||
@ -147,19 +218,20 @@ def paypal_webhook(request):
|
||||
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": {}})
|
||||
else:
|
||||
print("Webhook payload 中缺少 parent_payment")
|
||||
return JsonResponse({"code": 400, "message": "Webhook payload 中缺少 parent_payment", "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:
|
||||
print(f"处理 PayPal Webhook 时发生错误: {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)
|
||||
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:
|
||||
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')
|
||||
email = social_account.extra_data.get('email')
|
||||
username = social_account.extra_data.get('name')
|
||||
print(f'从 social_account 获取的 google_id: {google_id}, email: {email}, username: {username}')
|
||||
|
||||
google_id = social_account.extra_data['sub'] # 使用 'sub' 字段
|
||||
email = social_account.extra_data['email']
|
||||
username = social_account.extra_data['name']
|
||||
if not google_id:
|
||||
# 如果 google_id 为空,不要继续创建用户,记录日志或处理错误
|
||||
print('google_id 为空,终止处理')
|
||||
return
|
||||
|
||||
# 优化:根据 google_id 和 email 双重检查用户是否已存在
|
||||
try:
|
||||
custom_user = User.objects.get(google_id=google_id)
|
||||
print(f'根据 google_id 找到用户: {custom_user.username}')
|
||||
except User.DoesNotExist:
|
||||
print(f'没有找到 google_id 为 {google_id} 的用户,检查 email: {email}')
|
||||
# 进一步检查是否有相同的 email 用户存在
|
||||
if User.objects.filter(email=email).exists():
|
||||
custom_user = User.objects.get(email=email)
|
||||
print(f'找到 email 为 {email} 的用户: {custom_user.username}')
|
||||
# 如果用户存在但 google_id 不同,更新 google_id
|
||||
custom_user.google_id = google_id
|
||||
custom_user.save()
|
||||
print(f'更新用户的 google_id 为: {google_id}')
|
||||
else:
|
||||
custom_user = User.objects.create(
|
||||
username=username,
|
||||
email=email,
|
||||
google_id=google_id,
|
||||
password_hash='', # Google 登录不需要密码
|
||||
# password_hash='', # Google 登录不需要密码
|
||||
)
|
||||
print(f'创建新用户: {custom_user.username},google_id: {google_id}')
|
||||
UserSource.objects.create(user=custom_user, source='Google')
|
||||
print(f'创建 UserSource 记录,来源为 Google')
|
||||
|
||||
# 更新登录次数和最后登录IP
|
||||
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.last_login_ip = request.META.get('REMOTE_ADDR')
|
||||
custom_user.last_login_ip = ip
|
||||
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:
|
||||
pass
|
||||
print('未找到与用户关联的 Google social_account')
|
||||
|
@ -22,6 +22,7 @@ from .aliyun_sms import send_verification_sms, verify_sms_code
|
||||
# 定义积分奖励值
|
||||
REWARD_POINTS = 50 # 例如奖励50积分
|
||||
|
||||
|
||||
def check_and_reward_points(user, openid):
|
||||
"""
|
||||
根据 openid 查询原系统会员状态,为原系统的用户增加一天会员时长(不论是否为会员)。
|
||||
@ -151,7 +152,7 @@ def send_verification_email_view(request):
|
||||
if request.method == 'POST':
|
||||
try:
|
||||
body = json.loads(request.body)
|
||||
email = body.get('phone_number')
|
||||
email = body.get('email')
|
||||
if not email:
|
||||
return JsonResponse({'code': 400, 'message': '邮箱地址是必须的'})
|
||||
|
||||
@ -193,8 +194,8 @@ def send_verification_sms_view(request):
|
||||
if not phone_number:
|
||||
return JsonResponse({'code': 400, 'message': '手机号码是必须的'})
|
||||
|
||||
sign_name = "福铭科技" # 替换为实际的签名名称
|
||||
template_code = "SMS_299200388" # 替换为实际的短信模板代码
|
||||
sign_name = "光映" # 替换为实际的签名名称
|
||||
template_code = "SMS_473670066" # 替换为实际的短信模板代码
|
||||
|
||||
response = send_verification_sms(phone_number, sign_name, template_code)
|
||||
return JsonResponse(response)
|
||||
@ -379,7 +380,7 @@ def send_verification_code_view(request):
|
||||
if '@' in identifier:
|
||||
response = send_verification_email(identifier)
|
||||
else:
|
||||
response = send_verification_sms(identifier, "福铭科技", "SMS_299200388")
|
||||
response = send_verification_sms(identifier, "光映", "SMS_473670066")
|
||||
|
||||
return JsonResponse(response)
|
||||
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"
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
DEBUG = False
|
||||
|
||||
ALLOWED_HOSTS = ['*']
|
||||
# settings.py
|
||||
@ -63,7 +63,7 @@ AUTHENTICATION_BACKENDS = (
|
||||
'django.contrib.auth.backends.ModelBackend',
|
||||
'allauth.account.auth_backends.AuthenticationBackend',
|
||||
)
|
||||
LOGIN_REDIRECT_URL = '/user/userinfo/' # 登录后重定向的URL
|
||||
LOGIN_REDIRECT_URL = '/create' # 登录后重定向的URL
|
||||
LOGIN_URL = '/'
|
||||
LOGOUT_REDIRECT_URL = '/'
|
||||
|
||||
@ -159,10 +159,10 @@ DATABASES = {
|
||||
{
|
||||
'ENGINE': 'django.db.backends.mysql', # 数据库引擎
|
||||
'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端口
|
||||
'USER': 'admin_data', # 数据库用户名
|
||||
'PASSWORD': 'mPmFz2NeXSYbzrt5', # 数据库密码
|
||||
'PASSWORD': 'kyRz3c3hGMmDADrW', # 数据库密码
|
||||
'OPTIONS': {
|
||||
'charset': 'utf8mb4',
|
||||
'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
|
||||
@ -250,20 +250,19 @@ ALIPAY_PUBLIC_KEY_PRODUCTION_PC = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo
|
||||
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_PUBLIC_KEY_PRODUCTION_MOBILE = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAomw6g4rBmCr/QoX3NI3DVLyDpkaUytZ2uFhdfQaegIDAuUfZfgpTCASlAtO82t8ISAbSOSyp9CUpwdGV4EYOiCBbLxMYB6taaHPiIjJ1zNT1EakJzWgU53hz1AVeABB9kdAvMqSvjH6KLoVupmqm4Li8ZwDW9M2ANAmyDfKgiF0Lt4aUUnaZktoCrTWTkpmtfRZCHNACj851IllvN2wyC4OL7dJq5UzOFxmn07Dy/2z4UAhaaSAyRVawpOui5AIYJTXZERLYL3KMyRnMuZoFq3xltzVTzRPM06nRa9RfeVNVwWVtGBIe/r8tcg5wyhI57KUszGNOmUIm/se6G2lnAQIDAQAB' # 生产环境移动端支付宝公钥
|
||||
|
||||
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
|
||||
|
||||
# PayPal 配置
|
||||
PAYPAL_CLIENT_ID_SANDBOX = 'AfwWNEZE92XpbmoHywwdDEXH2x2Elak1Gxbireb5bv-u17OtKiJUuz7CMLnqayAZkqeU2kGtWXHXcXGS'
|
||||
PAYPAL_SECRET_KEY_SANDBOX = 'ELmuFW7AspHp4km8amEhlM-NB3OGGx_iuqQbntTQ-2RTnJWbxdLTl6xlET1F1ezxSHbU1CUpK0_8ToI3'
|
||||
PAYPAL_CLIENT_ID_PRODUCTION = 'YOUR_PRODUCTION_CLIENT_ID' # 替换为实际的生产环境客户端ID
|
||||
PAYPAL_SECRET_KEY_PRODUCTION = 'YOUR_PRODUCTION_SECRET_KEY' # 替换为实际的生产环境密钥
|
||||
PAYPAL_CLIENT_ID_PRODUCTION = 'Aelz9E_u5mlLP_-8nOGuXS14P-osTWYqxPx8HknC1PNBqRtG_RzAtWblryvr0o8pIyqIomI-2KMFagk2' # 替换为实际的生产环境客户端ID
|
||||
PAYPAL_SECRET_KEY_PRODUCTION = 'EIA_O_JeOWUjolXK3yi4VC88wpcZaIYgQvAPJ251LX_OTsatYzjt_Y2aFKLjXt5fInRkdTfeIbrwlZEh' # 替换为实际的生产环境密钥
|
||||
|
||||
PAYPAL_MODE = 'sandbox' #'sandbox' if DEBUG else 'live' # 根据DEBUG模式选择环境
|
||||
PAYPAL_RETURN_URL = 'https://www.typeframes.ai/user/plan_list/' # 支付成功后跳转的URL
|
||||
PAYPAL_CANCEL_URL = 'https://www.typeframes.ai/user/plan_list/' # 支付取消后跳转的URL
|
||||
PAYPAL_MODE = 'sandbox' if DEBUG else 'live' # 根据DEBUG模式选择环境
|
||||
PAYPAL_RETURN_URL = 'https://www.typeframes.ai/create' # 支付成功后跳转的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]
|
||||
chdir = /app
|
||||
# 项目目录
|
||||
chdir = /www/wwwroot/Ai_Admin
|
||||
|
||||
# 指定项目application
|
||||
module = WebSite.wsgi:application
|
||||
|
||||
# 进程个数
|
||||
processes = 4
|
||||
|
||||
# 线程个数
|
||||
threads = 2
|
||||
|
||||
# 指定启动时的pid文件路径(用于停止服务和重启服务,请勿删除)
|
||||
pidfile = /www/wwwroot/Ai_Admin/uwsgi.pid
|
||||
|
||||
# 指定ip及端口
|
||||
http = 0.0.0.0:3001
|
||||
http=0.0.0.0:3001
|
||||
|
||||
# 启动uwsgi的用户名和用户组
|
||||
uid = root
|
||||
gid = root
|
||||
|
||||
# 启用主进程
|
||||
master = true
|
||||
@ -14,20 +28,18 @@ master = true
|
||||
buffer-size = 32768
|
||||
|
||||
http-timeout = 60
|
||||
|
||||
post-buffering = 8192
|
||||
|
||||
# 后台运行,并输出日志
|
||||
daemonize = /www/wwwroot/Ai_Admin/uwsgi.log
|
||||
|
||||
# 处理 SIGTERM 信号以便优雅地关闭
|
||||
die-on-term = true
|
||||
|
||||
# 处理静态和媒体文件
|
||||
static-map = /static=/app/static
|
||||
static-map = /media=/app/media
|
||||
static-map = /media/avatars=/app/media/avatars
|
||||
static-map = /media/audios=/app/media/audios
|
||||
static-map = /.well-known/acme-challenge/=/app/.well-known/acme-challenge
|
||||
|
||||
# 日志输出到标准输出
|
||||
logger = stdout
|
||||
|
||||
# 启用thunder lock
|
||||
thunder-lock = true
|
||||
# 添加以下配置以处理静态和媒体文件
|
||||
static-map = /static=/www/wwwroot/Ai_Admin/static
|
||||
static-map = /media=/www/wwwroot/Ai_Admin/media
|
||||
static-map = /media/avatars=/www/wwwroot/Ai_Admin/media/avatars
|
||||
static-map = /media/audios=/www/wwwroot/Ai_Admin/media/audios
|
||||
static-map = /.well-known/acme-challenge/=/www/wwwroot/java_node_ssl/.well-known/acme-challenge
|
Loading…
Reference in New Issue
Block a user